{"version":3,"file":"print-mode.test.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.test.ts"],"names":[],"mappings":"","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { MemoryHistorySnapshot } from \"../core/memory.js\";\nimport { resolveSnapshotSelector } from \"../core/snapshot-selector-resolver.js\";\nimport type { TodoItem } from \"../core/tools/todo-write.js\";\nimport type { UltraplanArtifact, UltraplanRunResult } from \"../core/ultraplan.js\";\nimport { getPrintModeLocalCommandOutput } from \"./print-mode.js\";\n\nfunction makeSnapshot(\n\tentryId: string,\n\titems: Array<{ key: string; value: string }>,\n\trecordedAt = \"2026-04-01T12:00:00.000Z\",\n\tisCurrent = false,\n): MemoryHistorySnapshot {\n\treturn {\n\t\tentryId,\n\t\tparentId: null,\n\t\trecordedAt,\n\t\titems: items.map((item) => ({ ...item, timestamp: recordedAt })),\n\t\tisCurrent,\n\t};\n}\n\nfunction makeUltraplanArtifact(overrides?: Partial<UltraplanArtifact>): UltraplanArtifact {\n\treturn {\n\t\tversion: 1,\n\t\tplannerMode: \"local_subagent\",\n\t\tplannerAgent: \"planner\",\n\t\texecutionState: \"plan_only\",\n\t\tobjective: \"Ship local-first Ultraplan\",\n\t\tassumptions: [\"Planner subagent is available\"],\n\t\tconstraints: [\"No auto-execution\"],\n\t\tphases: [{ title: \"Planning\", steps: [\"Generate plan\", \"Persist artifact\"] }],\n\t\trisks: [\"Malformed planner output\"],\n\t\trecommendedExecutionOrder: [\"Plan\", \"Review\", \"Execute later\"],\n\t\tactionableNextSteps: [\"Inspect the stored plan\"],\n\t\tcreatedAt: \"2026-04-02T12:00:00.000Z\",\n\t\t...overrides,\n\t};\n}\n\nfunction makeSession(\n\tsnapshots: readonly MemoryHistorySnapshot[],\n\tartifact?: UltraplanArtifact,\n\tapplyFn?: () => { applied: TodoItem[]; displayText: string },\n\treviseFn?: (instruction: string) => Promise<UltraplanRunResult>,\n\tbriefOnly = false,\n) {\n\tlet briefOnlyState = briefOnly;\n\n\tconst btwNotes: string[] = [];\n\n\treturn {\n\t\tget briefOnly() {\n\t\t\treturn briefOnlyState;\n\t\t},\n\t\tsetBriefOnly: (enabled: boolean) => {\n\t\t\tbriefOnlyState = enabled;\n\t\t},\n\t\tqueueByTheWay: (note: string) => {\n\t\t\tbtwNotes.push(note);\n\t\t},\n\t\tgetPendingByTheWayNotes: () => btwNotes,\n\t\tgetMemoryHistory: () => snapshots,\n\t\tresolveMemorySnapshotSelector: (input: string) => resolveSnapshotSelector(input, snapshots),\n\t\tgetLatestUltraplanPlan: () => artifact,\n\t\trunUltraplan: async (objective: string): Promise<UltraplanRunResult> => ({\n\t\t\tartifact: makeUltraplanArtifact({ objective }),\n\t\t\tdisplayText: `planned: ${objective}`,\n\t\t\trawPlannerOutput: \"{}\",\n\t\t}),\n\t\trunUltraplanRevise:\n\t\t\treviseFn ??\n\t\t\t(async (instruction: string): Promise<UltraplanRunResult> => ({\n\t\t\t\tartifact: makeUltraplanArtifact({ objective: `Revised: ${instruction}` }),\n\t\t\t\tdisplayText: `revised: ${instruction}`,\n\t\t\t\trawPlannerOutput: \"{}\",\n\t\t\t})),\n\t\tapplyUltraplan: applyFn ?? (() => ({ applied: [] as TodoItem[], displayText: \"no plan\" })),\n\t};\n}\n\ndescribe(\"getPrintModeLocalCommandOutput\", () => {\n\tit(\"handles /brief status and toggle commands in print mode\", async () => {\n\t\tconst session = makeSession([]);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/brief status\")).toContain(\n\t\t\t\"Brief-only mode is disabled for this session only (runtime-only).\",\n\t\t);\n\t\texpect(session.briefOnly).toBe(false);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/brief on\")).toContain(\n\t\t\t\"Enabled brief-only mode for this session only (runtime-only).\",\n\t\t);\n\t\texpect(session.briefOnly).toBe(true);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/brief status\")).toContain(\n\t\t\t\"Brief-only mode is enabled for this session only (runtime-only).\",\n\t\t);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/brief off\")).toContain(\n\t\t\t\"Disabled brief-only mode for this session only (runtime-only).\",\n\t\t);\n\t\texpect(session.briefOnly).toBe(false);\n\t});\n\n\tit(\"returns usage for invalid /brief commands in print mode\", async () => {\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"/brief\")).toBe(\"Usage: /brief <on|off|status>\");\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"/brief maybe\")).toBe(\n\t\t\t\"Usage: /brief <on|off|status>\",\n\t\t);\n\t});\n\n\tit(\"queues /btw guidance for the next turn in print mode\", async () => {\n\t\tconst session = makeSession([]);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/btw tighten the acceptance criteria\")).toContain(\n\t\t\t\"Queued by-the-way guidance for the next turn only (runtime-only).\",\n\t\t);\n\t\texpect(session.getPendingByTheWayNotes()).toEqual([\"tighten the acceptance criteria\"]);\n\n\t\texpect(await getPrintModeLocalCommandOutput(session, \"/btw keep the patch narrow\")).toContain(\n\t\t\t\"Pending BTW notes: 2.\",\n\t\t);\n\t\texpect(session.getPendingByTheWayNotes()).toEqual([\"tighten the acceptance criteria\", \"keep the patch narrow\"]);\n\t});\n\n\tit(\"returns usage for invalid /btw commands in print mode\", async () => {\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"/btw\")).toBe(\"Usage: /btw <note>\");\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"/btw    \")).toBe(\"Usage: /btw <note>\");\n\t});\n\n\tit(\"handles /memory history in print mode\", async () => {\n\t\tconst snapshots = [\n\t\t\tmakeSnapshot(\"baseline01-1111\", [{ key: \"alpha\", value: \"first value\" }], \"2026-04-01T10:00:00.000Z\"),\n\t\t\tmakeSnapshot(\"target001-2222\", [{ key: \"beta\", value: \"second value\" }], \"2026-04-01T12:00:00.000Z\", true),\n\t\t];\n\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession(snapshots), \"/memory history\");\n\n\t\texpect(output).toContain(\"Use /memory diff <baselineId> <targetId> to compare any two snapshots.\");\n\t\texpect(output).toContain(\"[target00]\");\n\t});\n\n\tit(\"handles explicit /memory diff selectors in print mode\", async () => {\n\t\tconst snapshots = [\n\t\t\tmakeSnapshot(\"baseline01-1111\", [{ key: \"alpha\", value: \"first\" }], \"2026-04-01T10:00:00.000Z\"),\n\t\t\tmakeSnapshot(\"target001-2222\", [{ key: \"alpha\", value: \"second\" }], \"2026-04-01T12:00:00.000Z\", true),\n\t\t];\n\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession(snapshots), \"/memory diff [baseline] [target00]\");\n\n\t\texpect(output).toContain(\"Baseline: \");\n\t\texpect(output).toContain(\"ID: [baseline] baseline01-1111\");\n\t\texpect(output).toContain(\"~ Changed (1)\");\n\t});\n\n\tit(\"handles adjacent /memory diff in print mode\", async () => {\n\t\tconst snapshots = [\n\t\t\tmakeSnapshot(\"baseline01-1111\", [{ key: \"alpha\", value: \"first\" }], \"2026-04-01T10:00:00.000Z\"),\n\t\t\tmakeSnapshot(\"target001-2222\", [{ key: \"alpha\", value: \"second\" }], \"2026-04-01T12:00:00.000Z\", true),\n\t\t];\n\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession(snapshots), \"/memory diff\");\n\n\t\texpect(output).toContain(\"Comparing: \");\n\t\texpect(output).toContain(\"(snapshot comparison · not an event log)\");\n\t\texpect(output).toContain(\"~ Changed (1)\");\n\t});\n\n\tit(\"handles initial-snapshot /memory diff in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([\n\t\t\t\tmakeSnapshot(\"baseline01-1111\", [{ key: \"alpha\", value: \"first\" }], \"2026-04-01T10:00:00.000Z\", true),\n\t\t\t]),\n\t\t\t\"/memory diff\",\n\t\t);\n\n\t\texpect(output).toContain(\"Initial snapshot — 1 item(s)\");\n\t\texpect(output).toContain(\"(snapshot comparison · not an event log)\");\n\t});\n\n\tit(\"handles selector resolution failures in print mode\", async () => {\n\t\tconst snapshots = [\n\t\t\tmakeSnapshot(\"baseline01-1111\", [{ key: \"alpha\", value: \"first\" }], \"2026-04-01T10:00:00.000Z\", true),\n\t\t];\n\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession(snapshots), \"/memory diff [] missing\");\n\n\t\texpect(output).toContain(\"Snapshot resolution failed in current branch history.\");\n\t\texpect(output).toContain(\"Baseline selector is empty.\");\n\t\texpect(output).toContain(\"Target ID not found: missing\");\n\t});\n\n\tit(\"handles empty diff history in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession([]), \"/memory diff\");\n\t\texpect(output).toBe(\"No memory snapshots found. Nothing to diff against.\");\n\t});\n\n\tit(\"shows the persisted Ultraplan artifact honestly in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession([], makeUltraplanArtifact()), \"/ultraplan show\");\n\n\t\texpect(output).toContain(\"Ultraplan\");\n\t\texpect(output).toContain(\"Planner mode: local planner subagent (planner)\");\n\t\texpect(output).toContain(\"Execution: planning only; no execution has started\");\n\t\texpect(output).toContain(\"Persisted as session-owned Ultraplan state on the current branch.\");\n\t});\n\n\tit(\"runs the local Ultraplan entrypoint in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession([]), \"/ultraplan map the next slice\");\n\t\texpect(output).toBe(\"planned: map the next slice\");\n\t});\n\n\tit(\"ignores unrelated prompts\", async () => {\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"hello\")).toBeUndefined();\n\t\texpect(await getPrintModeLocalCommandOutput(makeSession([]), \"/memory list\")).toBeUndefined();\n\t});\n\n\tit(\"applies the persisted Ultraplan plan to todo state in print mode\", async () => {\n\t\tconst artifact = makeUltraplanArtifact({\n\t\t\tactionableNextSteps: [\"Step one\", \"Step two\"],\n\t\t});\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([], artifact, () => ({\n\t\t\t\tapplied: [\n\t\t\t\t\t{ content: \"Step one\", activeForm: \"Step one\", status: \"pending\" },\n\t\t\t\t\t{ content: \"Step two\", activeForm: \"Step two\", status: \"pending\" },\n\t\t\t\t],\n\t\t\t\tdisplayText:\n\t\t\t\t\t\"Applied 2 Ultraplan step(s) from the latest persisted plan into session todo state.\\n\" +\n\t\t\t\t\t\"Source: actionable next steps. Todo total: 2.\\n\\n\" +\n\t\t\t\t\t\"The Ultraplan artifact remains preserved separately as plan state. Apply did not start execution.\",\n\t\t\t})),\n\t\t\t\"/ultraplan apply\",\n\t\t);\n\n\t\texpect(output).toContain(\"Applied 2 Ultraplan step(s)\");\n\t\texpect(output).toContain(\"session todo state\");\n\t\texpect(output).toContain(\"Apply did not start execution\");\n\t});\n\n\tit(\"throws when /ultraplan apply is called without a plan\", async () => {\n\t\tawait expect(\n\t\t\tgetPrintModeLocalCommandOutput(\n\t\t\t\tmakeSession([], undefined, () => {\n\t\t\t\t\tthrow new Error(\"No persisted Ultraplan plan found. Run /ultraplan <objective> first.\");\n\t\t\t\t}),\n\t\t\t\t\"/ultraplan apply\",\n\t\t\t),\n\t\t).rejects.toThrow(\"No persisted Ultraplan plan found\");\n\t});\n\n\tit(\"handles /ultraplan revise with instruction in print mode\", async () => {\n\t\tlet capturedInstruction: string | undefined;\n\t\tconst artifact = makeUltraplanArtifact();\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([], artifact, undefined, async (instruction: string) => {\n\t\t\t\tcapturedInstruction = instruction;\n\t\t\t\treturn {\n\t\t\t\t\tartifact: makeUltraplanArtifact({ objective: `Revised: ${instruction}` }),\n\t\t\t\t\tdisplayText: `revised: ${instruction}`,\n\t\t\t\t\trawPlannerOutput: \"{}\",\n\t\t\t\t};\n\t\t\t}),\n\t\t\t\"/ultraplan revise Add a third step to Phase 1\",\n\t\t);\n\n\t\texpect(capturedInstruction).toBe(\"Add a third step to Phase 1\");\n\t\texpect(output).toBe(\"revised: Add a third step to Phase 1\");\n\t});\n\n\tit(\"handles /ultraplan regenerate with instruction in print mode\", async () => {\n\t\tlet capturedInstruction: string | undefined;\n\t\tconst artifact = makeUltraplanArtifact();\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([], artifact, undefined, async (instruction: string) => {\n\t\t\t\tcapturedInstruction = instruction;\n\t\t\t\treturn {\n\t\t\t\t\tartifact: makeUltraplanArtifact({ objective: \"Regenerated plan\" }),\n\t\t\t\t\tdisplayText: `revised: ${instruction}`,\n\t\t\t\t\trawPlannerOutput: \"{}\",\n\t\t\t\t};\n\t\t\t}),\n\t\t\t\"/ultraplan regenerate tighten the next steps\",\n\t\t);\n\n\t\texpect(capturedInstruction).toBe(\"tighten the next steps\");\n\t\texpect(output).toBe(\"revised: tighten the next steps\");\n\t});\n\n\tit(\"returns usage when /ultraplan revise is called without instruction in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([], makeUltraplanArtifact()),\n\t\t\t\"/ultraplan revise\",\n\t\t);\n\t\texpect(output).toContain(\"Usage:\");\n\t\texpect(output).toContain(\"revise <instruction>\");\n\t});\n\n\tit(\"returns usage when /ultraplan regenerate is called without instruction in print mode\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(\n\t\t\tmakeSession([], makeUltraplanArtifact()),\n\t\t\t\"/ultraplan regenerate\",\n\t\t);\n\t\texpect(output).toContain(\"Usage:\");\n\t\texpect(output).toContain(\"regenerate <instruction>\");\n\t});\n\n\tit(\"throws when /ultraplan revise is called without an existing plan\", async () => {\n\t\tawait expect(\n\t\t\tgetPrintModeLocalCommandOutput(\n\t\t\t\tmakeSession([], undefined, undefined, async () => {\n\t\t\t\t\tthrow new Error(\"No persisted Ultraplan plan found. Run /ultraplan <objective> first.\");\n\t\t\t\t}),\n\t\t\t\t\"/ultraplan revise update the phases\",\n\t\t\t),\n\t\t).rejects.toThrow(\"No persisted Ultraplan plan found\");\n\t});\n\n\tit(\"provides updated usage message when /ultraplan is called without arguments\", async () => {\n\t\tconst output = await getPrintModeLocalCommandOutput(makeSession([]), \"/ultraplan\");\n\t\texpect(output).toContain(\"Usage:\");\n\t\texpect(output).toContain(\"revise <instruction>\");\n\t\texpect(output).toContain(\"regenerate <instruction>\");\n\t});\n});\n"]}