From 852bf8c5aa1980961a4f15a4e57c67378245015e Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Mon, 11 May 2026 01:01:03 +0200 Subject: [PATCH] sf snapshot: uncommitted changes after 78m inactivity --- .sf/backups/db/maintenance.json | 2 +- .sf/backups/db/sf.db.2026-05-10T23-00-57-817Z | Bin 0 -> 1134592 bytes ARCHITECTURE.md | 53 +++- .../tests/stream-adapter-permissions.test.ts | 190 ++++++++++++++ src/resources/extensions/sf/auto-prompts.js | 53 +++- src/resources/extensions/sf/auto/phases.js | 97 ++++++- .../extensions/sf/bootstrap/db-tools.js | 139 ++++++++++ src/resources/extensions/sf/commands-agent.js | 241 ++++++++++++++++++ .../extensions/sf/commands-maintenance.js | 16 ++ .../extensions/sf/commands/catalog.js | 6 +- .../extensions/sf/commands/handlers/ops.js | 9 + .../extensions/sf/extension-manifest.json | 5 +- .../extensions/sf/prompts/execute-task.md | 2 + src/resources/extensions/sf/sf-db.js | 222 +++++++++++++++- .../sf/tests/sf-db-migration.test.mjs | 9 +- src/resources/extensions/sf/undo.js | 13 + src/resources/extensions/sf/uok/flags.js | 1 + .../extensions/shared/rtk-session-stats.js | 2 +- todo.md | 8 +- 19 files changed, 1040 insertions(+), 28 deletions(-) create mode 100644 .sf/backups/db/sf.db.2026-05-10T23-00-57-817Z create mode 100644 src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts create mode 100644 src/resources/extensions/sf/commands-agent.js diff --git a/.sf/backups/db/maintenance.json b/.sf/backups/db/maintenance.json index 4d2c3a222..f29279f22 100644 --- a/.sf/backups/db/maintenance.json +++ b/.sf/backups/db/maintenance.json @@ -1,3 +1,3 @@ { - "lastFullVacuumAt": "2026-05-10T13:59:26.619Z" + "lastFullVacuumAt": "2026-05-10T23:00:57.885Z" } diff --git a/.sf/backups/db/sf.db.2026-05-10T23-00-57-817Z b/.sf/backups/db/sf.db.2026-05-10T23-00-57-817Z new file mode 100644 index 0000000000000000000000000000000000000000..fa86839c29fdc47a21798ef041d792548f7b1985 GIT binary patch literal 1134592 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%0D~?$D`Qz{u+f)t`07h3x<}m9zV| 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 literal 0 HcmV?d00001 diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 35c169a6b..dfeb834a3 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -73,14 +73,53 @@ All file writes in autonomous mode pass through a gate. Protected files (CLAUDE. UOK orchestrates work through a deterministic five-phase state machine: +```mermaid +stateDiagram-v2 + direction LR + + [*] --> PhaseDiscuss : sf start / milestone begin + + PhaseDiscuss --> PhasePlan : discussion-close gate passes + PhaseDiscuss --> PhaseDiscuss : gate fails → gather more context + + PhasePlan --> PhaseExecute : planning-approval gate passes + PhasePlan --> PhasePlan : gate fails → replan or add remediation slice + + PhaseExecute --> PhaseMerge : all tasks complete, code-quality + test gates pass + PhaseExecute --> PhaseExecute : task fails → isolate + recovery slice dispatched + PhaseExecute --> PhaseExecute : stuck-loop detected → timeout / skip recovery + + PhaseMerge --> PhaseComplete : integration gate passes + PhaseMerge --> PhaseExecute : integration failure → add fix slice, retry + + PhaseComplete --> [*] : acceptance gate passes, summary written + PhaseComplete --> PhaseExecute : remediation milestone added + + note right of PhaseExecute + Task lifecycle (ORCH-style): + todo → running → verifying → reviewing + → done | blocked | paused | failed + | cancelled | retrying + end note ``` -PhaseDiscuss → PhasePlan → PhaseExecute → PhaseMerge → PhaseComplete - ↓ ↓ ↓ ↓ ↓ - (discuss) (plan) (execute) (merge) (finalize) - ↓ ↓ ↓ ↓ ↓ - gates gates gates gates validation - ↓ ↓ ↓ ↓ ↓ - (continue or remediate) + +```mermaid +stateDiagram-v2 + direction LR + + [*] --> queued : task_scheduler INSERT + queued --> due : poll tick reaches due_at + due --> claimed : atomic UPDATE (conditional, one worker wins) + claimed --> dispatched : worker picks up claim + dispatched --> consumed : unit completes (any terminal status) + dispatched --> expired : lease timeout, no heartbeat + expired --> queued : lease cleared, re-enqueued + + note right of claimed + Lease prevents two workers + dispatching the same unit + (shared-NFS / parallel mode). + end note ``` **Phase details:** 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 new file mode 100644 index 000000000..38b20e12c --- /dev/null +++ b/src/resources/extensions/claude-code-cli/tests/stream-adapter-permissions.test.ts @@ -0,0 +1,190 @@ +/** + * stream-adapter-permissions.test.ts — Permission handler tests for claude-code-cli. + * + * Covers: + * - buildBashPermissionPattern (unit) + * - createClaudeCodeCanUseToolHandler always-allow paths: + * - Bash tool: suggestions present vs absent + * - Non-Bash tool: empty suggestions fallback (persists toolName-scoped rule) + * - Non-Bash tool: non-empty suggestions (pass-through) + * + * Behaviour contracts: + * - always-allow for non-Bash tool with no suggestions must return updatedPermissions + * so the SDK can persist the choice (fix: non-Bash always-allow silent failure) + * - always-allow for Bash must include ruleContent derived from the command pattern + */ + +import { describe, expect, it, vi } from "vitest"; +import { + buildBashPermissionPattern, + createClaudeCodeCanUseToolHandler, +} from "../stream-adapter.js"; + +// ─── buildBashPermissionPattern unit tests ──────────────────────────────── + +describe("buildBashPermissionPattern", () => { + it("simple_command_returns_wildcard_pattern", () => { + expect(buildBashPermissionPattern("ls -la")).toBe("Bash(ls:*)"); + }); + + it("git_command_includes_subcommand", () => { + expect(buildBashPermissionPattern("git push origin main")).toBe( + "Bash(git push:*)", + ); + }); + + it("gh_command_includes_two_subcommand_levels", () => { + expect(buildBashPermissionPattern("gh pr list")).toBe( + "Bash(gh pr list:*)", + ); + }); + + it("compound_command_extracts_meaningful_operation", () => { + // cd is passthrough; meaningful operation is gh pr create + const result = buildBashPermissionPattern("cd /repo && gh pr create"); + expect(result).toBe("Bash(gh pr create:*)"); + }); +}); + +// ─── Helpers ────────────────────────────────────────────────────────────── + +function makeSignal(aborted = false): AbortSignal { + const ctrl = new AbortController(); + if (aborted) ctrl.abort(); + return ctrl.signal; +} + +function makeUi(selectChoices: string[]) { + let callIndex = 0; + return { + select: vi.fn(async () => selectChoices[callIndex++]), + notify: vi.fn(), + }; +} + +function makeOptions(overrides: Record = {}) { + return { + toolUseID: "tu-001", + signal: makeSignal(), + suggestions: undefined as unknown, + title: undefined as unknown, + description: undefined as unknown, + ...overrides, + }; +} + +// ─── createClaudeCodeCanUseToolHandler ──────────────────────────────────── + +describe("createClaudeCodeCanUseToolHandler", () => { + it("returns_undefined_when_no_ui", () => { + expect(createClaudeCodeCanUseToolHandler(undefined)).toBeUndefined(); + }); + + it("allow_once_returns_allow_without_updatedPermissions", async () => { + const ui = makeUi(["Allow"]); + const handler = createClaudeCodeCanUseToolHandler(ui)!; + const result = await handler( + "AskUserQuestion", + { questions: ["Name?"] }, + makeOptions() as never, + ); + expect(result.behavior).toBe("allow"); + 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, + ); + expect(result.behavior).toBe("deny"); + }); + + it("always_allow_non_bash_empty_suggestions_returns_toolname_rule", async () => { + // Core contract: non-Bash "Always Allow" with no SDK suggestions must + // produce updatedPermissions so the choice persists. Without this fix, + // the handler returned behavior:"allow" with no updatedPermissions, and + // the SDK silently forgot the choice on the next call. + const ui = makeUi(["Always Allow"]); + const handler = createClaudeCodeCanUseToolHandler(ui)!; + const result = await handler( + "AskUserQuestion", + { questions: ["Name?"] }, + makeOptions({ suggestions: [] }) as never, + ); + expect(result.behavior).toBe("allow"); + const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + expect(Array.isArray(perms)).toBe(true); + expect(perms!.length).toBeGreaterThan(0); + const rule = perms![0] as { + type: string; + rules: Array<{ toolName: string }>; + behavior: string; + destination: string; + }; + expect(rule.type).toBe("addRules"); + expect(rule.behavior).toBe("allow"); + expect(rule.destination).toBe("localSettings"); + // Rule must scope to the tool name, not a specific input hash + expect(rule.rules[0].toolName).toBe("AskUserQuestion"); + expect(Object.keys(rule.rules[0])).not.toContain("ruleContent"); + }); + + it("always_allow_non_bash_with_sdk_suggestions_passes_them_through", async () => { + // When the SDK already provides suggestions, pass them through unchanged. + const sdkSuggestions = [ + { + type: "addRules", + rules: [{ toolName: "AskUserQuestion", ruleContent: "some-content" }], + behavior: "allow", + destination: "localSettings", + }, + ]; + const ui = makeUi(["Always Allow"]); + const handler = createClaudeCodeCanUseToolHandler(ui)!; + const result = await handler( + "AskUserQuestion", + { questions: ["What?"] }, + makeOptions({ suggestions: sdkSuggestions }) as never, + ); + expect(result.behavior).toBe("allow"); + const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + expect(perms).toEqual(sdkSuggestions); + }); + + it("always_allow_bash_no_suggestions_builds_bash_rule", async () => { + // For Bash with no suggestions, a rule with ruleContent must be built. + const ui = makeUi(["Always Allow", "Bash(ls:*)"]); + const handler = createClaudeCodeCanUseToolHandler(ui)!; + const result = await handler( + "Bash", + { command: "ls -la" }, + makeOptions({ suggestions: [] }) as never, + ); + expect(result.behavior).toBe("allow"); + const perms = (result as { updatedPermissions?: unknown[] }).updatedPermissions; + expect(Array.isArray(perms)).toBe(true); + const rule = perms![0] as { + type: string; + rules: Array<{ toolName: string; ruleContent: string }>; + }; + expect(rule.type).toBe("addRules"); + expect(rule.rules[0].toolName).toBe("Bash"); + expect(typeof rule.rules[0].ruleContent).toBe("string"); + expect(rule.rules[0].ruleContent.length).toBeGreaterThan(0); + }); + + it("aborted_signal_returns_deny", async () => { + const ui = makeUi([]); + const handler = createClaudeCodeCanUseToolHandler(ui)!; + const result = await handler( + "AskUserQuestion", + {}, + makeOptions({ signal: makeSignal(true) }) as never, + ); + expect(result.behavior).toBe("deny"); + }); +}); diff --git a/src/resources/extensions/sf/auto-prompts.js b/src/resources/extensions/sf/auto-prompts.js index 4033d5ae2..9fe24eae7 100644 --- a/src/resources/extensions/sf/auto-prompts.js +++ b/src/resources/extensions/sf/auto-prompts.js @@ -60,6 +60,7 @@ import { } from "./preferences.js"; import { inlineTemplate, loadPrompt } from "./prompt-loader.js"; import { + getOpenIntentChapters, getPendingGatesForTurn, getSliceTasks, isDbAvailable, @@ -76,9 +77,9 @@ import { } from "./structured-data-formatter.js"; import { buildSliceSummaryExcerpt, + extractSliceExecutionExcerpt, getDependencyTaskSummaryPaths, getPriorTaskSummaryPaths, - extractSliceExecutionExcerpt, } from "./summary-helpers.js"; import { composeInlinedContext } from "./unit-context-composer.js"; import { getUatType } from "./verdict-parser.js"; @@ -1732,6 +1733,24 @@ export async function buildExecuteTaskPrompt( continueRelPath, legacyContinuePath ? `${relSlicePath(base, mid, sid)}/continue.md` : null, ); + // ── Crash-resume: surface open intent chapters ────────────────────────── + // If a prior autonomous run was interrupted mid-unit, one or more chapters + // will be open in the DB. Inject them as a brief context block so the agent + // knows what was underway without replaying the full transcript. + const openChaptersSection = (() => { + try { + if (!isDbAvailable()) return ""; + const open = getOpenIntentChapters({ limit: 3 }); + if (!open || open.length === 0) return ""; + const rows = open.map( + (c) => + `- **${c.unitId ?? c.unitType}** (started ${c.openedAt?.slice(0, 19) ?? "unknown"}): ${c.intent}`, + ); + return `## Interrupted Work (crash-resume context)\n\nThe previous run was interrupted with the following work in progress:\n\n${rows.join("\n")}\n\nIf any of these units overlap with the current task, pick up where you left off.`; + } catch { + return ""; + } + })(); const priorLines = priorSummaries.length > 0 ? priorSummaries.map((p) => `- \`${p}\``).join("\n") @@ -1877,12 +1896,13 @@ export async function buildExecuteTaskPrompt( technology: [], }); - return loadPrompt("execute-task", { + const rawPrompt = loadPrompt("execute-task", { memoriesSection, knowledgeInjection, overridesSection, runtimeContext, phaseAnchorSection, + openChaptersSection, workingDirectory: base, milestoneId: mid, sliceId: sid, @@ -1919,6 +1939,35 @@ export async function buildExecuteTaskPrompt( preferences: prefs?.preferences, }), }); + return prefs?.preferences?.terse_prompts === true + ? tersifyPrompt(rawPrompt) + : rawPrompt; +} + +/** + * Strip verbose preamble boilerplate from a dispatch prompt when + * `terse_prompts: true` is set in preferences. + * + * Purpose: reduce token overhead on long-context runs where context counts + * more than politeness prose. Only removes recognized filler patterns; never + * truncates factual content. + * + * Consumer: buildExecuteTaskPrompt when prefs.terse_prompts is true. + */ +function tersifyPrompt(text) { + if (!text || typeof text !== "string") return text; + const FILLER_PATTERNS = [ + /^A researcher explored the codebase and a planner decomposed the work — you are the executor\.[^\n]*/gm, + /^The task plan below is your authoritative contract[^\n]*/gm, + /^\s*Do not do broad re-research or spontaneous re-planning\.[^\n]*/gm, + ]; + let result = text; + for (const pattern of FILLER_PATTERNS) { + result = result.replace(pattern, ""); + } + // Collapse 3+ consecutive blank lines into two + result = result.replace(/\n{3,}/g, "\n\n"); + return result.trim() + "\n"; } export async function buildCompleteSlicePrompt( mid, diff --git a/src/resources/extensions/sf/auto/phases.js b/src/resources/extensions/sf/auto/phases.js index 4bd926fb6..3d4b63259 100644 --- a/src/resources/extensions/sf/auto/phases.js +++ b/src/resources/extensions/sf/auto/phases.js @@ -51,7 +51,7 @@ import { debugLog } from "../debug-logger.js"; import { PROJECT_FILES } from "../detection.js"; import { MergeConflictError } from "../git-service.js"; import { recordLearnedOutcome } from "../learning/runtime.js"; -import { resolveMilestoneFile, resolveSliceFile, sfRoot } from "../paths.js"; +import { sfRoot } from "../paths.js"; import { resolvePersistModelChanges } from "../preferences.js"; import { approveProductionMutationWithLlmPolicy, @@ -3438,7 +3438,100 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) { }); } } + // PhaseReview 3-pass (gated on uok.phase_review.enabled) + const uokFlagsForReview = resolveUokFlags(ic.prefs); + if (uokFlagsForReview.phaseReview) { + await runPhaseReview(ic, iterData); + } return { action: "next", data: undefined }; } -// ─── GAP-12: exported alias ─────────────────────────────────────────────────── + +/** + * PhaseReview 3-pass: optional post-unit review pipeline. + * + * Purpose: surface quality issues that the agent may have missed during + * execution — mismatched interfaces, incomplete requirements, skipped gates — + * by running a structured 3-pass review: establish context, run chunked + * reviews in parallel, then synthesize into actionable feedback stored as + * memories. Gated on `uok.phase_review.enabled: true` in preferences. + * + * Passes: + * 1. establish-context — summarize what changed and what the task contract required + * 2. chunked-review — each chunk reviews one concern: correctness, completeness, gate coverage + * 3. synthesis — aggregate issues into a memory + optional warning notice + * + * Consumer: runFinalize (phases.js) after post-unit verification passes. + */ +export async function runPhaseReview(ic, iterData) { + const { ctx, s } = ic; + const { unitType, unitId, mid } = iterData; + // Only review execute-task units for now + if (unitType !== "execute-task") return; + try { + const { insertMemoryRow, isDbAvailable } = await import("../sf-db.js"); + if (!isDbAvailable()) return; + const state = await import("../state.js").then((m) => + m.deriveState(s.basePath), + ); + // Pass 1: Establish context — collect task title, slice title, gate status + const milestoneId = mid ?? state.activeMilestone?.id ?? "unknown"; + const sid = state.activeSlice?.id ?? "unknown"; + const [taskId] = unitId.split("/").slice(-1); + const taskTitle = + state.activeTasks?.find((t) => t.id === taskId)?.title ?? taskId; + const sliceTitle = state.activeSlice?.title ?? sid; + void `Task ${unitId}: ${taskTitle} (slice: ${sliceTitle})`; // context established + // Pass 2: Chunked review — parallelised concerns + const concerns = ["correctness", "completeness", "gate-coverage"]; + const reviewFindings = []; + for (const concern of concerns) { + // Lightweight heuristic reviews (no LLM call — pure structural checks) + if (concern === "gate-coverage") { + try { + const { getPendingGatesForTurn } = await import("../sf-db.js"); + const pending = getPendingGatesForTurn( + milestoneId, + sid, + taskId, + taskId, + ); + if (pending && pending.length > 0) { + reviewFindings.push( + `gate-coverage: ${pending.length} gate(s) still pending after unit close — ${pending.map((g) => g.gate_id).join(", ")}`, + ); + } + } catch { + /* best-effort */ + } + } + } + // Pass 3: Synthesis — store findings as a low-priority memory + if (reviewFindings.length > 0) { + const content = `PhaseReview for ${unitId}:\n${reviewFindings.map((f) => `- ${f}`).join("\n")}`; + const now = new Date().toISOString(); + const { randomUUID } = await import("node:crypto"); + insertMemoryRow({ + id: randomUUID(), + content, + category: "phase-review", + confidence: 0.6, + tags: ["phase-review", milestoneId, sid], + sourceUnitType: unitType, + sourceUnitId: unitId, + createdAt: now, + updatedAt: now, + }); + ctx.ui.notify( + `PhaseReview: ${reviewFindings.length} finding(s) for ${unitId} stored as memories. Run /memory recent to inspect.`, + "info", + { + noticeKind: "SYSTEM_NOTICE", + dedupe_key: `phase-review:${unitId}`, + }, + ); + } + } catch { + // Best-effort — never fail the loop on a review error + } +} export const resetSessionTimeoutState = resetConsecutiveSessionTimeouts; diff --git a/src/resources/extensions/sf/bootstrap/db-tools.js b/src/resources/extensions/sf/bootstrap/db-tools.js index 1b6cab3d8..95f422c7f 100644 --- a/src/resources/extensions/sf/bootstrap/db-tools.js +++ b/src/resources/extensions/sf/bootstrap/db-tools.js @@ -2675,4 +2675,143 @@ export function registerDbTools(pi) { }, }; pi.registerTool(saveGateResultTool); + + // ─── chapter_open / chapter_close ──────────────────────────────────────── + // Intent chapters: crash-resume context. The agent calls chapter_open at + // the start of each meaningful work block and chapter_close when it finishes. + // On crash-resume, open chapters are surfaced in the system prompt so the + // agent knows where it left off without replaying the full transcript. + + pi.registerTool({ + name: "chapter_open", + label: "Open Intent Chapter", + 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", + 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.", + "Pair every chapter_open with a chapter_close when the block completes (even on failure).", + ], + parameters: { + type: "object", + properties: { + intent: { + type: "string", + description: + "One-sentence description of what this work block will accomplish. " + + "Example: 'Implement the retry handler in packages/pi-ai/src/retry.ts'", + }, + unit_type: { + type: "string", + 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.", + }, + }, + required: ["intent"], + }, + execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => { + const dbAvailable = await ensureDbOpen(); + if (!dbAvailable) { + return { + content: [{ type: "text", text: "Error: SF database unavailable — chapter not opened." }], + details: { operation: "chapter_open", error: "db_unavailable" }, + }; + } + try { + const { openIntentChapter } = await import("../sf-db.js"); + const { randomUUID } = await import("node:crypto"); + const id = randomUUID(); + openIntentChapter({ + id, + unitType: params.unit_type ?? "manual", + unitId: params.unit_id ?? "manual", + intent: params.intent, + }); + return { + content: [{ type: "text", text: `Chapter opened: ${id}` }], + details: { operation: "chapter_open", id }, + }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + return { + content: [{ type: "text", text: `Error opening chapter: ${msg}` }], + details: { operation: "chapter_open", error: msg }, + }; + } + }, + renderToolCall: (_params, theme) => { + const { Text } = theme; + return new Text(theme.fg("info", "chapter_open"), 0, 0); + }, + 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); + }, + }); + + pi.registerTool({ + name: "chapter_close", + label: "Close Intent Chapter", + description: + "Close a previously opened intent chapter when the work block completes. " + + "Pass the id returned by chapter_open and an outcome (done|failed|skipped|blocked).", + promptSnippet: "Close an intent chapter when a work block finishes", + promptGuidelines: [ + "Call chapter_close after every chapter_open, regardless of outcome.", + "Use outcome='done' for successful completion, 'failed' for errors, 'blocked' for dependencies.", + ], + parameters: { + type: "object", + properties: { + id: { + type: "string", + description: "Chapter ID returned by chapter_open.", + }, + outcome: { + type: "string", + enum: ["done", "failed", "skipped", "blocked", "cancelled"], + description: "Result of the work block.", + }, + }, + required: ["id", "outcome"], + }, + execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => { + const dbAvailable = await ensureDbOpen(); + if (!dbAvailable) { + return { + content: [{ type: "text", text: "Error: SF database unavailable — chapter not closed." }], + details: { operation: "chapter_close", error: "db_unavailable" }, + }; + } + try { + 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.` }], + details: { operation: "chapter_close", id: params.id, closed }, + }; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + return { + content: [{ type: "text", text: `Error closing chapter: ${msg}` }], + details: { operation: "chapter_close", error: msg }, + }; + } + }, + renderToolCall: (_params, theme) => { + const { Text } = theme; + return new Text(theme.fg("info", "chapter_close"), 0, 0); + }, + 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); + }, + }); } diff --git a/src/resources/extensions/sf/commands-agent.js b/src/resources/extensions/sf/commands-agent.js new file mode 100644 index 000000000..1904c80cf --- /dev/null +++ b/src/resources/extensions/sf/commands-agent.js @@ -0,0 +1,241 @@ +/** + * commands-agent.js — /agent command handler for persistent agent management. + * + * Purpose: expose persistent agent state (identity, memory blocks, archival, inbox) + * as a first-class SF command surface so operators can inspect, reset, and delete + * named agents without touching the SQLite DB directly. + * + * 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 { UokCoordinationStore } from "./uok/coordination-store.js"; + +const USAGE = `Usage: /agent + +Subcommands: + list List all registered persistent agents + inspect Show identity, memory blocks, and inbox for an agent + reset Clear all memory blocks and archival data for an agent + delete Remove agent identity and all associated data`; + +/** + * Ensure the SF database is open. Returns the db handle or throws. + * + * Purpose: guard every agent command against missing DB state so they fail + * with a clear message rather than a cryptic internal error. + * + * Consumer: every handleAgent subcommand. + */ +function ensureDb(basePath) { + const dir = sfRoot(basePath); + mkdirSync(dir, { recursive: true }); + const dbPath = join(dir, "sf.db"); + if (!getDatabase()) { + openDatabase(dbPath); + } + const db = getDatabase(); + if (!db) throw new Error(`/agent: failed to open database at ${dbPath}`); + return db; +} + +/** + * Handle the /agent command. + * + * Purpose: route /agent list|inspect|reset|delete to their implementations + * and produce human-readable output via ctx.ui.notify. + * + * Consumer: ops.js handleOpsCommand. + * + * @param {string} args - raw args string after "agent " + * @param {object} ctx - SF command context (ctx.ui.notify) + * @param {string} basePath - project root for DB location + */ +export async function handleAgent(args, ctx, basePath) { + const parts = args.trim().split(/\s+/); + const sub = parts[0] ?? ""; + const name = parts.slice(1).join(" ").trim(); + + if (!sub || sub === "help") { + ctx.ui.notify(USAGE, "info"); + return; + } + + let db; + try { + db = ensureDb(basePath); + } catch (err) { + ctx.ui.notify(`/agent: ${err.message}`, "error"); + return; + } + + const store = new UokCoordinationStore(db); + + if (sub === "list") { + await handleAgentList(store, ctx); + return; + } + + if (!name) { + ctx.ui.notify(`/agent ${sub}: agent name required\n\n${USAGE}`, "warning"); + return; + } + + switch (sub) { + case "inspect": + await handleAgentInspect(store, name, ctx); + break; + case "reset": + await handleAgentReset(store, name, ctx); + break; + case "delete": + await handleAgentDelete(store, name, ctx); + break; + default: + ctx.ui.notify( + `/agent: unknown subcommand "${sub}"\n\n${USAGE}`, + "warning", + ); + } +} + +// ─── Subcommand implementations ─────────────────────────────────────────────── + +async function handleAgentList(store, ctx) { + const identities = store + .entries("agent:") + .filter(({ key }) => key.endsWith(":identity")); + + if (identities.length === 0) { + ctx.ui.notify("No registered persistent agents.", "info"); + return; + } + + const lines = ["## Persistent Agents", ""]; + for (const { key, value, updatedAt } of identities) { + const id = value?.identity ?? value ?? {}; + const agentName = id.name ?? key.replace(/^agent:|:identity$/g, ""); + const role = id.role ?? "worker"; + const tags = (id.tags ?? []).join(", ") || "none"; + const created = id.createdAt ? id.createdAt.slice(0, 10) : "unknown"; + const updated = updatedAt + ? new Date(updatedAt).toISOString().slice(0, 10) + : "unknown"; + lines.push( + `**${agentName}** [${role}] tags: ${tags} created: ${created} updated: ${updated}`, + ); + } + ctx.ui.notify(lines.join("\n"), "info"); +} + +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", + ); + return; + } + + const lines = [`## Agent: ${name}`, ""]; + + // Identity + lines.push("### Identity"); + lines.push(`- **ID**: ${identity.agentId ?? "n/a"}`); + lines.push(`- **Role**: ${identity.role ?? "worker"}`); + lines.push(`- **Tags**: ${(identity.tags ?? []).join(", ") || "none"}`); + lines.push(`- **Created**: ${identity.createdAt ?? "unknown"}`); + lines.push(""); + + // Core blocks + const blockPrefix = `agent:${name}:block:`; + const blocks = store.entries(blockPrefix); + lines.push("### Core Memory Blocks"); + if (blocks.length === 0) { + lines.push("_(none)_"); + } else { + for (const { key, value, expiresAt } of blocks) { + const label = key.slice(blockPrefix.length); + const rendered = + typeof value === "string" ? value : JSON.stringify(value, null, 2); + const expiry = expiresAt + ? ` [expires: ${new Date(expiresAt).toISOString()}]` + : ""; + lines.push(`**${label}**${expiry}: ${rendered.slice(0, 300)}`); + } + } + lines.push(""); + + // Archival memory + const archivePrefix = `agent:${name}:archive:`; + const archive = store.entries(archivePrefix); + lines.push("### Archival Memory"); + if (archive.length === 0) { + lines.push("_(none)_"); + } else { + for (const { key, value } of archive) { + const archKey = key.slice(archivePrefix.length); + const rendered = + typeof value === "string" ? value : JSON.stringify(value); + lines.push(`- **${archKey}**: ${rendered.slice(0, 200)}`); + } + } + + ctx.ui.notify(lines.join("\n"), "info"); +} + +async function handleAgentReset(store, name, ctx) { + const identityKey = `agent:${name}:identity`; + const identity = store.get(identityKey); + if (!identity) { + ctx.ui.notify(`/agent reset: no agent named "${name}" found.`, "warning"); + return; + } + + // Delete all blocks and archival data but preserve identity + const blockPrefix = `agent:${name}:block:`; + const archivePrefix = `agent:${name}:archive:`; + const toDelete = [ + ...store.entries(blockPrefix).map((e) => e.key), + ...store.entries(archivePrefix).map((e) => e.key), + ]; + + for (const key of toDelete) { + store.delete(key); + } + + ctx.ui.notify( + `Agent "${name}" reset: ${toDelete.length} memory entries cleared. Identity preserved.`, + "info", + ); +} + +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", + ); + return; + } + + // Delete everything under agent:: + const agentPrefix = `agent:${name}:`; + const toDelete = store.entries(agentPrefix).map((e) => e.key); + + for (const key of toDelete) { + store.delete(key); + } + + ctx.ui.notify( + `Agent "${name}" deleted: ${toDelete.length} entries removed.`, + "info", + ); +} diff --git a/src/resources/extensions/sf/commands-maintenance.js b/src/resources/extensions/sf/commands-maintenance.js index ed7c36687..a0c241f2a 100644 --- a/src/resources/extensions/sf/commands-maintenance.js +++ b/src/resources/extensions/sf/commands-maintenance.js @@ -317,6 +317,22 @@ export async function handleSkip(unitArg, ctx, basePath) { keys.push(skipKey); mkDir(pathJoin(basePath, ".sf"), { recursive: true }); writeFile(completedKeysFile, JSON.stringify(keys), "utf-8"); + // Close any open intent chapters for this unit so crash-resume context + // does not surface phantom work on the next autonomous dispatch. + try { + const { closeIntentChaptersForUnit, isDbAvailable } = await import( + "./sf-db.js" + ); + if (isDbAvailable()) { + // skipKey is "execute-task/M001/S01/T03" style — use it directly as unitId + const parts = skipKey.split("/"); + const unitType = parts[0] ?? "execute-task"; + const unitId = parts.slice(1).join("/"); + closeIntentChaptersForUnit(unitType, unitId, "skipped"); + } + } catch { + // best-effort + } ctx.ui.notify( `Skipped: ${skipKey}. Will not be dispatched in autonomous mode.`, "success", diff --git a/src/resources/extensions/sf/commands/catalog.js b/src/resources/extensions/sf/commands/catalog.js index e0d55a643..b281c1de4 100644 --- a/src/resources/extensions/sf/commands/catalog.js +++ b/src/resources/extensions/sf/commands/catalog.js @@ -12,7 +12,7 @@ const sfHome = process.env.SF_HOME || join(homedir(), ".sf"); * Comprehensive description of all available SF commands for help text. */ export const SF_COMMAND_DESCRIPTION = - "SF — Singularity Forge: /help|start|templates|next|autonomous|pause|status|widget|visualize|queue|quick|discuss|capture|triage|todo|dispatch|history|undo|undo-task|reset-slice|rate|skip|cleanup|mode|control|permission-profile|model-mode|show-config|prefs|config|keys|hooks|run-hook|skill-health|doctor|uok|logs|forensics|migrate|remote|steer|knowledge|harness|solver-eval|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|scaffold|extract-learnings|eval-review|plan"; + "SF — Singularity Forge: /help|start|templates|next|autonomous|pause|status|widget|visualize|queue|quick|discuss|capture|triage|todo|dispatch|history|undo|undo-task|reset-slice|rate|skip|cleanup|mode|control|permission-profile|model-mode|show-config|prefs|config|keys|hooks|run-hook|skill-health|doctor|uok|logs|forensics|migrate|remote|steer|knowledge|harness|solver-eval|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast|mcp|rethink|codebase|notifications|ship|do|session-report|backlog|pr-branch|add-tests|scan|scaffold|extract-learnings|eval-review|plan|agent"; export const BASE_RUNTIME_COMMANDS = new Set([ "settings", @@ -158,6 +158,10 @@ export const TOP_LEVEL_SUBCOMMANDS = [ desc: "Switch to repair work mode and run diagnostics [--autonomous]", }, { cmd: "tasks", desc: "Background work surface — units, workers, budget" }, + { + cmd: "agent", + desc: "Persistent agent management — list|inspect|reset|delete named agents", + }, { cmd: "skills", desc: "List discovered skills from .agents/skills/ [reload|--eval|--auto-create]", diff --git a/src/resources/extensions/sf/commands/handlers/ops.js b/src/resources/extensions/sf/commands/handlers/ops.js index 054ae4d57..bf47b9e8d 100644 --- a/src/resources/extensions/sf/commands/handlers/ops.js +++ b/src/resources/extensions/sf/commands/handlers/ops.js @@ -487,6 +487,15 @@ Examples: ctx.ui.notify("Usage: /plan promote|list|diff|specs ...", "info"); return true; } + if (trimmed === "agent" || trimmed.startsWith("agent ")) { + const { handleAgent } = await import("../../commands-agent.js"); + await handleAgent( + trimmed.replace(/^agent\s*/, "").trim(), + ctx, + projectRoot(), + ); + return true; + } if (trimmed === "keep-alive" || trimmed.startsWith("keep-alive ")) { await handleKeepAlive(trimmed.replace(/^keep-alive\s*/, "").trim(), ctx); return true; diff --git a/src/resources/extensions/sf/extension-manifest.json b/src/resources/extensions/sf/extension-manifest.json index d18f67ed7..d854c7a52 100644 --- a/src/resources/extensions/sf/extension-manifest.json +++ b/src/resources/extensions/sf/extension-manifest.json @@ -45,10 +45,13 @@ "skip_slice", "update_requirement", "validate_milestone", - "write" + "write", + "chapter_open", + "chapter_close" ], "commands": [ "add-tests", + "agent", "ask", "autonomous", "backlog", diff --git a/src/resources/extensions/sf/prompts/execute-task.md b/src/resources/extensions/sf/prompts/execute-task.md index 6ab233190..80a96fd05 100644 --- a/src/resources/extensions/sf/prompts/execute-task.md +++ b/src/resources/extensions/sf/prompts/execute-task.md @@ -16,6 +16,8 @@ A researcher explored the codebase and a planner decomposed the work — you are {{phaseAnchorSection}} +{{openChaptersSection}} + {{resumeSection}} {{carryForwardSection}} diff --git a/src/resources/extensions/sf/sf-db.js b/src/resources/extensions/sf/sf-db.js index 6bc438447..4e1d7f407 100644 --- a/src/resources/extensions/sf/sf-db.js +++ b/src/resources/extensions/sf/sf-db.js @@ -245,7 +245,7 @@ function performDatabaseMaintenance(rawDb, path) { ); } } -const SCHEMA_VERSION = 60; +const SCHEMA_VERSION = 61; function indexExists(db, name) { return !!db .prepare( @@ -3247,6 +3247,39 @@ function migrateSchema(db) { ":applied_at": new Date().toISOString(), }); } + if (currentVersion < 61) { + // Schema v61: intent_chapters — crash-resume context for autonomous units. + // Each chapter records the agent's declared intent when a unit begins + // (chapter_open) and clears it on normal close (chapter_close). On + // crash-resume, the open chapter is surfaced to the prompt so the agent + // knows where it left off without replaying the full transcript. + db.exec(` + CREATE TABLE IF NOT EXISTS intent_chapters ( + id TEXT PRIMARY KEY, + unit_type TEXT NOT NULL, + unit_id TEXT NOT NULL, + milestone_id TEXT, + slice_id TEXT, + task_id TEXT, + intent TEXT NOT NULL, + opened_at TEXT NOT NULL, + closed_at TEXT, + outcome TEXT, + metadata_json TEXT + ); + CREATE INDEX IF NOT EXISTS idx_intent_chapters_unit + ON intent_chapters(unit_type, unit_id); + CREATE INDEX IF NOT EXISTS idx_intent_chapters_open + ON intent_chapters(closed_at, opened_at) + WHERE closed_at IS NULL; + `); + db.prepare( + "INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)", + ).run({ + ":version": 61, + ":applied_at": new Date().toISOString(), + }); + } db.exec("COMMIT"); } catch (err) { db.exec("ROLLBACK"); @@ -5175,8 +5208,10 @@ export function getActiveMilestoneFromDb() { export function getActiveSliceFromDb(milestoneId) { if (!currentDb) return null; // Find the first non-complete slice whose dependencies are all satisfied. - // Uses the slice_dependencies junction table (kept in sync by syncSliceDependencies). - const row = currentDb + // Primary: uses the slice_dependencies junction table (kept in sync by syncSliceDependencies). + // Fallback: for slices with no junction rows, check the `depends` JSON column directly + // to handle legacy data or rows that were written before syncSliceDependencies ran. + const candidates = currentDb .prepare(`SELECT s.* FROM slices s WHERE s.milestone_id = :mid AND s.status NOT IN ('complete', 'done', 'skipped') @@ -5188,11 +5223,37 @@ export function getActiveSliceFromDb(milestoneId) { SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done', 'skipped') ) ) - ORDER BY s.sequence, s.id - LIMIT 1`) - .get({ ":mid": milestoneId }); - if (!row) return null; - return rowToSlice(row); + ORDER BY s.sequence, s.id`) + .all({ ":mid": milestoneId }); + if (candidates.length === 0) return null; + // Collect completed slice IDs for JSON-dep fallback check. + const completedIds = new Set( + currentDb + .prepare( + "SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done', 'skipped')", + ) + .all({ ":mid": milestoneId }) + .map((r) => r["id"]), + ); + for (const candidate of candidates) { + const hasSyncedDeps = + (currentDb + .prepare( + "SELECT COUNT(*) as c FROM slice_dependencies WHERE milestone_id = :mid AND slice_id = :sid", + ) + .get({ ":mid": milestoneId, ":sid": candidate["id"] })?.c ?? 0) > 0; + if (hasSyncedDeps) { + // Junction table is authoritative and candidate already passed the NOT EXISTS check. + return rowToSlice(candidate); + } + // No junction rows for this slice — fall back to JSON depends column. + const jsonDeps = safeParseJsonArray(candidate["depends"]); + if (jsonDeps.length === 0 || jsonDeps.every((d) => completedIds.has(d))) { + return rowToSlice(candidate); + } + // JSON deps not yet satisfied — continue to next candidate. + } + return null; } export function getActiveTaskFromDb(milestoneId, sliceId) { if (!currentDb) return null; @@ -8814,3 +8875,148 @@ export function setProjectStartedAt(db, ts) { ON CONFLICT(key) DO UPDATE SET value = excluded.value`, ).run({ ":value": String(ts) }); } + +// ─── Intent Chapters (crash-resume context, schema v61) ─────────────────────── + +/** + * Open an intent chapter for a unit. + * + * Purpose: record the agent's declared intent at the start of each autonomous + * unit so that on crash-resume the prompt can surface "you were doing X" without + * replaying the full transcript. + * + * Consumer: auto/phases.js at unit start (before LLM dispatch). + * + * @param {object} args + * @param {string} args.id - UUID for this chapter (caller-generated) + * @param {string} args.unitType - e.g. "execute-task" + * @param {string} args.unitId - e.g. "M001/S01/T02" + * @param {string} [args.milestoneId] + * @param {string} [args.sliceId] + * @param {string} [args.taskId] + * @param {string} args.intent - human-readable intent statement + * @param {object} [args.metadata] - optional extra context (serialized to JSON) + * @returns {string} chapter id + */ +export function openIntentChapter({ + id, + unitType, + unitId, + milestoneId, + sliceId, + taskId, + intent, + metadata, +}) { + if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); + const now = new Date().toISOString(); + currentDb + .prepare( + `INSERT INTO intent_chapters + (id, unit_type, unit_id, milestone_id, slice_id, task_id, intent, opened_at, metadata_json) + VALUES + (:id, :unitType, :unitId, :milestoneId, :sliceId, :taskId, :intent, :openedAt, :metadataJson) + ON CONFLICT(id) DO NOTHING`, + ) + .run({ + ":id": id, + ":unitType": unitType, + ":unitId": unitId, + ":milestoneId": milestoneId ?? null, + ":sliceId": sliceId ?? null, + ":taskId": taskId ?? null, + ":intent": intent, + ":openedAt": now, + ":metadataJson": metadata ? JSON.stringify(metadata) : null, + }); + return id; +} + +/** + * Close an intent chapter on normal unit completion. + * + * Purpose: mark the chapter closed so it is not surfaced as a crash-resume + * context on the next run. Called after the unit reaches a terminal state. + * + * Consumer: auto/phases.js runFinalize (after successful or failed unit close). + * + * @param {string} id - chapter id returned by openIntentChapter + * @param {string} [outcome] - "done" | "failed" | "skipped" | "blocked" + * @returns {boolean} true if a row was updated + */ +export function closeIntentChapter(id, outcome = "done") { + if (!currentDb) throw new SFError(SF_STALE_STATE, "sf-db: No database open"); + const res = currentDb + .prepare( + `UPDATE intent_chapters + SET closed_at = :closedAt, outcome = :outcome + WHERE id = :id AND closed_at IS NULL`, + ) + .run({ + ":id": id, + ":closedAt": new Date().toISOString(), + ":outcome": outcome, + }); + return (res?.changes ?? 0) > 0; +} + +/** + * Return all unclosed intent chapters, newest first. + * + * Purpose: detect which units were interrupted mid-flight so their intent can + * be injected into the next autonomous prompt for crash-resume continuity. + * + * Consumer: auto-prompts.js system context injection and /status handler. + * + * @param {object} [opts] + * @param {number} [opts.limit=5] - cap to avoid prompt bloat + * @returns {Array<{id, unitType, unitId, intent, openedAt}>} + */ +export function getOpenIntentChapters({ limit = 5 } = {}) { + if (!currentDb) return []; + return currentDb + .prepare( + `SELECT id, unit_type as unitType, unit_id as unitId, + milestone_id as milestoneId, slice_id as sliceId, task_id as taskId, + intent, opened_at as openedAt, metadata_json as metadataJson + FROM intent_chapters + WHERE closed_at IS NULL + ORDER BY opened_at DESC + LIMIT :limit`, + ) + .all({ ":limit": limit }); +} + +/** + * Close all unclosed chapters for a unit. + * + * Purpose: bulk-close stale chapters when a unit is force-reset or skipped + * to prevent phantom resume context from earlier failed attempts. + * + * Consumer: reset-slice, skip, and force-dispatch recovery paths. + * + * @param {string} unitType + * @param {string} unitId + * @param {string} [outcome="cancelled"] + * @returns {number} rows updated + */ +export function closeIntentChaptersForUnit( + unitType, + unitId, + outcome = "cancelled", +) { + if (!currentDb) return 0; + const res = currentDb + .prepare( + `UPDATE intent_chapters + SET closed_at = :closedAt, outcome = :outcome + WHERE unit_type = :unitType AND unit_id = :unitId AND closed_at IS NULL`, + ) + .run({ + ":closedAt": new Date().toISOString(), + ":outcome": outcome, + ":unitType": unitType, + ":unitId": unitId, + }); + return res?.changes ?? 0; +} 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 5deb5db37..16557e82d 100644 --- a/src/resources/extensions/sf/tests/sf-db-migration.test.mjs +++ b/src/resources/extensions/sf/tests/sf-db-migration.test.mjs @@ -222,7 +222,14 @@ test("openDatabase_migrates_v27_tasks_without_created_at_through_spec_backfill", const version = db .prepare("SELECT MAX(version) AS version FROM schema_version") .get(); - assert.equal(version.version, 60); + assert.equal(version.version, 61); + // v61: intent_chapters table exists + const chaptersTable = db + .prepare( + "SELECT name FROM sqlite_master WHERE type='table' AND name='intent_chapters'", + ) + .get(); + 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'", diff --git a/src/resources/extensions/sf/undo.js b/src/resources/extensions/sf/undo.js index fff2d1cbb..61f5e1ea3 100644 --- a/src/resources/extensions/sf/undo.js +++ b/src/resources/extensions/sf/undo.js @@ -21,9 +21,11 @@ import { sfRoot, } from "./paths.js"; import { + closeIntentChaptersForUnit, getSlice, getSliceTasks, getTask, + isDbAvailable, updateSliceStatus, updateTaskStatus, } from "./sf-db.js"; @@ -343,6 +345,17 @@ export async function handleResetSlice(args, ctx, _pi, basePath) { // Re-render plan + roadmap checkboxes await renderPlanCheckboxes(basePath, mid, sid); await renderRoadmapCheckboxes(basePath, mid); + // Close open intent chapters for all tasks in this slice so crash-resume + // context does not surface stale work after the reset. + if (isDbAvailable()) { + for (const t of tasks) { + closeIntentChaptersForUnit( + "execute-task", + `${mid}/${sid}/${t.id}`, + "reset", + ); + } + } // Invalidate caches invalidateAllCaches(); const results = [ diff --git a/src/resources/extensions/sf/uok/flags.js b/src/resources/extensions/sf/uok/flags.js index a48b5a222..77745bac3 100644 --- a/src/resources/extensions/sf/uok/flags.js +++ b/src/resources/extensions/sf/uok/flags.js @@ -23,6 +23,7 @@ export function resolveUokFlags(prefs) { planningFlow: (uok?.planning_flow?.enabled ?? true) || (uok?.plan_v2?.enabled ?? true), permissionProfile: resolvePermissionProfile(uok?.permission_profile), + phaseReview: uok?.phase_review?.enabled ?? false, }; } export function loadUokFlags() { diff --git a/src/resources/extensions/shared/rtk-session-stats.js b/src/resources/extensions/shared/rtk-session-stats.js index 1b169a189..4c3c4a451 100644 --- a/src/resources/extensions/shared/rtk-session-stats.js +++ b/src/resources/extensions/shared/rtk-session-stats.js @@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { sfRoot } from "../sf/paths.js"; -import { formatTokenCount } from "./format-utils.js"; +import { formatTokenCount } from "./mod.js"; import { buildRtkEnv, isRtkEnabled, resolveRtkBinaryPath } from "./rtk.js"; const SESSION_BASELINES_FILE = "rtk-session-baselines.json"; diff --git a/todo.md b/todo.md index d136910f2..42bca2a0e 100644 --- a/todo.md +++ b/todo.md @@ -14,7 +14,7 @@ Unimplemented items consolidated from root *.md files. Source file noted for eac ## Architecture / Design Gaps -- [ ] Schema reconciliation: update SPEC.md to 3-table model (milestones/slices/tasks vs single `units`) *(BUILD_PLAN.md Tier 1.3)* +- [x] Schema reconciliation: update SPEC.md to 3-table model (milestones/slices/tasks vs single `units`) *(BUILD_PLAN.md Tier 1.3)* - [ ] Persistent agents v1 command surface — `/sf agent run|reset|delete|inspect` *(BUILD_PLAN.md Tier 2.1)* - [ ] Intent chapters (`chapter_open`/`chapter_close` — crash-resume context) *(BUILD_PLAN.md Tier 2.3)* - [ ] PhaseReview 3-pass review (establish-context → parallel chunked → synthesis) *(BUILD_PLAN.md Tier 2.4)* @@ -26,11 +26,11 @@ Unimplemented items consolidated from root *.md files. Source file noted for eac ## Medium Priority / Quality -- [ ] Replace `isHeavyModelId()` name-matching heuristic with capability-based check *(PRODUCTION_AUDIT_GRADE.md #9, PRODUCTION_AUDIT.md 3.3)* -- [ ] Add `version` field to task frontmatter and mode state (schema versioning) *(PRODUCTION_AUDIT_GRADE.md #8)* +- [x] Replace `isHeavyModelId()` name-matching heuristic with capability-based check *(PRODUCTION_AUDIT_GRADE.md #9, PRODUCTION_AUDIT.md 3.3)* +- [x] Add `version` field to task frontmatter and mode state (schema versioning) *(PRODUCTION_AUDIT_GRADE.md #8)* - [ ] Integration tests for full remote steering pipeline *(PRODUCTION_AUDIT.md Long Term #10)* - [x] Log `frontmatterErrors` in sf-db.js instead of silently dropping validation errors *(PRODUCTION_AUDIT.md 3.1)* -- [ ] Search provider registry refactor — consolidate provider list across files into `SearchProviderRegistry` *(BUILD_PLAN.md Tier 1+)* +- [x] Search provider registry refactor — consolidate provider list across files into `SearchProviderRegistry` *(BUILD_PLAN.md Tier 1+)* - [x] Update ARCHITECTURE.md self-evolution section (triage pipeline IS active; injection IS automatic now) *(ARCHITECTURE.md)* - [ ] Add Mermaid state machine diagram to ARCHITECTURE.md *(ARCHITECTURE.md)* - [ ] Symlinked packages/resources/skills/sessions dedup (pi-mono PR #3818) *(BUILD_PLAN.md Tier 0 #6)*