From 0b5fa75c0d4ff27a03e7568f82f5c32dc70283fa Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Mon, 11 May 2026 04:02:31 +0200 Subject: [PATCH] fix(lint): fix all pre-existing lint failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - check-sf-extension-inventory.mjs: expand parseDirectRegisteredCommands() scan to include 7 more files (guards/inturn.js, notifications/notify.js, permissions/index.js, ui/usage-bar.js, commands/legacy/audit.js, commands/legacy/create-extension.js, commands/legacy/create-slash-command.js) and filter results by BASE_RUNTIME_COMMAND_NAMES to exclude doc-string false positives ("name" in create-slash-command.js template text) - extension-manifest.json: remove 'clear' (subcommand of logs/notifications, never a top-level pi.registerCommand) - packages/pi-agent-core/src/db/sf-db.ts: fix 23 noVoidTypeReturn errors - openDatabase: void → boolean (caller uses return value at line 5625) - claimEscalationOverride: void → boolean (caller checks at escalation.js:243) - resolveSelfFeedbackEntry: void → boolean (caller checks at self-feedback.js:387) - copyWorktreeDb: void → boolean (caller checks at reconcileWorktreeDb) - compactUokMessages: void → {before,after} (caller returns value at message-bus.js:238) - insertSessionTurn: void → bigint|null (caller uses id at session-recorder.js:104) - expireStaleMemories: void → number (caller uses count at auto-start.js:1047) - deleteMemorySourceRow: void → boolean (caller returns value at memory-source-store.js:107) - deleteMemoryEmbedding: void → boolean (caller returns value at memory-embeddings.js:328) - updateBacklogItemStatus: remove dead return expression (callers discard value) - removeBacklogItem: remove dead return expression (callers discard value) - updateGateCircuitBreaker: remove dead return {total,avgMs,...} (wrong-type code accidentally merged from getGateLatencyStats, never reachable) - markUokMessageRead: remove dead return true/false (callers discard value) - Auto-fix formatting and organizeImports in ~30 source files (biome --write) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .sf/backups/db/sf.db.2026-05-09T21-41-14-119Z | Bin 1839104 -> 0 bytes .sf/backups/db/sf.db.2026-05-11T01-53-05-325Z | Bin 0 -> 1163264 bytes .sf/metrics.db-shm | Bin 32768 -> 32768 bytes .sf/metrics.db-wal | Bin 3213632 -> 4008792 bytes packages/agent-core/tsconfig.json | 12 +- .../ai/src/providers/google-gemini-cli.ts | 2 +- packages/ai/tsconfig.json | 19 +- .../src/core/chat-controller-ordering.test.ts | 210 +++-- .../src/core/compaction-orchestrator.ts | 6 +- .../src/core/fallback-resolver.ts | 4 +- .../src/core/image-overflow-recovery.ts | 6 +- packages/coding-agent/src/core/mcp/auth.ts | 132 ++-- packages/coding-agent/src/core/mcp/config.ts | 143 ++-- .../src/core/mcp/connection-manager.ts | 548 +++++++------- packages/coding-agent/src/core/mcp/index.ts | 26 +- packages/coding-agent/src/core/messages.ts | 6 +- .../core/providers/web-search-middleware.ts | 4 +- .../coding-agent/src/core/session-manager.ts | 6 +- packages/coding-agent/src/core/tools/find.ts | 2 +- packages/coding-agent/src/index.ts | 40 +- .../src/modes/interactive/components/armin.ts | 6 +- .../modes/interactive/components/daxnuts.ts | 6 +- .../interactive/components/model-selector.ts | 2 +- .../components/scoped-models-selector.ts | 2 +- .../components/show-images-selector.ts | 6 +- .../interactive/components/theme-selector.ts | 6 +- .../components/thinking-selector.ts | 6 +- .../src/modes/interactive/interactive-mode.ts | 4 +- .../src/resources/extensions/memory/index.ts | 5 +- .../coding-agent/src/utils/image-resize.ts | 2 +- packages/coding-agent/tsconfig.json | 18 +- .../google-gemini-cli-provider/src/index.ts | 7 +- .../google-gemini-cli-provider/tsconfig.json | 19 +- .../pi-agent-core/src/db/gate-registry.ts | 12 +- packages/pi-agent-core/src/db/index.ts | 2 +- packages/pi-agent-core/src/db/sf-db.ts | 568 +++++++++++--- .../pi-agent-core/src/db/task-frontmatter.ts | 20 +- .../pi-agent-core/src/db/uok/trace-writer.ts | 11 +- packages/pi-agent-core/tsconfig.json | 12 +- packages/tui/src/index.ts | 4 +- packages/tui/tsconfig.json | 17 +- scripts/check-circular-deps.mjs | 9 +- scripts/check-sf-extension-inventory.mjs | 17 +- scripts/generate-features-inventory.mjs | 8 +- scripts/validate-pack.js | 8 +- .../extensions/bg-shell/bg-shell-lifecycle.js | 3 +- .../extensions/bg-shell/bg-shell-tool.js | 2 +- .../tests/stream-adapter-permissions.test.ts | 23 +- src/resources/extensions/mcp-client/auth.js | 5 +- src/resources/extensions/mcp-client/index.js | 716 +++++++++--------- .../search-the-web/native-search.js | 4 +- .../extensions/search-the-web/provider.js | 18 +- src/resources/extensions/sf/auto-dispatch.js | 22 +- src/resources/extensions/sf/auto-post-unit.js | 2 +- .../extensions/sf/auto-runaway-guard.js | 26 +- src/resources/extensions/sf/auto-timers.js | 16 +- src/resources/extensions/sf/auto-worktree.js | 6 +- src/resources/extensions/sf/auto.js | 6 +- src/resources/extensions/sf/auto/phases.js | 12 +- src/resources/extensions/sf/auto/run-unit.js | 13 +- .../extensions/sf/bootstrap/db-tools.js | 95 ++- .../extensions/sf/bootstrap/register-hooks.js | 13 +- .../extensions/sf/bootstrap/system-context.js | 10 +- src/resources/extensions/sf/commands-agent.js | 14 +- .../extensions/sf/commands-memory.js | 8 +- .../extensions/sf/commands-prefs-wizard.js | 5 +- .../extensions/sf/dashboard-overlay.js | 8 +- .../sf/deep-project-setup-policy.js | 10 +- src/resources/extensions/sf/detection.js | 3 +- .../extensions/sf/dev-workflow-engine.js | 3 +- .../extensions/sf/doctor-providers.js | 9 +- src/resources/extensions/sf/export-html.js | 5 +- .../extensions/sf/extension-manifest.json | 8 +- src/resources/extensions/sf/guided-flow.js | 9 +- src/resources/extensions/sf/index.js | 20 +- src/resources/extensions/sf/init-wizard.js | 4 +- src/resources/extensions/sf/key-manager.js | 4 +- .../extensions/sf/knowledge-compounding.js | 2 +- .../sf/learning/bayesian-blender.mjs | 6 +- .../sf/learning/outcome-recorder.test.mjs | 88 ++- .../extensions/sf/model-catalog-cache.js | 15 +- .../extensions/sf/preferences-models.js | 22 +- src/resources/extensions/sf/preferences.js | 2 +- .../extensions/sf/provider-catalog-config.js | 4 +- .../extensions/sf/record-promoter.js | 9 +- src/resources/extensions/sf/reports.js | 5 +- .../extensions/sf/requirement-promoter.js | 6 +- src/resources/extensions/sf/setup-catalog.js | 8 +- src/resources/extensions/sf/sf-db.js | 105 ++- .../extensions/sf/subagent-inheritance.js | 6 +- .../extensions/sf/subagent/background-jobs.js | 10 +- src/resources/extensions/sf/subagent/index.js | 66 +- .../extensions/sf/summary-helpers.js | 19 +- .../auto-dispatch-canonical-plan.test.mjs | 2 +- .../sf/tests/doctor-providers.test.mjs | 18 +- .../memory-embeddings-llm-gateway.test.mjs | 7 +- .../sf/tests/preferences-models.test.mjs | 11 +- .../tests/remote-steering-pipeline.test.mjs | 30 +- .../sf/tests/schedule-dispatch.test.mjs | 2 +- .../sf/tests/sf-db-migration.test.mjs | 25 +- .../sf/tests/sift-retrieval-evidence.test.mjs | 2 +- .../sf/tests/summary-helpers.test.mjs | 10 +- .../sf/tests/uok-metrics-exposition.test.mjs | 12 +- .../extensions/sf/triage-self-feedback.js | 9 +- src/resources/extensions/sf/ui/index.js | 5 +- .../extensions/sf/uok-parity-summary.js | 2 +- .../extensions/sf/uok/a2a-agent-server.js | 24 +- .../extensions/sf/uok/a2a-transport.js | 8 +- .../extensions/sf/uok/auto-dispatch.js | 17 +- .../extensions/sf/uok/auto-runaway-guard.js | 5 +- .../extensions/sf/uok/auto-unit-closeout.js | 2 +- .../extensions/sf/uok/auto-verification.js | 18 +- src/resources/extensions/sf/uok/index.js | 68 +- src/resources/extensions/sf/uok/kernel.ts | 483 ++++++------ .../extensions/sf/uok/trace-writer.js | 7 +- .../extensions/sf/worktree-resolver.js | 5 +- src/resources/extensions/shared/mod.js | 2 +- .../extensions/shared/path-display.js | 8 + src/tests/app-smoke.test.ts | 7 +- src/tests/mcp-client-oauth.test.ts | 2 +- src/tests/native-search.test.ts | 26 +- tsconfig.extensions.json | 4 +- vitest.config.ts | 10 +- web/components/sf/app-shell.tsx | 2 +- web/components/sf/chat-mode.tsx | 83 +- web/components/sf/file-content-viewer.tsx | 83 +- web/components/ui/chart.tsx | 5 +- web/components/ui/resizable.tsx | 6 +- web/lib/__tests__/onboarding-logic.test.ts | 19 +- web/lib/workflow-actions.ts | 6 +- 130 files changed, 2535 insertions(+), 1918 deletions(-) delete mode 100644 .sf/backups/db/sf.db.2026-05-09T21-41-14-119Z create mode 100644 .sf/backups/db/sf.db.2026-05-11T01-53-05-325Z create mode 100644 src/resources/extensions/shared/path-display.js diff --git a/.sf/backups/db/sf.db.2026-05-09T21-41-14-119Z b/.sf/backups/db/sf.db.2026-05-09T21-41-14-119Z deleted file mode 100644 index 3bf7381bbb56e2d2bdbf6f303823322dedfe58cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1839104 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 z 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%0AV#~bA=BzRv6kw)a|)PUxpFm5 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ΞQKBbKdflihGrrU?O0q*B{ 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 EKZ`Ca7ytkO literal 0 HcmV?d00001 diff --git a/.sf/metrics.db-shm b/.sf/metrics.db-shm index 3315b42fa1f4db9b50686fe074f03582adec7716..3b59fbfe544f1f07351e944e530fa43636cc98e2 100644 GIT binary patch delta 1522 zcmb7?dr(zX6vofqzZ-L7Za2K(z#%h|TjB#wn+Kb^baEJcr%zWpZ^{sDxYps1w zRh6!)(v^W9#yWB(SSZJdIfdi+wd44THtnqq7P*qfFE|^htgPFU{Zo7U`9UTBSKn=J zZ{qt;pR0$*@vy%-!;@#z&LtMZE$Zzczgqlh@wY{+ok#L6i-i`+mTR#1D%UD6+h`^9`(*s~S!}VvBGHn4d&Uja*R<(jzQ_|$j>+}- z=k&I-g@b#F`>oZ(NyEO4u(5o?@Phr0$4qg>P8euK`ProMzdo*CmL3vbI;`&7+bZlK zg^$#4$_pDpUwJyl=|O~=J&h{ntg}<4==J)rR?OrPOtU8tH;rGMIyG8X>Z2O&WEF2p z;x}_K(-&3FQ@kzJKdR7$snJTmBf&XsE@Yiazl^~QA(>Rhb3He6J2}iIpZh6h1#79| zX}0q+ud#>yd`2@T#d)I1$qu^jpp06Mh+Ty;=Vv5({9MDmY@m@3MOGaXYn$m+)+_pCb3K6-P*L~rNxY73U{%D3O4aPtzs2t5@)&H<5<8J z-V^C`?OWxPD8JsW&*|aZ!Xlm#VWy|mX;B5bQ!nSR5Lr<^Zlj^wUYX-_gWed15#$E$ z;|cbOq|B7f8|j|Qdfwnm5w26AK)%+l1U`{`t|^@#bkAWOuhS;PE|Xah^u}{F*D;yJ zJWELE($LQZTX2zvvG6V0G%Zc@Ud~X)Fp>FeWUtsA3mquVQ2Gmb|2_2mvQ(8G z%avTkDAJg~jZ7t*SjM0LM7N IDT$NyzxoVh9{>OV delta 580 zcmZo@U}|V!s+V}A%K!q!K+MR%Ai%@Sz#z=Tz)+x~9X89IF+|ZQ?xjS1{cQQCXY&lY~fXw}m1fb$TQHG68W;~O(L|SaVz#m}%Bzjo5Uoy;ORA;JX+RMZ^xzS6W z`!&OCMop%Aru|IJK>pXs|D1#-Z;G@6D&D}j`Iie9Bb2v?Y4R_RXOo+}awhwD=|Kfu z7$^VmmH}}lU*HenWn-Aepv0KW*v7b)@yz6nk=8)bN0ZO^@x@r&Okb)Boou*pxB_vInjDRQ&&uOih-$e*!(J{gBj|E49;?f97YMI=}h0CHrTKq zW!T3U$#flRg8<{?XGym<2gUwkoV+X50P3`9Op|wIfH^>Wr)=JlX$B4%AZN$s2iaPT zKt{vlu3Wv%ORGe7rQ!x7(7_ir M>r}VE0$Yq30Gp}aH2?qr diff --git a/.sf/metrics.db-wal b/.sf/metrics.db-wal index 481019a5599dbf97291e59340323f9f4fd86a147..857ff205cf6009d3d5270e4b8f3b78eae9e1f59e 100644 GIT binary patch delta 51189 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 sDk-a|s;O&eYH91}>ggL88X232P0h?LEUm0 { // ToolExecutionComponent uses the global theme singleton. // Install a minimal no-op theme implementation for this unit test. - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolId = "mcp-tool-1"; @@ -192,14 +191,13 @@ test("chat-controller renders content blocks in content[] index order (tool-firs }); test("chat-controller renders serverToolUse before trailing text matching content[] index order", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolId = "mcp-secure-1"; @@ -282,14 +280,13 @@ test("chat-controller renders serverToolUse before trailing text matching conten }); test("chat-controller keeps pre-tool prose visible until post-tool prose arrives, then prunes it", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -400,14 +397,13 @@ test("chat-controller keeps pre-tool prose visible until post-tool prose arrives }); test("chat-controller keeps pre-tool thinking visible for adapter MCP turns without post-tool prose", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -483,14 +479,13 @@ test("chat-controller keeps pre-tool thinking visible for adapter MCP turns with }); test("chat-controller prunes orphaned provisional text after adapter sub-turn shrink when MCP tools appear", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -625,14 +620,13 @@ test("chat-controller prunes orphaned provisional text after adapter sub-turn sh }); test("chat-controller pins latest assistant text above editor when tool calls are present", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolId = "tool-pin-1"; @@ -697,14 +691,13 @@ test("chat-controller pins latest assistant text above editor when tool calls ar }); test("chat-controller clears pinned zone when a new assistant message starts", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolCall = { @@ -764,14 +757,13 @@ test("chat-controller clears pinned zone when a new assistant message starts", a }); test("chat-controller clears pinned zone when the agent turn ends", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolCall = { @@ -826,14 +818,13 @@ test("chat-controller clears pinned zone when the agent turn ends", async () => }); test("chat-controller clears pinned zone when assistant message ends", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); const toolCall = { @@ -887,14 +878,13 @@ test("chat-controller clears pinned zone when assistant message ends", async () }); test("chat-controller does not pin when there are no tool calls", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); @@ -931,14 +921,13 @@ test("chat-controller does not pin when there are no tool calls", async () => { // Expected chatContainer order: textRun(A), toolExec(T1), textRun(B), toolExec(T2), textRun(C) // Each AssistantMessageComponent must render ONLY its own text — no duplication after message_end. test("chat-controller renders interleaved text and tool blocks in content[] index order (#4144)", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -1117,14 +1106,13 @@ test("chat-controller renders interleaved text and tool blocks in content[] inde }); test("chat-controller does not duplicate text when content is [text, tool, text] (interleaved stream)", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -1237,14 +1225,13 @@ test("chat-controller does not duplicate text when content is [text, tool, text] // sub-turn children must stay frozen; new sub-turn segments must append after // them, and the pinned "Latest Output" mirror must re-evaluate for the new sub-turn. test("chat-controller freezes prior sub-turn and appends new segments when content shrinks", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); @@ -1426,14 +1413,13 @@ test("chat-controller freezes prior sub-turn and appends new segments when conte // pinned "Latest Output" mirror can display text from the new sub-turn instead // of staying frozen on a stale snapshot (the "bottom green stays" symptom). test("chat-controller updates pinned zone after sub-turn shrink", async () => { - (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = - { - fg: (_key: string, text: string) => text, - bg: (_key: string, text: string) => text, - bold: (text: string) => text, - italic: (text: string) => text, - truncate: (text: string) => text, - }; + (globalThis as any)[Symbol.for("@singularity-forge/coding-agent:theme")] = { + fg: (_key: string, text: string) => text, + bg: (_key: string, text: string) => text, + bold: (text: string) => text, + italic: (text: string) => text, + truncate: (text: string) => text, + }; const host = createHost(); host.getMarkdownThemeWithSettings = () => ({}); diff --git a/packages/coding-agent/src/core/compaction-orchestrator.ts b/packages/coding-agent/src/core/compaction-orchestrator.ts index 1fddfa277..3ee476b2b 100644 --- a/packages/coding-agent/src/core/compaction-orchestrator.ts +++ b/packages/coding-agent/src/core/compaction-orchestrator.ts @@ -151,7 +151,8 @@ export class CompactionOrchestrator { if (extensionCompaction) { summary = extensionCompaction.summary; firstKeptEntryId = extensionCompaction.firstKeptEntryId; - tokensBefore = extensionCompaction.tokensBefore ?? preparation.tokensBefore; + tokensBefore = + extensionCompaction.tokensBefore ?? preparation.tokensBefore; details = extensionCompaction.details; } else { const result = await compact( @@ -397,7 +398,8 @@ export class CompactionOrchestrator { if (extensionCompaction) { summary = extensionCompaction.summary; firstKeptEntryId = extensionCompaction.firstKeptEntryId; - tokensBefore = extensionCompaction.tokensBefore ?? preparation.tokensBefore; + tokensBefore = + extensionCompaction.tokensBefore ?? preparation.tokensBefore; details = extensionCompaction.details; } else { const compactResult = await compact( diff --git a/packages/coding-agent/src/core/fallback-resolver.ts b/packages/coding-agent/src/core/fallback-resolver.ts index abaa64dbf..33cfa7f37 100644 --- a/packages/coding-agent/src/core/fallback-resolver.ts +++ b/packages/coding-agent/src/core/fallback-resolver.ts @@ -187,7 +187,9 @@ export class FallbackResolver { if (this.emitBeforeModelSelect) { try { const unitType = this._unitContext?.unitType ?? "execute-task"; - const unitId = this._unitContext?.unitId ?? `fallback:${currentModel.provider}/${currentModel.id}`; + const unitId = + this._unitContext?.unitId ?? + `fallback:${currentModel.provider}/${currentModel.id}`; const result = await this.emitBeforeModelSelect({ unitType, unitId, diff --git a/packages/coding-agent/src/core/image-overflow-recovery.ts b/packages/coding-agent/src/core/image-overflow-recovery.ts index ef83c1ce1..6d9f4b5e7 100644 --- a/packages/coding-agent/src/core/image-overflow-recovery.ts +++ b/packages/coding-agent/src/core/image-overflow-recovery.ts @@ -10,11 +10,7 @@ * @see https://github.com/singularity-forge/sf-run/issues/2874 */ -import type { - ImageContent, - Message, - TextContent, -} from "@singularity-forge/ai"; +import type { ImageContent, Message, TextContent } from "@singularity-forge/ai"; /** * Maximum image dimension (px) that the Anthropic API allows in many-image diff --git a/packages/coding-agent/src/core/mcp/auth.ts b/packages/coding-agent/src/core/mcp/auth.ts index 1fc3457b9..9dc3bcece 100644 --- a/packages/coding-agent/src/core/mcp/auth.ts +++ b/packages/coding-agent/src/core/mcp/auth.ts @@ -10,28 +10,28 @@ import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth. import type { OAuthConfig } from "./config.js"; export interface AuthConfig { - headers?: Record; - oauth?: OAuthConfig; + headers?: Record; + oauth?: OAuthConfig; } export interface HttpTransportOptions { - authProvider?: OAuthClientProvider; - requestInit?: { headers: Record }; + authProvider?: OAuthClientProvider; + requestInit?: { headers: Record }; } function resolveEnvValue(value: string): string { - return value.replace( - /\$\{([^}]+)\}/g, - (_match: string, varName: string) => process.env[varName] ?? "", - ); + return value.replace( + /\$\{([^}]+)\}/g, + (_match: string, varName: string) => process.env[varName] ?? "", + ); } function resolveHeaders(raw: Record): Record { - const resolved: Record = {}; - for (const [key, value] of Object.entries(raw)) { - resolved[key] = typeof value === "string" ? resolveEnvValue(value) : value; - } - return resolved; + const resolved: Record = {}; + for (const [key, value] of Object.entries(raw)) { + resolved[key] = typeof value === "string" ? resolveEnvValue(value) : value; + } + return resolved; } /** @@ -42,44 +42,48 @@ function resolveHeaders(raw: Record): Record { * * Consumer: buildHttpTransportOpts when the server config has an oauth block. */ -export function createCliOAuthProvider(config: OAuthConfig): OAuthClientProvider { - let storedTokens: Parameters[0] | undefined; - let storedCodeVerifier = ""; - return { - get redirectUrl() { - return config.redirectUrl ?? "http://localhost:0/callback"; - }, - get clientMetadata() { - return { - redirect_uris: [config.redirectUrl ?? "http://localhost:0/callback"], - client_name: "sf", - ...(config.scopes ? { scope: config.scopes.join(" ") } : {}), - }; - }, - clientInformation() { - return { - client_id: config.clientId, - ...(config.clientSecret ? { client_secret: config.clientSecret } : {}), - }; - }, - tokens() { - return storedTokens; - }, - saveTokens(tokens) { - storedTokens = tokens; - }, - redirectToAuthorization(authorizationUrl) { - console.error( - `[MCP OAuth] Authorization required. Visit:\n ${authorizationUrl.toString()}`, - ); - }, - saveCodeVerifier(codeVerifier) { - storedCodeVerifier = codeVerifier; - }, - codeVerifier() { - return storedCodeVerifier; - }, - }; +export function createCliOAuthProvider( + config: OAuthConfig, +): OAuthClientProvider { + let storedTokens: + | Parameters[0] + | undefined; + let storedCodeVerifier = ""; + return { + get redirectUrl() { + return config.redirectUrl ?? "http://localhost:0/callback"; + }, + get clientMetadata() { + return { + redirect_uris: [config.redirectUrl ?? "http://localhost:0/callback"], + client_name: "sf", + ...(config.scopes ? { scope: config.scopes.join(" ") } : {}), + }; + }, + clientInformation() { + return { + client_id: config.clientId, + ...(config.clientSecret ? { client_secret: config.clientSecret } : {}), + }; + }, + tokens() { + return storedTokens; + }, + saveTokens(tokens) { + storedTokens = tokens; + }, + redirectToAuthorization(authorizationUrl) { + console.error( + `[MCP OAuth] Authorization required. Visit:\n ${authorizationUrl.toString()}`, + ); + }, + saveCodeVerifier(codeVerifier) { + storedCodeVerifier = codeVerifier; + }, + codeVerifier() { + return storedCodeVerifier; + }, + }; } /** @@ -96,16 +100,18 @@ export function createCliOAuthProvider(config: OAuthConfig): OAuthClientProvider * * Consumer: McpConnectionManager.getOrConnect() for HTTP transport setup. */ -export function buildHttpTransportOpts(authConfig: AuthConfig): HttpTransportOptions { - const opts: HttpTransportOptions = {}; - if (authConfig.oauth) { - opts.authProvider = createCliOAuthProvider(authConfig.oauth); - return opts; - } - if (authConfig.headers && Object.keys(authConfig.headers).length > 0) { - opts.requestInit = { - headers: resolveHeaders(authConfig.headers), - }; - } - return opts; +export function buildHttpTransportOpts( + authConfig: AuthConfig, +): HttpTransportOptions { + const opts: HttpTransportOptions = {}; + if (authConfig.oauth) { + opts.authProvider = createCliOAuthProvider(authConfig.oauth); + return opts; + } + if (authConfig.headers && Object.keys(authConfig.headers).length > 0) { + opts.requestInit = { + headers: resolveHeaders(authConfig.headers), + }; + } + return opts; } diff --git a/packages/coding-agent/src/core/mcp/config.ts b/packages/coding-agent/src/core/mcp/config.ts index d0c4fb8f6..543b8a360 100644 --- a/packages/coding-agent/src/core/mcp/config.ts +++ b/packages/coding-agent/src/core/mcp/config.ts @@ -11,22 +11,22 @@ import { homedir } from "node:os"; import { join } from "node:path"; export interface OAuthConfig { - clientId: string; - clientSecret?: string; - scopes?: string[]; - redirectUrl?: string; + clientId: string; + clientSecret?: string; + scopes?: string[]; + redirectUrl?: string; } export interface McpServerConfig { - name: string; - transport: "stdio" | "http" | "unknown"; - command?: string; - args?: string[]; - env?: Record; - cwd?: string; - url?: string; - headers?: Record; - oauth?: OAuthConfig; + name: string; + transport: "stdio" | "http" | "unknown"; + command?: string; + args?: string[]; + env?: Record; + cwd?: string; + url?: string; + headers?: Record; + oauth?: OAuthConfig; } /** @@ -39,51 +39,66 @@ export interface McpServerConfig { * Consumer: McpConnectionManager.readConfigs(), mcp_servers tool. */ export function readMcpConfigs(): McpServerConfig[] { - const servers: McpServerConfig[] = []; - const seen = new Set(); - const sfHome = process.env["SF_HOME"] ?? join(homedir(), ".sf"); - const configPaths = [ - join(process.cwd(), ".mcp.json"), - join(process.cwd(), ".sf", "mcp.json"), - join(sfHome, "mcp.json"), - join(sfHome, "agent", "mcp.json"), - join(homedir(), ".mcp.json"), - ]; - for (const configPath of configPaths) { - try { - if (!existsSync(configPath)) continue; - const raw = readFileSync(configPath, "utf-8"); - const data = JSON.parse(raw) as Record; - const mcpServers = (data["mcpServers"] ?? data["servers"]) as Record | undefined; - if (!mcpServers || typeof mcpServers !== "object") continue; - for (const [name, config] of Object.entries(mcpServers)) { - if (seen.has(name)) continue; - seen.add(name); - const cfg = config as Record; - const hasCommand = typeof cfg["command"] === "string"; - const hasUrl = typeof cfg["url"] === "string"; - const transport: McpServerConfig["transport"] = hasCommand ? "stdio" : hasUrl ? "http" : "unknown"; - const hasHeaders = hasUrl && cfg["headers"] && typeof cfg["headers"] === "object"; - const hasOAuth = hasUrl && cfg["oauth"] && typeof cfg["oauth"] === "object"; - servers.push({ - name, - transport, - ...(hasCommand && { - command: cfg["command"] as string, - args: Array.isArray(cfg["args"]) ? (cfg["args"] as string[]) : undefined, - env: cfg["env"] && typeof cfg["env"] === "object" ? (cfg["env"] as Record) : undefined, - cwd: typeof cfg["cwd"] === "string" ? cfg["cwd"] : undefined, - }), - ...(hasUrl && { url: cfg["url"] as string }), - headers: hasHeaders ? (cfg["headers"] as Record) : undefined, - oauth: hasOAuth ? (cfg["oauth"] as OAuthConfig) : undefined, - }); - } - } catch { - // Non-fatal — config file may not exist or be malformed - } - } - return servers; + const servers: McpServerConfig[] = []; + const seen = new Set(); + const sfHome = process.env["SF_HOME"] ?? join(homedir(), ".sf"); + const configPaths = [ + join(process.cwd(), ".mcp.json"), + join(process.cwd(), ".sf", "mcp.json"), + join(sfHome, "mcp.json"), + join(sfHome, "agent", "mcp.json"), + join(homedir(), ".mcp.json"), + ]; + for (const configPath of configPaths) { + try { + if (!existsSync(configPath)) continue; + const raw = readFileSync(configPath, "utf-8"); + const data = JSON.parse(raw) as Record; + const mcpServers = (data["mcpServers"] ?? data["servers"]) as + | Record + | undefined; + if (!mcpServers || typeof mcpServers !== "object") continue; + for (const [name, config] of Object.entries(mcpServers)) { + if (seen.has(name)) continue; + seen.add(name); + const cfg = config as Record; + const hasCommand = typeof cfg["command"] === "string"; + const hasUrl = typeof cfg["url"] === "string"; + const transport: McpServerConfig["transport"] = hasCommand + ? "stdio" + : hasUrl + ? "http" + : "unknown"; + const hasHeaders = + hasUrl && cfg["headers"] && typeof cfg["headers"] === "object"; + const hasOAuth = + hasUrl && cfg["oauth"] && typeof cfg["oauth"] === "object"; + servers.push({ + name, + transport, + ...(hasCommand && { + command: cfg["command"] as string, + args: Array.isArray(cfg["args"]) + ? (cfg["args"] as string[]) + : undefined, + env: + cfg["env"] && typeof cfg["env"] === "object" + ? (cfg["env"] as Record) + : undefined, + cwd: typeof cfg["cwd"] === "string" ? cfg["cwd"] : undefined, + }), + ...(hasUrl && { url: cfg["url"] as string }), + headers: hasHeaders + ? (cfg["headers"] as Record) + : undefined, + oauth: hasOAuth ? (cfg["oauth"] as OAuthConfig) : undefined, + }); + } + } catch { + // Non-fatal — config file may not exist or be malformed + } + } + return servers; } /** @@ -95,11 +110,11 @@ export function readMcpConfigs(): McpServerConfig[] { * Consumer: McpConnectionManager.getOrConnect(). */ export function getServerConfig( - name: string, - configs: McpServerConfig[], + name: string, + configs: McpServerConfig[], ): McpServerConfig | undefined { - const trimmed = name.trim(); - return configs.find( - (s) => s.name === trimmed || s.name.toLowerCase() === trimmed.toLowerCase(), - ); + const trimmed = name.trim(); + return configs.find( + (s) => s.name === trimmed || s.name.toLowerCase() === trimmed.toLowerCase(), + ); } diff --git a/packages/coding-agent/src/core/mcp/connection-manager.ts b/packages/coding-agent/src/core/mcp/connection-manager.ts index 183fd2e61..b8838e46f 100644 --- a/packages/coding-agent/src/core/mcp/connection-manager.ts +++ b/packages/coding-agent/src/core/mcp/connection-manager.ts @@ -12,63 +12,67 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js" import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; import { buildHttpTransportOpts } from "./auth.js"; -import { getServerConfig, readMcpConfigs, type McpServerConfig } from "./config.js"; +import { + getServerConfig, + type McpServerConfig, + readMcpConfigs, +} from "./config.js"; -export type { McpServerConfig, OAuthConfig } from "./config.js"; export type { AuthConfig, HttpTransportOptions } from "./auth.js"; +export type { McpServerConfig, OAuthConfig } from "./config.js"; export interface McpToolDefinition { - name: string; - description: string; - inputSchema?: unknown; + name: string; + description: string; + inputSchema?: unknown; } export interface ConnectionStatus { - connected: boolean; - tools: string[]; - error?: string; + connected: boolean; + tools: string[]; + error?: string; } export interface RegisterToolParams { - name: string; - label: string; - description: string; - inputSchemaRaw: unknown; - execute: ( - id: string, - params: Record, - signal?: AbortSignal, - ) => Promise<{ - content: { type: "text"; text: string }[]; - details: Record; - }>; + name: string; + label: string; + description: string; + inputSchemaRaw: unknown; + execute: ( + id: string, + params: Record, + signal?: AbortSignal, + ) => Promise<{ + content: { type: "text"; text: string }[]; + details: Record; + }>; } export type RegisterToolFn = (params: RegisterToolParams) => void; const SAFE_CHILD_ENV_KEYS = new Set([ - "PATH", - "HOME", - "USER", - "LOGNAME", - "SHELL", - "LANG", - "LC_ALL", - "LC_CTYPE", - "LC_MESSAGES", - "LC_NUMERIC", - "LC_TIME", - "TMPDIR", - "TMP", - "TEMP", - "TZ", - "TERM", - "COLORTERM", + "PATH", + "HOME", + "USER", + "LOGNAME", + "SHELL", + "LANG", + "LC_ALL", + "LC_CTYPE", + "LC_MESSAGES", + "LC_NUMERIC", + "LC_TIME", + "TMPDIR", + "TMP", + "TEMP", + "TZ", + "TERM", + "COLORTERM", ]); interface ActiveConnection { - client: Client; - transport: Transport; + client: Client; + transport: Transport; } /** @@ -83,245 +87,267 @@ interface ActiveConnection { * Consumer: mcp-client extension (one instance per extension activation). */ export class McpConnectionManager { - private readonly connections = new Map(); - private configCache: McpServerConfig[] | null = null; - private readonly autoRegisteredServers = new Set(); - private readonly toolCache = new Map(); + private readonly connections = new Map(); + private configCache: McpServerConfig[] | null = null; + private readonly autoRegisteredServers = new Set(); + private readonly toolCache = new Map(); - /** Read (and cache) the full ordered list of configured MCP servers. */ - readConfigs(): McpServerConfig[] { - if (this.configCache) return this.configCache; - this.configCache = readMcpConfigs(); - return this.configCache; - } + /** Read (and cache) the full ordered list of configured MCP servers. */ + readConfigs(): McpServerConfig[] { + if (this.configCache) return this.configCache; + this.configCache = readMcpConfigs(); + return this.configCache; + } - /** Invalidate the config cache so the next readConfigs() re-reads from disk. */ - invalidateConfigCache(): void { - this.configCache = null; - } + /** Invalidate the config cache so the next readConfigs() re-reads from disk. */ + invalidateConfigCache(): void { + this.configCache = null; + } - /** Return the config for a single server by name (case-insensitive fallback). */ - getServerConfig(name: string): McpServerConfig | undefined { - return getServerConfig(name, this.readConfigs()); - } + /** Return the config for a single server by name (case-insensitive fallback). */ + getServerConfig(name: string): McpServerConfig | undefined { + return getServerConfig(name, this.readConfigs()); + } - /** - * Return true if the given server name is currently connected. - * - * Purpose: let the mcp_servers tool show live connection status without - * triggering a connection. - * - * Consumer: formatServerList in the extension wrapper. - */ - isConnected(name: string): boolean { - return this.connections.has(name); - } + /** + * Return true if the given server name is currently connected. + * + * Purpose: let the mcp_servers tool show live connection status without + * triggering a connection. + * + * Consumer: formatServerList in the extension wrapper. + */ + isConnected(name: string): boolean { + return this.connections.has(name); + } - /** Return cached tools for a server, or undefined if not yet discovered. */ - getCachedTools(serverName: string): McpToolDefinition[] | undefined { - return this.toolCache.get(serverName); - } + /** Return cached tools for a server, or undefined if not yet discovered. */ + getCachedTools(serverName: string): McpToolDefinition[] | undefined { + return this.toolCache.get(serverName); + } - /** Store discovered tools in the cache. */ - setCachedTools(serverName: string, tools: McpToolDefinition[]): void { - this.toolCache.set(serverName, tools); - } + /** Store discovered tools in the cache. */ + setCachedTools(serverName: string, tools: McpToolDefinition[]): void { + this.toolCache.set(serverName, tools); + } - /** - * Return a live MCP Client for the named server, connecting lazily on first call. - * - * Purpose: provide a single canonical connect path so every tool (discover, - * call, auto-registered) always gets the same cached client. - * - * Consumer: mcp_discover, mcp_call, registerToolsForServer execute functions. - */ - async getOrConnect(name: string, signal?: AbortSignal): Promise { - const config = this.getServerConfig(name); - if (!config) { - throw new Error( - `Unknown MCP server: "${name}". Use mcp_servers to list available servers.`, - ); - } - const existing = this.connections.get(config.name); - if (existing) return existing.client; + /** + * Return a live MCP Client for the named server, connecting lazily on first call. + * + * Purpose: provide a single canonical connect path so every tool (discover, + * call, auto-registered) always gets the same cached client. + * + * Consumer: mcp_discover, mcp_call, registerToolsForServer execute functions. + */ + async getOrConnect(name: string, signal?: AbortSignal): Promise { + const config = this.getServerConfig(name); + if (!config) { + throw new Error( + `Unknown MCP server: "${name}". Use mcp_servers to list available servers.`, + ); + } + const existing = this.connections.get(config.name); + if (existing) return existing.client; - const client = new Client({ name: "sf", version: "1.0.0" }); - let transport: Transport; + const client = new Client({ name: "sf", version: "1.0.0" }); + let transport: Transport; - if (config.transport === "stdio" && config.command) { - transport = new StdioClientTransport({ - command: config.command, - args: config.args, - env: this.buildChildEnv(config.env), - cwd: config.cwd, - stderr: "pipe", - }); - } else if (config.transport === "http" && config.url) { - const resolvedUrl = config.url.replace( - /\$\{([^}]+)\}/g, - (_: string, varName: string) => process.env[varName] ?? "", - ); - const httpOpts = buildHttpTransportOpts({ - headers: config.headers, - oauth: config.oauth, - }); - transport = new StreamableHTTPClientTransport( - new URL(resolvedUrl), - httpOpts, - ); - } else { - throw new Error( - `Server "${config.name}" has unsupported transport: ${config.transport}`, - ); - } + if (config.transport === "stdio" && config.command) { + transport = new StdioClientTransport({ + command: config.command, + args: config.args, + env: this.buildChildEnv(config.env), + cwd: config.cwd, + stderr: "pipe", + }); + } else if (config.transport === "http" && config.url) { + const resolvedUrl = config.url.replace( + /\$\{([^}]+)\}/g, + (_: string, varName: string) => process.env[varName] ?? "", + ); + const httpOpts = buildHttpTransportOpts({ + headers: config.headers, + oauth: config.oauth, + }); + transport = new StreamableHTTPClientTransport( + new URL(resolvedUrl), + httpOpts, + ); + } else { + throw new Error( + `Server "${config.name}" has unsupported transport: ${config.transport}`, + ); + } - try { - await client.connect(transport, { signal, timeout: 30000 }); - } catch (err) { - try { await transport.close(); } catch { /* best-effort */ } - try { await client.close(); } catch { /* best-effort */ } - throw err; - } + try { + await client.connect(transport, { signal, timeout: 30000 }); + } catch (err) { + try { + await transport.close(); + } catch { + /* best-effort */ + } + try { + await client.close(); + } catch { + /* best-effort */ + } + throw err; + } - this.connections.set(config.name, { client, transport }); - return client; - } + this.connections.set(config.name, { client, transport }); + return client; + } - /** - * Close all active connections and clear the tool cache. - * - * Purpose: ensure clean shutdown on session end so no dangling stdio child - * processes or HTTP keep-alive connections survive the session. - * - * Consumer: session_shutdown and session_switch lifecycle hooks. - */ - async closeAll(): Promise { - const closing = Array.from(this.connections.entries()).map( - async ([name, conn]) => { - try { await conn.transport.close(); } catch { /* best-effort */ } - try { await conn.client.close(); } catch { /* best-effort */ } - this.connections.delete(name); - }, - ); - await Promise.allSettled(closing); - this.toolCache.clear(); - this.autoRegisteredServers.clear(); - } + /** + * Close all active connections and clear the tool cache. + * + * Purpose: ensure clean shutdown on session end so no dangling stdio child + * processes or HTTP keep-alive connections survive the session. + * + * Consumer: session_shutdown and session_switch lifecycle hooks. + */ + async closeAll(): Promise { + const closing = Array.from(this.connections.entries()).map( + async ([name, conn]) => { + try { + await conn.transport.close(); + } catch { + /* best-effort */ + } + try { + await conn.client.close(); + } catch { + /* best-effort */ + } + this.connections.delete(name); + }, + ); + await Promise.allSettled(closing); + this.toolCache.clear(); + this.autoRegisteredServers.clear(); + } - /** - * Alias for closeAll — named for the /mcp reload command surface. - * - * Purpose: allow reload command to disconnect all servers so the next - * mcp_discover or mcp_call lazily reconnects with fresh config. - * - * Consumer: /mcp reload command handler. - */ - async disconnectAll(): Promise { - await this.closeAll(); - } + /** + * Alias for closeAll — named for the /mcp reload command surface. + * + * Purpose: allow reload command to disconnect all servers so the next + * mcp_discover or mcp_call lazily reconnects with fresh config. + * + * Consumer: /mcp reload command handler. + */ + async disconnectAll(): Promise { + await this.closeAll(); + } - /** - * Return the live connection status for a named server. - * Safe to call even when the server has never been connected. - * - * Purpose: provide non-destructive status inspection for the status command. - * - * Consumer: /mcp status command handler. - */ - getConnectionStatus(name: string): ConnectionStatus { - const conn = this.connections.get(name); - const cached = this.toolCache.get(name); - return { - connected: !!conn, - tools: cached ? cached.map((t) => t.name) : [], - error: undefined, - }; - } + /** + * Return the live connection status for a named server. + * Safe to call even when the server has never been connected. + * + * Purpose: provide non-destructive status inspection for the status command. + * + * Consumer: /mcp status command handler. + */ + getConnectionStatus(name: string): ConnectionStatus { + const conn = this.connections.get(name); + const cached = this.toolCache.get(name); + return { + connected: !!conn, + tools: cached ? cached.map((t) => t.name) : [], + error: undefined, + }; + } - /** - * Register MCP tools discovered for a server as first-class agent tools. - * No-op if the server's tools were already registered in this session. - * - * Purpose: surface each MCP tool by its real name so the LLM can call - * tools directly (e.g. serena_find_symbol) without the mcp_call indirection. - * - * Consumer: mcp_discover execute handler, after listTools() succeeds. - * - * @param serverName Canonical server name from the config. - * @param tools Tool list returned by client.listTools(). - * @param registerTool Extension-provided callback that registers one tool. - */ - registerToolsForServer( - serverName: string, - tools: McpToolDefinition[], - registerTool: RegisterToolFn, - ): void { - if (this.autoRegisteredServers.has(serverName)) return; - this.autoRegisteredServers.add(serverName); - for (const tool of tools) { - const piToolName = `${serverName}_${tool.name}`; - const description = tool.description || `MCP tool: ${tool.name} on ${serverName}`; - try { - registerTool({ - name: piToolName, - label: `${serverName}:${tool.name}`, - description, - inputSchemaRaw: tool.inputSchema, - execute: async (_id, params, signal) => { - const client = await this.getOrConnect(serverName, signal); - const result = await client.callTool( - { name: tool.name, arguments: params }, - undefined, - { signal, timeout: 60000 }, - ); - const contentItems = result.content as { type: string; text?: string }[]; - const raw = contentItems - .map((c) => (c.type === "text" ? (c.text ?? "") : JSON.stringify(c))) - .join("\n"); - return { - content: [{ type: "text" as const, text: raw }], - details: { server: serverName, tool: tool.name }, - }; - }, - }); - } catch { - // Non-fatal — tool registration can fail if schema is unconvertible - } - } - } + /** + * Register MCP tools discovered for a server as first-class agent tools. + * No-op if the server's tools were already registered in this session. + * + * Purpose: surface each MCP tool by its real name so the LLM can call + * tools directly (e.g. serena_find_symbol) without the mcp_call indirection. + * + * Consumer: mcp_discover execute handler, after listTools() succeeds. + * + * @param serverName Canonical server name from the config. + * @param tools Tool list returned by client.listTools(). + * @param registerTool Extension-provided callback that registers one tool. + */ + registerToolsForServer( + serverName: string, + tools: McpToolDefinition[], + registerTool: RegisterToolFn, + ): void { + if (this.autoRegisteredServers.has(serverName)) return; + this.autoRegisteredServers.add(serverName); + for (const tool of tools) { + const piToolName = `${serverName}_${tool.name}`; + const description = + tool.description || `MCP tool: ${tool.name} on ${serverName}`; + try { + registerTool({ + name: piToolName, + label: `${serverName}:${tool.name}`, + description, + inputSchemaRaw: tool.inputSchema, + execute: async (_id, params, signal) => { + const client = await this.getOrConnect(serverName, signal); + const result = await client.callTool( + { name: tool.name, arguments: params }, + undefined, + { signal, timeout: 60000 }, + ); + const contentItems = result.content as { + type: string; + text?: string; + }[]; + const raw = contentItems + .map((c) => + c.type === "text" ? (c.text ?? "") : JSON.stringify(c), + ) + .join("\n"); + return { + content: [{ type: "text" as const, text: raw }], + details: { server: serverName, tool: tool.name }, + }; + }, + }); + } catch { + // Non-fatal — tool registration can fail if schema is unconvertible + } + } + } - /** - * Build a sanitised child environment for stdio transport processes. - * - * Purpose: prevent leaking host secrets or unwanted env vars into MCP - * server child processes by allow-listing safe keys and merging config- - * provided env on top. - * - * Consumer: getOrConnect() when creating a StdioClientTransport. - */ - buildChildEnv(configEnv?: Record): Record { - const safe: Record = {}; - for (const key of SAFE_CHILD_ENV_KEYS) { - const val = process.env[key]; - if (val !== undefined) safe[key] = val; - } - return { ...safe, ...this.resolveEnv(configEnv ?? {}) }; - } + /** + * Build a sanitised child environment for stdio transport processes. + * + * Purpose: prevent leaking host secrets or unwanted env vars into MCP + * server child processes by allow-listing safe keys and merging config- + * provided env on top. + * + * Consumer: getOrConnect() when creating a StdioClientTransport. + */ + buildChildEnv(configEnv?: Record): Record { + const safe: Record = {}; + for (const key of SAFE_CHILD_ENV_KEYS) { + const val = process.env[key]; + if (val !== undefined) safe[key] = val; + } + return { ...safe, ...this.resolveEnv(configEnv ?? {}) }; + } - private resolveEnv(env: Record): Record { - const resolved: Record = {}; - for (const [key, value] of Object.entries(env)) { - if (typeof value === "string") { - resolved[key] = value.replace( - /\$\{([^}]+)\}/g, - (_match: string, varName: string) => process.env[varName] ?? "", - ); - } else { - resolved[key] = value; - } - } - return resolved; - } + private resolveEnv(env: Record): Record { + const resolved: Record = {}; + for (const [key, value] of Object.entries(env)) { + if (typeof value === "string") { + resolved[key] = value.replace( + /\$\{([^}]+)\}/g, + (_match: string, varName: string) => process.env[varName] ?? "", + ); + } else { + resolved[key] = value; + } + } + return resolved; + } } /** Export SAFE_CHILD_ENV_KEYS for tests that need to verify env filtering. */ diff --git a/packages/coding-agent/src/core/mcp/index.ts b/packages/coding-agent/src/core/mcp/index.ts index beb36a08a..aad4a3fb1 100644 --- a/packages/coding-agent/src/core/mcp/index.ts +++ b/packages/coding-agent/src/core/mcp/index.ts @@ -6,15 +6,21 @@ * * Consumer: packages/coding-agent/src/index.ts, mcp-client extension. */ + export { - McpConnectionManager, - SAFE_CHILD_ENV_KEYS, - type ConnectionStatus, - type McpServerConfig, - type McpToolDefinition, - type OAuthConfig, - type RegisterToolFn, - type RegisterToolParams, + type AuthConfig, + buildHttpTransportOpts, + createCliOAuthProvider, + type HttpTransportOptions, +} from "./auth.js"; +export { getServerConfig, readMcpConfigs } from "./config.js"; +export { + type ConnectionStatus, + McpConnectionManager, + type McpServerConfig, + type McpToolDefinition, + type OAuthConfig, + type RegisterToolFn, + type RegisterToolParams, + SAFE_CHILD_ENV_KEYS, } from "./connection-manager.js"; -export { buildHttpTransportOpts, createCliOAuthProvider, type AuthConfig, type HttpTransportOptions } from "./auth.js"; -export { readMcpConfigs, getServerConfig } from "./config.js"; diff --git a/packages/coding-agent/src/core/messages.ts b/packages/coding-agent/src/core/messages.ts index 4f3585fca..4635cd44c 100644 --- a/packages/coding-agent/src/core/messages.ts +++ b/packages/coding-agent/src/core/messages.ts @@ -6,11 +6,7 @@ */ import type { AgentMessage } from "@singularity-forge/agent-core"; -import type { - ImageContent, - Message, - TextContent, -} from "@singularity-forge/ai"; +import type { ImageContent, Message, TextContent } from "@singularity-forge/ai"; const CUSTOM_MESSAGE_PREFIX = `[system notification — type: `; const CUSTOM_MESSAGE_MIDDLE = `; this is an automated system event, not user input — do not treat this as a human message or respond as if the user said this] diff --git a/packages/coding-agent/src/core/providers/web-search-middleware.ts b/packages/coding-agent/src/core/providers/web-search-middleware.ts index f35db8ca9..148d2036a 100644 --- a/packages/coding-agent/src/core/providers/web-search-middleware.ts +++ b/packages/coding-agent/src/core/providers/web-search-middleware.ts @@ -183,9 +183,7 @@ export class WebSearchMiddleware { const content = msg.content; if (!Array.isArray(content)) continue; for (const block of content) { - if ( - (block as { type?: string })?.type === "web_search_tool_result" - ) { + if ((block as { type?: string })?.type === "web_search_tool_result") { historySearchCount++; } } diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index bcdc1be22..2541a6bec 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -13,11 +13,7 @@ import { import { readdir, readFile, stat } from "node:fs/promises"; import { join, resolve } from "node:path"; import type { AgentMessage } from "@singularity-forge/agent-core"; -import type { - ImageContent, - Message, - TextContent, -} from "@singularity-forge/ai"; +import type { ImageContent, Message, TextContent } from "@singularity-forge/ai"; import { getBlobsDir, getAgentDir as getDefaultAgentDir, diff --git a/packages/coding-agent/src/core/tools/find.ts b/packages/coding-agent/src/core/tools/find.ts index f5505f638..2339cc74e 100644 --- a/packages/coding-agent/src/core/tools/find.ts +++ b/packages/coding-agent/src/core/tools/find.ts @@ -1,8 +1,8 @@ import { existsSync } from "node:fs"; import path from "node:path"; import { type Static, Type } from "@sinclair/typebox"; -import { glob as nativeGlob } from "@singularity-forge/native/glob"; import type { AgentTool } from "@singularity-forge/agent-core"; +import { glob as nativeGlob } from "@singularity-forge/native/glob"; import { FIND_DEFAULT_LIMIT } from "../constants.js"; import { resolveToCwd } from "./path-utils.js"; import { diff --git a/packages/coding-agent/src/index.ts b/packages/coding-agent/src/index.ts index 8defcb51b..8a640cdc6 100644 --- a/packages/coding-agent/src/index.ts +++ b/packages/coding-agent/src/index.ts @@ -169,6 +169,16 @@ export { } from "./core/extensions/index.js"; // Footer data provider (git branch + extension statuses - data not otherwise available to extensions) export type { ReadonlyFooterDataProvider } from "./core/footer-data-provider.js"; +// MCP connection manager +export { + buildHttpTransportOpts, + type ConnectionStatus, + McpConnectionManager, + type McpServerConfig, + type McpToolDefinition, + type RegisterToolFn, + type RegisterToolParams, +} from "./core/mcp/index.js"; export { FederatedMemoryProvider } from "./core/memory/federated-memory.js"; export { convertToLlm } from "./core/messages.js"; export type { @@ -204,6 +214,15 @@ export type { ResolvedResource, } from "./core/package-manager.js"; export { DefaultPackageManager } from "./core/package-manager.js"; +// Native provider middleware +export { + CUSTOM_SEARCH_TOOL_NAMES, + MAX_NATIVE_SEARCHES_PER_SESSION, + setPreferBraveResolver, + stripThinkingFromHistory, + WebSearchMiddleware, + webSearchMiddleware, +} from "./core/providers/web-search-middleware.js"; export { getAllowedCommandPrefixes, SAFE_COMMAND_PREFIXES, @@ -215,15 +234,6 @@ export type { ResourceLoader, } from "./core/resource-loader.js"; export { DefaultResourceLoader } from "./core/resource-loader.js"; -// Native provider middleware -export { - CUSTOM_SEARCH_TOOL_NAMES, - MAX_NATIVE_SEARCHES_PER_SESSION, - setPreferBraveResolver, - stripThinkingFromHistory, - WebSearchMiddleware, - webSearchMiddleware, -} from "./core/providers/web-search-middleware.js"; // SDK for programmatic usage export { type CreateAgentSessionOptions, @@ -442,7 +452,6 @@ export { export { attachJsonlLineReader, serializeJsonLine } from "./modes/rpc/jsonl.js"; // Clipboard utilities export { copyToClipboard } from "./utils/clipboard.js"; -export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.js"; // Pure formatting utilities (duration, token counts, sparklines, ANSI, etc.) export { fileLink, @@ -455,17 +464,8 @@ export { stripAnsi, truncateWithEllipsis, } from "./utils/format.js"; +export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.js"; // Cross-platform path display export { toPosixPath } from "./utils/path-display.js"; // Shell utilities export { getShellConfig, sanitizeCommand } from "./utils/shell.js"; -// MCP connection manager -export { - McpConnectionManager, - buildHttpTransportOpts, - type McpServerConfig, - type ConnectionStatus, - type McpToolDefinition, - type RegisterToolFn, - type RegisterToolParams, -} from "./core/mcp/index.js"; diff --git a/packages/coding-agent/src/modes/interactive/components/armin.ts b/packages/coding-agent/src/modes/interactive/components/armin.ts index 85027d69d..5b929fe9c 100644 --- a/packages/coding-agent/src/modes/interactive/components/armin.ts +++ b/packages/coding-agent/src/modes/interactive/components/armin.ts @@ -2,11 +2,7 @@ * Armin says hi! A fun easter egg with animated XBM art. */ -import { - type Component, - type TUI, - visibleWidth, -} from "@singularity-forge/tui"; +import { type Component, type TUI, visibleWidth } from "@singularity-forge/tui"; import { theme } from "../theme/theme.js"; // XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground diff --git a/packages/coding-agent/src/modes/interactive/components/daxnuts.ts b/packages/coding-agent/src/modes/interactive/components/daxnuts.ts index cbabcd822..3a8e1f9fc 100644 --- a/packages/coding-agent/src/modes/interactive/components/daxnuts.ts +++ b/packages/coding-agent/src/modes/interactive/components/daxnuts.ts @@ -4,11 +4,7 @@ * A heartfelt tribute to dax (@thdxr) for providing free Kimi K2.5 access via OpenCode. */ -import { - type Component, - type TUI, - visibleWidth, -} from "@singularity-forge/tui"; +import { type Component, type TUI, visibleWidth } from "@singularity-forge/tui"; import { theme } from "../theme/theme.js"; // 32x32 RGB image of dax, hex encoded (3 bytes per pixel) diff --git a/packages/coding-agent/src/modes/interactive/components/model-selector.ts b/packages/coding-agent/src/modes/interactive/components/model-selector.ts index fcc19eeae..0adc99f30 100644 --- a/packages/coding-agent/src/modes/interactive/components/model-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/model-selector.ts @@ -1,5 +1,4 @@ import { type Model, modelsAreEqual } from "@singularity-forge/ai"; -import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import { Container, type Focusable, @@ -9,6 +8,7 @@ import { Text, type TUI, } from "@singularity-forge/tui"; +import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import type { ModelRegistry } from "../../../core/model-registry.js"; import type { SettingsManager } from "../../../core/settings-manager.js"; import { theme } from "../theme/theme.js"; diff --git a/packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts b/packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts index ab84c41a5..27fd4e903 100644 --- a/packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/scoped-models-selector.ts @@ -1,5 +1,4 @@ import type { Model } from "@singularity-forge/ai"; -import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import { Container, type Focusable, @@ -10,6 +9,7 @@ import { Spacer, Text, } from "@singularity-forge/tui"; +import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import { theme } from "../theme/theme.js"; import { DynamicBorder } from "./dynamic-border.js"; import { providerDisplayName } from "./model-selector.js"; diff --git a/packages/coding-agent/src/modes/interactive/components/show-images-selector.ts b/packages/coding-agent/src/modes/interactive/components/show-images-selector.ts index ca616a612..83fe6e84e 100644 --- a/packages/coding-agent/src/modes/interactive/components/show-images-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/show-images-selector.ts @@ -1,8 +1,4 @@ -import { - Container, - type SelectItem, - SelectList, -} from "@singularity-forge/tui"; +import { Container, type SelectItem, SelectList } from "@singularity-forge/tui"; import { getSelectListTheme } from "../theme/theme.js"; import { DynamicBorder } from "./dynamic-border.js"; diff --git a/packages/coding-agent/src/modes/interactive/components/theme-selector.ts b/packages/coding-agent/src/modes/interactive/components/theme-selector.ts index 63b0bbc48..dea364b92 100644 --- a/packages/coding-agent/src/modes/interactive/components/theme-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/theme-selector.ts @@ -1,8 +1,4 @@ -import { - Container, - type SelectItem, - SelectList, -} from "@singularity-forge/tui"; +import { Container, type SelectItem, SelectList } from "@singularity-forge/tui"; import { getAvailableThemes, getSelectListTheme } from "../theme/theme.js"; import { DynamicBorder } from "./dynamic-border.js"; diff --git a/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts b/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts index 245cca33c..ff2334d98 100644 --- a/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts @@ -1,9 +1,5 @@ import type { ThinkingLevel } from "@singularity-forge/agent-core"; -import { - Container, - type SelectItem, - SelectList, -} from "@singularity-forge/tui"; +import { Container, type SelectItem, SelectList } from "@singularity-forge/tui"; import { getSelectListTheme } from "../theme/theme.js"; import { DynamicBorder } from "./dynamic-border.js"; diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index f4e8cd4c0..47c4cda7a 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -9,13 +9,13 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; -import { listDescendants } from "@singularity-forge/native"; import type { AgentMessage } from "@singularity-forge/agent-core"; import type { AssistantMessage, ImageContent, Message, } from "@singularity-forge/ai"; +import { listDescendants } from "@singularity-forge/native"; import type { AutocompleteItem, EditorComponent, @@ -26,7 +26,6 @@ import type { OverlayOptions, SlashCommand, } from "@singularity-forge/tui"; -import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import { CombinedAutocompleteProvider, type Component, @@ -42,6 +41,7 @@ import { type Terminal as TuiTerminal, visibleWidth, } from "@singularity-forge/tui"; +import { fuzzyFilter } from "@singularity-forge/tui/fuzzy"; import { APP_NAME, getDebugLogPath, diff --git a/packages/coding-agent/src/resources/extensions/memory/index.ts b/packages/coding-agent/src/resources/extensions/memory/index.ts index e1ee45f29..40eae5273 100644 --- a/packages/coding-agent/src/resources/extensions/memory/index.ts +++ b/packages/coding-agent/src/resources/extensions/memory/index.ts @@ -15,10 +15,7 @@ import { existsSync, mkdirSync, rmSync } from "node:fs"; import { join } from "node:path"; import { completeSimple } from "@singularity-forge/ai"; import type { ExtensionAPI } from "@singularity-forge/coding-agent"; -import { - getAgentDir, - SettingsManager, -} from "@singularity-forge/coding-agent"; +import { getAgentDir, SettingsManager } from "@singularity-forge/coding-agent"; import { getFullMemory, getMemorySummary, runStartup } from "./pipeline.js"; import { MemoryStorage } from "./storage.js"; diff --git a/packages/coding-agent/src/utils/image-resize.ts b/packages/coding-agent/src/utils/image-resize.ts index 00b14a505..7e2a4c112 100644 --- a/packages/coding-agent/src/utils/image-resize.ts +++ b/packages/coding-agent/src/utils/image-resize.ts @@ -1,10 +1,10 @@ +import type { ImageContent } from "@singularity-forge/ai"; import type { NativeImageHandle } from "@singularity-forge/native/image"; import { ImageFormat, parseImage, SamplingFilter, } from "@singularity-forge/native/image"; -import type { ImageContent } from "@singularity-forge/ai"; export interface ImageResizeOptions { maxWidth?: number; // Default: 2000 diff --git a/packages/coding-agent/tsconfig.json b/packages/coding-agent/tsconfig.json index 8b4a00922..2292f8619 100644 --- a/packages/coding-agent/tsconfig.json +++ b/packages/coding-agent/tsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "target": "ES2024", "module": "Node16", - "lib": [ - "ES2024" - ], + "lib": ["ES2024"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, @@ -19,18 +17,10 @@ "resolveJsonModule": true, "allowImportingTsExtensions": false, "useDefineForClassFields": false, - "types": [ - "node" - ], + "types": ["node"], "outDir": "./dist", "rootDir": "./src" }, - "include": [ - "src/**/*.ts", - "src/**/*.d.ts" - ], - "exclude": [ - "node_modules", - "dist" - ] + "include": ["src/**/*.ts", "src/**/*.d.ts"], + "exclude": ["node_modules", "dist"] } diff --git a/packages/google-gemini-cli-provider/src/index.ts b/packages/google-gemini-cli-provider/src/index.ts index d71ff3ed7..4630472c6 100644 --- a/packages/google-gemini-cli-provider/src/index.ts +++ b/packages/google-gemini-cli-provider/src/index.ts @@ -7,14 +7,11 @@ * * Consumer: `@singularity-forge/ai` Google Gemini provider. */ +import { AuthType, makeFakeConfig } from "@google/gemini-cli-core"; import { - AuthType, - makeFakeConfig, -} from "@google/gemini-cli-core"; -import { + type ContentGenerator, createContentGenerator, createContentGeneratorConfig, - type ContentGenerator, } from "@google/gemini-cli-core/dist/src/core/contentGenerator.js"; export interface GeminiCliContentGeneratorOptions { diff --git a/packages/google-gemini-cli-provider/tsconfig.json b/packages/google-gemini-cli-provider/tsconfig.json index e8a3610d0..e22f0f518 100644 --- a/packages/google-gemini-cli-provider/tsconfig.json +++ b/packages/google-gemini-cli-provider/tsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "target": "ES2024", "module": "Node16", - "lib": [ - "ES2024" - ], + "lib": ["ES2024"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, @@ -19,19 +17,10 @@ "resolveJsonModule": true, "allowImportingTsExtensions": false, "useDefineForClassFields": false, - "types": [ - "node" - ], + "types": ["node"], "outDir": "./dist", "rootDir": "./src" }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules", - "dist", - "**/*.d.ts", - "src/**/*.d.ts" - ] + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "**/*.d.ts", "src/**/*.d.ts"] } diff --git a/packages/pi-agent-core/src/db/gate-registry.ts b/packages/pi-agent-core/src/db/gate-registry.ts index 5cefb8686..71457da7d 100644 --- a/packages/pi-agent-core/src/db/gate-registry.ts +++ b/packages/pi-agent-core/src/db/gate-registry.ts @@ -7,7 +7,17 @@ */ import { SF_PARSE_ERROR, SFError } from "./errors.js"; -export type GateId = "Q3" | "Q4" | "Q5" | "Q6" | "Q7" | "Q8" | "MV01" | "MV02" | "MV03" | "MV04"; +export type GateId = + | "Q3" + | "Q4" + | "Q5" + | "Q6" + | "Q7" + | "Q8" + | "MV01" + | "MV02" + | "MV03" + | "MV04"; export interface GateDefinition { id: GateId; diff --git a/packages/pi-agent-core/src/db/index.ts b/packages/pi-agent-core/src/db/index.ts index 8b2886a0f..5906c3fe8 100644 --- a/packages/pi-agent-core/src/db/index.ts +++ b/packages/pi-agent-core/src/db/index.ts @@ -1,5 +1,5 @@ -export * from "./sf-db.js"; export * from "./errors.js"; export * from "./gate-registry.js"; +export * from "./sf-db.js"; export * from "./task-frontmatter.js"; export * from "./workflow-logger.js"; diff --git a/packages/pi-agent-core/src/db/sf-db.ts b/packages/pi-agent-core/src/db/sf-db.ts index 0a7af817b..9011007fa 100644 --- a/packages/pi-agent-core/src/db/sf-db.ts +++ b/packages/pi-agent-core/src/db/sf-db.ts @@ -5,7 +5,10 @@ export type DbRow = Record; /** Wrapper around node:sqlite prepared statements. */ export interface DbStatement { - run(...params: unknown[]): { changes?: number; lastInsertRowid?: number | bigint }; + run(...params: unknown[]): { + changes?: number; + lastInsertRowid?: number | bigint; + }; get(...params: unknown[]): DbRow | undefined; all(...params: unknown[]): DbRow[]; } @@ -80,7 +83,11 @@ export interface SlicePlanningPayload { proofLevel?: string; integrationClosure?: string; observabilityImpact?: string; - adversarialReview?: { partner?: string; combatant?: string; architect?: string }; + adversarialReview?: { + partner?: string; + combatant?: string; + architect?: string; + }; planningMeeting?: unknown; [key: string]: unknown; } @@ -203,8 +210,8 @@ import { taskFrontmatterFromRecord, withTaskFrontmatter, } from "./task-frontmatter.js"; -import { logError, logWarning } from "./workflow-logger.js"; import { readTraceEvents } from "./uok/trace-writer.js"; +import { logError, logWarning } from "./workflow-logger.js"; let loadAttempted = false; function loadProvider(): void { @@ -220,17 +227,19 @@ function normalizeRow(row: unknown): Record | undefined { return row as Record; } function normalizeRows(rows: unknown[]): Record[] { - return rows.map((r) => normalizeRow(r)).filter((r): r is Record => r != null); + return rows + .map((r) => normalizeRow(r)) + .filter((r): r is Record => r != null); } const DB_QUERY_TIMEOUT_MS = 30_000; const DB_BACKUP_MIN_INTERVAL_MS = 15 * 60 * 1000; const DB_BACKUP_RETENTION = 24; const DB_FULL_VACUUM_MIN_INTERVAL_MS = 6 * 60 * 60 * 1000; -function createAdapter(rawDb: import('node:sqlite').DatabaseSync): DbAdapter { - const db: import('node:sqlite').DatabaseSync = rawDb; +function createAdapter(rawDb: import("node:sqlite").DatabaseSync): DbAdapter { + const db: import("node:sqlite").DatabaseSync = rawDb; const stmtCache = new Map(); - function wrapStmt(raw: import('node:sqlite').StatementSync): DbStatement { + function wrapStmt(raw: import("node:sqlite").StatementSync): DbStatement { return { run(...params: unknown[]) { return raw.run(...params); @@ -279,7 +288,7 @@ export function withQueryTimeout( return operation(); } catch (err) { const errMsg = (err as Error)?.message; -if (errMsg?.includes("timeout") || errMsg?.includes("busy")) { + if (errMsg?.includes("timeout") || errMsg?.includes("busy")) { logWarning( "sf-db", `Query timed out after ${timeoutMs}ms, returning fallback`, @@ -289,7 +298,7 @@ if (errMsg?.includes("timeout") || errMsg?.includes("busy")) { throw err; } } -function openRawDb(path: string): import('node:sqlite').DatabaseSync { +function openRawDb(path: string): import("node:sqlite").DatabaseSync { loadProvider(); return new DatabaseSync(path); } @@ -346,7 +355,10 @@ function readDatabaseMaintenanceState(path: string): Record { return {}; } } -function writeDatabaseMaintenanceState(path: string, state: Record): void { +function writeDatabaseMaintenanceState( + path: string, + state: Record, +): void { try { writeFileSync( databaseMaintenancePath(path), @@ -357,7 +369,10 @@ function writeDatabaseMaintenanceState(path: string, state: Record = {}): boolean { @@ -1644,14 +1665,17 @@ function isEmptyMilestoneSpec(row: Record): boolean { if (!row) return true; return ( (row["vision"] ?? "") === "" && - (parseJsonOrFallback(row["success_criteria"], []) as unknown[]).length === 0 && + (parseJsonOrFallback(row["success_criteria"], []) as unknown[]).length === + 0 && (parseJsonOrFallback(row["key_risks"], []) as unknown[]).length === 0 && - (parseJsonOrFallback(row["proof_strategy"], []) as unknown[]).length === 0 && + (parseJsonOrFallback(row["proof_strategy"], []) as unknown[]).length === + 0 && (row["verification_contract"] ?? "") === "" && (row["verification_integration"] ?? "") === "" && (row["verification_operational"] ?? "") === "" && (row["verification_uat"] ?? "") === "" && - (parseJsonOrFallback(row["definition_of_done"], []) as unknown[]).length === 0 && + (parseJsonOrFallback(row["definition_of_done"], []) as unknown[]).length === + 0 && (row["requirement_coverage"] ?? "") === "" && (row["boundary_map_markdown"] ?? "") === "" && (row["vision_meeting_json"] ?? "") === "" && @@ -3417,7 +3441,7 @@ export function getDatabase(): DbAdapter | null { /** * Open the database at the specified path. Returns true if successful. */ -export function openDatabase(path: string): void { +export function openDatabase(path: string): boolean { _dbOpenAttempted = true; if (currentDb && currentPath !== path) closeDatabase(); if (currentDb && currentPath === path) return true; @@ -3445,7 +3469,10 @@ export function openDatabase(path: string): void { try { adapter.close(); } catch (e) { - logWarning("db", `close after VACUUM failed: ${(e as Error)?.message}`); + logWarning( + "db", + `close after VACUUM failed: ${(e as Error)?.message}`, + ); } throw retryErr; } @@ -3904,10 +3931,16 @@ export function insertMilestone(m: MilestoneInput): void { ":sequence": m.sequence ?? 0, }); if (hasPlanningPayload(m.planning as Record)) { - insertMilestoneSpecIfAbsent(m.id, (m.planning ?? {}) as Record); + insertMilestoneSpecIfAbsent( + m.id, + (m.planning ?? {}) as Record, + ); } } -function insertMilestoneSpecIfAbsent(milestoneId: string, planning: Record = {}): void { +function insertMilestoneSpecIfAbsent( + milestoneId: string, + planning: Record = {}, +): void { if (!hasPlanningPayload(planning)) return; const existing = (currentDb as DbAdapter) .prepare("SELECT * FROM milestone_specs WHERE id = ?") @@ -3968,7 +4001,10 @@ function insertMilestoneSpecIfAbsent(milestoneId: string, planning: Record): void { +export function upsertMilestonePlanning( + milestoneId: string, + planning: Record, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); insertMilestoneSpecIfAbsent(milestoneId, planning); currentDb @@ -4099,7 +4135,11 @@ export function insertSlice(s: SliceInput): void { }); insertSliceSpecIfAbsent(s.milestoneId, s.id, s.planning ?? {}); } -function insertSliceSpecIfAbsent(milestoneId: string, sliceId: string, planning: Record = {}): void { +function insertSliceSpecIfAbsent( + milestoneId: string, + sliceId: string, + planning: Record = {}, +): void { currentDb .prepare(`INSERT OR IGNORE INTO slice_specs ( milestone_id, slice_id, goal, success_criteria, proof_level, @@ -4142,7 +4182,11 @@ export function clearSliceSketch(milestoneId: string, sliceId: string): void { * mark a slice as a sketch (e.g., a re-plan flow that wants to revert to * sketch-then-refine). */ -export function setSliceSketchFlag(milestoneId: string, sliceId: string, isSketch: boolean): void { +export function setSliceSketchFlag( + milestoneId: string, + sliceId: string, + isSketch: boolean, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -4160,7 +4204,10 @@ export function setSliceSketchFlag(milestoneId: string, sliceId: string, isSketc * resolver so path logic stays in one place. Safe to call repeatedly — only * flips rows that meet the predicate. */ -export function autoHealSketchFlags(milestoneId: string, hasPlanFile: (sliceId: string) => boolean): void { +export function autoHealSketchFlags( + milestoneId: string, + hasPlanFile: (sliceId: string) => boolean, +): void { if (!currentDb) return; const rows = currentDb .prepare( @@ -4168,8 +4215,8 @@ export function autoHealSketchFlags(milestoneId: string, hasPlanFile: (sliceId: ) .all({ ":mid": milestoneId }); for (const row of rows) { - if (hasPlanFile(row['id'] as string)) { - setSliceSketchFlag(milestoneId, row['id'] as string, false); + if (hasPlanFile(row["id"] as string)) { + setSliceSketchFlag(milestoneId, row["id"] as string, false); } } } @@ -4181,7 +4228,10 @@ export function autoHealSketchFlags(milestoneId: string, hasPlanFile: (sliceId: * * Used by `/escalate list` to enumerate cross-slice escalations. */ -export function listEscalationArtifacts(milestoneId: string, includeResolved = false): DbRow[] { +export function listEscalationArtifacts( + milestoneId: string, + includeResolved = false, +): DbRow[] { if (!currentDb) return []; const filter = includeResolved ? "escalation_artifact_path IS NOT NULL" @@ -4193,7 +4243,11 @@ export function listEscalationArtifacts(milestoneId: string, includeResolved = f .all({ ":mid": milestoneId }); return rows.map(rowToTask); } -export function upsertSlicePlanning(milestoneId: string, sliceId: string, planning: Record): void { +export function upsertSlicePlanning( + milestoneId: string, + sliceId: string, + planning: Record, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); insertSliceSpecIfAbsent(milestoneId, sliceId, planning); currentDb @@ -4334,10 +4388,20 @@ function hasTaskSpecIntent(planning: Record = {}): boolean { } return false; } -function insertTaskSpecIfAbsent(milestoneId: string, sliceId: string, taskId: string, planning: Record = {}): void { +function insertTaskSpecIfAbsent( + milestoneId: string, + sliceId: string, + taskId: string, + planning: Record = {}, +): void { if (!hasTaskSpecIntent(planning)) return; - const { normalized: frontmatter, errors } = taskFrontmatterFromRecord(planning); - if (errors?.length) logWarning("sf-db:insertTaskSpec", `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${errors.join(", ")}`); + const { normalized: frontmatter, errors } = + taskFrontmatterFromRecord(planning); + if (errors?.length) + logWarning( + "sf-db:insertTaskSpec", + `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${errors.join(", ")}`, + ); currentDb .prepare(`INSERT OR IGNORE INTO task_specs ( milestone_id, slice_id, task_id, verify, inputs, expected_output, @@ -4370,7 +4434,11 @@ function insertTaskSpecIfAbsent(milestoneId: string, sliceId: string, taskId: st ":created_at": new Date().toISOString(), }); } -function insertTaskSchedulerIfAbsent(milestoneId: string, sliceId: string, taskId: string): void { +function insertTaskSchedulerIfAbsent( + milestoneId: string, + sliceId: string, + taskId: string, +): void { upsertTaskSchedulerStatus(milestoneId, sliceId, taskId, "queued", { onlyIfAbsent: true, }); @@ -4485,7 +4553,11 @@ export function setTaskEscalationAwaitingReview( /** SF ADR-011 P2: clear both escalation flags (called when an escalation is * resolved or its artifact is removed). Leaves escalation_artifact_path so * the resolution audit trail survives. */ -export function clearTaskEscalationFlags(milestoneId: string, sliceId: string, taskId: string): void { +export function clearTaskEscalationFlags( + milestoneId: string, + sliceId: string, + taskId: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare(`UPDATE tasks @@ -4504,7 +4576,10 @@ export function clearTaskEscalationFlags(milestoneId: string, sliceId: string, t * escalation_override_applied=0. The artifact's respondedAt is checked by * the caller (claimOverrideForInjection in escalation.ts) — keeping artifact * schema knowledge out of the DB layer. */ -export function findUnappliedEscalationOverride(milestoneId: string, sliceId: string): DbRow | undefined { +export function findUnappliedEscalationOverride( + milestoneId: string, + sliceId: string, +): DbRow | undefined { if (!currentDb) return null; const row = currentDb .prepare(`SELECT id, escalation_artifact_path @@ -4525,7 +4600,11 @@ export function findUnappliedEscalationOverride(milestoneId: string, sliceId: st * Returns true when this caller successfully flipped 0→1 (race winner) or * false when another caller claimed it first (race loser). Use this to * guarantee the override is injected exactly once. */ -export function claimEscalationOverride(milestoneId: string, sliceId: string, taskId: string): void { +export function claimEscalationOverride( + milestoneId: string, + sliceId: string, + taskId: string, +): boolean { if (!currentDb) return; const result = currentDb .prepare(`UPDATE tasks @@ -4555,11 +4634,21 @@ export function setTaskBlockerDiscovered( ":tid": taskId, }); } -export function upsertTaskPlanning(milestoneId: string, sliceId: string, taskId: string, planning: Record): void { +export function upsertTaskPlanning( + milestoneId: string, + sliceId: string, + taskId: string, + planning: Record, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); insertTaskSpecIfAbsent(milestoneId, sliceId, taskId, planning); - const { normalized: frontmatter, errors: fmErrors } = taskFrontmatterFromRecord(planning); - if (fmErrors?.length) logWarning("sf-db:upsertTaskPlanning", `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${fmErrors.join(", ")}`); + const { normalized: frontmatter, errors: fmErrors } = + taskFrontmatterFromRecord(planning); + if (fmErrors?.length) + logWarning( + "sf-db:upsertTaskPlanning", + `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${fmErrors.join(", ")}`, + ); const hasTaskStatus = planning.taskStatus !== undefined || planning.task_status !== undefined || @@ -4665,7 +4754,10 @@ function rowToSlice(row: Record): Record { is_sketch: row["is_sketch"] ?? 0, }; } -export function getSlice(milestoneId: string, sliceId: string): DbRow | undefined { +export function getSlice( + milestoneId: string, + sliceId: string, +): DbRow | undefined { if (!currentDb) return null; const row = currentDb .prepare("SELECT * FROM slices WHERE milestone_id = :mid AND id = :sid") @@ -4673,7 +4765,12 @@ export function getSlice(milestoneId: string, sliceId: string): DbRow | undefine if (!row) return null; return rowToSlice(row); } -export function updateSliceStatus(milestoneId: string, sliceId: string, status: string, completedAt: string | null): void { +export function updateSliceStatus( + milestoneId: string, + sliceId: string, + status: string, + completedAt: string | null, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare(`UPDATE slices SET status = :status, completed_at = :completed_at @@ -4689,7 +4786,11 @@ export function updateSliceStatus(milestoneId: string, sliceId: string, status: * Store the UAT verdict for a slice. Called when an ASSESSMENT or UAT_RESULT * file is written so the DB is the canonical source for verdict checks. */ -export function setSliceUatVerdict(milestoneId: string, sliceId: string, verdict: string): void { +export function setSliceUatVerdict( + milestoneId: string, + sliceId: string, + verdict: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -4700,7 +4801,10 @@ export function setSliceUatVerdict(milestoneId: string, sliceId: string, verdict /** * Returns the stored UAT verdict for a slice, or null if not yet recorded. */ -export function getSliceUatVerdict(milestoneId: string, sliceId: string): string | null { +export function getSliceUatVerdict( + milestoneId: string, + sliceId: string, +): string | null { if (!currentDb) return null; const row = currentDb .prepare( @@ -4774,7 +4878,12 @@ export function backfillUatVerdicts(basePath: string): void { } } } -export function setTaskSummaryMd(milestoneId: string, sliceId: string, taskId: string, md: string): void { +export function setTaskSummaryMd( + milestoneId: string, + sliceId: string, + taskId: string, + md: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -4782,7 +4891,12 @@ export function setTaskSummaryMd(milestoneId: string, sliceId: string, taskId: s ) .run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId, ":md": md }); } -export function setSliceSummaryMd(milestoneId: string, sliceId: string, summaryMd: string, uatMd: string): void { +export function setSliceSummaryMd( + milestoneId: string, + sliceId: string, + summaryMd: string, + uatMd: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -4888,7 +5002,11 @@ function rowToTask(row) { escalation_artifact_path: row["escalation_artifact_path"] ?? null, }); } -export function getTask(milestoneId: string, sliceId: string, taskId: string): DbRow | undefined { +export function getTask( + milestoneId: string, + sliceId: string, + taskId: string, +): DbRow | undefined { if (!currentDb) return null; const row = currentDb .prepare( @@ -4936,7 +5054,11 @@ export function insertVerificationEvidence(e: VerificationEvidenceInput): void { ":created_at": new Date().toISOString(), }); } -export function getVerificationEvidence(milestoneId: string, sliceId: string, taskId: string): DbRow[] { +export function getVerificationEvidence( + milestoneId: string, + sliceId: string, + taskId: string, +): DbRow[] { if (!currentDb) return []; const rows = currentDb .prepare( @@ -5041,7 +5163,10 @@ export function listSelfFeedbackEntries(): DbRow[] { .all(); return rows.map(rowToSelfFeedback); } -export function resolveSelfFeedbackEntry(entryId: string, resolution: Record): void { +export function resolveSelfFeedbackEntry( + entryId: string, + resolution: Record, +): boolean { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const existing = currentDb .prepare("SELECT * FROM self_feedback WHERE id = :id") @@ -5226,7 +5351,11 @@ export function addBacklogItem({ }); return itemId; } -export function updateBacklogItemStatus(id: string, status: string, note = ""): void { +export function updateBacklogItemStatus( + id: string, + status: string, + note = "", +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const now = new Date().toISOString(); const result = currentDb @@ -5242,21 +5371,24 @@ export function updateBacklogItemStatus(id: string, status: string, note = ""): ":note": note, ":updated_at": now, }); - return (result?.changes ?? 0) > 0; + void ((result?.changes ?? 0) > 0); } export function removeBacklogItem(id: string): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); - const result = currentDb + currentDb .prepare("DELETE FROM backlog_items WHERE id = :id") .run({ ":id": id }); - return (result?.changes ?? 0) > 0; } /** * Update a milestone's status in the database. * Used by park/unpark to keep the DB in sync with the filesystem marker. * See: https://github.com/singularity-forge/sf-run/issues/2694 */ -export function updateMilestoneStatus(milestoneId: string, status: string, completedAt: string | null): void { +export function updateMilestoneStatus( + milestoneId: string, + status: string, + completedAt: string | null, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -5319,7 +5451,10 @@ export function getActiveSliceFromDb(milestoneId: string): DbRow | undefined { if (!row) return null; return rowToSlice(row); } -export function getActiveTaskFromDb(milestoneId: string, sliceId: string): DbRow | undefined { +export function getActiveTaskFromDb( + milestoneId: string, + sliceId: string, +): DbRow | undefined { if (!currentDb) return null; const row = currentDb .prepare( @@ -5369,7 +5504,10 @@ export function getSliceStatusSummary(milestoneId: string): DbRow[] { .map((r) => ({ id: r["id"], status: r["status"] })); } /** Fast task status check — avoids deserializing JSON arrays and large text fields. */ -export function getActiveTaskIdFromDb(milestoneId: string, sliceId: string): string | null { +export function getActiveTaskIdFromDb( + milestoneId: string, + sliceId: string, +): string | null { if (!currentDb) return null; const row = currentDb .prepare( @@ -5384,7 +5522,10 @@ export function getActiveTaskIdFromDb(milestoneId: string, sliceId: string): str }; } /** Count tasks by status for a slice — useful for progress reporting without full row load. */ -export function getSliceTaskCounts(milestoneId: string, sliceId: string): DbRow | undefined { +export function getSliceTaskCounts( + milestoneId: string, + sliceId: string, +): DbRow | undefined { if (!currentDb) return { total: 0, done: 0, pending: 0 }; const row = currentDb .prepare(`SELECT @@ -5402,7 +5543,11 @@ export function getSliceTaskCounts(milestoneId: string, sliceId: string): DbRow } // ─── Slice Dependencies (junction table) ───────────────────────────────── /** Sync the slice_dependencies junction table from a slice's JSON depends array. */ -export function syncSliceDependencies(milestoneId: string, sliceId: string, depends: string[]): void { +export function syncSliceDependencies( + milestoneId: string, + sliceId: string, + depends: string[], +): void { if (!currentDb) return; currentDb .prepare( @@ -5418,7 +5563,10 @@ export function syncSliceDependencies(milestoneId: string, sliceId: string, depe } } /** Get all slices that depend on a given slice. */ -export function getDependentSlices(milestoneId: string, sliceId: string): DbRow[] { +export function getDependentSlices( + milestoneId: string, + sliceId: string, +): DbRow[] { if (!currentDb) return []; return currentDb .prepare( @@ -5428,7 +5576,7 @@ export function getDependentSlices(milestoneId: string, sliceId: string): DbRow[ .map((r) => r["slice_id"]); } // ─── Worktree DB Helpers ────────────────────────────────────────────────── -export function copyWorktreeDb(srcDbPath: string, destDbPath: string): void { +export function copyWorktreeDb(srcDbPath: string, destDbPath: string): boolean { try { if (!existsSync(srcDbPath)) return false; const destDir = dirname(destDbPath); @@ -6099,7 +6247,9 @@ export function recordUokRunExit(entry) { ":status": entry.status ?? "ok", ":started_at": entry.startedAt ?? now, ":ended_at": now, - ":error": entry.error ? capErrorForStorage(entry.error, entry.runId) : null, + ":error": entry.error + ? capErrorForStorage(entry.error, entry.runId) + : null, ":flags_json": JSON.stringify(entry.flags ?? {}), ":updated_at": now, }); @@ -6420,7 +6570,10 @@ export function getRecentLlmTaskOutcomes(hours = 24, limit = 100): DbRow[] { * * Consumer: uok/cost-guard-gate.js, uok/outcome-learning-gate.js. */ -export function getLlmTaskOutcomeStats(modelId: string, windowHours = 24): DbRow[] { +export function getLlmTaskOutcomeStats( + modelId: string, + windowHours = 24, +): DbRow[] { if (!currentDb) { return { total: 0, @@ -6483,13 +6636,18 @@ export function getLlmTaskOutcomeStats(modelId: string, windowHours = 24): DbRow * * Consumer: uok/diagnostic-synthesis.js, uok/gate-runner.js health checks. */ -export function getGateRunStats(gateId: string, windowHours = 24): DbRow | undefined { +export function getGateRunStats( + gateId: string, + windowHours = 24, +): DbRow | undefined { try { - const basePath = currentPath && currentPath !== ":memory:" - ? dirname(dirname(currentPath)) - : process.cwd(); - const events = readTraceEvents(basePath, "gate_run", windowHours) - .filter((e) => e.gateId === gateId); + const basePath = + currentPath && currentPath !== ":memory:" + ? dirname(dirname(currentPath)) + : process.cwd(); + const events = readTraceEvents(basePath, "gate_run", windowHours).filter( + (e) => e.gateId === gateId, + ); const stats = { total: events.length, pass: 0, @@ -6587,7 +6745,10 @@ export function getGateCircuitBreaker(gateId: string): DbRow | undefined { * * Consumer: uok/gate-runner.js after executing a gate. */ -export function updateGateCircuitBreaker(gateId: string, updates: Record): void { +export function updateGateCircuitBreaker( + gateId: string, + updates: Record, +): void { if (!currentDb) return; currentDb .prepare( @@ -6613,22 +6774,34 @@ export function updateGateCircuitBreaker(gateId: string, updates: Record e.gateId === gateId && typeof e.durationMs === "number") .map((e) => e.durationMs) .sort((a, b) => a - b); - if (durations.length === 0) return { p50: null, p95: null, count: 0, total: 0, avgMs: 0, p50Ms: 0, p95Ms: 0, maxMs: 0 }; + if (durations.length === 0) + return { + p50: null, + p95: null, + count: 0, + total: 0, + avgMs: 0, + p50Ms: 0, + p95Ms: 0, + maxMs: 0, + }; const p50Ms = durations[Math.floor(durations.length * 0.5)] ?? 0; const p95Ms = durations[Math.floor(durations.length * 0.95)] ?? 0; const maxMs = durations[durations.length - 1] ?? 0; - const avgMs = Math.round(durations.reduce((s, v) => s + v, 0) / durations.length); + const avgMs = Math.round( + durations.reduce((s, v) => s + v, 0) / durations.length, + ); return { p50: p50Ms, p95: p95Ms, @@ -6640,14 +6813,24 @@ export function getGateLatencyStats(gateId: string, windowHours = 24): DbRow[] { maxMs, }; } catch { - return { p50: null, p95: null, count: 0, total: 0, avgMs: 0, p50Ms: 0, p95Ms: 0, maxMs: 0 }; + return { + p50: null, + p95: null, + count: 0, + total: 0, + avgMs: 0, + p50Ms: 0, + p95Ms: 0, + maxMs: 0, + }; } } export function getDistinctGateIds(): string[] { try { - const basePath = currentPath && currentPath !== ":memory:" - ? dirname(dirname(currentPath)) - : process.cwd(); + const basePath = + currentPath && currentPath !== ":memory:" + ? dirname(dirname(currentPath)) + : process.cwd(); const events = readTraceEvents(basePath, "gate_run", 24 * 30); // 30 days return [...new Set(events.map((e) => e.gateId).filter(Boolean))]; } catch { @@ -6705,7 +6888,11 @@ export function getUokMessagesForAgent( return []; } } -export function getUokConversation(agentA: string, agentB: string, limit = 1000): DbRow[] { +export function getUokConversation( + agentA: string, + agentB: string, + limit = 1000, +): DbRow[] { if (!currentDb) return []; try { const rows = currentDb @@ -6742,9 +6929,8 @@ export function markUokMessageRead(messageId: string, agentId: string): void { ":agent_id": agentId, ":read_at": new Date().toISOString(), }); - return true; } catch { - return false; + // best-effort } } export function getUokMessageUnreadCount(agentId: string): number { @@ -6765,7 +6951,10 @@ export function getUokMessageUnreadCount(agentId: string): number { return 0; } } -export function compactUokMessages(retentionDays: number): void { +export function compactUokMessages(retentionDays: number): { + before: number; + after: number; +} { if (!currentDb) return { before: 0, after: 0 }; try { const cutoff = new Date( @@ -6847,7 +7036,9 @@ export function getUokMessageBusMetrics(): DbRow | undefined { function normalizeScheduleScope(scope: unknown): string { return scope === "global" ? "global" : "project"; } -function scheduleEntryFromRow(row: Record): Record { +function scheduleEntryFromRow( + row: Record, +): Record { if (!row) return null; const full = parseJsonObject(row.full_json, {}); return { @@ -6872,7 +7063,11 @@ function scheduleEntryFromRow(row: Record): Record, importedFrom: string | null = null): void { +export function insertScheduleEntry( + scope: string, + entry: Record, + importedFrom: string | null = null, +): void { if (!currentDb) return; const normalizedScope = normalizeScheduleScope(scope); const schemaVersion = entry.schemaVersion ?? 1; @@ -7092,14 +7287,19 @@ export function getRepoFileObservations(): DbRow[] { function intBool(value: unknown): boolean { return value ? 1 : 0; } -function parseJsonObject(raw: unknown, fallback: Record = {}): Record { +function parseJsonObject( + raw: unknown, + fallback: Record = {}, +): Record { try { return JSON.parse(raw); } catch { return fallback; } } -function solverEvalRunFromRow(row: Record): Record { +function solverEvalRunFromRow( + row: Record, +): Record { return { runId: row["run_id"], suiteSource: row["suite_source"], @@ -7112,7 +7312,9 @@ function solverEvalRunFromRow(row: Record): Record): Record { +function solverEvalCaseFromRow( + row: Record, +): Record { return { runId: row["run_id"], caseId: row["case_id"], @@ -7131,7 +7333,9 @@ function solverEvalCaseFromRow(row: Record): Record): Record { +function headlessRunFromRow( + row: Record, +): Record { return { runId: row["run_id"], command: row["command"], @@ -7442,7 +7646,9 @@ export function unarchiveSession(sessionId: string): void { * Consumer: session-recorder.js on before_agent_start (user_message) and * agent_end (assistant_response patch). */ -export function insertSessionTurn(entry: Record): void { +export function insertSessionTurn( + entry: Record, +): bigint | null { if (!currentDb) return null; const result = currentDb .prepare(`INSERT INTO turns @@ -7469,7 +7675,11 @@ export function insertSessionTurn(entry: Record): void { * * Consumer: session-recorder.js on agent_end. */ -export function patchTurnResponse(sessionId: string, turnIndex: number, assistantResponse: string): void { +export function patchTurnResponse( + sessionId: string, + turnIndex: number, + assistantResponse: string, +): void { if (!currentDb) return; currentDb .prepare(`UPDATE turns SET assistant_response = :resp @@ -7815,7 +8025,9 @@ export function restoreManifest(manifest: Record): void { * Used by workflow-migration.ts to populate engine tables from parsed ROADMAP/PLAN * files. All operations run inside a single transaction. */ -export function bulkInsertLegacyHierarchy(payload: Record): void { +export function bulkInsertLegacyHierarchy( + payload: Record, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const db = currentDb; const { milestones, slices, tasks, clearMilestoneIds, createdAt } = payload; @@ -7874,18 +8086,38 @@ export function bulkInsertLegacyHierarchy(payload: Record): voi // All memory writes go through sf-db.ts so the single-writer invariant // holds. These are direct pass-throughs to the SQL previously in // memory-store.ts — same bindings, same behavior. -export function getActiveMemories({ category, limit = 200 }: { category?: string; limit?: number } = {}): DbRow[] { +export function getActiveMemories({ + category, + limit = 200, +}: { + category?: string; + limit?: number; +} = {}): DbRow[] { if (!currentDb) return []; const rows = category - ? currentDb.prepare("SELECT * FROM active_memories WHERE category = ? ORDER BY updated_at DESC LIMIT ?").all(category, limit) - : currentDb.prepare("SELECT * FROM active_memories ORDER BY updated_at DESC LIMIT ?").all(limit); + ? currentDb + .prepare( + "SELECT * FROM active_memories WHERE category = ? ORDER BY updated_at DESC LIMIT ?", + ) + .all(category, limit) + : currentDb + .prepare( + "SELECT * FROM active_memories ORDER BY updated_at DESC LIMIT ?", + ) + .all(limit); return rows.map((r) => ({ id: r["id"], category: r["category"], content: r["content"], confidence: r["confidence"], sourceUnitId: r["source_unit_id"], - tags: (() => { try { return JSON.parse(r["tags"] ?? "[]"); } catch { return []; } })(), + tags: (() => { + try { + return JSON.parse(r["tags"] ?? "[]"); + } catch { + return []; + } + })(), createdAt: r["created_at"], updatedAt: r["updated_at"], })); @@ -7916,7 +8148,12 @@ export function rewriteMemoryId(placeholderId: string, realId: string): void { ":placeholder": placeholderId, }); } -export function updateMemoryContentRow(id: string, content: string, confidence: number, updatedAt: string): void { +export function updateMemoryContentRow( + id: string, + content: string, + confidence: number, + updatedAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); if (confidence != null) { currentDb @@ -7945,7 +8182,11 @@ export function incrementMemoryHitCount(id: string, updatedAt: string): void { ) .run({ ":updated_at": updatedAt, ":id": id }); } -export function supersedeMemoryRow(oldId: string, newId: string, updatedAt: string): void { +export function supersedeMemoryRow( + oldId: string, + newId: string, + updatedAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -7953,7 +8194,11 @@ export function supersedeMemoryRow(oldId: string, newId: string, updatedAt: stri ) .run({ ":new_id": newId, ":updated_at": updatedAt, ":old_id": oldId }); } -export function markMemoryUnitProcessed(unitKey: string, activityFile: string | null, processedAt: string): void { +export function markMemoryUnitProcessed( + unitKey: string, + activityFile: string | null, + processedAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare(`INSERT OR IGNORE INTO memory_processed_units (unit_key, activity_file, processed_at) @@ -7982,7 +8227,10 @@ export function decayMemoriesBefore(cutoffTs: string, now: string): void { * Consumer: called at autonomous mode startup from auto-start.js. * Returns the number of memories superseded. */ -export function expireStaleMemories(unstartedTtlDays = 28, maxTtlDays = 90): void { +export function expireStaleMemories( + unstartedTtlDays = 28, + maxTtlDays = 90, +): number { if (!currentDb) return 0; const now = new Date().toISOString(); const cutoffUnstarted = new Date( @@ -8005,7 +8253,10 @@ export function expireStaleMemories(unstartedTtlDays = 28, maxTtlDays = 90): voi }); return result.changes ?? 0; } -export function supersedeLowestRankedMemories(limit: number, now: string): void { +export function supersedeLowestRankedMemories( + limit: number, + now: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare(`UPDATE memories SET superseded_by = 'CAP_EXCEEDED', updated_at = :now @@ -8035,7 +8286,7 @@ export function insertMemorySourceRow(args: Record): void { ":tags": JSON.stringify(args.tags ?? []), }); } -export function deleteMemorySourceRow(id: string): void { +export function deleteMemorySourceRow(id: string): boolean { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const res = currentDb .prepare("DELETE FROM memory_sources WHERE id = :id") @@ -8061,7 +8312,10 @@ export function insertJudgment(entry: Record): void { // Judgment logging is best-effort } } -export function getJudgmentsForUnit(unitIdPrefix: string, limit = 1000): DbRow[] { +export function getJudgmentsForUnit( + unitIdPrefix: string, + limit = 1000, +): DbRow[] { if (!currentDb) return []; try { const rows = currentDb @@ -8175,7 +8429,7 @@ export function upsertMemoryEmbedding(args: Record): void { ":updated_at": args.updatedAt, }); } -export function deleteMemoryEmbedding(memoryId: string): void { +export function deleteMemoryEmbedding(memoryId: string): boolean { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const res = currentDb .prepare("DELETE FROM memory_embeddings WHERE memory_id = :id") @@ -8296,7 +8550,10 @@ export function getMilestoneAuditTrail(milestoneId: string): DbRow[] { * Purpose: Support data archaeology and decision-tree reconstruction. * Consumer: forensics tools, doctor checks, audit/compliance queries. */ -export function getSliceAuditTrail(milestoneId: string, sliceId: string): DbRow[] { +export function getSliceAuditTrail( + milestoneId: string, + sliceId: string, +): DbRow[] { if (!currentDb) return []; return currentDb .prepare(` @@ -8318,7 +8575,11 @@ export function getSliceAuditTrail(milestoneId: string, sliceId: string): DbRow[ * Purpose: Support data archaeology and decision-tree reconstruction. * Consumer: forensics tools, doctor checks, audit/compliance queries. */ -export function getTaskAuditTrail(milestoneId: string, sliceId: string, taskId: string): DbRow[] { +export function getTaskAuditTrail( + milestoneId: string, + sliceId: string, + taskId: string, +): DbRow[] { if (!currentDb) return []; return currentDb .prepare(` @@ -8352,7 +8613,10 @@ export function getMilestoneSpec(milestoneId: string): DbRow | undefined { * Purpose: Retrieve spec intent for re-planning or spec validation. * Consumer: plan-slice and spec validation tools. */ -export function getSliceSpec(milestoneId: string, sliceId: string): DbRow | undefined { +export function getSliceSpec( + milestoneId: string, + sliceId: string, +): DbRow | undefined { if (!currentDb) return null; return currentDb .prepare( @@ -8366,7 +8630,11 @@ export function getSliceSpec(milestoneId: string, sliceId: string): DbRow | unde * Purpose: Retrieve spec intent for re-planning or spec validation. * Consumer: plan-task and spec validation tools. */ -export function getTaskSpec(milestoneId: string, sliceId: string, taskId: string): DbRow | undefined { +export function getTaskSpec( + milestoneId: string, + sliceId: string, + taskId: string, +): DbRow | undefined { if (!currentDb) return null; return currentDb .prepare( @@ -8387,7 +8655,17 @@ export function getTaskSpec(milestoneId: string, sliceId: string, taskId: string * * Consumer: autonomous-solver, plan-slice, quality gates, eval runners. */ -export function startValidationRun({ milestoneId, sliceId, taskId, contract }: { milestoneId: string; sliceId: string; taskId: string; contract: string }): string { +export function startValidationRun({ + milestoneId, + sliceId, + taskId, + contract, +}: { + milestoneId: string; + sliceId: string; + taskId: string; + contract: string; +}): string { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const runId = crypto.randomUUID(); currentDb @@ -8452,7 +8730,11 @@ export function completeValidationRun({ * * Consumer: any surface that needs "are we passing?" for a milestone/slice/task. */ -export function getLatestValidationState(milestoneId: string, sliceId: string, taskId: string): DbRow | undefined { +export function getLatestValidationState( + milestoneId: string, + sliceId: string, + taskId: string, +): DbRow | undefined { if (!currentDb) return null; const rows = currentDb .prepare( @@ -8477,7 +8759,12 @@ export function getLatestValidationState(milestoneId: string, sliceId: string, t * * Consumer: forensics, eval review, audit trail queries. */ -export function getValidationHistory(milestoneId: string, sliceId: string, taskId: string, limit = 20): DbRow[] { +export function getValidationHistory( + milestoneId: string, + sliceId: string, + taskId: string, + limit = 20, +): DbRow[] { if (!currentDb) return []; return currentDb .prepare( @@ -8503,7 +8790,11 @@ export function getValidationHistory(milestoneId: string, sliceId: string, taskI * Purpose: replace .sf/triage/evals|inbox|skills JSONL files with queryable DB rows. * Consumer: commands-todo.js triageTodoDump after successful triage. */ -export function insertTriageRun(id: string, sourceFile: string | null, createdAt: string): void { +export function insertTriageRun( + id: string, + sourceFile: string | null, + createdAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -8523,7 +8814,12 @@ export function insertTriageRun(id: string, sourceFile: string | null, createdAt * Purpose: store eval candidates in DB instead of .evals.jsonl. * Consumer: commands-todo.js triageTodoDump. */ -export function insertTriageEval(id: string, runId: string, data: Record, createdAt: string): void { +export function insertTriageEval( + id: string, + runId: string, + data: Record, + createdAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -8577,7 +8873,12 @@ export function insertTriageItem( * Purpose: store skill proposals in DB instead of .skills.jsonl. * Consumer: commands-todo.js triageTodoDump. */ -export function insertTriageSkill(id: string, runId: string, data: Record, createdAt: string): void { +export function insertTriageSkill( + id: string, + runId: string, + data: Record, + createdAt: string, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); currentDb .prepare( @@ -8658,7 +8959,9 @@ export function incrementRuntimeCounter(key: string): number { * Purpose: replace .sf/runtime/validation-attention/{mid}.json reads. * Consumer: auto-dispatch.js hasActiveValidationAttentionMarker. */ -export function getValidationAttentionMarker(milestoneId: string): DbRow | undefined { +export function getValidationAttentionMarker( + milestoneId: string, +): DbRow | undefined { if (!currentDb) return null; return ( currentDb @@ -8674,7 +8977,10 @@ export function getValidationAttentionMarker(milestoneId: string): DbRow | undef * Purpose: replace .sf/runtime/validation-attention/{mid}.json writes. * Consumer: auto-dispatch.js writeValidationAttentionMarker. */ -export function upsertValidationAttentionMarker(milestoneId: string, marker: Record): void { +export function upsertValidationAttentionMarker( + milestoneId: string, + marker: Record, +): void { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); const now = new Date().toISOString(); currentDb @@ -8705,7 +9011,12 @@ export function upsertValidationAttentionMarker(milestoneId: string, marker: Rec * Purpose: persist adaptive tier learning to DB so routing decisions survive restarts. * Consumer: routing-history.js recordOutcome. */ -export function upsertRoutingOutcome(db: DbAdapter, pattern: string, tier: string, success: boolean): void { +export function upsertRoutingOutcome( + db: DbAdapter, + pattern: string, + tier: string, + success: boolean, +): void { db.prepare( `INSERT INTO routing_history (pattern, tier, success_count, fail_count, updated_at) VALUES (:pattern, :tier, :success_count, :fail_count, :updated_at) @@ -8740,7 +9051,10 @@ export function getAllRoutingHistory(db: DbAdapter): DbRow[] { * Purpose: targeted pattern lookup for adaptive tier queries. * Consumer: routing-history.js getRoutingHistoryForPattern. */ -export function getRoutingHistoryForPattern(db: DbAdapter, pattern: string): DbRow[] { +export function getRoutingHistoryForPattern( + db: DbAdapter, + pattern: string, +): DbRow[] { return db .prepare( "SELECT tier, success_count, fail_count FROM routing_history WHERE pattern = ?", @@ -8753,7 +9067,12 @@ export function getRoutingHistoryForPattern(db: DbAdapter, pattern: string): DbR * Purpose: persist user feedback for later analysis and weighted outcome application. * Consumer: routing-history.js recordFeedback. */ -export function insertRoutingFeedback(db: DbAdapter, pattern: string, tier: string, feedback: string): void { +export function insertRoutingFeedback( + db: DbAdapter, + pattern: string, + tier: string, + feedback: string, +): void { db.prepare( `INSERT INTO routing_feedback (pattern, tier, feedback, recorded_at) VALUES (:pattern, :tier, :feedback, :recorded_at)`, @@ -8777,7 +9096,9 @@ export function clearRoutingHistory(db: DbAdapter): void { // ─── Unit Metrics CRUD ──────────────────────────────────────────────────────── -function rowToUnitMetrics(row: Record): Record { +function rowToUnitMetrics( + row: Record, +): Record { const unit = { type: row["type"], id: row["id"], @@ -8826,7 +9147,10 @@ function rowToUnitMetrics(row: Record): Record * * Consumer: metrics.js saveLedger (called after every unit snapshot). */ -export function upsertUnitMetrics(db: DbAdapter, unit: Record): void { +export function upsertUnitMetrics( + db: DbAdapter, + unit: Record, +): void { db.prepare( `INSERT OR REPLACE INTO unit_metrics ( type, id, started_at, finished_at, model, auto_session_key, diff --git a/packages/pi-agent-core/src/db/task-frontmatter.ts b/packages/pi-agent-core/src/db/task-frontmatter.ts index 547eddc8c..a7e5f3161 100644 --- a/packages/pi-agent-core/src/db/task-frontmatter.ts +++ b/packages/pi-agent-core/src/db/task-frontmatter.ts @@ -9,7 +9,13 @@ * sf-db row mapping, and task state machine. */ -export const RISK_LEVELS = ["none", "low", "medium", "high", "critical"] as const; +export const RISK_LEVELS = [ + "none", + "low", + "medium", + "high", + "critical", +] as const; export type RiskLevel = (typeof RISK_LEVELS)[number]; export const MUTATION_SCOPES = [ @@ -196,7 +202,9 @@ export interface ValidationResult { normalized: TaskFrontmatter; } -export function validateTaskFrontmatter(frontmatter: FrontmatterInput = {}): ValidationResult { +export function validateTaskFrontmatter( + frontmatter: FrontmatterInput = {}, +): ValidationResult { const errors: string[] = []; const normalized: Record = { ...DEFAULT_TASK_FRONTMATTER, @@ -454,7 +462,13 @@ export function computeTaskPriority(task: TaskRecord): number { const fm = task.frontmatter ?? buildTaskRecord(task).frontmatter; let score = 50; - const riskScores: Record = { none: 0, low: 5, medium: 15, high: 30, critical: 50 }; + const riskScores: Record = { + none: 0, + low: 5, + medium: 15, + high: 30, + critical: 50, + }; score += riskScores[fm.risk] ?? 0; const scopeScores: Record = { diff --git a/packages/pi-agent-core/src/db/uok/trace-writer.ts b/packages/pi-agent-core/src/db/uok/trace-writer.ts index 8c6980362..3f86b9362 100644 --- a/packages/pi-agent-core/src/db/uok/trace-writer.ts +++ b/packages/pi-agent-core/src/db/uok/trace-writer.ts @@ -7,12 +7,7 @@ * * Consumer: sf-db.ts gate statistics functions (getGateStats, etc.) */ -import { - existsSync, - readdirSync, - readFileSync, - statSync, -} from "node:fs"; +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; function sfRoot(basePath: string): string { @@ -54,9 +49,7 @@ export function readTraceEvents( try { const filePath = join(dir, file); if (statSync(filePath).mtimeMs < cutoff) continue; - const lines = readFileSync(filePath, "utf-8") - .split("\n") - .filter(Boolean); + const lines = readFileSync(filePath, "utf-8").split("\n").filter(Boolean); for (const line of lines) { try { const ev = JSON.parse(line) as Record; diff --git a/packages/pi-agent-core/tsconfig.json b/packages/pi-agent-core/tsconfig.json index 6a2c23cf2..24f67372f 100644 --- a/packages/pi-agent-core/tsconfig.json +++ b/packages/pi-agent-core/tsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "target": "ES2024", "module": "Node16", - "lib": [ - "ES2024" - ], + "lib": ["ES2024"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, @@ -19,15 +17,11 @@ "resolveJsonModule": true, "allowImportingTsExtensions": false, "useDefineForClassFields": false, - "types": [ - "node" - ], + "types": ["node"], "outDir": "./dist", "rootDir": "./src" }, - "include": [ - "src/**/*.ts" - ], + "include": ["src/**/*.ts"], "exclude": [ "node_modules", "dist", diff --git a/packages/tui/src/index.ts b/packages/tui/src/index.ts index 9d7b5085b..370b77136 100644 --- a/packages/tui/src/index.ts +++ b/packages/tui/src/index.ts @@ -72,8 +72,6 @@ export { } from "./keys.js"; // Render safety — prevents one failing component from blanking the TUI export { tryRender } from "./render-guard.js"; -// TUI input listener — used with `TUI.addInputListener` -export type { InputListener } from "./tui-input-dispatch.js"; // Input buffering for batch splitting export { StdinBuffer, @@ -117,5 +115,7 @@ export { type SizeValue, TUI, } from "./tui.js"; +// TUI input listener — used with `TUI.addInputListener` +export type { InputListener } from "./tui-input-dispatch.js"; // Utilities export { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "./utils.js"; diff --git a/packages/tui/tsconfig.json b/packages/tui/tsconfig.json index 2af393ca5..5274850db 100644 --- a/packages/tui/tsconfig.json +++ b/packages/tui/tsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "target": "ES2024", "module": "Node16", - "lib": [ - "ES2024" - ], + "lib": ["ES2024"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, @@ -19,17 +17,10 @@ "resolveJsonModule": true, "allowImportingTsExtensions": false, "useDefineForClassFields": false, - "types": [ - "node" - ], + "types": ["node"], "outDir": "./dist", "rootDir": "./src" }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "dist" - ] + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/scripts/check-circular-deps.mjs b/scripts/check-circular-deps.mjs index 59f036d06..4b7874f83 100644 --- a/scripts/check-circular-deps.mjs +++ b/scripts/check-circular-deps.mjs @@ -1,4 +1,5 @@ #!/usr/bin/env node + /** * check-circular-deps.mjs — detect circular imports across the SF codebase. * @@ -10,9 +11,9 @@ * Exit 0 = no cycles found. Exit 1 = cycles detected (or scan error). */ -import madge from "madge"; -import { resolve, dirname } from "node:path"; +import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; +import madge from "madge"; const __dirname = dirname(fileURLToPath(import.meta.url)); const root = resolve(__dirname, ".."); @@ -25,7 +26,9 @@ const entries = extOnly ? [resolve(root, "src/resources/extensions/sf")] : [resolve(root, "src"), resolve(root, "packages")]; -console.error(`Scanning: ${entries.map((e) => e.replace(root + "/", "")).join(", ")}`); +console.error( + `Scanning: ${entries.map((e) => e.replace(root + "/", "")).join(", ")}`, +); let result; try { diff --git a/scripts/check-sf-extension-inventory.mjs b/scripts/check-sf-extension-inventory.mjs index 9e55d959a..92df00715 100644 --- a/scripts/check-sf-extension-inventory.mjs +++ b/scripts/check-sf-extension-inventory.mjs @@ -198,7 +198,18 @@ function parseHandledTopLevelCommands() { } function parseDirectRegisteredCommands() { - const files = ["ui/color-band.js", "ui/emoji.js", "subagent/index.js"]; + const files = [ + "commands/legacy/audit.js", + "commands/legacy/create-extension.js", + "commands/legacy/create-slash-command.js", + "guards/inturn.js", + "notifications/notify.js", + "permissions/index.js", + "subagent/index.js", + "ui/color-band.js", + "ui/emoji.js", + "ui/usage-bar.js", + ]; const commands = new Set(); for (const file of files) { const source = read(join(sfRoot, file)); @@ -262,7 +273,9 @@ function main() { catalogCommands.filter( (command) => !BASE_RUNTIME_COMMAND_NAMES.has(command), ), - parseDirectRegisteredCommands(), + parseDirectRegisteredCommands().filter( + (command) => !BASE_RUNTIME_COMMAND_NAMES.has(command), + ), ), ); const missingManifestTools = registeredTools.filter( diff --git a/scripts/generate-features-inventory.mjs b/scripts/generate-features-inventory.mjs index 7b233568c..45ed4cc71 100644 --- a/scripts/generate-features-inventory.mjs +++ b/scripts/generate-features-inventory.mjs @@ -49,9 +49,7 @@ export function parseKnownProviders() { const src = readFileSync(providersPath, "utf8"); const match = src.match(/export type KnownProvider =([\s\S]*?);/); if (!match) - throw new Error( - "Could not find KnownProvider in packages/ai/src/types.ts", - ); + throw new Error("Could not find KnownProvider in packages/ai/src/types.ts"); const providers = [...match[1].matchAll(/"([^"]+)"/g)].map((m) => m[1]); return uniqueSorted(providers); } @@ -84,9 +82,7 @@ export function parseSfNativeTools() { "Could not find provides.tools in src/resources/extensions/sf/extension-manifest.json", ); } - return uniqueSorted( - tools.filter((tool) => typeof tool === "string"), - ); + return uniqueSorted(tools.filter((tool) => typeof tool === "string")); } export function parseSearchProviders() { diff --git a/scripts/validate-pack.js b/scripts/validate-pack.js index 0041f1e91..845b117a5 100644 --- a/scripts/validate-pack.js +++ b/scripts/validate-pack.js @@ -58,13 +58,7 @@ try { console.log( "==> Checking workspace packages for @singularity-forge/* cross-deps...", ); - const workspaces = [ - "native", - "agent-core", - "ai", - "coding-agent", - "tui", - ]; + const workspaces = ["native", "agent-core", "ai", "coding-agent", "tui"]; let crossFailed = false; for (const ws of workspaces) { diff --git a/src/resources/extensions/bg-shell/bg-shell-lifecycle.js b/src/resources/extensions/bg-shell/bg-shell-lifecycle.js index 0e6027bab..01404113a 100644 --- a/src/resources/extensions/bg-shell/bg-shell-lifecycle.js +++ b/src/resources/extensions/bg-shell/bg-shell-lifecycle.js @@ -2,8 +2,9 @@ * bg_shell lifecycle hook registration — session events, compaction awareness, * context injection, process discovery, footer widget, and periodic maintenance. */ -import { truncateToWidth, visibleWidth } from "@singularity-forge/tui"; + import { formatTokenCount } from "@singularity-forge/coding-agent"; +import { truncateToWidth, visibleWidth } from "@singularity-forge/tui"; import { cleanupAll, cleanupSessionProcesses, diff --git a/src/resources/extensions/bg-shell/bg-shell-tool.js b/src/resources/extensions/bg-shell/bg-shell-tool.js index dafb033cc..950f0c257 100644 --- a/src/resources/extensions/bg-shell/bg-shell-tool.js +++ b/src/resources/extensions/bg-shell/bg-shell-tool.js @@ -3,8 +3,8 @@ */ import { Type } from "@sinclair/typebox"; import { StringEnum } from "@singularity-forge/ai"; -import { Text } from "@singularity-forge/tui"; import { toPosixPath } from "@singularity-forge/coding-agent"; +import { Text } from "@singularity-forge/tui"; import { queryShellEnv, runOnSession, sendAndWait } from "./interaction.js"; import { formatDigestText, diff --git a/src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts b/src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts index 38b20e12c..c9f33ebf7 100644 --- a/src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts +++ b/src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts @@ -34,9 +34,7 @@ describe("buildBashPermissionPattern", () => { }); it("gh_command_includes_two_subcommand_levels", () => { - expect(buildBashPermissionPattern("gh pr list")).toBe( - "Bash(gh pr list:*)", - ); + expect(buildBashPermissionPattern("gh pr list")).toBe("Bash(gh pr list:*)"); }); it("compound_command_extracts_meaningful_operation", () => { @@ -89,17 +87,15 @@ describe("createClaudeCodeCanUseToolHandler", () => { makeOptions() as never, ); expect(result.behavior).toBe("allow"); - expect((result as { updatedPermissions?: unknown }).updatedPermissions).toBeUndefined(); + expect( + (result as { updatedPermissions?: unknown }).updatedPermissions, + ).toBeUndefined(); }); it("deny_returns_deny_behavior", async () => { const ui = makeUi(["Deny"]); const handler = createClaudeCodeCanUseToolHandler(ui)!; - const result = await handler( - "AskUserQuestion", - {}, - makeOptions() as never, - ); + const result = await handler("AskUserQuestion", {}, makeOptions() as never); expect(result.behavior).toBe("deny"); }); @@ -116,7 +112,8 @@ describe("createClaudeCodeCanUseToolHandler", () => { makeOptions({ suggestions: [] }) as never, ); expect(result.behavior).toBe("allow"); - const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + const perms = (result as { updatedPermissions?: unknown[] }) + .updatedPermissions; expect(Array.isArray(perms)).toBe(true); expect(perms!.length).toBeGreaterThan(0); const rule = perms![0] as { @@ -151,7 +148,8 @@ describe("createClaudeCodeCanUseToolHandler", () => { makeOptions({ suggestions: sdkSuggestions }) as never, ); expect(result.behavior).toBe("allow"); - const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + const perms = (result as { updatedPermissions?: unknown[] }) + .updatedPermissions; expect(perms).toEqual(sdkSuggestions); }); @@ -165,7 +163,8 @@ describe("createClaudeCodeCanUseToolHandler", () => { makeOptions({ suggestions: [] }) as never, ); expect(result.behavior).toBe("allow"); - const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + const perms = (result as { updatedPermissions?: unknown[] }) + .updatedPermissions; expect(Array.isArray(perms)).toBe(true); const rule = perms![0] as { type: string; diff --git a/src/resources/extensions/mcp-client/auth.js b/src/resources/extensions/mcp-client/auth.js index 30463fb75..5941ce939 100644 --- a/src/resources/extensions/mcp-client/auth.js +++ b/src/resources/extensions/mcp-client/auth.js @@ -5,4 +5,7 @@ * This shim keeps backward compatibility for any import of ./auth.js from * within the extension or from tests. */ -export { buildHttpTransportOpts, createCliOAuthProvider } from "@singularity-forge/coding-agent"; +export { + buildHttpTransportOpts, + createCliOAuthProvider, +} from "@singularity-forge/coding-agent"; diff --git a/src/resources/extensions/mcp-client/index.js b/src/resources/extensions/mcp-client/index.js index 28e7b9ca3..cc318214c 100644 --- a/src/resources/extensions/mcp-client/index.js +++ b/src/resources/extensions/mcp-client/index.js @@ -15,11 +15,11 @@ */ import { Type } from "@sinclair/typebox"; import { -DEFAULT_MAX_BYTES, -DEFAULT_MAX_LINES, -McpConnectionManager, -formatSize, -truncateHead, + DEFAULT_MAX_BYTES, + DEFAULT_MAX_LINES, + formatSize, + McpConnectionManager, + truncateHead, } from "@singularity-forge/coding-agent"; import { Text } from "@singularity-forge/tui"; @@ -29,71 +29,71 @@ const manager = new McpConnectionManager(); // ─── JSON Schema → TypeBox converter ───────────────────────────────────────── // eslint-disable-next-line @typescript-eslint/no-explicit-any function jsonSchemaPropToTypeBox(schema) { -if (!schema || typeof schema !== "object") return Type.Any(); -const t = schema.type; -if (t === "string") return Type.String({ description: schema.description }); -if (t === "number" || t === "integer") -return Type.Number({ description: schema.description }); -if (t === "boolean") return Type.Boolean({ description: schema.description }); -if (t === "array") return Type.Array(Type.Any()); -if (t === "object") { -const props = schema.properties; -if (props) { -const entries = {}; -for (const [k, v] of Object.entries(props)) { -entries[k] = jsonSchemaPropToTypeBox(v); -} -return Type.Object(entries); -} -} -return Type.Any(); + if (!schema || typeof schema !== "object") return Type.Any(); + const t = schema.type; + if (t === "string") return Type.String({ description: schema.description }); + if (t === "number" || t === "integer") + return Type.Number({ description: schema.description }); + if (t === "boolean") return Type.Boolean({ description: schema.description }); + if (t === "array") return Type.Array(Type.Any()); + if (t === "object") { + const props = schema.properties; + if (props) { + const entries = {}; + for (const [k, v] of Object.entries(props)) { + entries[k] = jsonSchemaPropToTypeBox(v); + } + return Type.Object(entries); + } + } + return Type.Any(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any function jsonSchemaToTypeBox(schema) { -if (!schema || typeof schema !== "object") return Type.Object({}); -const obj = schema; -const props = obj.properties; -if (!props) return Type.Object({}); -const entries = {}; -for (const [k, v] of Object.entries(props)) { -entries[k] = jsonSchemaPropToTypeBox(v); -} -return Type.Object(entries); + if (!schema || typeof schema !== "object") return Type.Object({}); + const obj = schema; + const props = obj.properties; + if (!props) return Type.Object({}); + const entries = {}; + for (const [k, v] of Object.entries(props)) { + entries[k] = jsonSchemaPropToTypeBox(v); + } + return Type.Object(entries); } // ─── Formatters ─────────────────────────────────────────────────────────────── function formatServerList(servers) { -if (servers.length === 0) -return "No MCP servers configured. Add servers to .mcp.json or .sf/mcp.json."; -const lines = [`${servers.length} MCP servers configured:\n`]; -for (const s of servers) { -const connected = manager.isConnected(s.name) ? "✓" : "○"; -const cached = manager.getCachedTools(s.name); -const toolCount = cached ? ` — ${cached.length} tools` : ""; -lines.push(`${connected} ${s.name} (${s.transport})${toolCount}`); -} -lines.push( -"\nUse mcp_discover to see full tool schemas for a specific server.", -); -lines.push("Use mcp_call to invoke a tool: mcp_call(server, tool, args)."); -return lines.join("\n"); + if (servers.length === 0) + return "No MCP servers configured. Add servers to .mcp.json or .sf/mcp.json."; + const lines = [`${servers.length} MCP servers configured:\n`]; + for (const s of servers) { + const connected = manager.isConnected(s.name) ? "✓" : "○"; + const cached = manager.getCachedTools(s.name); + const toolCount = cached ? ` — ${cached.length} tools` : ""; + lines.push(`${connected} ${s.name} (${s.transport})${toolCount}`); + } + lines.push( + "\nUse mcp_discover to see full tool schemas for a specific server.", + ); + lines.push("Use mcp_call to invoke a tool: mcp_call(server, tool, args)."); + return lines.join("\n"); } function formatToolList(serverName, tools) { -const lines = [`${serverName} — ${tools.length} tools:\n`]; -for (const tool of tools) { -lines.push(`## ${tool.name}`); -if (tool.description) lines.push(tool.description); -if (tool.inputSchema) { -lines.push("```json"); -lines.push(JSON.stringify(tool.inputSchema, null, 2)); -lines.push("```"); -} -lines.push(""); -} -lines.push( -`Call with: mcp_call(server="${serverName}", tool="", args={...})`, -); -return lines.join("\n"); + const lines = [`${serverName} — ${tools.length} tools:\n`]; + for (const tool of tools) { + lines.push(`## ${tool.name}`); + if (tool.description) lines.push(tool.description); + if (tool.inputSchema) { + lines.push("```json"); + lines.push(JSON.stringify(tool.inputSchema, null, 2)); + lines.push("```"); + } + lines.push(""); + } + lines.push( + `Call with: mcp_call(server="${serverName}", tool="", args={...})`, + ); + return lines.join("\n"); } // ─── Status helpers (consumed by /sf mcp) ──────────────────────────────────── @@ -105,7 +105,7 @@ return lines.join("\n"); * Consumer: /mcp reload command handler in commands-mcp-status.js. */ export async function disconnectAll() { -await manager.disconnectAll(); + await manager.disconnectAll(); } /** @@ -113,311 +113,315 @@ await manager.disconnectAll(); * Safe to call even when the server has never been connected. */ export function getConnectionStatus(name) { -return manager.getConnectionStatus(name); + return manager.getConnectionStatus(name); } // ─── Test-exported helpers ──────────────────────────────────────────────────── export function _buildMcpChildEnvForTest(env) { -return manager.buildChildEnv(env); + return manager.buildChildEnv(env); } export function _buildMcpTrustConfirmOptionsForTest(signal) { -return { timeout: 120_000, signal }; + return { timeout: 120_000, signal }; } // ─── Extension ──────────────────────────────────────────────────────────────── export default function (pi) { -// ── mcp_servers ────────────────────────────────────────────────────────── -pi.registerTool({ -name: "mcp_servers", -label: "MCP Servers", -description: -"List all available MCP servers configured in project files (.mcp.json, .sf/mcp.json). " + -"Shows server names, transport type, and connection status. After mcp_discover, each server's " + -"tools are auto-registered as first-class pi tools (e.g. serena_find_symbol).", -promptSnippet: "List available MCP servers from project configuration", -promptGuidelines: [ -"Call mcp_servers to see what MCP servers are available before trying to use one.", -"After mcp_discover(server), the server's tools appear as real pi tools.", -"MCP servers provide external integrations (Twitter, Linear, Railway, etc.) via the Model Context Protocol.", -"After listing, use mcp_discover(server) to get tool schemas, then mcp_call(server, tool, args) to invoke.", -], -parameters: Type.Object({ -refresh: Type.Optional( -Type.Boolean({ -description: "Force refresh the server list (default: use cache)", -}), -), -}), -async execute(_id, params) { -if (params.refresh) manager.invalidateConfigCache(); -const servers = manager.readConfigs(); -return { -content: [{ type: "text", text: formatServerList(servers) }], -details: { -serverCount: servers.length, -cached: !params.refresh, -}, -}; -}, -renderCall(args, theme) { -let text = theme.fg("toolTitle", theme.bold("mcp_servers")); -if (args.refresh) text += theme.fg("warning", " (refresh)"); -return new Text(text, 0, 0); -}, -renderResult(result, { isPartial }, theme) { -if (isPartial) -return new Text(theme.fg("warning", "Reading MCP config..."), 0, 0); -const d = result.details; -return new Text( -theme.fg("success", `${d?.serverCount ?? 0} servers configured`), -0, -0, -); -}, -}); + // ── mcp_servers ────────────────────────────────────────────────────────── + pi.registerTool({ + name: "mcp_servers", + label: "MCP Servers", + description: + "List all available MCP servers configured in project files (.mcp.json, .sf/mcp.json). " + + "Shows server names, transport type, and connection status. After mcp_discover, each server's " + + "tools are auto-registered as first-class pi tools (e.g. serena_find_symbol).", + promptSnippet: "List available MCP servers from project configuration", + promptGuidelines: [ + "Call mcp_servers to see what MCP servers are available before trying to use one.", + "After mcp_discover(server), the server's tools appear as real pi tools.", + "MCP servers provide external integrations (Twitter, Linear, Railway, etc.) via the Model Context Protocol.", + "After listing, use mcp_discover(server) to get tool schemas, then mcp_call(server, tool, args) to invoke.", + ], + parameters: Type.Object({ + refresh: Type.Optional( + Type.Boolean({ + description: "Force refresh the server list (default: use cache)", + }), + ), + }), + async execute(_id, params) { + if (params.refresh) manager.invalidateConfigCache(); + const servers = manager.readConfigs(); + return { + content: [{ type: "text", text: formatServerList(servers) }], + details: { + serverCount: servers.length, + cached: !params.refresh, + }, + }; + }, + renderCall(args, theme) { + let text = theme.fg("toolTitle", theme.bold("mcp_servers")); + if (args.refresh) text += theme.fg("warning", " (refresh)"); + return new Text(text, 0, 0); + }, + renderResult(result, { isPartial }, theme) { + if (isPartial) + return new Text(theme.fg("warning", "Reading MCP config..."), 0, 0); + const d = result.details; + return new Text( + theme.fg("success", `${d?.serverCount ?? 0} servers configured`), + 0, + 0, + ); + }, + }); -// ── mcp_discover ───────────────────────────────────────────────────────── -pi.registerTool({ -name: "mcp_discover", -label: "MCP Discover", -description: -"Get detailed tool signatures and JSON schemas for a specific MCP server. " + -"Connects to the server on first call (lazy connection). " + -"After discovery, each MCP tool is auto-registered as a first-class pi tool " + -"(e.g. serena_find_symbol) — the LLM can call them directly without mcp_call.", -promptSnippet: -"Discover MCP server tools and register them as first-class pi tools", -promptGuidelines: [ -"Call mcp_discover(server) to connect to an MCP server and surface its tools.", -"After discovery, the LLM sees each tool by its real name (e.g. serena_search_for_pattern).", -"Call tools directly by their names instead of going through mcp_call.", -], -parameters: Type.Object({ -server: Type.String({ -description: -"MCP server name (from mcp_servers output), e.g. 'railway', 'twitter-mcp', 'linear'", -}), -}), -async execute(_id, params, signal) { -try { -const cached = manager.getCachedTools(params.server); -if (cached) { -const text = formatToolList(params.server, cached); -const truncation = truncateHead(text, { -maxLines: DEFAULT_MAX_LINES, -maxBytes: DEFAULT_MAX_BYTES, -}); -let finalText = truncation.content; -if (truncation.truncated) { -finalText += `\n\n[Truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; -} -return { -content: [{ type: "text", text: finalText }], -details: { -server: params.server, -toolCount: cached.length, -cached: true, -}, -}; -} -const client = await manager.getOrConnect(params.server, signal); -const result = await client.listTools(undefined, { -signal, -timeout: 30000, -}); -const tools = (result.tools ?? []).map((t) => ({ -name: t.name, -description: t.description ?? "", -inputSchema: t.inputSchema, -})); -manager.setCachedTools(params.server, tools); -// Auto-register each MCP tool as a first-class pi tool. -manager.registerToolsForServer(params.server, tools, ({ name, label, description, inputSchemaRaw, execute }) => { -const paramType = inputSchemaRaw -? jsonSchemaToTypeBox(inputSchemaRaw) -: Type.Object({}); -pi.registerTool({ -name, -label, -description, -parameters: paramType, -async execute(id, toolParams, toolSignal) { -const res = await execute(id, toolParams, toolSignal); -const truncation = truncateHead(res.content[0]?.text ?? "", { -maxLines: DEFAULT_MAX_LINES, -maxBytes: DEFAULT_MAX_BYTES, -}); -let finalText = truncation.content; -if (truncation.truncated) { -finalText += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines]`; -} -return { -content: [{ type: "text", text: finalText }], -details: res.details, -}; -}, -}); -}); -const text = formatToolList(params.server, tools); -const truncation = truncateHead(text, { -maxLines: DEFAULT_MAX_LINES, -maxBytes: DEFAULT_MAX_BYTES, -}); -let finalText = truncation.content; -if (truncation.truncated) { -finalText += `\n\n[Truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; -} -return { -content: [{ type: "text", text: finalText }], -details: { -server: params.server, -toolCount: tools.length, -cached: false, -}, -}; -} catch (err) { -const msg = err instanceof Error ? err.message : String(err); -throw new Error( -`Failed to discover tools for "${params.server}": ${msg}`, -); -} -}, -renderCall(args, theme) { -let text = theme.fg("toolTitle", theme.bold("mcp_discover ")); -text += theme.fg("accent", args.server); -return new Text(text, 0, 0); -}, -renderResult(result, { isPartial }, theme) { -if (isPartial) -return new Text(theme.fg("warning", "Discovering tools..."), 0, 0); -const d = result.details; -return new Text( -theme.fg("success", `${d?.toolCount ?? 0} tools`) + -theme.fg("dim", ` · ${d?.server}`), -0, -0, -); -}, -}); + // ── mcp_discover ───────────────────────────────────────────────────────── + pi.registerTool({ + name: "mcp_discover", + label: "MCP Discover", + description: + "Get detailed tool signatures and JSON schemas for a specific MCP server. " + + "Connects to the server on first call (lazy connection). " + + "After discovery, each MCP tool is auto-registered as a first-class pi tool " + + "(e.g. serena_find_symbol) — the LLM can call them directly without mcp_call.", + promptSnippet: + "Discover MCP server tools and register them as first-class pi tools", + promptGuidelines: [ + "Call mcp_discover(server) to connect to an MCP server and surface its tools.", + "After discovery, the LLM sees each tool by its real name (e.g. serena_search_for_pattern).", + "Call tools directly by their names instead of going through mcp_call.", + ], + parameters: Type.Object({ + server: Type.String({ + description: + "MCP server name (from mcp_servers output), e.g. 'railway', 'twitter-mcp', 'linear'", + }), + }), + async execute(_id, params, signal) { + try { + const cached = manager.getCachedTools(params.server); + if (cached) { + const text = formatToolList(params.server, cached); + const truncation = truncateHead(text, { + maxLines: DEFAULT_MAX_LINES, + maxBytes: DEFAULT_MAX_BYTES, + }); + let finalText = truncation.content; + if (truncation.truncated) { + finalText += `\n\n[Truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; + } + return { + content: [{ type: "text", text: finalText }], + details: { + server: params.server, + toolCount: cached.length, + cached: true, + }, + }; + } + const client = await manager.getOrConnect(params.server, signal); + const result = await client.listTools(undefined, { + signal, + timeout: 30000, + }); + const tools = (result.tools ?? []).map((t) => ({ + name: t.name, + description: t.description ?? "", + inputSchema: t.inputSchema, + })); + manager.setCachedTools(params.server, tools); + // Auto-register each MCP tool as a first-class pi tool. + manager.registerToolsForServer( + params.server, + tools, + ({ name, label, description, inputSchemaRaw, execute }) => { + const paramType = inputSchemaRaw + ? jsonSchemaToTypeBox(inputSchemaRaw) + : Type.Object({}); + pi.registerTool({ + name, + label, + description, + parameters: paramType, + async execute(id, toolParams, toolSignal) { + const res = await execute(id, toolParams, toolSignal); + const truncation = truncateHead(res.content[0]?.text ?? "", { + maxLines: DEFAULT_MAX_LINES, + maxBytes: DEFAULT_MAX_BYTES, + }); + let finalText = truncation.content; + if (truncation.truncated) { + finalText += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines]`; + } + return { + content: [{ type: "text", text: finalText }], + details: res.details, + }; + }, + }); + }, + ); + const text = formatToolList(params.server, tools); + const truncation = truncateHead(text, { + maxLines: DEFAULT_MAX_LINES, + maxBytes: DEFAULT_MAX_BYTES, + }); + let finalText = truncation.content; + if (truncation.truncated) { + finalText += `\n\n[Truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; + } + return { + content: [{ type: "text", text: finalText }], + details: { + server: params.server, + toolCount: tools.length, + cached: false, + }, + }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + throw new Error( + `Failed to discover tools for "${params.server}": ${msg}`, + ); + } + }, + renderCall(args, theme) { + let text = theme.fg("toolTitle", theme.bold("mcp_discover ")); + text += theme.fg("accent", args.server); + return new Text(text, 0, 0); + }, + renderResult(result, { isPartial }, theme) { + if (isPartial) + return new Text(theme.fg("warning", "Discovering tools..."), 0, 0); + const d = result.details; + return new Text( + theme.fg("success", `${d?.toolCount ?? 0} tools`) + + theme.fg("dim", ` · ${d?.server}`), + 0, + 0, + ); + }, + }); -// ── mcp_call ───────────────────────────────────────────────────────────── -pi.registerTool({ -name: "mcp_call", -label: "MCP Call", -description: -"Call a tool on an MCP server. Provide the server name, tool name, and arguments. " + -"Connects to the server on first call (lazy connection). " + -"Use mcp_discover first to see available tools and their required arguments.", -promptSnippet: "Call a tool on an MCP server", -promptGuidelines: [ -"Always use mcp_discover first to understand the tool's parameters before calling mcp_call.", -"Arguments are passed as a JSON object matching the tool's input schema.", -], -parameters: Type.Object({ -server: Type.String({ -description: "MCP server name, e.g. 'railway', 'twitter-mcp'", -}), -tool: Type.String({ -description: "Tool name on that server, e.g. 'railway_list_projects'", -}), -args: Type.Optional( -Type.Object( -{}, -{ -additionalProperties: true, -description: -"Tool arguments as key-value pairs matching the tool's input schema", -}, -), -), -}), -async execute(_id, params, signal) { -try { -const client = await manager.getOrConnect(params.server, signal); -const result = await client.callTool( -{ name: params.tool, arguments: params.args ?? {} }, -undefined, -{ signal, timeout: 60000 }, -); -const contentItems = result.content; -const raw = contentItems -.map((c) => (c.type === "text" ? (c.text ?? "") : JSON.stringify(c))) -.join("\n"); -const truncation = truncateHead(raw, { -maxLines: DEFAULT_MAX_LINES, -maxBytes: DEFAULT_MAX_BYTES, -}); -let finalText = truncation.content; -if (truncation.truncated) { -finalText += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; -} -return { -content: [{ type: "text", text: finalText }], -details: { -server: params.server, -tool: params.tool, -charCount: finalText.length, -truncated: truncation.truncated, -}, -}; -} catch (err) { -const msg = err instanceof Error ? err.message : String(err); -throw new Error( -`MCP call failed: ${params.server}.${params.tool}\n${msg}`, -); -} -}, -renderCall(args, theme) { -let text = theme.fg("toolTitle", theme.bold("mcp_call ")); -text += theme.fg("accent", `${args.server}.${args.tool}`); -if (args.args && Object.keys(args.args).length > 0) { -const preview = Object.entries(args.args) -.slice(0, 3) -.map(([k, v]) => { -const val = typeof v === "string" ? v : JSON.stringify(v); -return `${k}:${val.length > 30 ? val.slice(0, 30) + "…" : val}`; -}) -.join(" "); -text += " " + theme.fg("muted", preview); -} -return new Text(text, 0, 0); -}, -renderResult(result, { isPartial, expanded }, theme) { -if (isPartial) -return new Text(theme.fg("warning", "Calling MCP tool..."), 0, 0); -const d = result.details; -let text = theme.fg("success", `✓ ${d?.server}.${d?.tool}`); -text += theme.fg( -"dim", -` · ${(d?.charCount ?? 0).toLocaleString()} chars`, -); -if (d?.truncated) text += theme.fg("warning", " · truncated"); -if (expanded) { -const content = result.content[0]; -if (content?.type === "text") { -const preview = content.text.split("\n").slice(0, 15).join("\n"); -text += "\n\n" + theme.fg("dim", preview); -} -} -return new Text(text, 0, 0); -}, -}); + // ── mcp_call ───────────────────────────────────────────────────────────── + pi.registerTool({ + name: "mcp_call", + label: "MCP Call", + description: + "Call a tool on an MCP server. Provide the server name, tool name, and arguments. " + + "Connects to the server on first call (lazy connection). " + + "Use mcp_discover first to see available tools and their required arguments.", + promptSnippet: "Call a tool on an MCP server", + promptGuidelines: [ + "Always use mcp_discover first to understand the tool's parameters before calling mcp_call.", + "Arguments are passed as a JSON object matching the tool's input schema.", + ], + parameters: Type.Object({ + server: Type.String({ + description: "MCP server name, e.g. 'railway', 'twitter-mcp'", + }), + tool: Type.String({ + description: "Tool name on that server, e.g. 'railway_list_projects'", + }), + args: Type.Optional( + Type.Object( + {}, + { + additionalProperties: true, + description: + "Tool arguments as key-value pairs matching the tool's input schema", + }, + ), + ), + }), + async execute(_id, params, signal) { + try { + const client = await manager.getOrConnect(params.server, signal); + const result = await client.callTool( + { name: params.tool, arguments: params.args ?? {} }, + undefined, + { signal, timeout: 60000 }, + ); + const contentItems = result.content; + const raw = contentItems + .map((c) => (c.type === "text" ? (c.text ?? "") : JSON.stringify(c))) + .join("\n"); + const truncation = truncateHead(raw, { + maxLines: DEFAULT_MAX_LINES, + maxBytes: DEFAULT_MAX_BYTES, + }); + let finalText = truncation.content; + if (truncation.truncated) { + finalText += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)})]`; + } + return { + content: [{ type: "text", text: finalText }], + details: { + server: params.server, + tool: params.tool, + charCount: finalText.length, + truncated: truncation.truncated, + }, + }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + throw new Error( + `MCP call failed: ${params.server}.${params.tool}\n${msg}`, + ); + } + }, + renderCall(args, theme) { + let text = theme.fg("toolTitle", theme.bold("mcp_call ")); + text += theme.fg("accent", `${args.server}.${args.tool}`); + if (args.args && Object.keys(args.args).length > 0) { + const preview = Object.entries(args.args) + .slice(0, 3) + .map(([k, v]) => { + const val = typeof v === "string" ? v : JSON.stringify(v); + return `${k}:${val.length > 30 ? val.slice(0, 30) + "…" : val}`; + }) + .join(" "); + text += " " + theme.fg("muted", preview); + } + return new Text(text, 0, 0); + }, + renderResult(result, { isPartial, expanded }, theme) { + if (isPartial) + return new Text(theme.fg("warning", "Calling MCP tool..."), 0, 0); + const d = result.details; + let text = theme.fg("success", `✓ ${d?.server}.${d?.tool}`); + text += theme.fg( + "dim", + ` · ${(d?.charCount ?? 0).toLocaleString()} chars`, + ); + if (d?.truncated) text += theme.fg("warning", " · truncated"); + if (expanded) { + const content = result.content[0]; + if (content?.type === "text") { + const preview = content.text.split("\n").slice(0, 15).join("\n"); + text += "\n\n" + theme.fg("dim", preview); + } + } + return new Text(text, 0, 0); + }, + }); -// ── Lifecycle ───────────────────────────────────────────────────────────── -pi.on("session_start", async (_event, ctx) => { -const servers = manager.readConfigs(); -if (servers.length > 0) { -ctx.ui.notify( -`MCP client ready — ${servers.length} server(s) configured`, -"info", -); -} -}); -pi.on("session_shutdown", async () => { -await manager.closeAll(); -}); -pi.on("session_switch", async () => { -await manager.closeAll(); -manager.invalidateConfigCache(); -}); + // ── Lifecycle ───────────────────────────────────────────────────────────── + pi.on("session_start", async (_event, ctx) => { + const servers = manager.readConfigs(); + if (servers.length > 0) { + ctx.ui.notify( + `MCP client ready — ${servers.length} server(s) configured`, + "info", + ); + } + }); + pi.on("session_shutdown", async () => { + await manager.closeAll(); + }); + pi.on("session_switch", async () => { + await manager.closeAll(); + manager.invalidateConfigCache(); + }); } diff --git a/src/resources/extensions/search-the-web/native-search.js b/src/resources/extensions/search-the-web/native-search.js index c7f66d6ad..4e5f884d6 100644 --- a/src/resources/extensions/search-the-web/native-search.js +++ b/src/resources/extensions/search-the-web/native-search.js @@ -115,7 +115,9 @@ export function registerNativeSearchHooks(pi) { pi.on("before_provider_request", async (event, _ctx) => { let modelHint = event.model; if (!modelHint && isAnthropicProvider !== null) { - modelHint = { provider: isAnthropicProvider ? "anthropic" : "not-anthropic" }; + modelHint = { + provider: isAnthropicProvider ? "anthropic" : "not-anthropic", + }; } return webSearchMiddleware.applyToPayload(event.payload, modelHint); }); diff --git a/src/resources/extensions/search-the-web/provider.js b/src/resources/extensions/search-the-web/provider.js index b429597da..505d175de 100644 --- a/src/resources/extensions/search-the-web/provider.js +++ b/src/resources/extensions/search-the-web/provider.js @@ -111,11 +111,11 @@ export function setSearchProviderPreference(pref, authPath) { * Each entry's `getKey` is evaluated at resolution time so hot-reloaded env vars work. */ const PROVIDER_REGISTRY = [ - { name: "tavily", getKey: getTavilyApiKey }, - { name: "brave", getKey: getBraveApiKey }, - { name: "serper", getKey: getSerperApiKey }, - { name: "exa", getKey: getExaApiKey }, - { name: "ollama", getKey: getOllamaApiKey }, + { name: "tavily", getKey: getTavilyApiKey }, + { name: "brave", getKey: getBraveApiKey }, + { name: "serper", getKey: getSerperApiKey }, + { name: "exa", getKey: getExaApiKey }, + { name: "ollama", getKey: getOllamaApiKey }, { name: "minimax", getKey: getMiniMaxSearchApiKey }, ]; @@ -145,9 +145,11 @@ export function resolveSearchProvider(overridePreference) { /** Returns pref if its key exists, otherwise walks registry in order. */ const resolveWithFallback = (pref) => { if (hasKey(pref)) return pref; - return PROVIDER_REGISTRY - .filter((p) => p.name !== pref) - .find((p) => p.getKey().length > 0)?.name ?? null; + return ( + PROVIDER_REGISTRY.filter((p) => p.name !== pref).find( + (p) => p.getKey().length > 0, + )?.name ?? null + ); }; // Determine effective preference diff --git a/src/resources/extensions/sf/auto-dispatch.js b/src/resources/extensions/sf/auto-dispatch.js index 83fdcd47b..3b90b51e1 100644 --- a/src/resources/extensions/sf/auto-dispatch.js +++ b/src/resources/extensions/sf/auto-dispatch.js @@ -6,15 +6,15 @@ * continue to work without changes. */ export { -DISPATCH_RULES, -enhanceUnitRankingWithMemory, -extractValidationAttentionPlan, -formatTaskCompleteFailurePrompt, -getDispatchRuleNames, -getRewriteCount, -getUatCount, -incrementUatCount, -isVerificationNotApplicable, -resolveDispatch, -setRewriteCount, + DISPATCH_RULES, + enhanceUnitRankingWithMemory, + extractValidationAttentionPlan, + formatTaskCompleteFailurePrompt, + getDispatchRuleNames, + getRewriteCount, + getUatCount, + incrementUatCount, + isVerificationNotApplicable, + resolveDispatch, + setRewriteCount, } from "./uok/auto-dispatch.js"; diff --git a/src/resources/extensions/sf/auto-post-unit.js b/src/resources/extensions/sf/auto-post-unit.js index 08666dc92..62be26013 100644 --- a/src/resources/extensions/sf/auto-post-unit.js +++ b/src/resources/extensions/sf/auto-post-unit.js @@ -19,7 +19,6 @@ import { writeBlockerPlaceholder, } from "./auto-recovery.js"; import { isDeterministicPolicyError } from "./auto-tool-tracking.js"; -import { closeoutUnit } from "./uok/auto-unit-closeout.js"; import { runSafely } from "./auto-utils.js"; import { syncStateToProjectRoot } from "./auto-worktree.js"; import { invalidateAllCaches } from "./cache.js"; @@ -82,6 +81,7 @@ import { } from "./sf-db.js"; import { deriveState } from "./state.js"; import { parseUnitId } from "./unit-id.js"; +import { closeoutUnit } from "./uok/auto-unit-closeout.js"; import { resolveUokFlags } from "./uok/flags.js"; import { UokGateRunner } from "./uok/gate-runner.js"; import { diff --git a/src/resources/extensions/sf/auto-runaway-guard.js b/src/resources/extensions/sf/auto-runaway-guard.js index c509f0f16..99f3575b5 100644 --- a/src/resources/extensions/sf/auto-runaway-guard.js +++ b/src/resources/extensions/sf/auto-runaway-guard.js @@ -6,17 +6,17 @@ * continue to work without changes. */ export { -clearRunawayGuardState, -collectSessionTokenUsage, -collectWorktreeFingerprint, -countChangedFiles, -DEFAULT_RUNAWAY_CHANGED_FILES_WARNING, -DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS, -DEFAULT_RUNAWAY_ELAPSED_MINUTES, -DEFAULT_RUNAWAY_MIN_INTERVAL_MS, -DEFAULT_RUNAWAY_TOOL_CALL_WARNING, -DEFAULT_RUNAWAY_TOKEN_WARNING, -evaluateRunawayGuard, -resetRunawayGuardState, -resolveRunawayGuardConfig, + clearRunawayGuardState, + collectSessionTokenUsage, + collectWorktreeFingerprint, + countChangedFiles, + DEFAULT_RUNAWAY_CHANGED_FILES_WARNING, + DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS, + DEFAULT_RUNAWAY_ELAPSED_MINUTES, + DEFAULT_RUNAWAY_MIN_INTERVAL_MS, + DEFAULT_RUNAWAY_TOKEN_WARNING, + DEFAULT_RUNAWAY_TOOL_CALL_WARNING, + evaluateRunawayGuard, + resetRunawayGuardState, + resolveRunawayGuardConfig, } from "./uok/auto-runaway-guard.js"; diff --git a/src/resources/extensions/sf/auto-timers.js b/src/resources/extensions/sf/auto-timers.js index 75b3b9ba1..bb3bb292a 100644 --- a/src/resources/extensions/sf/auto-timers.js +++ b/src/resources/extensions/sf/auto-timers.js @@ -7,13 +7,6 @@ */ import { saveActivityLog } from "./activity-log.js"; import { resolveAgentEndCancelled } from "./auto/resolve.js"; -import { - collectSessionTokenUsage, - collectWorktreeFingerprint, - countChangedFiles, - evaluateRunawayGuard, - resolveRunawayGuardConfig, -} from "./uok/auto-runaway-guard.js"; import { detectWorkingTreeActivity } from "./auto-supervisor.js"; import { recoverTimedOutUnit } from "./auto-timeout-recovery.js"; import { @@ -24,7 +17,6 @@ import { getTotalToolCallCount, hasInteractiveToolInFlight, } from "./auto-tool-tracking.js"; -import { closeoutUnit } from "./uok/auto-unit-closeout.js"; import { computeBudgets, resolveExecutorContextWindow, @@ -33,6 +25,14 @@ import { resolveAutoSupervisorConfig } from "./preferences.js"; import { writeRunawayRecoveryArtifact } from "./runaway-recovery.js"; import { recordSelfFeedback } from "./self-feedback.js"; import { getMilestoneSlices, getSliceTasks, isDbAvailable } from "./sf-db.js"; +import { + collectSessionTokenUsage, + collectWorktreeFingerprint, + countChangedFiles, + evaluateRunawayGuard, + resolveRunawayGuardConfig, +} from "./uok/auto-runaway-guard.js"; +import { closeoutUnit } from "./uok/auto-unit-closeout.js"; import { readUnitRuntimeRecord, writeUnitRuntimeRecord, diff --git a/src/resources/extensions/sf/auto-worktree.js b/src/resources/extensions/sf/auto-worktree.js index be0ba214c..6ec16281d 100644 --- a/src/resources/extensions/sf/auto-worktree.js +++ b/src/resources/extensions/sf/auto-worktree.js @@ -552,7 +552,9 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) { } // Forward-sync project preferences from project root to worktree (additive only). { - const worktreeHasPreferences = existsSync(join(wtSf, PROJECT_PREFERENCES_FILE)); + const worktreeHasPreferences = existsSync( + join(wtSf, PROJECT_PREFERENCES_FILE), + ); if (!worktreeHasPreferences) { const src = join(mainSf, PROJECT_PREFERENCES_FILE); const dst = join(wtSf, PROJECT_PREFERENCES_FILE); @@ -567,7 +569,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) { `preferences copy failed (${PROJECT_PREFERENCES_FILE}): ${err instanceof Error ? err.message : String(err)}`, ); } - } + } } } // Sync milestones: copy entire milestone directories that are missing diff --git a/src/resources/extensions/sf/auto.js b/src/resources/extensions/sf/auto.js index c29352ca5..a668deb6b 100644 --- a/src/resources/extensions/sf/auto.js +++ b/src/resources/extensions/sf/auto.js @@ -52,7 +52,6 @@ import { clearSliceProgressCache, updateSliceProgressCache, } from "./auto-dashboard.js"; -import { DISPATCH_RULES, resolveDispatch } from "./uok/auto-dispatch.js"; import { _resetPendingResolve, isSessionSwitchInFlight, @@ -86,8 +85,6 @@ import { isQueuedUserMessageSkip, isToolInvocationError, } from "./auto-tool-tracking.js"; -import { closeoutUnit } from "./uok/auto-unit-closeout.js"; -import { runPostUnitVerification } from "./uok/auto-verification.js"; import { autoWorktreeBranch, checkResourcesStale, @@ -174,6 +171,9 @@ import { captureAvailableSkills, resetSkillTelemetry, } from "./skill-telemetry.js"; +import { DISPATCH_RULES, resolveDispatch } from "./uok/auto-dispatch.js"; +import { closeoutUnit } from "./uok/auto-unit-closeout.js"; +import { runPostUnitVerification } from "./uok/auto-verification.js"; import { writeUokDiagnostics } from "./uok/diagnostic-synthesis.js"; import { resolveUokFlags } from "./uok/flags.js"; import { diff --git a/src/resources/extensions/sf/auto/phases.js b/src/resources/extensions/sf/auto/phases.js index 8d73512b5..446c7e086 100644 --- a/src/resources/extensions/sf/auto/phases.js +++ b/src/resources/extensions/sf/auto/phases.js @@ -24,12 +24,6 @@ import { diagnoseExpectedArtifact, verifyExpectedArtifact, } from "../auto-recovery.js"; -import { - collectSessionTokenUsage, - collectWorktreeFingerprint, - countChangedFiles, - resetRunawayGuardState, -} from "../uok/auto-runaway-guard.js"; import { formatToolCallSummary, resetToolCallCounts, @@ -87,6 +81,12 @@ import { getEligibleSlices } from "../slice-parallel-eligibility.js"; import { startSliceParallel } from "../slice-parallel-orchestrator.js"; import { handleProductAudit } from "../tools/product-audit-tool.js"; import { parseUnitId } from "../unit-id.js"; +import { + collectSessionTokenUsage, + collectWorktreeFingerprint, + countChangedFiles, + resetRunawayGuardState, +} from "../uok/auto-runaway-guard.js"; import { resolveUokFlags } from "../uok/flags.js"; import { UokGateRunner } from "../uok/gate-runner.js"; import { emitModelAutoResolvedEvent } from "../uok/model-route-evidence.js"; diff --git a/src/resources/extensions/sf/auto/run-unit.js b/src/resources/extensions/sf/auto/run-unit.js index 5a759dacc..3becec295 100644 --- a/src/resources/extensions/sf/auto/run-unit.js +++ b/src/resources/extensions/sf/auto/run-unit.js @@ -3,18 +3,19 @@ * * Imports from: auto/types, auto/resolve */ -import { - collectSessionTokenUsage, - collectWorktreeFingerprint, - countChangedFiles, - resetRunawayGuardState, -} from "../uok/auto-runaway-guard.js"; + import { scopeActiveToolsForUnitType } from "../constants.js"; import { debugLog } from "../debug-logger.js"; import { resolveAutoSupervisorConfig, resolvePersistModelChanges, } from "../preferences.js"; +import { + collectSessionTokenUsage, + collectWorktreeFingerprint, + countChangedFiles, + resetRunawayGuardState, +} from "../uok/auto-runaway-guard.js"; import { logWarning } from "../workflow-logger.js"; import { _clearCurrentResolve, diff --git a/src/resources/extensions/sf/bootstrap/db-tools.js b/src/resources/extensions/sf/bootstrap/db-tools.js index 95f422c7f..7cccc8297 100644 --- a/src/resources/extensions/sf/bootstrap/db-tools.js +++ b/src/resources/extensions/sf/bootstrap/db-tools.js @@ -142,7 +142,7 @@ export function registerDbTools(pi) { const message = d?.reason ?? textContent ?? d?.error ?? "unknown"; return new Text(theme.fg("error", `Error: ${message}`), 0, 0); } - let text = theme.fg("success", `Decision ${d?.id ?? ""} saved`); + const text = theme.fg("success", `Decision ${d?.id ?? ""} saved`); return new Text(text, 0, 0); }, }; @@ -211,7 +211,8 @@ export function registerDbTools(pi) { description: "Update an existing requirement by ID and return confirmation — only fields you provide are changed. " + "Call this when a requirement's status, validation evidence, description, or owning slice changes after it was first recorded.", - promptSnippet: "Update an existing requirement by ID (only provided fields are changed)", + promptSnippet: + "Update an existing requirement by ID (only provided fields are changed)", promptGuidelines: [ "id is required and must be an existing requirement identifier (e.g. R001).", "All other fields are optional — only the fields you provide are updated.", @@ -257,7 +258,7 @@ export function registerDbTools(pi) { 0, ); } - let text = theme.fg("success", `Requirement ${d?.id ?? ""} updated`); + const text = theme.fg("success", `Requirement ${d?.id ?? ""} updated`); return new Text(text, 0, 0); }, }; @@ -323,8 +324,7 @@ export function registerDbTools(pi) { description: "Record a new requirement and return its auto-assigned ID (e.g. R001). " + "Call this when a functional, non-functional, or operational requirement is identified that the project must satisfy.", - promptSnippet: - "Record a new requirement (auto-assigns ID, persists to DB)", + promptSnippet: "Record a new requirement (auto-assigns ID, persists to DB)", promptGuidelines: [ "Requirement IDs are auto-assigned — never guess or provide one.", "class, description, why, and source are required; all other fields are optional.", @@ -373,7 +373,7 @@ export function registerDbTools(pi) { 0, ); } - let text = theme.fg("success", `Requirement ${d?.id ?? ""} saved`); + const text = theme.fg("success", `Requirement ${d?.id ?? ""} saved`); return new Text(text, 0, 0); }, }; @@ -747,7 +747,12 @@ export function registerDbTools(pi) { const { insertMemoryRow } = await import("../sf-db.js"); const id = `K-${randomUUID()}`; const now = new Date().toISOString(); - const confidenceScore = params.confidence === "medium" ? 0.6 : params.confidence === "low" ? 0.3 : 0.9; + const confidenceScore = + params.confidence === "medium" + ? 0.6 + : params.confidence === "low" + ? 0.3 + : 0.9; insertMemoryRow({ id, category: params.category ?? "knowledge", @@ -791,11 +796,13 @@ export function registerDbTools(pi) { ], parameters: Type.Object({ content: Type.String({ - description: "The knowledge insight to persist — complete and self-contained", + description: + "The knowledge insight to persist — complete and self-contained", }), category: Type.Optional( Type.String({ - description: "Category (default: 'knowledge'). E.g. 'architecture', 'tooling', 'process'", + description: + "Category (default: 'knowledge'). E.g. 'architecture', 'tooling', 'process'", }), ), confidence: Type.Optional( @@ -805,7 +812,8 @@ export function registerDbTools(pi) { ), tags: Type.Optional( Type.Array(Type.String(), { - description: "Optional string tags for filtering (e.g. ['mcp', 'transport'])", + description: + "Optional string tags for filtering (e.g. ['mcp', 'transport'])", }), ), }), @@ -814,13 +822,18 @@ export function registerDbTools(pi) { let text = theme.fg("toolTitle", theme.bold("save_knowledge ")); if (args.category) text += theme.fg("accent", `[${args.category}] `); if (args.content) - text += theme.fg("muted", args.content.slice(0, 60) + (args.content.length > 60 ? "…" : "")); + text += theme.fg( + "muted", + args.content.slice(0, 60) + (args.content.length > 60 ? "…" : ""), + ); return new Text(text, 0, 0); }, renderResult(result, _options, theme) { const d = result.details; if (result.isError || d?.error) { - const textContent = result.content?.find?.((item) => item?.type === "text")?.text; + const textContent = result.content?.find?.( + (item) => item?.type === "text", + )?.text; const message = d?.reason ?? textContent ?? d?.error ?? "unknown"; return new Text(theme.fg("error", `Error: ${message}`), 0, 0); } @@ -2688,7 +2701,8 @@ export function registerDbTools(pi) { description: "Record the agent's intent at the start of a work block so crash-resume can surface it. " + "Call at the top of each autonomous work block with a clear one-sentence intent.", - promptSnippet: "Open an intent chapter before starting a significant block of work", + promptSnippet: + "Open an intent chapter before starting a significant block of work", promptGuidelines: [ "Call chapter_open before starting any significant work block (a task, a multi-step investigation, a refactor).", "Keep the intent concise — one sentence stating what you are about to accomplish.", @@ -2705,11 +2719,13 @@ export function registerDbTools(pi) { }, unit_type: { type: "string", - description: "UOK unit type (e.g. 'execute-task', 'plan-slice'). Optional — defaults to current unit.", + description: + "UOK unit type (e.g. 'execute-task', 'plan-slice'). Optional — defaults to current unit.", }, unit_id: { type: "string", - description: "UOK unit ID (e.g. 'M001/S01/T02'). Optional — defaults to current unit.", + description: + "UOK unit ID (e.g. 'M001/S01/T02'). Optional — defaults to current unit.", }, }, required: ["intent"], @@ -2718,7 +2734,12 @@ export function registerDbTools(pi) { const dbAvailable = await ensureDbOpen(); if (!dbAvailable) { return { - content: [{ type: "text", text: "Error: SF database unavailable — chapter not opened." }], + content: [ + { + type: "text", + text: "Error: SF database unavailable — chapter not opened.", + }, + ], details: { operation: "chapter_open", error: "db_unavailable" }, }; } @@ -2750,8 +2771,17 @@ export function registerDbTools(pi) { }, renderToolResult: (d, theme) => { const { Text } = theme; - if (d?.error) return new Text(theme.fg("error", `chapter_open error: ${d.error}`), 0, 0); - return new Text(theme.fg("success", `chapter opened: ${d?.id ?? ""}`), 0, 0); + if (d?.error) + return new Text( + theme.fg("error", `chapter_open error: ${d.error}`), + 0, + 0, + ); + return new Text( + theme.fg("success", `chapter opened: ${d?.id ?? ""}`), + 0, + 0, + ); }, }); @@ -2785,7 +2815,12 @@ export function registerDbTools(pi) { const dbAvailable = await ensureDbOpen(); if (!dbAvailable) { return { - content: [{ type: "text", text: "Error: SF database unavailable — chapter not closed." }], + content: [ + { + type: "text", + text: "Error: SF database unavailable — chapter not closed.", + }, + ], details: { operation: "chapter_close", error: "db_unavailable" }, }; } @@ -2793,7 +2828,14 @@ export function registerDbTools(pi) { const { closeIntentChapter } = await import("../sf-db.js"); const closed = closeIntentChapter(params.id, params.outcome); return { - content: [{ type: "text", text: closed ? `Chapter ${params.id} closed (${params.outcome}).` : `Chapter ${params.id} not found or already closed.` }], + content: [ + { + type: "text", + text: closed + ? `Chapter ${params.id} closed (${params.outcome}).` + : `Chapter ${params.id} not found or already closed.`, + }, + ], details: { operation: "chapter_close", id: params.id, closed }, }; } catch (err) { @@ -2810,8 +2852,17 @@ export function registerDbTools(pi) { }, renderToolResult: (d, theme) => { const { Text } = theme; - if (d?.error) return new Text(theme.fg("error", `chapter_close error: ${d.error}`), 0, 0); - return new Text(theme.fg("success", `chapter closed: ${d?.id ?? ""}`), 0, 0); + if (d?.error) + return new Text( + theme.fg("error", `chapter_close error: ${d.error}`), + 0, + 0, + ); + return new Text( + theme.fg("success", `chapter closed: ${d?.id ?? ""}`), + 0, + 0, + ); }, }); } diff --git a/src/resources/extensions/sf/bootstrap/register-hooks.js b/src/resources/extensions/sf/bootstrap/register-hooks.js index 4f0affaf8..7873ee50f 100644 --- a/src/resources/extensions/sf/bootstrap/register-hooks.js +++ b/src/resources/extensions/sf/bootstrap/register-hooks.js @@ -8,9 +8,11 @@ import { writeFileSync, } from "node:fs"; import { join, relative, resolve } from "node:path"; -import { isToolCallEventType } from "@singularity-forge/coding-agent"; +import { + formatTokenCount, + isToolCallEventType, +} from "@singularity-forge/coding-agent"; import { resetAskUserQuestionsCache } from "../../ask-user-questions.js"; -import { formatTokenCount } from "@singularity-forge/coding-agent"; import { saveActivityLog } from "../activity-log.js"; import { getAutoDashboardData, @@ -46,11 +48,7 @@ import { resetLearningRuntime, selectLearnedModel, } from "../learning/runtime.js"; -import { - observeToolResult, - resetToolWatchdog, -} from "../tool-watchdog.js"; -import { NOTICE_KIND, initNotificationStore } from "../notification-store.js"; +import { initNotificationStore, NOTICE_KIND } from "../notification-store.js"; import { initNotificationWidget } from "../notification-widget.js"; import { isParallelActive, @@ -77,6 +75,7 @@ import { import { initSessionRecorder } from "../session-recorder.js"; import { deriveState } from "../state.js"; import { countGoogleGeminiCliTokens } from "../token-counter.js"; +import { observeToolResult, resetToolWatchdog } from "../tool-watchdog.js"; import { getSessionTodoCompactionBlock } from "../tools/session-todo-tool.js"; import { parseUnitId } from "../unit-id.js"; import { logWarning as safetyLogWarning } from "../workflow-logger.js"; diff --git a/src/resources/extensions/sf/bootstrap/system-context.js b/src/resources/extensions/sf/bootstrap/system-context.js index b173ffd4a..0a56e5f8c 100644 --- a/src/resources/extensions/sf/bootstrap/system-context.js +++ b/src/resources/extensions/sf/bootstrap/system-context.js @@ -45,6 +45,11 @@ import { resolveModelWithFallbacksForUnit } from "../preferences-models.js"; import { resolveSkillReference } from "../preferences-skills.js"; import { getTemplatesDir, loadPrompt } from "../prompt-loader.js"; import { buildRepositoryVcsContextBlock } from "../repository-vcs-context.js"; +import { + getActiveMemories, + isDbAvailable, + listSelfFeedbackEntries, +} from "../sf-db.js"; import { detectNewSkills, formatSkillsXml, @@ -52,11 +57,6 @@ import { } from "../skill-discovery.js"; import { deriveState } from "../state.js"; import { logWarning } from "../workflow-logger.js"; -import { - getActiveMemories, - isDbAvailable, - listSelfFeedbackEntries, -} from "../sf-db.js"; import { getActiveWorktreeName, getWorktreeOriginalCwd, diff --git a/src/resources/extensions/sf/commands-agent.js b/src/resources/extensions/sf/commands-agent.js index 1904c80cf..a3b3640dd 100644 --- a/src/resources/extensions/sf/commands-agent.js +++ b/src/resources/extensions/sf/commands-agent.js @@ -8,10 +8,10 @@ * Consumer: ops.js dispatcher for the /agent slash command. */ -import { getDatabase, openDatabase } from "./sf-db.js"; -import { sfRoot } from "./paths.js"; import { mkdirSync } from "node:fs"; import { join } from "node:path"; +import { sfRoot } from "./paths.js"; +import { getDatabase, openDatabase } from "./sf-db.js"; import { UokCoordinationStore } from "./uok/coordination-store.js"; const USAGE = `Usage: /agent @@ -135,10 +135,7 @@ async function handleAgentInspect(store, name, ctx) { const identityKey = `agent:${name}:identity`; const identity = store.get(identityKey); if (!identity) { - ctx.ui.notify( - `/agent inspect: no agent named "${name}" found.`, - "warning", - ); + ctx.ui.notify(`/agent inspect: no agent named "${name}" found.`, "warning"); return; } @@ -219,10 +216,7 @@ async function handleAgentDelete(store, name, ctx) { const identityKey = `agent:${name}:identity`; const identity = store.get(identityKey); if (!identity) { - ctx.ui.notify( - `/agent delete: no agent named "${name}" found.`, - "warning", - ); + ctx.ui.notify(`/agent delete: no agent named "${name}" found.`, "warning"); return; } diff --git a/src/resources/extensions/sf/commands-memory.js b/src/resources/extensions/sf/commands-memory.js index e7ffd18f6..b63698f65 100644 --- a/src/resources/extensions/sf/commands-memory.js +++ b/src/resources/extensions/sf/commands-memory.js @@ -218,9 +218,7 @@ async function handleSearch(ctx, parsed) { ctx.ui.notify("No matches.", "info"); return; } - const { loadGatewayConfigFromEnv } = await import( - "./memory-embeddings.js" - ); + const { loadGatewayConfigFromEnv } = await import("./memory-embeddings.js"); const gatewayConfig = loadGatewayConfigFromEnv(); const usingEmbeddings = !!gatewayConfig; const usingRerank = !!gatewayConfig?.rerankModel; @@ -418,9 +416,7 @@ async function handleBackfill(ctx) { return; } const before = readMemoryDbStatus(adapter); - const { loadGatewayConfigFromEnv } = await import( - "./memory-embeddings.js" - ); + const { loadGatewayConfigFromEnv } = await import("./memory-embeddings.js"); const gatewayConfig = loadGatewayConfigFromEnv(); if (!gatewayConfig) { ctx.ui.notify( diff --git a/src/resources/extensions/sf/commands-prefs-wizard.js b/src/resources/extensions/sf/commands-prefs-wizard.js index 7bc52b987..092831404 100644 --- a/src/resources/extensions/sf/commands-prefs-wizard.js +++ b/src/resources/extensions/sf/commands-prefs-wizard.js @@ -8,10 +8,7 @@ import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { runClaudeImportFlow } from "./claude-import.js"; -import { - loadFile, - saveFile, -} from "./files.js"; +import { loadFile, saveFile } from "./files.js"; import { getGlobalSFPreferencesPath, getProjectSFPreferencesPath, diff --git a/src/resources/extensions/sf/dashboard-overlay.js b/src/resources/extensions/sf/dashboard-overlay.js index 6da3859a9..3a51f3b2e 100644 --- a/src/resources/extensions/sf/dashboard-overlay.js +++ b/src/resources/extensions/sf/dashboard-overlay.js @@ -21,10 +21,6 @@ import { STATUS_COLOR, STATUS_GLYPH, } from "../shared/mod.js"; -import { - getWorkerBatches, - hasActiveWorkers, -} from "./subagent/worker-registry.js"; import { getAutoDashboardData } from "./auto.js"; import { estimateTimeRemaining } from "./auto-dashboard.js"; import { runEnvironmentChecks } from "./doctor-environment.js"; @@ -46,6 +42,10 @@ import { computeProgressScore } from "./progress-score.js"; import { getMilestoneSlices, getSliceTasks, isDbAvailable } from "./sf-db.js"; import { formattedShortcutPair } from "./shortcut-defs.js"; import { deriveState } from "./state.js"; +import { + getWorkerBatches, + hasActiveWorkers, +} from "./subagent/worker-registry.js"; import { writeUokDiagnostics } from "./uok/diagnostic-synthesis.js"; import { getActiveWorktreeName } from "./worktree-command.js"; diff --git a/src/resources/extensions/sf/deep-project-setup-policy.js b/src/resources/extensions/sf/deep-project-setup-policy.js index 86409ce51..6b41b5c00 100644 --- a/src/resources/extensions/sf/deep-project-setup-policy.js +++ b/src/resources/extensions/sf/deep-project-setup-policy.js @@ -20,9 +20,7 @@ export function researchDecisionPath(basePath) { export function isWorkflowPrefsCaptured(basePath) { // Check yaml (canonical) first, fallback to legacy md const sfRootPath = sfRoot(basePath); - const candidates = [ - join(sfRootPath, "preferences.yaml"), - ]; + const candidates = [join(sfRootPath, "preferences.yaml")]; for (const prefsPath of candidates) { if (!existsSync(prefsPath)) continue; let content; @@ -117,14 +115,16 @@ export function resolveDeepProjectSetupState(prefs, basePath) { }; } // DB-first: check for requirements in DB; fall back to file for unmigrated projects - const hasDbRequirements = isDbAvailable() && getActiveRequirements().length > 0; + const hasDbRequirements = + isDbAvailable() && getActiveRequirements().length > 0; if (!hasDbRequirements) { const requirementsPath = join(root, "REQUIREMENTS.md"); if (!existsSync(requirementsPath)) { return { status: "pending", stage: "requirements", - reason: "No requirements found (DB empty and .sf/REQUIREMENTS.md is missing).", + reason: + "No requirements found (DB empty and .sf/REQUIREMENTS.md is missing).", }; } if (!validateArtifact(requirementsPath, "requirements").ok) { diff --git a/src/resources/extensions/sf/detection.js b/src/resources/extensions/sf/detection.js index 677359bc0..41a55d1c0 100644 --- a/src/resources/extensions/sf/detection.js +++ b/src/resources/extensions/sf/detection.js @@ -310,8 +310,7 @@ export function detectV1Planning(basePath) { function detectV2Sf(basePath) { const sfPath = sfRoot(basePath); if (!existsSync(sfPath)) return null; - const hasPreferences = - existsSync(join(sfPath, "preferences.yaml")); + const hasPreferences = existsSync(join(sfPath, "preferences.yaml")); const hasContext = existsSync(join(sfPath, "CONTEXT.md")); let milestoneCount = 0; const milestonesPath = join(sfPath, "milestones"); diff --git a/src/resources/extensions/sf/dev-workflow-engine.js b/src/resources/extensions/sf/dev-workflow-engine.js index ba02d7bff..18b93180a 100644 --- a/src/resources/extensions/sf/dev-workflow-engine.js +++ b/src/resources/extensions/sf/dev-workflow-engine.js @@ -5,9 +5,10 @@ * and dispatch logic. This is the "dev" engine — it wraps the current SF * autonomous mode behavior behind the engine-polymorphic interface. */ -import { resolveDispatch } from "./uok/auto-dispatch.js"; + import { loadEffectiveSFPreferences } from "./preferences.js"; import { deriveState } from "./state.js"; +import { resolveDispatch } from "./uok/auto-dispatch.js"; // ─── Bridge: DispatchAction → EngineDispatchAction ──────────────────────── /** * Map a SF-specific DispatchAction (which carries `matchedRule`, `unitType`, diff --git a/src/resources/extensions/sf/doctor-providers.js b/src/resources/extensions/sf/doctor-providers.js index 3cfabba12..11c4a2dd7 100644 --- a/src/resources/extensions/sf/doctor-providers.js +++ b/src/resources/extensions/sf/doctor-providers.js @@ -14,7 +14,10 @@ import { existsSync } from "node:fs"; import { AuthStorage } from "@singularity-forge/coding-agent"; import { getAuthPath, PROVIDER_REGISTRY } from "./key-manager.js"; import { loadEffectiveSFPreferences } from "./preferences.js"; -import { getConfiguredEnvApiKey, getGatedEnvVarKey } from "./provider-env-auth.js"; +import { + getConfiguredEnvApiKey, + getGatedEnvVarKey, +} from "./provider-env-auth.js"; import { couldBeVaultUri } from "./vault-credential-resolver.js"; // ── Model → Provider ID mapping ─────────────────────────────────────────────── @@ -336,7 +339,9 @@ function checkOptionalProviders() { // "not configured" noise for alternative search providers when at least // one is already active (e.g. don't warn about missing BRAVE_API_KEY // when Tavily is configured). - const searchProviderIds = PROVIDER_REGISTRY.filter((p) => p.category === "search").map((p) => p.id); + const searchProviderIds = PROVIDER_REGISTRY.filter( + (p) => p.category === "search", + ).map((p) => p.id); const hasAnySearchProvider = searchProviderIds.some( (id) => resolveKey(id).found, ); diff --git a/src/resources/extensions/sf/export-html.js b/src/resources/extensions/sf/export-html.js index ca022b82e..fa573d569 100644 --- a/src/resources/extensions/sf/export-html.js +++ b/src/resources/extensions/sf/export-html.js @@ -19,7 +19,10 @@ * * Design: Linear-inspired — restrained palette, geometric status, no emoji. */ -import { formatDateShort, formatDuration } from "@singularity-forge/coding-agent"; +import { + formatDateShort, + formatDuration, +} from "@singularity-forge/coding-agent"; import { formatCost, formatTokenCount } from "./metrics.js"; export function generateHtmlReport(data, opts) { const generated = new Date().toISOString(); diff --git a/src/resources/extensions/sf/extension-manifest.json b/src/resources/extensions/sf/extension-manifest.json index 220e789f1..3cc72f617 100644 --- a/src/resources/extensions/sf/extension-manifest.json +++ b/src/resources/extensions/sf/extension-manifest.json @@ -64,7 +64,6 @@ "backlog", "capture", "chronicle", - "clear", "cleanup", "cmux", "codebase", @@ -204,11 +203,6 @@ "turn_start", "turn_end" ], - "shortcuts": [ - "Ctrl+Alt+G", - "Ctrl+Alt+H", - "Ctrl+Alt+M", - "Ctrl+Shift+H" - ] + "shortcuts": ["Ctrl+Alt+G", "Ctrl+Alt+H", "Ctrl+Alt+M", "Ctrl+Shift+H"] } } diff --git a/src/resources/extensions/sf/guided-flow.js b/src/resources/extensions/sf/guided-flow.js index 9de98842a..e248158f6 100644 --- a/src/resources/extensions/sf/guided-flow.js +++ b/src/resources/extensions/sf/guided-flow.js @@ -70,7 +70,12 @@ import { isSessionLockProcessAlive, readSessionLockData, } from "./session-lock.js"; -import { getAllMilestones, getMilestone, getMilestoneSlices, isDbAvailable } from "./sf-db.js"; +import { + getAllMilestones, + getMilestone, + getMilestoneSlices, + isDbAvailable, +} from "./sf-db.js"; import { deriveState } from "./state.js"; import { resolveUokFlags } from "./uok/flags.js"; import { UokGateRunner } from "./uok/gate-runner.js"; @@ -271,7 +276,7 @@ export function checkAutoStartAfterDiscuss() { if (isDbAvailable()) { const milestone = getMilestone(milestoneId); const dbSlices = getMilestoneSlices(milestoneId); - const hasContext = !!(milestone?.vision); + const hasContext = !!milestone?.vision; const hasRoadmap = dbSlices.length > 0; if (!hasContext && !hasRoadmap) return false; // Gate 3: Multi-milestone completeness warning (DB version) diff --git a/src/resources/extensions/sf/index.js b/src/resources/extensions/sf/index.js index 6d1000f1f..78122ff56 100644 --- a/src/resources/extensions/sf/index.js +++ b/src/resources/extensions/sf/index.js @@ -44,7 +44,9 @@ export default async function registerExtension(pi) { // Register SF-owned subagent tools after core bootstrap so model, preference, // inheritance, and retrieval-evidence integrations share one extension owner. try { - const { default: registerSFSubagents } = await import("./subagent/index.js"); + const { default: registerSFSubagents } = await import( + "./subagent/index.js" + ); registerSFSubagents(pi); } catch (err) { const { logWarning } = await import("./workflow-logger.js"); @@ -82,7 +84,9 @@ export default async function registerExtension(pi) { // Register SF notifications (completion beep/say/focus/threshold commands). try { - const { default: registerSFNotify } = await import("./notifications/notify.js"); + const { default: registerSFNotify } = await import( + "./notifications/notify.js" + ); registerSFNotify(pi); } catch (err) { const { logWarning } = await import("./workflow-logger.js"); @@ -94,7 +98,9 @@ export default async function registerExtension(pi) { // Register SF in-turn guard (duplicate tool-call loop detection). try { - const { default: registerSFInturnGuard } = await import("./guards/inturn.js"); + const { default: registerSFInturnGuard } = await import( + "./guards/inturn.js" + ); registerSFInturnGuard(pi); } catch (err) { const { logWarning } = await import("./workflow-logger.js"); @@ -106,7 +112,9 @@ export default async function registerExtension(pi) { // Register SF permissions (layered permission enforcement). try { - const { default: registerSFPermissions } = await import("./permissions/index.js"); + const { default: registerSFPermissions } = await import( + "./permissions/index.js" + ); registerSFPermissions(pi); } catch (err) { const { logWarning } = await import("./workflow-logger.js"); @@ -118,7 +126,9 @@ export default async function registerExtension(pi) { // Register SF legacy slash commands (/audit, /clear, /create-extension, /create-slash-command). try { - const { default: registerSFLegacyCommands } = await import("./commands/legacy/index.js"); + const { default: registerSFLegacyCommands } = await import( + "./commands/legacy/index.js" + ); registerSFLegacyCommands(pi); } catch (err) { const { logWarning } = await import("./workflow-logger.js"); diff --git a/src/resources/extensions/sf/init-wizard.js b/src/resources/extensions/sf/init-wizard.js index 301966e4e..27ce4c156 100644 --- a/src/resources/extensions/sf/init-wizard.js +++ b/src/resources/extensions/sf/init-wizard.js @@ -519,7 +519,9 @@ function bootstrapSfDirectory(basePath, prefs, signals) { ensureSiftIndexWarmup(basePath); } function buildPreferencesFile(prefs) { - const lines = ["# SF preferences — see ~/.sf/agent/extensions/sf/docs/preferences-reference.md for docs"]; + const lines = [ + "# SF preferences — see ~/.sf/agent/extensions/sf/docs/preferences-reference.md for docs", + ]; lines.push("version: 1"); lines.push(`mode: ${prefs.mode}`); // Git preferences diff --git a/src/resources/extensions/sf/key-manager.js b/src/resources/extensions/sf/key-manager.js index e0884ee70..c5007fe8e 100644 --- a/src/resources/extensions/sf/key-manager.js +++ b/src/resources/extensions/sf/key-manager.js @@ -292,7 +292,9 @@ export function getAllKeyStatuses(auth) { const rawCreds = auth.getCredentialsForProvider(provider.id); // Filter out empty-key entries (left by legacy removeProviderToken or skipped onboarding) const creds = rawCreds.filter((c) => !(c.type === "api_key" && !c.key)); - const envKey = isEnvAuthAllowed(provider.id) ? getProviderEnvKey(provider) : undefined; + const envKey = isEnvAuthAllowed(provider.id) + ? getProviderEnvKey(provider) + : undefined; if (creds.length > 0) { const firstCred = creds[0]; const desc = diff --git a/src/resources/extensions/sf/knowledge-compounding.js b/src/resources/extensions/sf/knowledge-compounding.js index fade4a555..d57f530ae 100644 --- a/src/resources/extensions/sf/knowledge-compounding.js +++ b/src/resources/extensions/sf/knowledge-compounding.js @@ -12,7 +12,7 @@ */ import { randomUUID } from "node:crypto"; import { readJudgmentLog } from "./judgment-log.js"; -import { insertMemoryRow, isDbAvailable, getActiveMemories } from "./sf-db.js"; +import { getActiveMemories, insertMemoryRow, isDbAvailable } from "./sf-db.js"; /** Map judgment-log string confidence to a numeric score for the REAL column. */ function confidenceScore(s) { diff --git a/src/resources/extensions/sf/learning/bayesian-blender.mjs b/src/resources/extensions/sf/learning/bayesian-blender.mjs index d8d232b6b..b9ff625a8 100644 --- a/src/resources/extensions/sf/learning/bayesian-blender.mjs +++ b/src/resources/extensions/sf/learning/bayesian-blender.mjs @@ -168,7 +168,11 @@ export function computeObservedScore( const sampleCount = stats.sample_count ?? 0; const hardFailureCount = stats.hard_failure_count ?? 0; - if (hardFailureCount > 0 && sampleCount > 0 && hardFailureCount / sampleCount > 0.5) { + if ( + hardFailureCount > 0 && + sampleCount > 0 && + hardFailureCount / sampleCount > 0.5 + ) { scaled *= 0.5; } diff --git a/src/resources/extensions/sf/learning/outcome-recorder.test.mjs b/src/resources/extensions/sf/learning/outcome-recorder.test.mjs index 5586d20f0..94e89d719 100644 --- a/src/resources/extensions/sf/learning/outcome-recorder.test.mjs +++ b/src/resources/extensions/sf/learning/outcome-recorder.test.mjs @@ -9,6 +9,7 @@ import assert from "node:assert/strict"; import { test } from "vitest"; +import { computeObservedScore } from "./bayesian-blender.mjs"; import { aggregateAllForUnitType, aggregateOutcomes, @@ -20,7 +21,6 @@ import { recordOutcomeBatch, validateOutcome, } from "./outcome-recorder.mjs"; -import { computeObservedScore } from "./bayesian-blender.mjs"; // --------------------------------------------------------------------------- // Minimal in-memory fake of the SQLite surface consumed by sf-learning. @@ -214,7 +214,8 @@ function summarize(rows) { rows.reduce((sum, r) => sum + effectiveWeight(r), 0) / rows.length; const hard_failure_count = rows.filter( - (r) => r.failure_mode === "quota_exhausted" || r.failure_mode === "auth_error", + (r) => + r.failure_mode === "quota_exhausted" || r.failure_mode === "auth_error", ).length; return { @@ -616,17 +617,88 @@ test("aggregateOutcomes_rate_limit_failures_rank_higher_than_quota_exhausted", ( // model with only rate_limit failures (weight 0.7) dbRateLimit._rows.push( - { id: 1, model_id: "model-x", provider: "p", unit_type: "execute-task", unit_id: "T01", succeeded: 0, failure_mode: "rate_limit", retries: 0, escalated: 0, verification_passed: null, blocker_discovered: 0, duration_ms: 100, tokens_total: 10, cost_usd: 0, recorded_at: now - 1000 }, - { id: 2, model_id: "model-x", provider: "p", unit_type: "execute-task", unit_id: "T02", succeeded: 0, failure_mode: "rate_limit", retries: 0, escalated: 0, verification_passed: null, blocker_discovered: 0, duration_ms: 100, tokens_total: 10, cost_usd: 0, recorded_at: now - 2000 }, + { + id: 1, + model_id: "model-x", + provider: "p", + unit_type: "execute-task", + unit_id: "T01", + succeeded: 0, + failure_mode: "rate_limit", + retries: 0, + escalated: 0, + verification_passed: null, + blocker_discovered: 0, + duration_ms: 100, + tokens_total: 10, + cost_usd: 0, + recorded_at: now - 1000, + }, + { + id: 2, + model_id: "model-x", + provider: "p", + unit_type: "execute-task", + unit_id: "T02", + succeeded: 0, + failure_mode: "rate_limit", + retries: 0, + escalated: 0, + verification_passed: null, + blocker_discovered: 0, + duration_ms: 100, + tokens_total: 10, + cost_usd: 0, + recorded_at: now - 2000, + }, ); // model with only quota_exhausted failures (weight 0.2) dbQuota._rows.push( - { id: 1, model_id: "model-x", provider: "p", unit_type: "execute-task", unit_id: "T01", succeeded: 0, failure_mode: "quota_exhausted", retries: 0, escalated: 0, verification_passed: null, blocker_discovered: 0, duration_ms: 100, tokens_total: 10, cost_usd: 0, recorded_at: now - 1000 }, - { id: 2, model_id: "model-x", provider: "p", unit_type: "execute-task", unit_id: "T02", succeeded: 0, failure_mode: "quota_exhausted", retries: 0, escalated: 0, verification_passed: null, blocker_discovered: 0, duration_ms: 100, tokens_total: 10, cost_usd: 0, recorded_at: now - 2000 }, + { + id: 1, + model_id: "model-x", + provider: "p", + unit_type: "execute-task", + unit_id: "T01", + succeeded: 0, + failure_mode: "quota_exhausted", + retries: 0, + escalated: 0, + verification_passed: null, + blocker_discovered: 0, + duration_ms: 100, + tokens_total: 10, + cost_usd: 0, + recorded_at: now - 1000, + }, + { + id: 2, + model_id: "model-x", + provider: "p", + unit_type: "execute-task", + unit_id: "T02", + succeeded: 0, + failure_mode: "quota_exhausted", + retries: 0, + escalated: 0, + verification_passed: null, + blocker_discovered: 0, + duration_ms: 100, + tokens_total: 10, + cost_usd: 0, + recorded_at: now - 2000, + }, ); - const statsRateLimit = aggregateOutcomes(dbRateLimit, "model-x", "execute-task", { now }); - const statsQuota = aggregateOutcomes(dbQuota, "model-x", "execute-task", { now }); + const statsRateLimit = aggregateOutcomes( + dbRateLimit, + "model-x", + "execute-task", + { now }, + ); + const statsQuota = aggregateOutcomes(dbQuota, "model-x", "execute-task", { + now, + }); assert.ok( statsRateLimit.effective_success_rate > statsQuota.effective_success_rate, diff --git a/src/resources/extensions/sf/model-catalog-cache.js b/src/resources/extensions/sf/model-catalog-cache.js index ef4243d7e..e90c29014 100644 --- a/src/resources/extensions/sf/model-catalog-cache.js +++ b/src/resources/extensions/sf/model-catalog-cache.js @@ -11,12 +11,12 @@ */ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; +import { sfRuntimeRoot } from "./paths.js"; import { DISCOVERABLE_PROVIDER_IDS, getProviderCatalogConfig, getProviderModelExcludePatterns, } from "./provider-catalog-config.js"; -import { sfRuntimeRoot } from "./paths.js"; const CATALOG_TTL_MS = 6 * 60 * 60 * 1000; @@ -37,7 +37,8 @@ export function readCachedModelIds(basePath, providerId) { if (!existsSync(path)) return null; const entry = JSON.parse(readFileSync(path, "utf-8")); if (!entry?.fetchedAt || !Array.isArray(entry.modelIds)) return null; - if (Date.now() - new Date(entry.fetchedAt).getTime() > CATALOG_TTL_MS) return null; + if (Date.now() - new Date(entry.fetchedAt).getTime() > CATALOG_TTL_MS) + return null; return entry.modelIds; } catch { return null; @@ -85,10 +86,16 @@ function parseModelIds(cfg, json) { // Google: { models: [{name: "models/gemini-..."}] } items = Array.isArray(json?.models) ? json.models : null; if (!items) return null; - return items.map((m) => (m.name ?? "").replace(/^models\//, "")).filter(Boolean); + return items + .map((m) => (m.name ?? "").replace(/^models\//, "")) + .filter(Boolean); } // OpenAI-compatible: { data: [{id}] } or { models: [{id}] } - items = Array.isArray(json?.data) ? json.data : Array.isArray(json?.models) ? json.models : null; + items = Array.isArray(json?.data) + ? json.data + : Array.isArray(json?.models) + ? json.models + : null; if (!items) return null; return items.map((m) => m.id ?? m.name).filter(Boolean); } diff --git a/src/resources/extensions/sf/preferences-models.js b/src/resources/extensions/sf/preferences-models.js index b1cf5aad6..198381031 100644 --- a/src/resources/extensions/sf/preferences-models.js +++ b/src/resources/extensions/sf/preferences-models.js @@ -9,6 +9,8 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; import { getModels, getProviders } from "@singularity-forge/ai"; +import { selectByBenchmarks } from "./benchmark-selector.js"; +import { defaultRoutingConfig, MODEL_CAPABILITY_TIER } from "./model-router.js"; import { DEFAULT_RUNAWAY_CHANGED_FILES_WARNING, DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS, @@ -16,8 +18,6 @@ import { DEFAULT_RUNAWAY_TOKEN_WARNING, DEFAULT_RUNAWAY_TOOL_CALL_WARNING, } from "./uok/auto-runaway-guard.js"; -import { selectByBenchmarks } from "./benchmark-selector.js"; -import { defaultRoutingConfig, MODEL_CAPABILITY_TIER } from "./model-router.js"; // ─── Lazy loader — breaks the preferences.js ↔ preferences-models.js cycle ── // preferences.js imports resolveProfileDefaults from here, and needs @@ -278,10 +278,12 @@ function resolveAutoBenchmarkPickForUnit(unitType, prefs) { const auth = getKeyManagerAuthStorage(); const configuredProviderIds = new Set( auth.getConfiguredProviders?.() ?? - getProviders().filter((p) => { - const creds = auth.getCredentialsForProvider(p); - return creds.some((c) => c.type === "oauth" || (c.type === "api_key" && c.key)); - }), + getProviders().filter((p) => { + const creds = auth.getCredentialsForProvider(p); + return creds.some( + (c) => c.type === "oauth" || (c.type === "api_key" && c.key), + ); + }), ); const candidates = []; for (const provider of getProviders()) { @@ -873,9 +875,13 @@ export function resolveSearchProviderFromPreferences() { export function isHeavyModelId(modelId) { if (!modelId || typeof modelId !== "string") return false; // Strip provider prefix (e.g. "anthropic/claude-opus-4-6" → "claude-opus-4-6") - const bare = modelId.includes("/") ? modelId.split("/").slice(1).join("/") : modelId; + const bare = modelId.includes("/") + ? modelId.split("/").slice(1).join("/") + : modelId; const tier = MODEL_CAPABILITY_TIER[bare] ?? MODEL_CAPABILITY_TIER[modelId]; if (tier !== undefined) return tier === "heavy"; // Fallback regex for models not yet in the tier map - return /\bopus\b|\bo1\b|\bo3\b|\bgpt-4-turbo\b|\bgpt-5\b|\bdeepseek-reasoner\b/i.test(modelId); + return /\bopus\b|\bo1\b|\bo3\b|\bgpt-4-turbo\b|\bgpt-5\b|\bdeepseek-reasoner\b/i.test( + modelId, + ); } diff --git a/src/resources/extensions/sf/preferences.js b/src/resources/extensions/sf/preferences.js index dc7eb22db..b36eb7988 100644 --- a/src/resources/extensions/sf/preferences.js +++ b/src/resources/extensions/sf/preferences.js @@ -12,8 +12,8 @@ import { existsSync, readFileSync } from "node:fs"; import { homedir } from "node:os"; import { dirname, join, resolve } from "node:path"; -import { parse as parseYaml } from "yaml"; import { normalizeStringArray } from "@singularity-forge/coding-agent"; +import { parse as parseYaml } from "yaml"; import { sfRoot } from "./paths.js"; import { _initPrefsLoader, diff --git a/src/resources/extensions/sf/provider-catalog-config.js b/src/resources/extensions/sf/provider-catalog-config.js index db18e5de1..6db6ade39 100644 --- a/src/resources/extensions/sf/provider-catalog-config.js +++ b/src/resources/extensions/sf/provider-catalog-config.js @@ -169,5 +169,7 @@ export function isProviderScopedRateLimit(providerId) { * Returns the exclude patterns for a provider's model list, or []. */ export function getProviderModelExcludePatterns(providerId) { - return PROVIDER_CATALOG_CONFIG[providerId]?.modelFilter?.excludePatterns ?? []; + return ( + PROVIDER_CATALOG_CONFIG[providerId]?.modelFilter?.excludePatterns ?? [] + ); } diff --git a/src/resources/extensions/sf/record-promoter.js b/src/resources/extensions/sf/record-promoter.js index e89c98c6a..78389e747 100644 --- a/src/resources/extensions/sf/record-promoter.js +++ b/src/resources/extensions/sf/record-promoter.js @@ -14,8 +14,8 @@ import { writeFileSync, } from "node:fs"; import { basename, join } from "node:path"; -import { logWarning } from "./workflow-logger.js"; import { addBacklogItem, isDbAvailable } from "./sf-db.js"; +import { logWarning } from "./workflow-logger.js"; // ─── Frontmatter Parser ────────────────────────────────────────────────────── /** * Parse the YAML frontmatter from a markdown file. @@ -268,7 +268,12 @@ export function promoteActionableRecords(basePath) { // Write to DB backlog (primary) if (isDbAvailable()) { try { - addBacklogItem({ id: milestoneId, title: milestoneId, source: "record-promoter", status: "promoted" }); + addBacklogItem({ + id: milestoneId, + title: milestoneId, + source: "record-promoter", + status: "promoted", + }); } catch { // non-fatal } diff --git a/src/resources/extensions/sf/reports.js b/src/resources/extensions/sf/reports.js index 2806d813f..fc36e63aa 100644 --- a/src/resources/extensions/sf/reports.js +++ b/src/resources/extensions/sf/reports.js @@ -15,7 +15,10 @@ */ import { existsSync, mkdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; -import { formatDateShort, formatDuration } from "@singularity-forge/coding-agent"; +import { + formatDateShort, + formatDuration, +} from "@singularity-forge/coding-agent"; import { atomicWriteSync } from "./atomic-write.js"; import { formatCost, formatTokenCount } from "./metrics.js"; import { sfRoot } from "./paths.js"; diff --git a/src/resources/extensions/sf/requirement-promoter.js b/src/resources/extensions/sf/requirement-promoter.js index 73d5280ed..c9c44dcff 100644 --- a/src/resources/extensions/sf/requirement-promoter.js +++ b/src/resources/extensions/sf/requirement-promoter.js @@ -14,7 +14,11 @@ import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { markResolved, readAllSelfFeedback } from "./self-feedback.js"; -import { getActiveRequirements, isDbAvailable, upsertRequirement } from "./sf-db.js"; +import { + getActiveRequirements, + isDbAvailable, + upsertRequirement, +} from "./sf-db.js"; // ─── Constants ─────────────────────────────────────────────────────────────── const COUNT_THRESHOLD = 5; diff --git a/src/resources/extensions/sf/setup-catalog.js b/src/resources/extensions/sf/setup-catalog.js index ea863dc75..f1bb3f443 100644 --- a/src/resources/extensions/sf/setup-catalog.js +++ b/src/resources/extensions/sf/setup-catalog.js @@ -120,7 +120,13 @@ export function getLlmProviderIds() { } // Key-free and meta search provider IDs that are valid as preferences but have // no PROVIDER_REGISTRY entry (no env-var key required). -const KEYLESS_SEARCH_PROVIDER_IDS = ["minimax", "ollama", "combosearch", "native", "auto"]; +const KEYLESS_SEARCH_PROVIDER_IDS = [ + "minimax", + "ollama", + "combosearch", + "native", + "auto", +]; /** * All valid values for the `search_provider` preference. * Derived from PROVIDER_REGISTRY (key-backed) plus keyless/meta providers. diff --git a/src/resources/extensions/sf/sf-db.js b/src/resources/extensions/sf/sf-db.js index 4e1d7f407..2e116b4ec 100644 --- a/src/resources/extensions/sf/sf-db.js +++ b/src/resources/extensions/sf/sf-db.js @@ -39,8 +39,8 @@ import { taskFrontmatterFromRecord, withTaskFrontmatter, } from "./task-frontmatter.js"; -import { logError, logWarning } from "./workflow-logger.js"; import { readTraceEvents } from "./uok/trace-writer.js"; +import { logError, logWarning } from "./workflow-logger.js"; let loadAttempted = false; function loadProvider() { @@ -1443,9 +1443,7 @@ function columnExists(db, table, column) { } function tableExists(db, table) { const row = db - .prepare( - `SELECT name FROM sqlite_master WHERE type='table' AND name=?`, - ) + .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`) .get(table); return row != null; } @@ -3223,7 +3221,9 @@ function migrateSchema(db) { "failure_mode", "ALTER TABLE llm_task_outcomes ADD COLUMN failure_mode TEXT DEFAULT NULL", ); - db.exec("CREATE INDEX IF NOT EXISTS idx_llm_task_outcomes_failure_mode ON llm_task_outcomes(model_id, failure_mode, recorded_at DESC)"); + db.exec( + "CREATE INDEX IF NOT EXISTS idx_llm_task_outcomes_failure_mode ON llm_task_outcomes(model_id, failure_mode, recorded_at DESC)", + ); db.prepare( "INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)", ).run({ @@ -4242,8 +4242,13 @@ function hasTaskSpecIntent(planning = {}) { } function insertTaskSpecIfAbsent(milestoneId, sliceId, taskId, planning = {}) { if (!hasTaskSpecIntent(planning)) return; - const { normalized: frontmatter, errors } = taskFrontmatterFromRecord(planning); - if (errors?.length) logWarning("sf-db:insertTaskSpec", `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${errors.join(", ")}`); + const { normalized: frontmatter, errors } = + taskFrontmatterFromRecord(planning); + if (errors?.length) + logWarning( + "sf-db:insertTaskSpec", + `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${errors.join(", ")}`, + ); currentDb .prepare(`INSERT OR IGNORE INTO task_specs ( milestone_id, slice_id, task_id, verify, inputs, expected_output, @@ -4464,8 +4469,13 @@ export function setTaskBlockerDiscovered( export function upsertTaskPlanning(milestoneId, sliceId, taskId, planning) { if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); insertTaskSpecIfAbsent(milestoneId, sliceId, taskId, planning); - const { normalized: frontmatter, errors: fmErrors } = taskFrontmatterFromRecord(planning); - if (fmErrors?.length) logWarning("sf-db:upsertTaskPlanning", `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${fmErrors.join(", ")}`); + const { normalized: frontmatter, errors: fmErrors } = + taskFrontmatterFromRecord(planning); + if (fmErrors?.length) + logWarning( + "sf-db:upsertTaskPlanning", + `frontmatter validation errors for ${milestoneId}/${sliceId}/${taskId}: ${fmErrors.join(", ")}`, + ); const hasTaskStatus = planning.taskStatus !== undefined || planning.task_status !== undefined || @@ -6035,7 +6045,9 @@ export function recordUokRunExit(entry) { ":status": entry.status ?? "ok", ":started_at": entry.startedAt ?? now, ":ended_at": now, - ":error": entry.error ? capErrorForStorage(entry.error, entry.runId) : null, + ":error": entry.error + ? capErrorForStorage(entry.error, entry.runId) + : null, ":flags_json": JSON.stringify(entry.flags ?? {}), ":updated_at": now, }); @@ -6425,11 +6437,13 @@ export function getLlmTaskOutcomeStats(modelId, windowHours = 24) { */ export function getGateRunStats(gateId, windowHours = 24) { try { - const basePath = currentPath && currentPath !== ":memory:" - ? dirname(dirname(currentPath)) - : process.cwd(); - const events = readTraceEvents(basePath, "gate_run", windowHours) - .filter((e) => e.gateId === gateId); + const basePath = + currentPath && currentPath !== ":memory:" + ? dirname(dirname(currentPath)) + : process.cwd(); + const events = readTraceEvents(basePath, "gate_run", windowHours).filter( + (e) => e.gateId === gateId, + ); const stats = { total: events.length, pass: 0, @@ -6557,18 +6571,31 @@ export function updateGateCircuitBreaker(gateId, updates) { } export function getGateLatencyStats(gateId, windowHours = 24) { try { - const basePath = currentPath && currentPath !== ":memory:" - ? dirname(dirname(currentPath)) - : process.cwd(); + const basePath = + currentPath && currentPath !== ":memory:" + ? dirname(dirname(currentPath)) + : process.cwd(); const durations = readTraceEvents(basePath, "gate_run", windowHours) .filter((e) => e.gateId === gateId && typeof e.durationMs === "number") .map((e) => e.durationMs) .sort((a, b) => a - b); - if (durations.length === 0) return { p50: null, p95: null, count: 0, total: 0, avgMs: 0, p50Ms: 0, p95Ms: 0, maxMs: 0 }; + if (durations.length === 0) + return { + p50: null, + p95: null, + count: 0, + total: 0, + avgMs: 0, + p50Ms: 0, + p95Ms: 0, + maxMs: 0, + }; const p50Ms = durations[Math.floor(durations.length * 0.5)] ?? 0; const p95Ms = durations[Math.floor(durations.length * 0.95)] ?? 0; const maxMs = durations[durations.length - 1] ?? 0; - const avgMs = Math.round(durations.reduce((s, v) => s + v, 0) / durations.length); + const avgMs = Math.round( + durations.reduce((s, v) => s + v, 0) / durations.length, + ); return { p50: p50Ms, p95: p95Ms, @@ -6580,14 +6607,24 @@ export function getGateLatencyStats(gateId, windowHours = 24) { maxMs, }; } catch { - return { p50: null, p95: null, count: 0, total: 0, avgMs: 0, p50Ms: 0, p95Ms: 0, maxMs: 0 }; + return { + p50: null, + p95: null, + count: 0, + total: 0, + avgMs: 0, + p50Ms: 0, + p95Ms: 0, + maxMs: 0, + }; } } export function getDistinctGateIds() { try { - const basePath = currentPath && currentPath !== ":memory:" - ? dirname(dirname(currentPath)) - : process.cwd(); + const basePath = + currentPath && currentPath !== ":memory:" + ? dirname(dirname(currentPath)) + : process.cwd(); const events = readTraceEvents(basePath, "gate_run", 24 * 30); // 30 days return [...new Set(events.map((e) => e.gateId).filter(Boolean))]; } catch { @@ -7817,15 +7854,29 @@ export function bulkInsertLegacyHierarchy(payload) { export function getActiveMemories({ category, limit = 200 } = {}) { if (!currentDb) return []; const rows = category - ? currentDb.prepare("SELECT * FROM active_memories WHERE category = ? ORDER BY updated_at DESC LIMIT ?").all(category, limit) - : currentDb.prepare("SELECT * FROM active_memories ORDER BY updated_at DESC LIMIT ?").all(limit); + ? currentDb + .prepare( + "SELECT * FROM active_memories WHERE category = ? ORDER BY updated_at DESC LIMIT ?", + ) + .all(category, limit) + : currentDb + .prepare( + "SELECT * FROM active_memories ORDER BY updated_at DESC LIMIT ?", + ) + .all(limit); return rows.map((r) => ({ id: r["id"], category: r["category"], content: r["content"], confidence: r["confidence"], sourceUnitId: r["source_unit_id"], - tags: (() => { try { return JSON.parse(r["tags"] ?? "[]"); } catch { return []; } })(), + tags: (() => { + try { + return JSON.parse(r["tags"] ?? "[]"); + } catch { + return []; + } + })(), createdAt: r["created_at"], updatedAt: r["updated_at"], })); diff --git a/src/resources/extensions/sf/subagent-inheritance.js b/src/resources/extensions/sf/subagent-inheritance.js index 775d34653..55febf550 100644 --- a/src/resources/extensions/sf/subagent-inheritance.js +++ b/src/resources/extensions/sf/subagent-inheritance.js @@ -15,7 +15,10 @@ import { resolveRunControlMode, resolveWorkMode, } from "./operating-model.js"; -import { isHeavyModelId, isProviderAllowedByLists } from "./preferences-models.js"; +import { + isHeavyModelId, + isProviderAllowedByLists, +} from "./preferences-models.js"; import { logWarning } from "./workflow-logger.js"; function providerFromModelId(modelId) { @@ -24,7 +27,6 @@ function providerFromModelId(modelId) { return provider && provider !== modelId ? provider : null; } - /** * Build an inheritance envelope from the current parent session. * diff --git a/src/resources/extensions/sf/subagent/background-jobs.js b/src/resources/extensions/sf/subagent/background-jobs.js index e8759cb53..54b0d25fe 100644 --- a/src/resources/extensions/sf/subagent/background-jobs.js +++ b/src/resources/extensions/sf/subagent/background-jobs.js @@ -74,7 +74,8 @@ export class SubagentBackgroundJobManager { const job = this.jobs.get(id); if (!job) return "not_found"; if (job.status === "running") return "already_running"; - if (this.getRunningJobs().length >= this.maxRunning) return "concurrency_limit"; + if (this.getRunningJobs().length >= this.maxRunning) + return "concurrency_limit"; // Cancel pending eviction — job is active again const evTimer = this.evictionTimers.get(id); if (evTimer) { @@ -99,7 +100,12 @@ export class SubagentBackgroundJobManager { appendTurn(id, role, content) { const job = this.jobs.get(id); if (!job) return; - job.turns.push({ turnIndex: job.turns.length, role, content, timestamp: Date.now() }); + job.turns.push({ + turnIndex: job.turns.length, + role, + content, + timestamp: Date.now(), + }); } /** Return all turns for a job, optionally filtered to those after `since` (exclusive). */ getTurns(id, since = 0) { diff --git a/src/resources/extensions/sf/subagent/index.js b/src/resources/extensions/sf/subagent/index.js index 8a31f8180..fd40dc28b 100644 --- a/src/resources/extensions/sf/subagent/index.js +++ b/src/resources/extensions/sf/subagent/index.js @@ -22,6 +22,8 @@ import { StringEnum } from "@singularity-forge/ai"; import { getMarkdownTheme } from "@singularity-forge/coding-agent"; import { Container, Markdown, Spacer, Text } from "@singularity-forge/tui"; import { CmuxClient, shellEscape } from "../../cmux/index.js"; +import { formatTokenCount } from "../../shared/mod.js"; +import { getCurrentPhase } from "../../shared/sf-phase-state.js"; import { buildSiftEnv, ensureSiftRuntimeDirs, @@ -35,8 +37,6 @@ import { buildSubagentInheritanceEnvelope, validateSubagentDispatch, } from "../subagent-inheritance.js"; -import { formatTokenCount } from "../../shared/mod.js"; -import { getCurrentPhase } from "../../shared/sf-phase-state.js"; import { discoverAgents } from "./agents.js"; import { SubagentBackgroundJobManager } from "./background-jobs.js"; import { @@ -1779,7 +1779,9 @@ export default function (pi) { const manager = getBackgroundJobs(); // Build a rerun factory for write_subagent multi-turn follow-ups. // Only single-mode dispatches (params.agent + params.task) support write_subagent. - const isSingleMode = Boolean(params.agent && params.task && !params.tasks && !params.chain); + const isSingleMode = Boolean( + params.agent && params.task && !params.tasks && !params.chain, + ); const dispatchContext = isSingleMode ? { originalTask: params.task, @@ -1831,7 +1833,11 @@ export default function (pi) { } return result; }); - jobId = manager.register(summarizeBackgroundInvocation(params), wrappedRun, dispatchContext); + jobId = manager.register( + summarizeBackgroundInvocation(params), + wrappedRun, + dispatchContext, + ); return { content: [ { @@ -2738,7 +2744,8 @@ export default function (pi) { description: "Background subagent job ID (for example sub_a1b2c3d4)", }), message: Type.String({ - description: "Follow-up message or instruction to send to the subagent.", + description: + "Follow-up message or instruction to send to the subagent.", }), }), async execute(_toolCallId, params) { @@ -2746,7 +2753,12 @@ export default function (pi) { const job = manager.getJob(params.job_id); if (!job) { return { - content: [{ type: "text", text: `Background subagent job not found: ${params.job_id}` }], + content: [ + { + type: "text", + text: `Background subagent job not found: ${params.job_id}`, + }, + ], details: undefined, isError: true, }; @@ -2784,19 +2796,23 @@ export default function (pi) { let enrichedTask = job.dispatchContext.originalTask; if (historyTurns.length > 0) { const historyText = historyTurns - .map((t) => `[${t.role === "agent" ? "Agent" : "User"} — turn ${t.turnIndex}]\n${t.content}`) + .map( + (t) => + `[${t.role === "agent" ? "Agent" : "User"} — turn ${t.turnIndex}]\n${t.content}`, + ) .join("\n\n"); enrichedTask += `\n\n---\nConversation history:\n${historyText}\n---`; } enrichedTask += `\n\nUser follow-up: ${params.message}`; - const resumeResult = manager.resume( - params.job_id, - (signal) => job.dispatchContext.rerunWithTask(enrichedTask, signal).then((result) => { - // Append the new agent response as a turn before the notification fires - const text = getPrimaryTextContent(result); - if (text) manager.appendTurn(params.job_id, "agent", text); - return result; - }), + const resumeResult = manager.resume(params.job_id, (signal) => + job.dispatchContext + .rerunWithTask(enrichedTask, signal) + .then((result) => { + // Append the new agent response as a turn before the notification fires + const text = getPrimaryTextContent(result); + if (text) manager.appendTurn(params.job_id, "agent", text); + return result; + }), ); if (resumeResult !== "resumed") { const messages = { @@ -2805,7 +2821,12 @@ export default function (pi) { already_running: `Background subagent ${params.job_id} is already running.`, }; return { - content: [{ type: "text", text: messages[resumeResult] ?? `Resume failed: ${resumeResult}` }], + content: [ + { + type: "text", + text: messages[resumeResult] ?? `Resume failed: ${resumeResult}`, + }, + ], details: undefined, isError: true, }; @@ -2847,7 +2868,12 @@ export default function (pi) { const job = manager.getJob(params.job_id); if (!job) { return { - content: [{ type: "text", text: `Background subagent job not found: ${params.job_id}` }], + content: [ + { + type: "text", + text: `Background subagent job not found: ${params.job_id}`, + }, + ], details: undefined, isError: true, }; @@ -2855,7 +2881,8 @@ export default function (pi) { const since = params.since_turn ?? 0; const turns = manager.getTurns(params.job_id, since); if (!turns || turns.length === 0) { - const status = job.status === "running" ? " (still running)" : ` (${job.status})`; + const status = + job.status === "running" ? " (still running)" : ` (${job.status})`; return { content: [ { @@ -2872,7 +2899,8 @@ export default function (pi) { return `**${label} [turn ${t.turnIndex}]**\n${t.content}`; }) .join("\n\n---\n\n"); - const statusLine = job.status === "running" ? " *(running)*" : ` *(${job.status})*`; + const statusLine = + job.status === "running" ? " *(running)*" : ` *(${job.status})*`; return { content: [ { diff --git a/src/resources/extensions/sf/summary-helpers.js b/src/resources/extensions/sf/summary-helpers.js index aca5e7675..9fdebb105 100644 --- a/src/resources/extensions/sf/summary-helpers.js +++ b/src/resources/extensions/sf/summary-helpers.js @@ -201,7 +201,9 @@ function escapeRegExpLocal(value) { } function extractMarkdownSectionLocal(content, heading) { - const match = new RegExp(`^## ${escapeRegExpLocal(heading)}\\s*$`, "m").exec(content); + const match = new RegExp(`^## ${escapeRegExpLocal(heading)}\\s*$`, "m").exec( + content, + ); if (!match) return null; const start = match.index + match[0].length; const rest = content.slice(start); @@ -228,11 +230,20 @@ export function extractSliceExecutionExcerpt(content, relPath) { const goalLine = lines.find((line) => line.startsWith("**Goal:**"))?.trim(); const demoLine = lines.find((line) => line.startsWith("**Demo:**"))?.trim(); const verification = extractMarkdownSectionLocal(content, "Verification"); - const observability = extractMarkdownSectionLocal(content, "Observability / Diagnostics"); + const observability = extractMarkdownSectionLocal( + content, + "Observability / Diagnostics", + ); const parts = ["## Slice Plan Excerpt", `Source: \`${relPath}\``]; if (goalLine) parts.push(goalLine); if (demoLine) parts.push(demoLine); - if (verification) parts.push("", "### Slice Verification", verification.trim()); - if (observability) parts.push("", "### Slice Observability / Diagnostics", observability.trim()); + if (verification) + parts.push("", "### Slice Verification", verification.trim()); + if (observability) + parts.push( + "", + "### Slice Observability / Diagnostics", + observability.trim(), + ); return parts.join("\n"); } diff --git a/src/resources/extensions/sf/tests/auto-dispatch-canonical-plan.test.mjs b/src/resources/extensions/sf/tests/auto-dispatch-canonical-plan.test.mjs index ff8bd771f..f625023c8 100644 --- a/src/resources/extensions/sf/tests/auto-dispatch-canonical-plan.test.mjs +++ b/src/resources/extensions/sf/tests/auto-dispatch-canonical-plan.test.mjs @@ -41,13 +41,13 @@ vi.mock("../auto-prompts.js", () => ({ checkNeedsRunUat: vi.fn(async () => null), })); -import { resolveDispatch } from "../uok/auto-dispatch.js"; import { closeDatabase, insertMilestone, insertSlice, openDatabase, } from "../sf-db.js"; +import { resolveDispatch } from "../uok/auto-dispatch.js"; function makeTempDir(prefix) { return mkdtempSync(join(tmpdir(), prefix)); diff --git a/src/resources/extensions/sf/tests/doctor-providers.test.mjs b/src/resources/extensions/sf/tests/doctor-providers.test.mjs index 5dcb8f15c..d2ac85d43 100644 --- a/src/resources/extensions/sf/tests/doctor-providers.test.mjs +++ b/src/resources/extensions/sf/tests/doctor-providers.test.mjs @@ -92,12 +92,9 @@ describe("doctor provider checks", () => { test("runProviderChecks_when_google_env_auth_is_default_off_treats_google_as_missing_required_route", () => { makePreferencesProject( - [ - "version: 1", - "models:", - " planning: google/gemini-2.5-pro", - "", - ].join("\n"), + ["version: 1", "models:", " planning: google/gemini-2.5-pro", ""].join( + "\n", + ), ); process.env.GEMINI_API_KEY = "test-google-key"; @@ -109,12 +106,9 @@ describe("doctor provider checks", () => { test("runProviderChecks_when_google_env_auth_is_enabled_accepts_google_env_key", () => { const project = makePreferencesProject( - [ - "version: 1", - "models:", - " planning: google/gemini-2.5-pro", - "", - ].join("\n"), + ["version: 1", "models:", " planning: google/gemini-2.5-pro", ""].join( + "\n", + ), ); mkdirSync(join(project, ".sf"), { recursive: true }); writeFileSync( diff --git a/src/resources/extensions/sf/tests/memory-embeddings-llm-gateway.test.mjs b/src/resources/extensions/sf/tests/memory-embeddings-llm-gateway.test.mjs index bd5ac774b..4c1496ba4 100644 --- a/src/resources/extensions/sf/tests/memory-embeddings-llm-gateway.test.mjs +++ b/src/resources/extensions/sf/tests/memory-embeddings-llm-gateway.test.mjs @@ -43,7 +43,11 @@ test("loadGatewayConfigFromEnv returns null when auth.json does not exist", () = }); test("loadGatewayConfigFromEnv reads key and url from auth.json", () => { - writeAuthJson({ key: "auth-key", url: "https://example.test/v1", type: "api_key" }); + writeAuthJson({ + key: "auth-key", + url: "https://example.test/v1", + type: "api_key", + }); const cfg = loadGatewayConfigFromEnv(); assert.equal(cfg.apiKey, "auth-key"); @@ -71,4 +75,3 @@ test("loadGatewayConfigFromEnv respects model env var overrides", () => { assert.equal(cfg.embeddingModel, "custom-embed"); assert.equal(cfg.rerankModel, "custom-rerank"); }); - diff --git a/src/resources/extensions/sf/tests/preferences-models.test.mjs b/src/resources/extensions/sf/tests/preferences-models.test.mjs index 7a3e922db..2cee5e096 100644 --- a/src/resources/extensions/sf/tests/preferences-models.test.mjs +++ b/src/resources/extensions/sf/tests/preferences-models.test.mjs @@ -46,13 +46,9 @@ function makePreferencesProject(projectPreferences, projectSettings) { describe("preferences model resolution", () => { test("resolveModelWithFallbacksForUnit_when_google_env_auth_is_default_off_skips_google_auto_benchmark_candidates", () => { makePreferencesProject( - [ - "version: 1", - "allowed_providers:", - " - google", - "models: {}", - "", - ].join("\n"), + ["version: 1", "allowed_providers:", " - google", "models: {}", ""].join( + "\n", + ), ); process.env.GEMINI_API_KEY = "test-google-key"; @@ -60,5 +56,4 @@ describe("preferences model resolution", () => { assert.equal(result, undefined); }); - }); diff --git a/src/resources/extensions/sf/tests/remote-steering-pipeline.test.mjs b/src/resources/extensions/sf/tests/remote-steering-pipeline.test.mjs index 2778e8240..284d7e427 100644 --- a/src/resources/extensions/sf/tests/remote-steering-pipeline.test.mjs +++ b/src/resources/extensions/sf/tests/remote-steering-pipeline.test.mjs @@ -72,7 +72,10 @@ describe("parse stage", () => { }); assert.strictEqual(result.steering, true); assert.strictEqual(result.directives.length, 1); - assert.deepStrictEqual(result.directives[0], { cmd: "mode", value: "build" }); + assert.deepStrictEqual(result.directives[0], { + cmd: "mode", + value: "build", + }); }); test("parseRemoteSteeringDirectives_when_text_has_all_axes_returns_all_four_directives", () => { @@ -131,7 +134,10 @@ describe("apply stage", () => { test("applyRemoteSteeringDirectives_when_control_directive_applies_changes_runControl", () => { const src = uniqueSrc(); - applyRemoteSteeringDirectives([{ cmd: "control", value: "autonomous" }], src); + applyRemoteSteeringDirectives( + [{ cmd: "control", value: "autonomous" }], + src, + ); assert.strictEqual(_modeState.runControl, "autonomous"); }); @@ -209,7 +215,10 @@ describe("format stage", () => { ]; const text = formatRemoteSteeringResults(results); assert.ok(text.includes("[ok] /mode build"), `missing ok mode: ${text}`); - assert.ok(text.includes("[ok] /control autonomous"), `missing ok control: ${text}`); + assert.ok( + text.includes("[ok] /control autonomous"), + `missing ok control: ${text}`, + ); }); test("formatRemoteSteeringResults_when_blocked_renders_blocked_marker_and_error", () => { @@ -217,7 +226,10 @@ describe("format stage", () => { { cmd: "mode", value: "review", applied: false, error: "Throttled" }, ]; const text = formatRemoteSteeringResults(results); - assert.ok(text.includes("[blocked] /mode review"), `missing blocked: ${text}`); + assert.ok( + text.includes("[blocked] /mode review"), + `missing blocked: ${text}`, + ); assert.ok(text.includes("Throttled"), `missing error text: ${text}`); }); @@ -259,7 +271,10 @@ describe("full pipeline: parse → apply → format", () => { assert.strictEqual(parsed.directives.length, 4); const applied = applyRemoteSteeringDirectives(parsed.directives, src); - assert.ok(applied.every((r) => r.applied), `Some failed: ${JSON.stringify(applied)}`); + assert.ok( + applied.every((r) => r.applied), + `Some failed: ${JSON.stringify(applied)}`, + ); assert.strictEqual(_modeState.workMode, "build"); assert.strictEqual(_modeState.runControl, "autonomous"); @@ -279,7 +294,10 @@ describe("full pipeline: parse → apply → format", () => { const formatted = formatRemoteSteeringResults(applied2); assert.strictEqual(applied2[0].applied, false); - assert.ok(formatted.includes("[blocked]"), `expected blocked: ${formatted}`); + assert.ok( + formatted.includes("[blocked]"), + `expected blocked: ${formatted}`, + ); // Mode should not have changed assert.strictEqual(_modeState.workMode, "build"); }); diff --git a/src/resources/extensions/sf/tests/schedule-dispatch.test.mjs b/src/resources/extensions/sf/tests/schedule-dispatch.test.mjs index ab47188c7..ebfc8b6d9 100644 --- a/src/resources/extensions/sf/tests/schedule-dispatch.test.mjs +++ b/src/resources/extensions/sf/tests/schedule-dispatch.test.mjs @@ -14,9 +14,9 @@ import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, it } from "vitest"; -import { DISPATCH_RULES } from "../uok/auto-dispatch.js"; import { createScheduleStore } from "../schedule/schedule-store.js"; import { generateULID } from "../schedule/schedule-ulid.js"; +import { DISPATCH_RULES } from "../uok/auto-dispatch.js"; describe("schedule-dispatch", () => { let testDir; diff --git a/src/resources/extensions/sf/tests/sf-db-migration.test.mjs b/src/resources/extensions/sf/tests/sf-db-migration.test.mjs index 16557e82d..ac9effcbd 100644 --- a/src/resources/extensions/sf/tests/sf-db-migration.test.mjs +++ b/src/resources/extensions/sf/tests/sf-db-migration.test.mjs @@ -229,7 +229,10 @@ test("openDatabase_migrates_v27_tasks_without_created_at_through_spec_backfill", "SELECT name FROM sqlite_master WHERE type='table' AND name='intent_chapters'", ) .get(); - assert.ok(chaptersTable, "intent_chapters table should exist after v61 migration"); + assert.ok( + chaptersTable, + "intent_chapters table should exist after v61 migration", + ); const taskSpec = db .prepare( "SELECT milestone_id, slice_id, task_id, verify FROM task_specs WHERE task_id = 'T01'", @@ -292,9 +295,15 @@ test("openDatabase_when_fresh_db_does_not_create_gate_runs_table", () => { // After v58 migration, gate_runs table no longer exists const tableInfo = getDatabase() - .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='gate_runs'") + .prepare( + "SELECT name FROM sqlite_master WHERE type='table' AND name='gate_runs'", + ) .get(); - assert.equal(tableInfo, undefined, "gate_runs table should not exist after v58 migration"); + assert.equal( + tableInfo, + undefined, + "gate_runs table should not exist after v58 migration", + ); }); test("reconcileWorktreeDb_when_worktree_lacks_product_research_column_merges_milestones", () => { @@ -342,9 +351,15 @@ test("openDatabase_migrates_v35_gate_cost_usd_drops_table_in_v58", () => { const db = getDatabase(); // After v58 migration, gate_runs is dropped const tableInfo = db - .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='gate_runs'") + .prepare( + "SELECT name FROM sqlite_master WHERE type='table' AND name='gate_runs'", + ) .get(); - assert.equal(tableInfo, undefined, "gate_runs should be dropped by v58 migration"); + assert.equal( + tableInfo, + undefined, + "gate_runs should be dropped by v58 migration", + ); }); test("openDatabase_memories_table_has_tags_column", () => { diff --git a/src/resources/extensions/sf/tests/sift-retrieval-evidence.test.mjs b/src/resources/extensions/sf/tests/sift-retrieval-evidence.test.mjs index 35b433007..543ac04da 100644 --- a/src/resources/extensions/sf/tests/sift-retrieval-evidence.test.mjs +++ b/src/resources/extensions/sf/tests/sift-retrieval-evidence.test.mjs @@ -15,9 +15,9 @@ import { import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, test } from "vitest"; -import registerSubagentExtension from "../subagent/index.js"; import { registerQueryTools } from "../bootstrap/query-tools.js"; import { closeDatabase, getRetrievalEvidence, openDatabase } from "../sf-db.js"; +import registerSubagentExtension from "../subagent/index.js"; import { registerSiftSearchTool } from "../tools/sift-search-tool.js"; const tmpRoots = []; diff --git a/src/resources/extensions/sf/tests/summary-helpers.test.mjs b/src/resources/extensions/sf/tests/summary-helpers.test.mjs index 7e704fcf9..0d768ff90 100644 --- a/src/resources/extensions/sf/tests/summary-helpers.test.mjs +++ b/src/resources/extensions/sf/tests/summary-helpers.test.mjs @@ -1,8 +1,6 @@ import assert from "node:assert/strict"; import { test } from "vitest"; -import { - extractSliceExecutionExcerpt, -} from "../summary-helpers.js"; +import { extractSliceExecutionExcerpt } from "../summary-helpers.js"; test("extractSliceExecutionExcerpt when content is null returns fallback", () => { const result = extractSliceExecutionExcerpt(null, "S01/PLAN.md"); @@ -59,11 +57,7 @@ test("extractSliceExecutionExcerpt extracts verification section", () => { }); test("extractSliceExecutionExcerpt omits missing sections gracefully", () => { - const content = [ - "# Slice Plan", - "", - "**Goal:** Minimal slice", - ].join("\n"); + const content = ["# Slice Plan", "", "**Goal:** Minimal slice"].join("\n"); const result = extractSliceExecutionExcerpt(content, "S01/PLAN.md"); assert.ok(result.includes("**Goal:** Minimal slice")); diff --git a/src/resources/extensions/sf/tests/uok-metrics-exposition.test.mjs b/src/resources/extensions/sf/tests/uok-metrics-exposition.test.mjs index fdaefcd1d..9e31fdb11 100644 --- a/src/resources/extensions/sf/tests/uok-metrics-exposition.test.mjs +++ b/src/resources/extensions/sf/tests/uok-metrics-exposition.test.mjs @@ -10,11 +10,7 @@ import { mkdirSync, mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, test } from "vitest"; -import { - closeDatabase, - insertUokMessage, - openDatabase, -} from "../sf-db.js"; +import { closeDatabase, insertUokMessage, openDatabase } from "../sf-db.js"; import { invalidateMetricsCache, readUokMetrics, @@ -45,7 +41,11 @@ function makeProject() { return dir; } -function recordGateRun(basePath, outcome, evaluatedAt = new Date().toISOString()) { +function recordGateRun( + basePath, + outcome, + evaluatedAt = new Date().toISOString(), +) { appendTraceEvent(basePath, `trace-${outcome}-${Date.now()}`, { type: "gate_run", traceId: `trace-${outcome}`, diff --git a/src/resources/extensions/sf/triage-self-feedback.js b/src/resources/extensions/sf/triage-self-feedback.js index 017c4888c..d8f0a3d2d 100644 --- a/src/resources/extensions/sf/triage-self-feedback.js +++ b/src/resources/extensions/sf/triage-self-feedback.js @@ -37,11 +37,16 @@ function readRequirementsContent(basePath) { if (isDbAvailable()) { const rows = getActiveRequirements(); if (rows.length > 0) { - return rows.map((r) => `- [${r.id}] ${r.title}: ${r.description ?? ""}`).join("\n"); + return rows + .map((r) => `- [${r.id}] ${r.title}: ${r.description ?? ""}`) + .join("\n"); } } const sfDir = sfRoot(basePath); - for (const p of [join(sfDir, "REQUIREMENTS.md"), join(sfDir, "requirements.md")]) { + for (const p of [ + join(sfDir, "REQUIREMENTS.md"), + join(sfDir, "requirements.md"), + ]) { if (existsSync(p)) return readFileSync(p, "utf-8"); } return "(no requirements found)"; diff --git a/src/resources/extensions/sf/ui/index.js b/src/resources/extensions/sf/ui/index.js index 6f77c5ba8..e6fd927d2 100644 --- a/src/resources/extensions/sf/ui/index.js +++ b/src/resources/extensions/sf/ui/index.js @@ -15,10 +15,7 @@ import { Key } from "@singularity-forge/tui"; import { getAutoSession } from "../auto/session.js"; import { isAutoActive } from "../auto.js"; import { projectRoot } from "../commands/context.js"; -import { - getExperimentalFlag, - setExperimentalFlag, -} from "../experimental.js"; +import { getExperimentalFlag, setExperimentalFlag } from "../experimental.js"; import { registerSessionColor } from "./color-band.js"; import { registerSessionEmoji } from "./emoji.js"; import { renderAutoFooter, renderFooter } from "./footer.js"; diff --git a/src/resources/extensions/sf/uok-parity-summary.js b/src/resources/extensions/sf/uok-parity-summary.js index 7da17eba6..c2c4b6982 100644 --- a/src/resources/extensions/sf/uok-parity-summary.js +++ b/src/resources/extensions/sf/uok-parity-summary.js @@ -1,10 +1,10 @@ import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; +import { NOTICE_KIND } from "./notification-store.js"; import { hasCurrentParityWarning, writeParityReport, } from "./uok/parity-report.js"; -import { NOTICE_KIND } from "./notification-store.js"; /** * Read the last UOK parity report from /.sf/runtime/uok-parity-report.json * and surface any divergences or errors via ctx.ui?.notify?.(). diff --git a/src/resources/extensions/sf/uok/a2a-agent-server.js b/src/resources/extensions/sf/uok/a2a-agent-server.js index 746e6845a..0a7fbff2a 100644 --- a/src/resources/extensions/sf/uok/a2a-agent-server.js +++ b/src/resources/extensions/sf/uok/a2a-agent-server.js @@ -18,17 +18,14 @@ import { randomUUID } from "node:crypto"; import { createServer } from "node:http"; -import express from "express"; -import { - DefaultRequestHandler, - InMemoryTaskStore, -} from "@a2a-js/sdk/server"; +import { AGENT_CARD_PATH } from "@a2a-js/sdk"; +import { DefaultRequestHandler, InMemoryTaskStore } from "@a2a-js/sdk/server"; import { agentCardHandler, jsonRpcHandler, UserBuilder, } from "@a2a-js/sdk/server/express"; -import { AGENT_CARD_PATH } from "@a2a-js/sdk"; +import express from "express"; import { buildAgentCard } from "./a2a-transport.js"; const agentName = process.env.SF_A2A_AGENT_NAME; @@ -37,9 +34,7 @@ const port = Number(process.env.SF_A2A_PORT ?? 34501); const basePath = process.env.SF_A2A_BASE_PATH ?? process.cwd(); if (!agentName) { - process.stderr.write( - "a2a-agent-server: SF_A2A_AGENT_NAME is required\n", - ); + process.stderr.write("a2a-agent-server: SF_A2A_AGENT_NAME is required\n"); process.exit(1); } @@ -161,7 +156,12 @@ class SwarmAgentExecutor { transport: "a2a", }; - const messageId = bus.send(from, to, envelope.payload ?? envelope, metadata); + const messageId = bus.send( + from, + to, + envelope.payload ?? envelope, + metadata, + ); return { status: "accepted", @@ -214,7 +214,9 @@ async function main() { }); // Signal readiness to the parent process. - process.stdout.write(JSON.stringify({ ready: true, port, agentName, role: agentRole }) + "\n"); + process.stdout.write( + JSON.stringify({ ready: true, port, agentName, role: agentRole }) + "\n", + ); process.on("SIGTERM", () => { process.exit(0); diff --git a/src/resources/extensions/sf/uok/a2a-transport.js b/src/resources/extensions/sf/uok/a2a-transport.js index 8729664e8..7b96af2fb 100644 --- a/src/resources/extensions/sf/uok/a2a-transport.js +++ b/src/resources/extensions/sf/uok/a2a-transport.js @@ -9,9 +9,9 @@ * Consumer: SwarmDispatchLayer._a2aDispatch() when SF_A2A_ENABLED is set. */ -import { randomUUID } from "node:crypto"; import { spawn } from "node:child_process"; -import { join, dirname, resolve } from "node:path"; +import { randomUUID } from "node:crypto"; +import { dirname, join, resolve } from "node:path"; const A2A_AGENT_SERVER_PATH = new URL("./a2a-agent-server.js", import.meta.url) .pathname; @@ -180,7 +180,9 @@ export class A2ATransport { child.on("error", (err) => { clearTimeout(timeout); reject( - new Error(`A2ATransport: failed to spawn agent ${agentName}: ${err.message}`), + new Error( + `A2ATransport: failed to spawn agent ${agentName}: ${err.message}`, + ), ); }); diff --git a/src/resources/extensions/sf/uok/auto-dispatch.js b/src/resources/extensions/sf/uok/auto-dispatch.js index e681305b1..bf7e8cf31 100644 --- a/src/resources/extensions/sf/uok/auto-dispatch.js +++ b/src/resources/extensions/sf/uok/auto-dispatch.js @@ -92,11 +92,14 @@ import { upsertValidationAttentionMarker, } from "../sf-db.js"; import { isClosedStatus, isInactiveStatus } from "../status-guards.js"; -import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js"; +import { extractVerdict, isAcceptableUatVerdict } from "../verdict-parser.js"; import { - buildDispatchEnvelope, - explainDispatch, -} from "./dispatch-envelope.js"; + checkNeedsReassessment, + checkNeedsRunUat, +} from "../workflow-helpers.js"; +import { logError, logWarning } from "../workflow-logger.js"; +import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js"; +import { buildDispatchEnvelope, explainDispatch } from "./dispatch-envelope.js"; import { selectReactiveDispatchBatch } from "./execution-graph.js"; import { resolveUokFlags } from "./flags.js"; import { UokGateRunner } from "./gate-runner.js"; @@ -105,12 +108,6 @@ import { decideUnitRuntimeDispatch, readUnitRuntimeRecord, } from "./unit-runtime.js"; -import { extractVerdict, isAcceptableUatVerdict } from "../verdict-parser.js"; -import { - checkNeedsReassessment, - checkNeedsRunUat, -} from "../workflow-helpers.js"; -import { logError, logWarning } from "../workflow-logger.js"; const MAX_PARALLEL_RESEARCH_SLICES = 8; const PARALLEL_RESEARCH_BLOCKING_PHASES = new Set([ diff --git a/src/resources/extensions/sf/uok/auto-runaway-guard.js b/src/resources/extensions/sf/uok/auto-runaway-guard.js index 1dc06a184..93179b4f8 100644 --- a/src/resources/extensions/sf/uok/auto-runaway-guard.js +++ b/src/resources/extensions/sf/uok/auto-runaway-guard.js @@ -17,10 +17,7 @@ export const DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS = 2; export const DEFAULT_RUNAWAY_MIN_INTERVAL_MS = 120_000; const EXECUTE_NO_PROGRESS_TOOL_WARNING = 25; const EXECUTE_NO_PROGRESS_TOKEN_WARNING = 500_000; -const DURABLE_SF_ARTIFACT_PATHS = [ - ".sf/milestones", - ".sf/approvals", -]; +const DURABLE_SF_ARTIFACT_PATHS = [".sf/milestones", ".sf/approvals"]; let state = null; export function resetRunawayGuardState(unitType, unitId, baseline) { state = { diff --git a/src/resources/extensions/sf/uok/auto-unit-closeout.js b/src/resources/extensions/sf/uok/auto-unit-closeout.js index 19f9fc48d..7954b0558 100644 --- a/src/resources/extensions/sf/uok/auto-unit-closeout.js +++ b/src/resources/extensions/sf/uok/auto-unit-closeout.js @@ -6,8 +6,8 @@ import { saveActivityLog } from "../activity-log.js"; import { snapshotUnitMetrics } from "../metrics.js"; import { updateSubscriptionTokensUsed } from "../preferences-models.js"; -import { writeTurnGitTransaction } from "./gitops.js"; import { logWarning } from "../workflow-logger.js"; +import { writeTurnGitTransaction } from "./gitops.js"; /** * Snapshot metrics, save activity log, and fire-and-forget memory extraction * for a completed unit. Returns the activity log file path (if any). diff --git a/src/resources/extensions/sf/uok/auto-verification.js b/src/resources/extensions/sf/uok/auto-verification.js index 52a0f11b1..0b9b5c0dc 100644 --- a/src/resources/extensions/sf/uok/auto-verification.js +++ b/src/resources/extensions/sf/uok/auto-verification.js @@ -25,6 +25,15 @@ import { import { isMilestoneComplete } from "../state.js"; import { isClosedStatus } from "../status-guards.js"; import { parseUnitId } from "../unit-id.js"; +import { extractVerdict } from "../verdict-parser.js"; +import { writeVerificationJSON } from "../verification-evidence.js"; +import { + captureRuntimeErrors, + formatFailureContext, + runDependencyAudit, + runVerificationGate, +} from "../verification-gate.js"; +import { logError, logWarning } from "../workflow-logger.js"; import { ChaosMonkeyGate } from "./chaos-monkey.js"; import { CostGuardGate } from "./cost-guard-gate.js"; import { resolveUokFlags } from "./flags.js"; @@ -36,15 +45,6 @@ import { formatExecuteTaskRecoveryStatus, inspectExecuteTaskDurability, } from "./unit-runtime.js"; -import { extractVerdict } from "../verdict-parser.js"; -import { writeVerificationJSON } from "../verification-evidence.js"; -import { - captureRuntimeErrors, - formatFailureContext, - runDependencyAudit, - runVerificationGate, -} from "../verification-gate.js"; -import { logError, logWarning } from "../workflow-logger.js"; function computeTokenCountFromSession(ctx) { const entries = ctx.sessionManager?.getEntries?.() ?? []; diff --git a/src/resources/extensions/sf/uok/index.js b/src/resources/extensions/sf/uok/index.js index 9c3d7c8a1..1f6af1d8d 100644 --- a/src/resources/extensions/sf/uok/index.js +++ b/src/resources/extensions/sf/uok/index.js @@ -36,6 +36,40 @@ export { isAuditEnvelopeEnabled, setAuditEnvelopeEnabled, } from "./audit-toggle.js"; +// ─── Autonomous Dispatch ─────────────────────────────────────────────────── +export { + DISPATCH_RULES, + enhanceUnitRankingWithMemory, + extractValidationAttentionPlan, + formatTaskCompleteFailurePrompt, + getDispatchRuleNames, + getRewriteCount, + getUatCount, + incrementUatCount, + isVerificationNotApplicable, + resolveDispatch, + setRewriteCount, +} from "./auto-dispatch.js"; +// ─── Runaway Guard ──────────────────────────────────────────────────────── +export { + clearRunawayGuardState, + collectSessionTokenUsage, + collectWorktreeFingerprint, + countChangedFiles, + DEFAULT_RUNAWAY_CHANGED_FILES_WARNING, + DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS, + DEFAULT_RUNAWAY_ELAPSED_MINUTES, + DEFAULT_RUNAWAY_MIN_INTERVAL_MS, + DEFAULT_RUNAWAY_TOKEN_WARNING, + DEFAULT_RUNAWAY_TOOL_CALL_WARNING, + evaluateRunawayGuard, + resetRunawayGuardState, + resolveRunawayGuardConfig, +} from "./auto-runaway-guard.js"; +// ─── Unit Closeout ──────────────────────────────────────────────────────── +export { closeoutUnit } from "./auto-unit-closeout.js"; +// ─── Post-Unit Verification ──────────────────────────────────────────────── +export { runPostUnitVerification } from "./auto-verification.js"; // ─── Gates ───────────────────────────────────────────────────────────────── export { ChaosMonkey, ChaosMonkeyGate } from "./chaos-monkey.js"; // ─── Model Policy ────────────────────────────────────────────────────────── @@ -222,37 +256,3 @@ export { nextWriteRecord, releaseWriterToken, } from "./writer.js"; -// ─── Autonomous Dispatch ─────────────────────────────────────────────────── -export { -DISPATCH_RULES, -enhanceUnitRankingWithMemory, -extractValidationAttentionPlan, -formatTaskCompleteFailurePrompt, -getDispatchRuleNames, -getRewriteCount, -getUatCount, -incrementUatCount, -isVerificationNotApplicable, -resolveDispatch, -setRewriteCount, -} from "./auto-dispatch.js"; -// ─── Runaway Guard ──────────────────────────────────────────────────────── -export { -clearRunawayGuardState, -collectSessionTokenUsage, -collectWorktreeFingerprint, -countChangedFiles, -DEFAULT_RUNAWAY_CHANGED_FILES_WARNING, -DEFAULT_RUNAWAY_DIAGNOSTIC_TURNS, -DEFAULT_RUNAWAY_ELAPSED_MINUTES, -DEFAULT_RUNAWAY_MIN_INTERVAL_MS, -DEFAULT_RUNAWAY_TOOL_CALL_WARNING, -DEFAULT_RUNAWAY_TOKEN_WARNING, -evaluateRunawayGuard, -resetRunawayGuardState, -resolveRunawayGuardConfig, -} from "./auto-runaway-guard.js"; -// ─── Unit Closeout ──────────────────────────────────────────────────────── -export { closeoutUnit } from "./auto-unit-closeout.js"; -// ─── Post-Unit Verification ──────────────────────────────────────────────── -export { runPostUnitVerification } from "./auto-verification.js"; diff --git a/src/resources/extensions/sf/uok/kernel.ts b/src/resources/extensions/sf/uok/kernel.ts index 111b5d02d..4d004ba99 100644 --- a/src/resources/extensions/sf/uok/kernel.ts +++ b/src/resources/extensions/sf/uok/kernel.ts @@ -12,15 +12,15 @@ import { randomUUID } from "node:crypto"; import { debugLog } from "../debug-logger.js"; import { -defaultPermissionProfileForRunControl, -resolvePermissionProfile, -resolveRunControlMode, -runControlModeForSession, + defaultPermissionProfileForRunControl, + resolvePermissionProfile, + resolveRunControlMode, + runControlModeForSession, } from "../operating-model.js"; import { -isDbAvailable, -recordUokRunExit, -recordUokRunStart, + isDbAvailable, + recordUokRunExit, + recordUokRunStart, } from "../sf-db.js"; import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js"; import { setAuditEnvelopeEnabled } from "./audit-toggle.js"; @@ -28,14 +28,14 @@ import { writeUokDiagnostics } from "./diagnostic-synthesis.js"; import { resolveUokFlags } from "./flags.js"; import { createTurnObserver } from "./loop-adapter.js"; import { -checkAndDrainMissingExit, -resetParityCommitBlock, -signalKernelEnter, + checkAndDrainMissingExit, + resetParityCommitBlock, + signalKernelEnter, } from "./parity-diff-capture.js"; import { -hasCurrentParityWarning, -writeParityHeartbeat, -writeParityReport, + hasCurrentParityWarning, + writeParityHeartbeat, + writeParityReport, } from "./parity-report.js"; // --------------------------------------------------------------------------- @@ -44,88 +44,92 @@ writeParityReport, /** Flags resolved from user preferences for this UOK run. */ interface UokFlags { -auditEnvelope?: boolean; -gitops?: boolean; -gitopsTurnAction?: string; -gitopsTurnPush?: boolean; -chaosMonkey?: boolean; -enabled?: boolean; -[key: string]: unknown; + auditEnvelope?: boolean; + gitops?: boolean; + gitopsTurnAction?: string; + gitopsTurnPush?: boolean; + chaosMonkey?: boolean; + enabled?: boolean; + [key: string]: unknown; } /** Lifecycle flags written to the DB run ledger and parity heartbeat. */ interface LifecycleFlags extends UokFlags { -runControl?: string; -permissionProfile?: string; -workMode?: string; -modelMode?: string; + runControl?: string; + permissionProfile?: string; + workMode?: string; + modelMode?: string; } export interface UokKernelTerminationArgs { -basePath: string; -runId?: string; -sessionId?: string | null; -flags?: UokFlags; -runControl?: string; -permissionProfile?: string; -/** Exit status — "ok" | "error" | "signal". Defaults to "signal". */ -status?: string; -error?: string; + basePath: string; + runId?: string; + sessionId?: string | null; + flags?: UokFlags; + runControl?: string; + permissionProfile?: string; + /** Exit status — "ok" | "error" | "signal". Defaults to "signal". */ + status?: string; + error?: string; } /** Arguments for {@link runAutoLoopWithUok}. */ export interface RunAutoLoopWithUokArgs { -/** Coding-agent context (opaque; provides sessionManager). */ -ctx: { -sessionManager?: { -getSessionId?: () => string | undefined; -}; -[key: string]: unknown; -}; -/** Pi/provider interface (opaque). */ -pi: unknown; -/** Mutable session state. */ -s: { -basePath: string; -workMode?: string; -modelMode?: string; -autoStartTime?: number; -currentUokRunId?: string; -[key: string]: unknown; -}; -/** Injected dependency bag. */ -deps: { -loadEffectiveSFPreferences?: () => { preferences?: Record } | null; -[key: string]: unknown; -}; -runControl?: string; -permissionProfile?: string; -/** The inner autonomous loop to execute inside the UOK wrapper. */ -runKernelLoop: ( -ctx: RunAutoLoopWithUokArgs["ctx"], -pi: unknown, -s: RunAutoLoopWithUokArgs["s"], -deps: Record, -) => Promise; + /** Coding-agent context (opaque; provides sessionManager). */ + ctx: { + sessionManager?: { + getSessionId?: () => string | undefined; + }; + [key: string]: unknown; + }; + /** Pi/provider interface (opaque). */ + pi: unknown; + /** Mutable session state. */ + s: { + basePath: string; + workMode?: string; + modelMode?: string; + autoStartTime?: number; + currentUokRunId?: string; + [key: string]: unknown; + }; + /** Injected dependency bag. */ + deps: { + loadEffectiveSFPreferences?: () => { + preferences?: Record; + } | null; + [key: string]: unknown; + }; + runControl?: string; + permissionProfile?: string; + /** The inner autonomous loop to execute inside the UOK wrapper. */ + runKernelLoop: ( + ctx: RunAutoLoopWithUokArgs["ctx"], + pi: unknown, + s: RunAutoLoopWithUokArgs["s"], + deps: Record, + ) => Promise; } // --------------------------------------------------------------------------- // Internals // --------------------------------------------------------------------------- -function refreshParityReport(basePath: string): ReturnType | null { -try { -return writeParityReport(basePath); -} catch (err) { -debugLog("uok-parity-report-write-failed", { -error: err instanceof Error ? err.message : String(err), -}); -return null; -} +function refreshParityReport( + basePath: string, +): ReturnType | null { + try { + return writeParityReport(basePath); + } catch (err) { + debugLog("uok-parity-report-write-failed", { + error: err instanceof Error ? err.message : String(err), + }); + return null; + } } function resolveKernelPathLabel(): string { -return "uok-kernel"; + return "uok-kernel"; } // --------------------------------------------------------------------------- @@ -142,53 +146,53 @@ return "uok-kernel"; * Consumer: auto signal cleanup and UOK parity tests. */ export function recordUokKernelTermination({ -basePath, -runId, -sessionId, -flags, -runControl, -permissionProfile, -status = "signal", -error, + basePath, + runId, + sessionId, + flags, + runControl, + permissionProfile, + status = "signal", + error, }: UokKernelTerminationArgs): ReturnType | null { -const endedAt = new Date().toISOString(); -const lifecycleFlags: LifecycleFlags = { -...(flags ?? {}), -...(runControl ? { runControl } : {}), -...(permissionProfile ? { permissionProfile } : {}), -}; -if (runId && isDbAvailable()) { -recordUokRunExit({ -runId, -sessionId, -path: resolveKernelPathLabel(), -flags: lifecycleFlags, -status, -endedAt, -...(error ? { error } : {}), -}); -} -writeParityHeartbeat(basePath, { -ts: endedAt, -...(runId ? { runId } : {}), -sessionId, -path: resolveKernelPathLabel(), -flags: lifecycleFlags, -...(runControl ? { runControl } : {}), -...(permissionProfile ? { permissionProfile } : {}), -phase: "exit", -status, -...(error ? { error } : {}), -}); -const report = refreshParityReport(basePath); -try { -writeUokDiagnostics(basePath); -} catch (err) { -debugLog("uok-diagnostics-write-failed", { -error: err instanceof Error ? err.message : String(err), -}); -} -return report; + const endedAt = new Date().toISOString(); + const lifecycleFlags: LifecycleFlags = { + ...(flags ?? {}), + ...(runControl ? { runControl } : {}), + ...(permissionProfile ? { permissionProfile } : {}), + }; + if (runId && isDbAvailable()) { + recordUokRunExit({ + runId, + sessionId, + path: resolveKernelPathLabel(), + flags: lifecycleFlags, + status, + endedAt, + ...(error ? { error } : {}), + }); + } + writeParityHeartbeat(basePath, { + ts: endedAt, + ...(runId ? { runId } : {}), + sessionId, + path: resolveKernelPathLabel(), + flags: lifecycleFlags, + ...(runControl ? { runControl } : {}), + ...(permissionProfile ? { permissionProfile } : {}), + phase: "exit", + status, + ...(error ? { error } : {}), + }); + const report = refreshParityReport(basePath); + try { + writeUokDiagnostics(basePath); + } catch (err) { + debugLog("uok-diagnostics-write-failed", { + error: err instanceof Error ? err.message : String(err), + }); + } + return report; } /** @@ -200,122 +204,127 @@ return report; * * Consumer: auto/dispatch.ts — called once per autonomous session activation. */ -export async function runAutoLoopWithUok(args: RunAutoLoopWithUokArgs): Promise { -const { ctx, pi, s, deps, runKernelLoop } = args; -const prefs = deps.loadEffectiveSFPreferences?.()?.preferences as Record | undefined; -const flags: UokFlags = { ...resolveUokFlags(prefs), enabled: true }; -const runControl: string = resolveRunControlMode( -args.runControl ?? runControlModeForSession(s), -); -const permissionProfile: string = resolvePermissionProfile( -args.permissionProfile ?? -(prefs?.uok as Record | undefined)?.permission_profile ?? -defaultPermissionProfileForRunControl(runControl), -); -// Include workMode and modelMode from session in lifecycle flags -const workMode: string = (s.workMode as string | undefined) ?? "chat"; -const modelMode: string = (s.modelMode as string | undefined) ?? "smart"; -const lifecycleFlags: LifecycleFlags = { -...flags, -runControl, -permissionProfile, -workMode, -modelMode, -}; +export async function runAutoLoopWithUok( + args: RunAutoLoopWithUokArgs, +): Promise { + const { ctx, pi, s, deps, runKernelLoop } = args; + const prefs = deps.loadEffectiveSFPreferences?.()?.preferences as + | Record + | undefined; + const flags: UokFlags = { ...resolveUokFlags(prefs), enabled: true }; + const runControl: string = resolveRunControlMode( + args.runControl ?? runControlModeForSession(s), + ); + const permissionProfile: string = resolvePermissionProfile( + args.permissionProfile ?? + (prefs?.uok as Record | undefined)?.permission_profile ?? + defaultPermissionProfileForRunControl(runControl), + ); + // Include workMode and modelMode from session in lifecycle flags + const workMode: string = (s.workMode as string | undefined) ?? "chat"; + const modelMode: string = (s.modelMode as string | undefined) ?? "smart"; + const lifecycleFlags: LifecycleFlags = { + ...flags, + runControl, + permissionProfile, + workMode, + modelMode, + }; -const healthVerdict = writeUokDiagnostics(s.basePath); -debugLog("uok-system-health-verdict", healthVerdict); + const healthVerdict = writeUokDiagnostics(s.basePath); + debugLog("uok-system-health-verdict", healthVerdict); -const previousReport = refreshParityReport(s.basePath); -const runId = `uok-${randomUUID()}`; -s.currentUokRunId = runId; -resetParityCommitBlock(); -if ( -previousReport && -(previousReport as { missingExitEvents?: number }).missingExitEvents != null && -(previousReport as { missingExitEvents: number }).missingExitEvents > 0 && -hasCurrentParityWarning(previousReport) -) { -checkAndDrainMissingExit( -(previousReport as { enterEvents: number }).enterEvents, -(previousReport as { exitEvents: number }).exitEvents, -); -} -setAuditEnvelopeEnabled(flags.auditEnvelope ?? false); -signalKernelEnter(); -const startedAt = new Date().toISOString(); -const sessionId = ctx.sessionManager?.getSessionId?.(); -if (isDbAvailable()) { -recordUokRunStart({ -runId, -sessionId, -path: resolveKernelPathLabel(), -flags: lifecycleFlags, -startedAt, -}); -} -writeParityHeartbeat(s.basePath, { -ts: startedAt, -runId, -sessionId, -path: resolveKernelPathLabel(), -flags: lifecycleFlags, -runControl, -permissionProfile, -phase: "enter", -}); -if (flags.auditEnvelope) { -emitUokAuditEvent( -s.basePath, -buildAuditEnvelope({ -traceId: `session:${String(s.autoStartTime || Date.now())}`, -category: "orchestration", -type: "uok-kernel-enter", -payload: { -flags: lifecycleFlags, -runControl, -permissionProfile, -workMode, -modelMode, -sessionId, -}, -}), -); -} -const decoratedDeps = { -...deps, -uokObserver: createTurnObserver({ -basePath: s.basePath, -gitAction: flags.gitopsTurnAction, -gitPush: flags.gitopsTurnPush, -enableAudit: flags.auditEnvelope, -enableGitops: flags.gitops, -enableChaosMonkey: flags.chaosMonkey, -runControl, -permissionProfile, -}), -uokRunControl: runControl, -uokPermissionProfile: permissionProfile, -}; -let status = "ok"; -let error: string | undefined; -try { -await runKernelLoop(ctx, pi, s, decoratedDeps); -} catch (err) { -status = "error"; -error = err instanceof Error ? err.message : String(err); -throw err; -} finally { -recordUokKernelTermination({ -basePath: s.basePath, -runId, -sessionId, -flags: lifecycleFlags, -runControl, -permissionProfile, -status, -...(error ? { error } : {}), -}); -if (s.currentUokRunId === runId) s.currentUokRunId = undefined; -} + const previousReport = refreshParityReport(s.basePath); + const runId = `uok-${randomUUID()}`; + s.currentUokRunId = runId; + resetParityCommitBlock(); + if ( + previousReport && + (previousReport as { missingExitEvents?: number }).missingExitEvents != + null && + (previousReport as { missingExitEvents: number }).missingExitEvents > 0 && + hasCurrentParityWarning(previousReport) + ) { + checkAndDrainMissingExit( + (previousReport as { enterEvents: number }).enterEvents, + (previousReport as { exitEvents: number }).exitEvents, + ); + } + setAuditEnvelopeEnabled(flags.auditEnvelope ?? false); + signalKernelEnter(); + const startedAt = new Date().toISOString(); + const sessionId = ctx.sessionManager?.getSessionId?.(); + if (isDbAvailable()) { + recordUokRunStart({ + runId, + sessionId, + path: resolveKernelPathLabel(), + flags: lifecycleFlags, + startedAt, + }); + } + writeParityHeartbeat(s.basePath, { + ts: startedAt, + runId, + sessionId, + path: resolveKernelPathLabel(), + flags: lifecycleFlags, + runControl, + permissionProfile, + phase: "enter", + }); + if (flags.auditEnvelope) { + emitUokAuditEvent( + s.basePath, + buildAuditEnvelope({ + traceId: `session:${String(s.autoStartTime || Date.now())}`, + category: "orchestration", + type: "uok-kernel-enter", + payload: { + flags: lifecycleFlags, + runControl, + permissionProfile, + workMode, + modelMode, + sessionId, + }, + }), + ); + } + const decoratedDeps = { + ...deps, + uokObserver: createTurnObserver({ + basePath: s.basePath, + gitAction: flags.gitopsTurnAction, + gitPush: flags.gitopsTurnPush, + enableAudit: flags.auditEnvelope, + enableGitops: flags.gitops, + enableChaosMonkey: flags.chaosMonkey, + runControl, + permissionProfile, + }), + uokRunControl: runControl, + uokPermissionProfile: permissionProfile, + }; + let status = "ok"; + let error: string | undefined; + try { + await runKernelLoop(ctx, pi, s, decoratedDeps); + } catch (err) { + status = "error"; + error = err instanceof Error ? err.message : String(err); + throw err; + } finally { + recordUokKernelTermination({ + basePath: s.basePath, + runId, + sessionId, + flags: lifecycleFlags, + runControl, + permissionProfile, + status, + ...(error ? { error } : {}), + }); + if (s.currentUokRunId === runId) s.currentUokRunId = undefined; + } } diff --git a/src/resources/extensions/sf/uok/trace-writer.js b/src/resources/extensions/sf/uok/trace-writer.js index 0ff139ad6..6c746a2da 100644 --- a/src/resources/extensions/sf/uok/trace-writer.js +++ b/src/resources/extensions/sf/uok/trace-writer.js @@ -64,15 +64,12 @@ export function readTraceEvents(basePath, type, windowHours = 24) { try { const filePath = join(dir, file); if (statSync(filePath).mtimeMs < cutoff) continue; - const lines = readFileSync(filePath, "utf-8") - .split("\n") - .filter(Boolean); + const lines = readFileSync(filePath, "utf-8").split("\n").filter(Boolean); for (const line of lines) { try { const ev = JSON.parse(line); if (!type || ev.type === type) { - if (!ev.ts || new Date(ev.ts).getTime() >= cutoff) - results.push(ev); + if (!ev.ts || new Date(ev.ts).getTime() >= cutoff) results.push(ev); } } catch { /* skip malformed lines */ diff --git a/src/resources/extensions/sf/worktree-resolver.js b/src/resources/extensions/sf/worktree-resolver.js index ce31badad..3cc0798e8 100644 --- a/src/resources/extensions/sf/worktree-resolver.js +++ b/src/resources/extensions/sf/worktree-resolver.js @@ -58,10 +58,7 @@ export class WorktreeResolver { rebuildGitService() { const gitConfig = this.deps.loadEffectiveSFPreferences()?.preferences?.git ?? {}; - this.s.gitService = new this.deps.GitService( - this.s.basePath, - gitConfig, - ); + this.s.gitService = new this.deps.GitService(this.s.basePath, gitConfig); } /** Restore basePath to originalBasePath and rebuild GitService. */ restoreToProjectRoot() { diff --git a/src/resources/extensions/shared/mod.js b/src/resources/extensions/shared/mod.js index c2495ca51..38388363e 100644 --- a/src/resources/extensions/shared/mod.js +++ b/src/resources/extensions/shared/mod.js @@ -7,8 +7,8 @@ export { normalizeStringArray, sparkline, stripAnsi, - truncateWithEllipsis, toPosixPath, + truncateWithEllipsis, } from "@singularity-forge/coding-agent"; export { parseFrontmatterMap, splitFrontmatter } from "./frontmatter.js"; export { diff --git a/src/resources/extensions/shared/path-display.js b/src/resources/extensions/shared/path-display.js new file mode 100644 index 000000000..92aa80e21 --- /dev/null +++ b/src/resources/extensions/shared/path-display.js @@ -0,0 +1,8 @@ +/** + * Compatibility shim — re-exports toPosixPath from @singularity-forge/coding-agent. + * + * The canonical implementation lives in packages/coding-agent/src/utils/path-display.ts. + * This file exists so the ~4 consumers that import "../shared/path-display.js" directly + * continue to work without changes. + */ +export { toPosixPath } from "@singularity-forge/coding-agent"; diff --git a/src/tests/app-smoke.test.ts b/src/tests/app-smoke.test.ts index 6154d2873..2c0ff4227 100644 --- a/src/tests/app-smoke.test.ts +++ b/src/tests/app-smoke.test.ts @@ -193,12 +193,7 @@ test("loader sets all 4 SF_ env vars and PI_PACKAGE_DIR", async (_t) => { const rel = p.slice(bundledExtensionsDir.length + 1); return rel.split(/[\\/]/)[0].replace(/\.(?:ts|js)$/, ""); }); - for (const core of [ - "sf", - "bg-shell", - "browser-tools", - "search-the-web", - ]) { + for (const core of ["sf", "bg-shell", "browser-tools", "search-the-web"]) { assert.ok( discoveredNames.includes(core), `core extension '${core}' is discoverable`, diff --git a/src/tests/mcp-client-oauth.test.ts b/src/tests/mcp-client-oauth.test.ts index ac5e9b5bb..2412d531b 100644 --- a/src/tests/mcp-client-oauth.test.ts +++ b/src/tests/mcp-client-oauth.test.ts @@ -12,8 +12,8 @@ */ import assert from "node:assert/strict"; -import { test } from "vitest"; import { buildHttpTransportOpts } from "@singularity-forge/coding-agent"; +import { test } from "vitest"; // ── Transport construction (SDK sanity checks) ─────────────────────────────── diff --git a/src/tests/native-search.test.ts b/src/tests/native-search.test.ts index 7cd45fb48..244197da4 100644 --- a/src/tests/native-search.test.ts +++ b/src/tests/native-search.test.ts @@ -1,11 +1,11 @@ import assert from "node:assert/strict"; -import { afterEach, test } from "vitest"; import { CUSTOM_SEARCH_TOOL_NAMES, MAX_NATIVE_SEARCHES_PER_SESSION, stripThinkingFromHistory, webSearchMiddleware, } from "@singularity-forge/coding-agent"; +import { afterEach, test } from "vitest"; import { BRAVE_TOOL_NAMES, registerNativeSearchHooks, @@ -99,7 +99,9 @@ test("applyToPayload injects web_search for Anthropic provider", async () => { tools: [{ name: "bash", type: "custom" }], }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "anthropic" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "anthropic", + }); const tools = (result as any)?.tools ?? payload.tools; const nativeTool = (tools as any[]).find( @@ -170,7 +172,9 @@ test("applyToPayload does NOT inject for claude model when provider is non-Anthr tools: [{ name: "bash", type: "custom" }], }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "copilot" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "copilot", + }); assert.equal( result, @@ -200,7 +204,9 @@ test("applyToPayload does NOT inject when provider is github-copilot", async () tools: [{ name: "bash", type: "custom" }], }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "github-copilot" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "github-copilot", + }); assert.equal( result, @@ -228,7 +234,9 @@ test("applyToPayload DOES inject when provider is anthropic", async () => { tools: [{ name: "bash", type: "custom" }], }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "anthropic" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "anthropic", + }); const tools = ((result as any)?.tools ?? payload.tools) as any[]; assert.ok( @@ -246,7 +254,9 @@ test("applyToPayload does not double-inject", async () => { tools: [{ type: "web_search_20250305", name: "web_search" }], }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "anthropic" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "anthropic", + }); assert.equal(result, undefined, "Should not modify when already injected"); const tools = payload.tools as any[]; @@ -261,7 +271,9 @@ test("applyToPayload creates tools array if missing", async () => { model: "claude-haiku-4-5-20251001", }; - const result = webSearchMiddleware.applyToPayload(payload, { provider: "anthropic" }); + const result = webSearchMiddleware.applyToPayload(payload, { + provider: "anthropic", + }); const tools = (result as any)?.tools ?? payload.tools; assert.ok(Array.isArray(tools), "Should create tools array"); diff --git a/tsconfig.extensions.json b/tsconfig.extensions.json index 4236ca0e9..0960890f5 100644 --- a/tsconfig.extensions.json +++ b/tsconfig.extensions.json @@ -15,9 +15,7 @@ ], "@singularity-forge/ai": ["./packages/ai/src/index.ts"], "@singularity-forge/ai/*": ["./packages/ai/src/*.ts"], - "@singularity-forge/agent-core": [ - "./packages/agent-core/src/index.ts" - ], + "@singularity-forge/agent-core": ["./packages/agent-core/src/index.ts"], "@singularity-forge/tui": ["./packages/tui/src/index.ts"], "@singularity-forge/native": ["./packages/native/src/index.ts"], "@singularity-forge/native/*": ["./packages/rust-engine/src/*/index.ts"], diff --git a/vitest.config.ts b/vitest.config.ts index 81036e14a..c90cfa21f 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -62,10 +62,7 @@ export default defineConfig({ __dirname, "packages/ai/src/bedrock-provider.ts", ), - "@singularity-forge/ai": resolve( - __dirname, - "packages/ai/src/index.ts", - ), + "@singularity-forge/ai": resolve(__dirname, "packages/ai/src/index.ts"), "@singularity-forge/agent-core": resolve( __dirname, "packages/agent-core/src/index.ts", @@ -74,10 +71,7 @@ export default defineConfig({ __dirname, "packages/tui/src/fuzzy.ts", ), - "@singularity-forge/tui": resolve( - __dirname, - "packages/tui/src/index.ts", - ), + "@singularity-forge/tui": resolve(__dirname, "packages/tui/src/index.ts"), "@singularity-forge/native/ast": resolve( __dirname, "packages/native/src/ast/index.ts", diff --git a/web/components/sf/app-shell.tsx b/web/components/sf/app-shell.tsx index 2a1049b84..cd0e1c031 100644 --- a/web/components/sf/app-shell.tsx +++ b/web/components/sf/app-shell.tsx @@ -15,6 +15,7 @@ import { ChatMode } from "@/components/sf/chat-mode"; import { CommandSurface } from "@/components/sf/command-surface"; import { Dashboard } from "@/components/sf/dashboard"; import { DualTerminal } from "@/components/sf/dual-terminal"; +import { ErrorBoundary } from "@/components/sf/error-boundary"; import { FilesView } from "@/components/sf/files-view"; import { FocusedPanel } from "@/components/sf/focused-panel"; import { OnboardingGate } from "@/components/sf/onboarding-gate"; @@ -33,7 +34,6 @@ import { import { StatusBar } from "@/components/sf/status-bar"; import { UpdateBanner } from "@/components/sf/update-banner"; import { VisualizerView } from "@/components/sf/visualizer-view"; -import { ErrorBoundary } from "@/components/sf/error-boundary"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { getAuthToken } from "@/lib/auth"; diff --git a/web/components/sf/chat-mode.tsx b/web/components/sf/chat-mode.tsx index 2c14868a2..09beb0003 100644 --- a/web/components/sf/chat-mode.tsx +++ b/web/components/sf/chat-mode.tsx @@ -496,47 +496,48 @@ let chatHighlighterPromise: Promise | null = null; function getChatHighlighter(): Promise { if (!chatHighlighterPromise) { chatHighlighterPromise = import("shiki") - .then((mod) => - mod.createHighlighter({ - themes: ["github-dark-default", "github-light-default"], - langs: [ - "typescript", - "tsx", - "javascript", - "jsx", - "json", - "jsonc", - "markdown", - "mdx", - "css", - "scss", - "less", - "html", - "xml", - "yaml", - "toml", - "bash", - "python", - "ruby", - "rust", - "go", - "java", - "kotlin", - "swift", - "c", - "cpp", - "csharp", - "php", - "sql", - "graphql", - "dockerfile", - "makefile", - "lua", - "diff", - "ini", - "dotenv", - ], - }) as Promise, + .then( + (mod) => + mod.createHighlighter({ + themes: ["github-dark-default", "github-light-default"], + langs: [ + "typescript", + "tsx", + "javascript", + "jsx", + "json", + "jsonc", + "markdown", + "mdx", + "css", + "scss", + "less", + "html", + "xml", + "yaml", + "toml", + "bash", + "python", + "ruby", + "rust", + "go", + "java", + "kotlin", + "swift", + "c", + "cpp", + "csharp", + "php", + "sql", + "graphql", + "dockerfile", + "makefile", + "lua", + "diff", + "ini", + "dotenv", + ], + }) as Promise, ) .catch((err) => { chatHighlighterPromise = null; diff --git a/web/components/sf/file-content-viewer.tsx b/web/components/sf/file-content-viewer.tsx index 000b54ae0..787704eab 100644 --- a/web/components/sf/file-content-viewer.tsx +++ b/web/components/sf/file-content-viewer.tsx @@ -123,47 +123,48 @@ let highlighterPromise: Promise | null = null; async function getHighlighter(): Promise { if (!highlighterPromise) { highlighterPromise = import("shiki") - .then((mod) => - mod.createHighlighter({ - themes: ["github-dark-default", "github-light-default"], - langs: [ - "typescript", - "tsx", - "javascript", - "jsx", - "json", - "jsonc", - "markdown", - "mdx", - "css", - "scss", - "less", - "html", - "xml", - "yaml", - "toml", - "bash", - "python", - "ruby", - "rust", - "go", - "java", - "kotlin", - "swift", - "c", - "cpp", - "csharp", - "php", - "sql", - "graphql", - "dockerfile", - "makefile", - "lua", - "diff", - "ini", - "dotenv", - ], - }) as Promise, + .then( + (mod) => + mod.createHighlighter({ + themes: ["github-dark-default", "github-light-default"], + langs: [ + "typescript", + "tsx", + "javascript", + "jsx", + "json", + "jsonc", + "markdown", + "mdx", + "css", + "scss", + "less", + "html", + "xml", + "yaml", + "toml", + "bash", + "python", + "ruby", + "rust", + "go", + "java", + "kotlin", + "swift", + "c", + "cpp", + "csharp", + "php", + "sql", + "graphql", + "dockerfile", + "makefile", + "lua", + "diff", + "ini", + "dotenv", + ], + }) as Promise, ) .catch((err) => { // Reset so the next call retries instead of returning a rejected promise forever diff --git a/web/components/ui/chart.tsx b/web/components/ui/chart.tsx index ede39246a..101a73ec8 100644 --- a/web/components/ui/chart.tsx +++ b/web/components/ui/chart.tsx @@ -253,7 +253,10 @@ function ChartLegendContent({ verticalAlign = "bottom", nameKey, }: React.ComponentProps<"div"> & - Pick & { + Pick< + RechartsPrimitive.DefaultLegendContentProps, + "payload" | "verticalAlign" + > & { hideIcon?: boolean; nameKey?: string; }) { diff --git a/web/components/ui/resizable.tsx b/web/components/ui/resizable.tsx index 9374fa957..a1009ced6 100644 --- a/web/components/ui/resizable.tsx +++ b/web/components/ui/resizable.tsx @@ -1,7 +1,7 @@ "use client"; import { GripVerticalIcon } from "lucide-react"; -import * as React from "react"; +import type * as React from "react"; import { Group, Panel, Separator } from "react-resizable-panels"; import { cn } from "@/lib/utils"; @@ -22,9 +22,7 @@ function ResizablePanelGroup({ ); } -function ResizablePanel({ - ...props -}: React.ComponentProps) { +function ResizablePanel({ ...props }: React.ComponentProps) { return ; } diff --git a/web/lib/__tests__/onboarding-logic.test.ts b/web/lib/__tests__/onboarding-logic.test.ts index 27aaf6e96..41f4694c0 100644 --- a/web/lib/__tests__/onboarding-logic.test.ts +++ b/web/lib/__tests__/onboarding-logic.test.ts @@ -163,12 +163,17 @@ describe("resolveOnboardingLockReason", () => { describe("redactSensitiveText", () => { test("redact_whenApiKeyInText_replacesWithPlaceholder", () => { const result = redactSensitiveText("key: sk-abcdef1234567890"); - assert.ok(!result.includes("sk-abcdef"), `expected redaction, got: ${result}`); + assert.ok( + !result.includes("sk-abcdef"), + `expected redaction, got: ${result}`, + ); assert.ok(result.includes("[redacted]")); }); test("redact_whenBearerToken_replacesWithPlaceholder", () => { - const result = redactSensitiveText("Authorization: Bearer eyJhbGciOiJSUzI1NiJ9"); + const result = redactSensitiveText( + "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9", + ); assert.ok(result.includes("Bearer [redacted]"), `got: ${result}`); }); @@ -186,14 +191,14 @@ describe("redactSensitiveText", () => { describe("extractErrorDetail", () => { test("extractErrorDetail_whenString_returnsItself", () => { - assert.equal(extractErrorDetail("something went wrong"), "something went wrong"); + assert.equal( + extractErrorDetail("something went wrong"), + "something went wrong", + ); }); test("extractErrorDetail_whenObjectWithMessage_returnsMessage", () => { - assert.equal( - extractErrorDetail({ message: "auth failed" }), - "auth failed", - ); + assert.equal(extractErrorDetail({ message: "auth failed" }), "auth failed"); }); test("extractErrorDetail_whenObjectWithError_returnsError", () => { diff --git a/web/lib/workflow-actions.ts b/web/lib/workflow-actions.ts index 955863916..4118adff3 100644 --- a/web/lib/workflow-actions.ts +++ b/web/lib/workflow-actions.ts @@ -96,7 +96,11 @@ export function deriveWorkflowAction( // Auto is not active if (phase === "complete") { // All milestones done — surface a distinct "New Milestone" action - primary = { label: "New Milestone", command: "/new-milestone", variant: "default" }; + primary = { + label: "New Milestone", + command: "/new-milestone", + variant: "default", + }; isNewMilestone = true; } else if (phase === "planning") { primary = { label: "Plan", command: "/discuss", variant: "default" };