Commit graph

4278 commits

Author SHA1 Message Date
Mikael Hugo
de77cf439f fix(tui): error boundary in doRender, extract autonomousStatus, clean parseCellSize
Some checks are pending
CI / detect-changes (push) Waiting to run
CI / docs-check (push) Blocked by required conditions
CI / lint (push) Blocked by required conditions
CI / build (push) Blocked by required conditions
CI / integration-tests (push) Blocked by required conditions
CI / windows-portability (push) Blocked by required conditions
CI / rtk-portability (linux, blacksmith-4vcpu-ubuntu-2404) (push) Blocked by required conditions
CI / rtk-portability (macos, macos-15) (push) Blocked by required conditions
CI / rtk-portability (windows, blacksmith-4vcpu-windows-2025) (push) Blocked by required conditions
- doRender() now catches render errors and emits a fallback line
- autonomousStatus ANSI formatting extracted to renderAutonomousStatus()
  with named color constants instead of raw escape strings
- parseCellSizeResponse extracted to pure function with proper validation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 12:41:47 +02:00
Mikael Hugo
2d34d3a386 fix(web): resolve ESLint regressions from eslint-config-next upgrade
- Escape unescaped entities (react/no-unescaped-entities) in step-remote,
  step-welcome, projects-view, settings-panels
- Add targeted eslint-disable-next-line for react-hooks/set-state-in-effect
  on established async-fetch and prop-sync patterns in useEffect bodies:
  chat-mode, file-content-viewer, files-view, step-dev-root, projects-view,
  settings-panels, update-banner, visualizer-view, carousel, use-mobile
- Add targeted eslint-disable-next-line for react-hooks/purity on Date.now()
  display timestamps in streaming chat messages (chat-mode)
- Remove now-unused eslint-disable directives (projects-view, settings-panels)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 12:18:58 +02:00
Mikael Hugo
b0a8f32a10 feat(tui): wire Ink bridge into TUI.start() and stop()
- TUI.useInk() opts into Ink-backed rendering (call before start())
- In start(): if _useInk || process.stdout.isTTY, mount Ink renderer via
  startInkRenderer() and skip the legacy differential render path entirely
- In stop(): unmount Ink handle and return early; legacy terminal cleanup
  (cursor repositioning, showCursor, terminal.stop) is skipped since Ink
  handles terminal restoration itself
- Passes this.render()/invalidate() via a plain Component wrapper to avoid
  the private handleInput TypeScript conflict
- Two new contract tests: useInk() flag and stop() Ink handle teardown
- 80/80 tests pass; legacy path unchanged for non-TTY (CI/tests)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 12:15:09 +02:00
Mikael Hugo
4e97058d7e feat(tui): add Ink bridge for gradual migration from custom renderer
Install ink@7.0.2 + react@19.2.6. Add JSX/react-jsx support to
packages/tui tsconfig. Create ink-bridge.tsx: LegacyComponentView wraps
existing Component objects as React nodes, startInkRenderer drives the
Ink render loop around any legacy Component tree.

Exports startInkRenderer from @singularity-forge/tui public API.
All 78 existing tui tests pass; 3 new ink-bridge tests added.

This is the infrastructure step for migrating components one-by-one from
the custom differential renderer to native Ink React components, without
breaking interactive mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 12:10:39 +02:00
Mikael Hugo
280303ef9a fix(lint): reformat 6 files touched during web dep upgrade
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 12:10:10 +02:00
Mikael Hugo
d447095bd7 build: switch full build pipeline to TypeScript 7 native (tsgo)
Replace tsc with tsgo in all build scripts — 5.6x faster emit.
tsgo has full emit parity for this codebase (NodeNext, ES2022, strict).

- build:core: tsc → tsgo (root tsconfig.json)
- copy-resources.cjs: typescript/bin/tsc → @typescript/native-preview/bin/tsgo.js
- All workspace packages (agent-core, ai, coding-agent, daemon,
  google-gemini-cli-provider, native, rpc-client, tui): tsc → tsgo

Benchmarks (root project):
  tsc --project tsconfig.json: 7.7s
  tsgo --project tsconfig.json: 1.4s  (5.6x faster)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:58:58 +02:00
Mikael Hugo
e09eb8f899 build: add TypeScript 7 (native preview) for fast type checking
- Remove vestigial experimentalDecorators/emitDecoratorMetadata from all
  package tsconfigs (no actual decorators in source — flags were from
  pi-mono vendor copy)
- Add @typescript/native-preview for 8-10x faster type checking (measured
  4.6x on this repo: tsc 6.5s vs tsgo 1.4s)
- Fix tsconfig.extensions.json: remove baseUrl (removed in tsgo/TS7) and
  use relative paths in paths mappings — compatible with both tsc and tsgo
- Add typecheck/typecheck:extensions scripts using tsgo

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:53:22 +02:00
Mikael Hugo
e50d96e1f8 chore(web): upgrade all dependencies to latest stable
- @hookform/resolvers 3.10.0 → 5.2.2
- @tailwindcss/postcss 4.2.1 → 4.3.0
- @types/node 24.12.2 → 25.6.2
- @uiw/codemirror-* 4.25.8 → 4.25.9
- autoprefixer 10.4.27 → 10.5.0
- esbuild 0.27.4 → 0.28.0
- eslint 9.39.4 → 9.x (pinned; eslint 10 incompatible with eslint-config-next)
- eslint-config-next 16.2.3 → 16.2.6
- lucide-react 0.564.0 → 1.14.0
- motion 12.36.0 → 12.38.0
- next 16.2.3 → 16.2.6
- postcss 8.5.8 → 8.5.14
- react/react-dom 19.2.4 → 19.2.6
- react-day-picker 9.13.2 → 10.0.0
- react-hook-form 7.71.2 → 7.75.0
- react-resizable-panels 2.1.9 → 4.11.0
- recharts 2.15.0 → 3.8.1
- sonner 1.7.4 → 2.0.7
- tailwindcss 4.2.1 → 4.3.0
- tw-animate-css 1.3.3 → 1.4.0
- typescript 5.7.3 → 6.0.3
- zod 3.25.76 → 4.4.3

Breaking changes fixed:
- react-resizable-panels v4: PanelGroup→Group, PanelResizeHandle→Separator
- react-day-picker v10: ClassNames.table renamed to month_grid
- recharts v3: TooltipContentProps/DefaultLegendContentProps type changes,
  DataKey type for key prop
- shiki: cast createHighlighter promise to local ShikiHighlighter type
- voice/route.ts: pass requestUrl through buildDigitsResponse
- pty-chat-parser.ts: declare _lastInputAt private field
- sf-workspace-store.tsx: fix stale pi-coding-agent import path,
  add import for locally-used workspace types

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:52:54 +02:00
Mikael Hugo
cab8b5decc refactor: strip internal pi branding (Phase 2A)
- CURSOR_MARKER: \x1b_pi:c\x07 → \x1b_sf:c\x07
- process.title: "pi" → "sf"
- PiManifest → SFManifest (with pi field backwards compat)
- readPiManifest → readSFManifest (loader.ts and package-manager.ts)
- readPiManifestFile → readSFManifestFile (package-manager.ts)
- .pi/skills → .sf/skills (keeps .pi/skills for backwards compat)
- User-facing path strings updated to .sf/ where appropriate
- ARCHITECTURE.md: "Pi coding-agent extension" → "coding-agent extension"
- Temp editor file: pi-editor-*.pi.md → sf-editor-*.sf.md
- Test fixtures: appName "pi" → "sf", pi manifest field → sf

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:50:55 +02:00
Mikael Hugo
02a4339a51 refactor: rename pi-* packages to forge-native names (Phase 1)
Rename all four packages/pi-* directories to forge-native names,
stripping the 'pi' identity and establishing forge's own:

- packages/pi-coding-agent → packages/coding-agent
- packages/pi-ai → packages/ai
- packages/pi-agent-core → packages/agent-core
- packages/pi-tui → packages/tui

Package names updated:
- @singularity-forge/pi-coding-agent → @singularity-forge/coding-agent
- @singularity-forge/pi-ai → @singularity-forge/ai
- @singularity-forge/pi-agent-core → @singularity-forge/agent-core
- @singularity-forge/pi-tui → @singularity-forge/tui

All import references, bare string references, path references,
internal variable names (_bundledPi*), and dist files updated.
@mariozechner/pi-* third-party compat aliases preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:28:01 +02:00
Mikael Hugo
6725a55591 feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
  inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
  pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
  API route pattern, test instructions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
Mikael Hugo
05953e9599 fix(lint): restore 0 Biome diagnostics and fix web-mode-onboarding test timeout
- Remove/prefix unused imports and variables across 11 src/ files to clear
  74 diagnostics introduced by 37 subsequent commits since run #3
- Fix pre-existing timeout in web-mode-onboarding integration test:
  - Add timeoutMs: 120_000 to launchPackagedWebHost call (was unbounded)
  - Raise AbortSignal.timeout on simple fetches 10s → 30s (under parallel load)
  - Raise overall test timeout 180s → 420s (budget: 120+60+30+30+120+30=390s)
- Log autoresearch run #4 and update lessons in autoresearch.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:01:43 +02:00
Mikael Hugo
b2bcb922de sf snapshot: uncommitted changes after 37m inactivity 2026-05-10 09:56:56 +02:00
Mikael Hugo
7e8e3aa846 sf snapshot: pre-dispatch, uncommitted changes after 30m inactivity 2026-05-10 09:19:51 +02:00
Mikael Hugo
e58e138457 feat(db): DB-only UAT verdicts — backfill on open, write on ASSESSMENT save, no file fallbacks
- sf-db.js: add backfillUatVerdicts(basePath) that scans ASSESSMENT/UAT_RESULT
  files for slices with no uat_verdict in DB and populates them on open
- dynamic-tools.js: call backfillUatVerdicts after openDatabase succeeds so
  all 3 repos with existing verdict files are covered on next launch
- workflow-tool-executors.js: call setSliceUatVerdict when saving ASSESSMENT
  at slice scope so future verdicts are written directly to DB
- workflow-helpers.js: remove all file fallbacks from checkNeedsRunUat;
  verdict check is DB-only (backfill guarantees DB is populated on open)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 08:49:45 +02:00
Mikael Hugo
6c113be473 fix(uat): treat ASSESSMENT file with verdict as completed UAT result
checkNeedsRunUat only checked for UAT_RESULT file, but the autonomous
runner writes ASSESSMENT files. This caused run-uat to dispatch 5x with
no verdict when only an ASSESSMENT (with verdict: PASS) existed.

Now ASSESSMENT file with any verdict counts as a completed UAT result,
stopping the infinite dispatch loop.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 08:32:21 +02:00
Mikael Hugo
d8c687702b fix(auto): cache lastCommandCtx from any SF command so Ctrl+Y works immediately
Previously required /autonomous first. Now any slash command (/next, /chat,
/clear etc.) caches the ExtensionCommandContext, so Ctrl+Y YOLO shortcut
works on first press after any command interaction.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 08:10:27 +02:00
Mikael Hugo
d56e68c789 fix(auto): revert YOLO shortcut to ctrl+y
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:59:10 +02:00
Mikael Hugo
60ee46aebb fix(auto): cache lastCommandCtx to survive shortcut-handler restarts
Shortcut handlers (registerShortcut) receive ExtensionContext which has
no newSession(). This caused autonomous mode started via Ctrl+Y to
always crash with 'newSession is not a function'.

- AutoSession.lastCommandCtx: new field that persists across stopAuto/reset
  so shortcut handlers can fall back to the last valid command context
- startAuto(): cache valid command ctx; fall back and notify user if ctx
  has no newSession; return early with actionable message if no cache yet
- dispatchHookUnit(): same guard — resolve hookCtx before s.cmdCtx = ctx
- run-unit.js: last-resort guard before newSession() call returns clean
  error category instead of TypeError
- steerable-autonomous-extension.js: rename ctrl+y → ctrl+alt+y to avoid
  conflict with terminal yank built-in

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:56:31 +02:00
Mikael Hugo
529138db9a sf snapshot: uncommitted changes after 33m inactivity 2026-05-10 07:54:07 +02:00
Mikael Hugo
7085ad850d refactor(tools): remove sf_ prefix from all remaining tool names
plan_milestone, plan_slice, plan_task, complete_task, complete_slice,
complete_milestone, skip_slice, replan_slice, reassess_roadmap,
validate_milestone, save_requirement, update_requirement, milestone_status

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:20:56 +02:00
Mikael Hugo
e7bd6a76b9 refactor(tools): improve description fields to be action-oriented and agent-facing
Rewrite all 13 renamed tool descriptions to follow Copilot tool conventions:
- Imperative verb opening
- One sentence on what it returns
- One sentence on when to use it
- No internal jargon or SF-specific acronyms

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:13:59 +02:00
Mikael Hugo
ac371926cb refactor(tools): rename SF tools to cleaner action-oriented names
Align tool names with Copilot coding agent conventions:
- sf_exec → run_command
- sf_exec_search → read_output
- sf_resume → resume_agent
- capture_thought → log_reasoning
- sf_log_judgment → log_decision
- sf_self_report → report_issue
- sf_self_feedback_resolve → resolve_issue
- sf_save_gate_result → record_gate
- sf_autonomous_checkpoint → checkpoint
- sf_milestone_generate_id → new_milestone_id
- sf_graph → memory_graph
- memory_query → memory_search
- sf_retrieval_evidence → search_evidence

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:10:41 +02:00
Mikael Hugo
1322bc7d9a feat: implement Copilot coding agent lessons in SF
- fix(compaction): tokensBefore undefined crash on reload
  compaction-orchestrator now falls back to preparation.totalTokens when
  extension returns tokensBefore: undefined; compaction-summary-message
  guards with ?? 0 defensively

- feat(exec): inline truncation notice in sf_exec digest
  appends [stdout truncated — read full output: <path>] when
  stdout_truncated=true so agent knows to use sf_exec_search

- feat(exec): wire onUpdate progress for sf_exec
  calls onUpdate before execution starts with status/command so TUI
  shows live feedback during long-running commands

- feat(security): prompt injection defense for external content
  new sanitize-external-content.js utility: strips HTML comments,
  detects 15 injection patterns (instruction override, role reassignment,
  fake system messages, encoded payloads); wired into exec-tool digest

- feat(tools): sf_session_todo tool (persisted cross-compaction)
  add/check/list ops; persists to .sf/session_todo.json; pending todos
  injected into compaction summary block for context continuity

- feat(hooks): shell hooks surface (.sf/hooks/pre-tool/*.sh, post-tool/*.sh)
  pre-tool hooks block tool execution (exit≠0 = block with stdout reason)
  post-tool hooks fire-and-forget; JSON context piped to stdin; 5s timeout

- fix(db): WAL autocheckpoint disabled to prevent corruption
  PRAGMA wal_autocheckpoint=0 in initSchema(); explicit checkpointWal()
  after successful finalize verification — the only safe checkpoint point

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 07:01:28 +02:00
Mikael Hugo
20c0d74106 sf snapshot: pre-dispatch, uncommitted changes after 31m inactivity 2026-05-10 06:26:32 +02:00
Mikael Hugo
074dab5644 sf snapshot: uncommitted changes after 59m inactivity 2026-05-10 05:55:06 +02:00
Mikael Hugo
97619cbc74 fix: resolve 3 test failures and 1 pre-existing code bug
- unit-runtime: fall back to STATE.md for nextActionAdvanced when DB is
  unavailable (restores test compat for reconcileDurableCompleteUnitRuntime-
  Records; DB path still preferred in production)
- browser-slash-command-dispatch: remove 'stop' from SF_PASSTHROUGH_COMMANDS
  so /stop correctly returns { kind: 'reject' } in browser mode (was falling
  through to prompt/rpc instead of builtin-reject)
- bg-events: export MAX_PENDING_ALERTS so process-manager can re-export it;
  satisfies session-memory-leaks contract test
- commands-handlers: guard effectiveScope assignment — only use requestedScope
  when mode=audit AND requestedScope is truthy (avoids undefined propagation)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 04:55:56 +02:00
Mikael Hugo
be785ea13f fix(tui): restore auto mode bottom banner
Remove setFooter(hideFooter) calls in auto-start.js and auto.js that were
overriding the sf-tui footer with a near-invisible stub. The sf-tui footer
already checks isAutoActive() and routes to renderAutoFooter — no override
needed. Also remove now-unused hideFooter import from auto.js.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 04:33:54 +02:00
Mikael Hugo
32d2faac50 chore: update metrics db wal/shm state
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 04:29:28 +02:00
Mikael Hugo
01d58c570d sf snapshot: uncommitted changes after 36m inactivity 2026-05-10 04:27:43 +02:00
Mikael Hugo
1a0222fc71 fix(uok): reclassify 'tool unavailable' when checkpoint tool IS registered
The repair loop was classifying agent reports of 'tool unavailable' as
'checkpoint-tool-unavailable' even when sf_autonomous_checkpoint IS
registered in the manifest. This caused a self-referential loop: the
repair prompt re-requested the same tool call, the agent re-reported
unavailability, and the cycle repeated (4 repair attempts).

Fix: before classifying as 'checkpoint-tool-unavailable', verify the tool
is in the manifest. If it IS registered, reclassify as
'mentioned-checkpoint-without-tool' — the tool exists, the agent just
didn't call it. Also added existsSync to the ES module fs import in
autonomous-solver.js.

Test: new case in autonomous-solver.test.mjs verifies the reclassification
when tool IS in manifest.
2026-05-10 03:51:25 +02:00
Mikael Hugo
6b7d327672 sf snapshot: uncommitted changes after 30m inactivity 2026-05-10 03:21:24 +02:00
Mikael Hugo
1a681caa86 fix(auto): repair retries reuse session context instead of starting cold
When the autonomous solver fails to produce a checkpoint and enters the
repair loop, subsequent retries previously called newSession() each time,
wiping the conversation history. The agent restarted cold with no memory
of what it had tried, what tools it had called, or why it failed — making
meaningful repair nearly impossible.

This change adds a keepSession option to runUnit(). When true, the
newSession() call and session-switch guard logic are skipped; the repair
prompt is sent as a follow-up in the existing conversation. The agent can
now see its prior tool calls, file reads, and failure context when deciding
how to fix the issue.

Policy:
- First attempt at each unit: keepSession=false (clean session, correct
  for independent slice boundaries — system prompt carries project state)
- Repair retries within the same unit: keepSession=true (agent carries
  full context of what it already tried)
- Next unit after success/failure: keepSession=false (clean boundary)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 02:50:57 +02:00
Mikael Hugo
b464f2a78e fix: auto-fallback to ready provider instead of stopping autonomous mode
When the selected model's provider is not request-ready:
1. Pre-flight check before runUnit: find any ready provider, switch to it
   and continue. Only stop if no ready provider exists.
2. Post-runUnit cancelled handler: same logic — reselect + return 'continue'
   instead of silently breaking.
3. Both paths now emit a visible ctx.ui.notify so the user can see what
   happened ('provider X not ready — retrying with Y/model').

Previously: cancelled instantly, all 4 repair attempts also cancelled,
paused with misleading solver-missing-checkpoint and no user notification.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 02:33:23 +02:00
Mikael Hugo
7c970088f1 fix: skip missing-checkpoint repair loop when runUnit is cancelled
When runUnit() returns status='cancelled' (provider not ready, session
failed, timeout), there is no checkpoint to repair. Previously the code
called assessAutonomousSolverTurn() which saw no checkpoint and entered
the 4-attempt repair loop — all of which also cancelled instantly,
burning retries before pausing with a misleading solver-missing-checkpoint
reason instead of surfacing the real provider/session error.

Now: cancelled result short-circuits to { action: 'none' }, skipping the
repair loop and falling through to the existing cancelled handler which
correctly surfaces provider-not-ready, timeout, and session-failed errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 02:29:41 +02:00
Mikael Hugo
d6bd49d0b6 fix: sfdb-doctor agent partial - lazy imports in agent-end-recovery, db-tools uses milestone-ids.js
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 02:18:55 +02:00
Mikael Hugo
a3f2479a4c fix: remove stale M001/M002 milestone dirs; fix dispatch-guard circular dep; fix telemetry normalization
- Remove stale .sf/milestones/M001/ and M002/ (not in DB, were blocking dispatch)
- dispatch-guard.js: import findMilestoneIds from milestone-ids.js directly (not
  via guided-flow.js, which is in the circular-dep cluster)
- auto.js: normalize 'Cannot dispatch' → prior-slice-blocker, 'SF resources updated'
  → resources-stale, 'Stuck:' → stuck in telemetry (was silently bucketing as 'other')

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 02:12:13 +02:00
Mikael Hugo
ea360f6ad2 feat: add circular dep detection tool + fix duplicate milestone dirs + fix metrics NULL
- Add scripts/check-circular-deps.mjs using madge; npm run check:circular
  and check:circular:ext scan src/ and the SF extension respectively
- findMilestoneIds() is now DB-first: reads from milestones table when DB is
  open so stale/duplicate filesystem dirs (M001/ and M001-6377a4/) are never
  returned; falls back to fs scan only during early bootstrap
- milestone-id-utils.js was a stale duplicate; replaced with re-exports from
  canonical milestone-ids.js
- metrics-central.js: guard null/undefined counter/gauge/histogram values
  with ?? 0 to prevent NOT NULL constraint failure on metrics.value

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 01:56:08 +02:00
Mikael Hugo
15185c2e7d sf snapshot: uncommitted changes after 60m inactivity 2026-05-10 01:29:08 +02:00
Mikael Hugo
f66555456f sf snapshot: uncommitted changes after 72m inactivity 2026-05-10 00:28:55 +02:00
Mikael Hugo
6f174cabc1 sf snapshot: uncommitted changes after 59m inactivity 2026-05-09 23:16:14 +02:00
Mikael Hugo
705f9e2ba1 fix: queue user prompt as followUp when system turn is streaming
When the agent is already streaming (system-triggered turn, e.g. autonomous
dispatch at startup) and the user sends a message without an explicit
streamingBehavior, default to followUp instead of steer.

Steer injects mid-stream into the current turn. FollowUp queues the
message as a clean new turn after the system work finishes — which is
what the user expects when they type their first message at startup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 22:17:09 +02:00
Mikael Hugo
c391abe08d fix: remove internal API names from user-facing busy-agent error messages
Replace 'Use steer() or followUp()' with plain language guidance.
Users see this when sending a message while the agent is still working.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 22:04:34 +02:00
Mikael Hugo
d895cf2a16 fix: silence OpenTelemetry diag and LogTape meta startup warnings
- Align google-gemini-cli-provider's @google/gemini-cli-core dep from
  0.40.1 → 0.41.2 to match root; npm deduplicates to a single module
  instance, so diag.setLogger is called only once (no 'overwritten' warn)
- Add logtape.meta logger config at 'warning' level to suppress LogTape's
  own 'loggers are configured' info message on every startup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 21:54:26 +02:00
Mikael Hugo
5065701a31 sf snapshot: uncommitted changes after 31m inactivity 2026-05-09 21:41:08 +02:00
Mikael Hugo
024485f050 feat(traceability): append SF-Session id to autonomous commit messages
- git-service.js autoCommit() accepts optional sessionId param
  - Appends 'SF-Session: <id>' trailer to commit message when present
  - Falls through cleanly when sessionId is undefined (quick tasks, templates)
- worktree.js autoCommitCurrentBranch() forwards sessionId
- auto-post-unit.js autoCommitUnit() reads session ID from getAutoSession()
  via s.cmdCtx?.sessionManager?.getSessionId?.() — same pattern as auto.js

Mirrors Copilot's session logs linked to each commit for cross-session traceability.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 21:10:02 +02:00
Mikael Hugo
692328ad45 feat(memory): TTL expiry — supersede stale memories after 28/90 days
- Add expireStaleMemories(unstartedTtlDays=28, maxTtlDays=90) to sf-db.js
  - Never-accessed (hit_count=0) memories expire after 28 days
  - All memories expire after 90 days regardless of hit_count
  - Marks superseded_by='ttl-expired' (non-destructive, same as CAP_EXCEEDED pattern)
  - Returns count of expired memories (non-fatal on failure)
- Call from auto-start.js after DB opens at autonomous session start
  - Logs warning with count if any memories expired
  - Catches errors silently — TTL failure never blocks autonomous start

Mirrors Copilot Memory's 28-day TTL model learned from research.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 21:09:53 +02:00
Mikael Hugo
d2eda0cc12 feat(yolo): bypass all sandboxing — iteration limit, memory gates, guard breaks
YOLO = all guardrails off. When s.isYolo() is true the loop:
- Skips MAX_LOOP_ITERATIONS stop (logs warning, keeps going)
- Skips memory pressure stop (logs warning, accepts OOM risk)
- Bypasses guard breaks (logs warning, continues to next unit)

Build mode respects all these gates. YOLO does not.

Also fix notify messages: YOLO = no sandboxing, not just 'no prompts'
(autonomous mode already skips prompts — YOLO removes the safety net).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 20:00:56 +02:00
Mikael Hugo
6c132d5db0 fix(modes): clarify Build vs YOLO — Build can still pause; YOLO = no stops
Build mode: autonomous + broad permissions, may still pause at gates or
risky operations.
YOLO: Build + deep model + no stops, no confirmations at all.

- Fix Ask→Build confirm dialog message (was wrongly saying 'no further prompts')
- Fix YOLO notify messages to be accurate about what YOLO uniquely adds
- YOLO-off message clarifies Build may still pause

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 19:57:56 +02:00
Mikael Hugo
b9ea000341 feat(modes): Ask mode gates autonomous start with Build mode confirmation
When SF would start autonomous execution (startAuto) and the session is
in Ask mode (runControl=manual), it shows a confirm dialog:

  'Switch to Build mode? SF will execute without further prompts.'
  [Switch to Build] [Stay in Ask]

- On confirm: atomically applies the build preset (autonomous +
  unrestricted), then proceeds with execution.
- On decline: returns without starting — user stays in Ask.
- skipModeGate option available for callers that already handle this
  (e.g., explicit /autonomous command after user intent is clear).

This covers all startAuto callers: checkAutoStartAfterDiscuss, guided
flow action buttons, /next, and /autonomous.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-09 19:56:24 +02:00