gsd-pi 2.18.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/cli.js +3 -3
- package/dist/onboarding.d.ts +3 -1
- package/dist/onboarding.js +77 -3
- package/dist/remote-questions-config.d.ts +1 -1
- package/dist/resources/extensions/google-search/index.ts +164 -47
- package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/dist/resources/extensions/gsd/auto.ts +690 -39
- package/dist/resources/extensions/gsd/captures.ts +384 -0
- package/dist/resources/extensions/gsd/commands.ts +654 -36
- package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/dist/resources/extensions/gsd/context-budget.ts +243 -0
- package/dist/resources/extensions/gsd/context-store.ts +195 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/dist/resources/extensions/gsd/db-writer.ts +341 -0
- package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/dist/resources/extensions/gsd/doctor.ts +283 -2
- package/dist/resources/extensions/gsd/export.ts +81 -2
- package/dist/resources/extensions/gsd/files.ts +39 -9
- package/dist/resources/extensions/gsd/git-service.ts +6 -0
- package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
- package/dist/resources/extensions/gsd/history.ts +0 -1
- package/dist/resources/extensions/gsd/index.ts +277 -1
- package/dist/resources/extensions/gsd/md-importer.ts +526 -0
- package/dist/resources/extensions/gsd/metrics.ts +84 -0
- package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/dist/resources/extensions/gsd/model-router.ts +256 -0
- package/dist/resources/extensions/gsd/notifications.ts +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/dist/resources/extensions/gsd/preferences.ts +198 -150
- package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/dist/resources/extensions/gsd/prompts/system.md +2 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/dist/resources/extensions/gsd/quick.ts +156 -0
- package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/dist/resources/extensions/gsd/skill-health.ts +417 -0
- package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/dist/resources/extensions/gsd/state.ts +30 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
- package/dist/resources/extensions/gsd/types.ts +29 -0
- package/dist/resources/extensions/gsd/undo.ts +0 -1
- package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/dist/resources/extensions/remote-questions/config.ts +4 -2
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/dist/resources/extensions/remote-questions/format.ts +166 -14
- package/dist/resources/extensions/remote-questions/manager.ts +14 -4
- package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/dist/resources/extensions/remote-questions/types.ts +2 -1
- package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/dist/resources/extensions/voice/index.ts +4 -3
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
- package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +43 -11
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -0
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +5 -0
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
- package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
- package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
- package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
- package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
- package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
- package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
- package/src/resources/extensions/google-search/index.ts +164 -47
- package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/src/resources/extensions/gsd/auto.ts +690 -39
- package/src/resources/extensions/gsd/captures.ts +384 -0
- package/src/resources/extensions/gsd/commands.ts +654 -36
- package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/src/resources/extensions/gsd/context-budget.ts +243 -0
- package/src/resources/extensions/gsd/context-store.ts +195 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/src/resources/extensions/gsd/db-writer.ts +341 -0
- package/src/resources/extensions/gsd/debug-logger.ts +178 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/src/resources/extensions/gsd/doctor.ts +283 -2
- package/src/resources/extensions/gsd/export.ts +81 -2
- package/src/resources/extensions/gsd/files.ts +39 -9
- package/src/resources/extensions/gsd/git-service.ts +6 -0
- package/src/resources/extensions/gsd/gsd-db.ts +752 -0
- package/src/resources/extensions/gsd/guided-flow.ts +26 -1
- package/src/resources/extensions/gsd/history.ts +0 -1
- package/src/resources/extensions/gsd/index.ts +277 -1
- package/src/resources/extensions/gsd/md-importer.ts +526 -0
- package/src/resources/extensions/gsd/metrics.ts +84 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/src/resources/extensions/gsd/model-router.ts +256 -0
- package/src/resources/extensions/gsd/notifications.ts +0 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/src/resources/extensions/gsd/preferences.ts +198 -150
- package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/src/resources/extensions/gsd/prompts/system.md +2 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/src/resources/extensions/gsd/quick.ts +156 -0
- package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/src/resources/extensions/gsd/skill-health.ts +417 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/src/resources/extensions/gsd/state.ts +30 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/src/resources/extensions/gsd/triage-ui.ts +175 -0
- package/src/resources/extensions/gsd/types.ts +29 -0
- package/src/resources/extensions/gsd/undo.ts +0 -1
- package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/src/resources/extensions/gsd/worktree-command.ts +18 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/src/resources/extensions/remote-questions/config.ts +4 -2
- package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/src/resources/extensions/remote-questions/format.ts +166 -14
- package/src/resources/extensions/remote-questions/manager.ts +14 -4
- package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/src/resources/extensions/remote-questions/types.ts +2 -1
- package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/src/resources/extensions/voice/index.ts +4 -3
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Tests for GSD visualizer overlay.
|
|
2
|
+
// Verifies filter mode, tab switching, and export key handling.
|
|
3
|
+
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { join, dirname } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const { assertTrue, assertEq, report } = createTestContext();
|
|
11
|
+
|
|
12
|
+
const overlaySrc = readFileSync(join(__dirname, "..", "visualizer-overlay.ts"), "utf-8");
|
|
13
|
+
|
|
14
|
+
console.log("\n=== Overlay: Tab Configuration ===");
|
|
15
|
+
|
|
16
|
+
assertTrue(
|
|
17
|
+
overlaySrc.includes("TAB_COUNT = 7"),
|
|
18
|
+
"TAB_COUNT is 7",
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
assertTrue(
|
|
22
|
+
overlaySrc.includes('"1 Progress"'),
|
|
23
|
+
"has Progress tab label",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
assertTrue(
|
|
27
|
+
overlaySrc.includes('"5 Agent"'),
|
|
28
|
+
"has Agent tab label",
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
assertTrue(
|
|
32
|
+
overlaySrc.includes('"6 Changes"'),
|
|
33
|
+
"has Changes tab label",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
assertTrue(
|
|
37
|
+
overlaySrc.includes('"7 Export"'),
|
|
38
|
+
"has Export tab label",
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
console.log("\n=== Overlay: Filter Mode ===");
|
|
42
|
+
|
|
43
|
+
assertTrue(
|
|
44
|
+
overlaySrc.includes('filterMode = false'),
|
|
45
|
+
"filterMode initialized to false",
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
assertTrue(
|
|
49
|
+
overlaySrc.includes('filterText = ""'),
|
|
50
|
+
"filterText initialized to empty string",
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
assertTrue(
|
|
54
|
+
overlaySrc.includes('filterField:'),
|
|
55
|
+
"has filterField state",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Filter mode entry via "/"
|
|
59
|
+
assertTrue(
|
|
60
|
+
overlaySrc.includes('data === "/"') || overlaySrc.includes("data === '/'"),
|
|
61
|
+
"/ key enters filter mode",
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Filter field cycling via "f"
|
|
65
|
+
assertTrue(
|
|
66
|
+
overlaySrc.includes('data === "f"') || overlaySrc.includes("data === 'f'"),
|
|
67
|
+
"f key cycles filter field",
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
console.log("\n=== Overlay: Tab Switching ===");
|
|
71
|
+
|
|
72
|
+
// Supports 1-7 keys
|
|
73
|
+
assertTrue(
|
|
74
|
+
overlaySrc.includes('"1234567"'),
|
|
75
|
+
"supports keys 1-7 for tab switching",
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Tab wraps with TAB_COUNT
|
|
79
|
+
assertTrue(
|
|
80
|
+
overlaySrc.includes("% TAB_COUNT"),
|
|
81
|
+
"tab key wraps around TAB_COUNT",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
console.log("\n=== Overlay: Export Key Interception ===");
|
|
85
|
+
|
|
86
|
+
assertTrue(
|
|
87
|
+
overlaySrc.includes("activeTab === 6"),
|
|
88
|
+
"export key handling checks for tab 7 (index 6)",
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
assertTrue(
|
|
92
|
+
overlaySrc.includes('handleExportKey'),
|
|
93
|
+
"has handleExportKey method",
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
assertTrue(
|
|
97
|
+
overlaySrc.includes('"m"') && overlaySrc.includes('"j"') && overlaySrc.includes('"s"'),
|
|
98
|
+
"handles m, j, s keys for export",
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
console.log("\n=== Overlay: Footer ===");
|
|
102
|
+
|
|
103
|
+
assertTrue(
|
|
104
|
+
overlaySrc.includes("Tab/1-7"),
|
|
105
|
+
"footer hint shows 1-7 tab range",
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
assertTrue(
|
|
109
|
+
overlaySrc.includes("/ filter"),
|
|
110
|
+
"footer hint mentions filter",
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
console.log("\n=== Overlay: Scroll Offsets ===");
|
|
114
|
+
|
|
115
|
+
assertTrue(
|
|
116
|
+
overlaySrc.includes(`new Array(TAB_COUNT).fill(0)`),
|
|
117
|
+
"scroll offsets sized to TAB_COUNT",
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
report();
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
// Tests for GSD visualizer view renderers.
|
|
2
|
+
// Tests the pure view functions with mock data — no file I/O.
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
renderProgressView,
|
|
6
|
+
renderDepsView,
|
|
7
|
+
renderMetricsView,
|
|
8
|
+
renderTimelineView,
|
|
9
|
+
renderAgentView,
|
|
10
|
+
renderChangelogView,
|
|
11
|
+
renderExportView,
|
|
12
|
+
} from "../visualizer-views.js";
|
|
13
|
+
import type { VisualizerData } from "../visualizer-data.js";
|
|
14
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
15
|
+
|
|
16
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
17
|
+
|
|
18
|
+
// ─── Mock theme ─────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
const mockTheme = {
|
|
21
|
+
fg: (_color: string, text: string) => text,
|
|
22
|
+
bold: (text: string) => text,
|
|
23
|
+
} as any;
|
|
24
|
+
|
|
25
|
+
// ─── Test data factories ────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
function makeVisualizerData(overrides: Partial<VisualizerData> = {}): VisualizerData {
|
|
28
|
+
return {
|
|
29
|
+
milestones: [],
|
|
30
|
+
phase: "executing",
|
|
31
|
+
totals: null,
|
|
32
|
+
byPhase: [],
|
|
33
|
+
bySlice: [],
|
|
34
|
+
byModel: [],
|
|
35
|
+
units: [],
|
|
36
|
+
criticalPath: {
|
|
37
|
+
milestonePath: [],
|
|
38
|
+
slicePath: [],
|
|
39
|
+
milestoneSlack: new Map(),
|
|
40
|
+
sliceSlack: new Map(),
|
|
41
|
+
},
|
|
42
|
+
remainingSliceCount: 0,
|
|
43
|
+
agentActivity: null,
|
|
44
|
+
changelog: { entries: [] },
|
|
45
|
+
...overrides,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── renderProgressView ─────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
console.log("\n=== renderProgressView ===");
|
|
52
|
+
|
|
53
|
+
{
|
|
54
|
+
const data = makeVisualizerData({
|
|
55
|
+
milestones: [
|
|
56
|
+
{
|
|
57
|
+
id: "M001",
|
|
58
|
+
title: "First Milestone",
|
|
59
|
+
status: "active",
|
|
60
|
+
dependsOn: [],
|
|
61
|
+
slices: [
|
|
62
|
+
{
|
|
63
|
+
id: "S01",
|
|
64
|
+
title: "Core Types",
|
|
65
|
+
done: true,
|
|
66
|
+
active: false,
|
|
67
|
+
risk: "low",
|
|
68
|
+
depends: [],
|
|
69
|
+
tasks: [],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "S02",
|
|
73
|
+
title: "State Engine",
|
|
74
|
+
done: false,
|
|
75
|
+
active: true,
|
|
76
|
+
risk: "high",
|
|
77
|
+
depends: ["S01"],
|
|
78
|
+
tasks: [
|
|
79
|
+
{ id: "T01", title: "Dispatch Loop", done: false, active: true },
|
|
80
|
+
{ id: "T02", title: "Session Mgmt", done: true, active: false },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "S03",
|
|
85
|
+
title: "Dashboard",
|
|
86
|
+
done: false,
|
|
87
|
+
active: false,
|
|
88
|
+
risk: "medium",
|
|
89
|
+
depends: ["S02"],
|
|
90
|
+
tasks: [],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "M002",
|
|
96
|
+
title: "Plugin Arch",
|
|
97
|
+
status: "pending",
|
|
98
|
+
dependsOn: ["M001"],
|
|
99
|
+
slices: [],
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const lines = renderProgressView(data, mockTheme, 80);
|
|
105
|
+
assertTrue(lines.length > 0, "progress view produces output");
|
|
106
|
+
assertTrue(lines.some(l => l.includes("M001")), "shows milestone M001");
|
|
107
|
+
assertTrue(lines.some(l => l.includes("S01")), "shows slice S01");
|
|
108
|
+
assertTrue(lines.some(l => l.includes("T01")), "shows task T01 for active slice");
|
|
109
|
+
assertTrue(lines.some(l => l.includes("M002")), "shows milestone M002");
|
|
110
|
+
assertTrue(lines.some(l => l.includes("depends on M001")), "shows dependency note");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
const data = makeVisualizerData({ milestones: [] });
|
|
115
|
+
const lines = renderProgressView(data, mockTheme, 80);
|
|
116
|
+
assertEq(lines.length, 0, "empty milestones produce no lines");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ─── Risk Heatmap ───────────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
console.log("\n=== Risk Heatmap ===");
|
|
122
|
+
|
|
123
|
+
{
|
|
124
|
+
const data = makeVisualizerData({
|
|
125
|
+
milestones: [
|
|
126
|
+
{
|
|
127
|
+
id: "M001",
|
|
128
|
+
title: "First",
|
|
129
|
+
status: "active",
|
|
130
|
+
dependsOn: [],
|
|
131
|
+
slices: [
|
|
132
|
+
{ id: "S01", title: "A", done: true, active: false, risk: "low", depends: [], tasks: [] },
|
|
133
|
+
{ id: "S02", title: "B", done: false, active: true, risk: "high", depends: [], tasks: [] },
|
|
134
|
+
{ id: "S03", title: "C", done: false, active: false, risk: "medium", depends: [], tasks: [] },
|
|
135
|
+
{ id: "S04", title: "D", done: false, active: false, risk: "high", depends: [], tasks: [] },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const lines = renderProgressView(data, mockTheme, 80);
|
|
142
|
+
assertTrue(lines.some(l => l.includes("Risk Heatmap")), "heatmap header present");
|
|
143
|
+
assertTrue(lines.some(l => l.includes("██")), "heatmap has colored blocks");
|
|
144
|
+
assertTrue(lines.some(l => l.includes("low") && l.includes("med") && l.includes("high")), "heatmap legend present");
|
|
145
|
+
assertTrue(lines.some(l => l.includes("1 low, 1 med, 2 high")), "risk summary counts");
|
|
146
|
+
assertTrue(lines.some(l => l.includes("1 high-risk not started")), "high-risk not started warning");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ─── Search/Filter ──────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
console.log("\n=== Search/Filter ===");
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
const data = makeVisualizerData({
|
|
155
|
+
milestones: [
|
|
156
|
+
{
|
|
157
|
+
id: "M001",
|
|
158
|
+
title: "Auth",
|
|
159
|
+
status: "active",
|
|
160
|
+
dependsOn: [],
|
|
161
|
+
slices: [
|
|
162
|
+
{ id: "S01", title: "JWT", done: false, active: false, risk: "low", depends: [], tasks: [] },
|
|
163
|
+
{ id: "S02", title: "OAuth", done: false, active: false, risk: "high", depends: [], tasks: [] },
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "M002",
|
|
168
|
+
title: "Dashboard",
|
|
169
|
+
status: "pending",
|
|
170
|
+
dependsOn: ["M001"],
|
|
171
|
+
slices: [],
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Filter by keyword "auth"
|
|
177
|
+
const filtered = renderProgressView(data, mockTheme, 80, { text: "auth", field: "all" });
|
|
178
|
+
assertTrue(filtered.some(l => l.includes("M001")), "filter shows matching milestone");
|
|
179
|
+
assertTrue(filtered.some(l => l.includes("Filter (all): auth")), "filter indicator present");
|
|
180
|
+
|
|
181
|
+
// Filter by risk "high"
|
|
182
|
+
const riskFiltered = renderProgressView(data, mockTheme, 80, { text: "high", field: "risk" });
|
|
183
|
+
assertTrue(riskFiltered.some(l => l.includes("M001")), "risk filter shows milestone with high-risk slice");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ─── renderDepsView ─────────────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
console.log("\n=== renderDepsView ===");
|
|
189
|
+
|
|
190
|
+
{
|
|
191
|
+
const data = makeVisualizerData({
|
|
192
|
+
milestones: [
|
|
193
|
+
{
|
|
194
|
+
id: "M001",
|
|
195
|
+
title: "First",
|
|
196
|
+
status: "active",
|
|
197
|
+
dependsOn: [],
|
|
198
|
+
slices: [
|
|
199
|
+
{ id: "S01", title: "A", done: false, active: true, risk: "low", depends: [], tasks: [] },
|
|
200
|
+
{ id: "S02", title: "B", done: false, active: false, risk: "low", depends: ["S01"], tasks: [] },
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: "M002",
|
|
205
|
+
title: "Second",
|
|
206
|
+
status: "pending",
|
|
207
|
+
dependsOn: ["M001"],
|
|
208
|
+
slices: [],
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
criticalPath: {
|
|
212
|
+
milestonePath: ["M001", "M002"],
|
|
213
|
+
slicePath: ["S01", "S02"],
|
|
214
|
+
milestoneSlack: new Map([["M001", 0], ["M002", 0]]),
|
|
215
|
+
sliceSlack: new Map([["S01", 0], ["S02", 0]]),
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const lines = renderDepsView(data, mockTheme, 80);
|
|
220
|
+
assertTrue(lines.length > 0, "deps view produces output");
|
|
221
|
+
assertTrue(lines.some(l => l.includes("M001") && l.includes("M002")), "shows milestone dep edge");
|
|
222
|
+
assertTrue(lines.some(l => l.includes("S01") && l.includes("S02")), "shows slice dep edge");
|
|
223
|
+
assertTrue(lines.some(l => l.includes("Critical Path")), "shows critical path section");
|
|
224
|
+
assertTrue(lines.some(l => l.includes("[CRITICAL]")), "shows CRITICAL badge");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
{
|
|
228
|
+
const data = makeVisualizerData({
|
|
229
|
+
milestones: [
|
|
230
|
+
{ id: "M001", title: "Only", status: "active", dependsOn: [], slices: [] },
|
|
231
|
+
],
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const lines = renderDepsView(data, mockTheme, 80);
|
|
235
|
+
assertTrue(lines.some(l => l.includes("No milestone dependencies")), "shows no-deps message");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ─── renderMetricsView ──────────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
console.log("\n=== renderMetricsView ===");
|
|
241
|
+
|
|
242
|
+
{
|
|
243
|
+
const data = makeVisualizerData({
|
|
244
|
+
totals: {
|
|
245
|
+
units: 5,
|
|
246
|
+
tokens: { input: 1000, output: 500, cacheRead: 200, cacheWrite: 100, total: 1800 },
|
|
247
|
+
cost: 2.50,
|
|
248
|
+
duration: 60000,
|
|
249
|
+
toolCalls: 15,
|
|
250
|
+
assistantMessages: 10,
|
|
251
|
+
userMessages: 5,
|
|
252
|
+
totalTruncationSections: 0,
|
|
253
|
+
continueHereFiredCount: 0,
|
|
254
|
+
},
|
|
255
|
+
byPhase: [
|
|
256
|
+
{
|
|
257
|
+
phase: "execution",
|
|
258
|
+
units: 3,
|
|
259
|
+
tokens: { input: 600, output: 300, cacheRead: 100, cacheWrite: 50, total: 1050 },
|
|
260
|
+
cost: 1.50,
|
|
261
|
+
duration: 40000,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
phase: "planning",
|
|
265
|
+
units: 2,
|
|
266
|
+
tokens: { input: 400, output: 200, cacheRead: 100, cacheWrite: 50, total: 750 },
|
|
267
|
+
cost: 1.00,
|
|
268
|
+
duration: 20000,
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
byModel: [
|
|
272
|
+
{
|
|
273
|
+
model: "claude-opus-4-6",
|
|
274
|
+
units: 5,
|
|
275
|
+
tokens: { input: 1000, output: 500, cacheRead: 200, cacheWrite: 100, total: 1800 },
|
|
276
|
+
cost: 2.50,
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
bySlice: [
|
|
280
|
+
{ sliceId: "M001/S01", units: 3, tokens: { input: 600, output: 300, cacheRead: 100, cacheWrite: 50, total: 1050 }, cost: 1.50, duration: 40000 },
|
|
281
|
+
{ sliceId: "M001/S02", units: 2, tokens: { input: 400, output: 200, cacheRead: 100, cacheWrite: 50, total: 750 }, cost: 1.00, duration: 20000 },
|
|
282
|
+
],
|
|
283
|
+
remainingSliceCount: 3,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const lines = renderMetricsView(data, mockTheme, 80);
|
|
287
|
+
assertTrue(lines.length > 0, "metrics view produces output");
|
|
288
|
+
assertTrue(lines.some(l => l.includes("$2.50")), "shows total cost");
|
|
289
|
+
assertTrue(lines.some(l => l.includes("execution")), "shows phase name");
|
|
290
|
+
assertTrue(lines.some(l => l.includes("claude-opus-4-6")), "shows model name");
|
|
291
|
+
assertTrue(lines.some(l => l.includes("Projections")), "shows projections section");
|
|
292
|
+
assertTrue(lines.some(l => l.includes("Avg cost/slice")), "shows avg cost per slice");
|
|
293
|
+
assertTrue(lines.some(l => l.includes("Projected remaining")), "shows projected remaining");
|
|
294
|
+
assertTrue(lines.some(l => l.includes("Burn rate")), "shows burn rate");
|
|
295
|
+
assertTrue(lines.some(l => l.includes("Cost trend")), "shows sparkline");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
{
|
|
299
|
+
const data = makeVisualizerData({ totals: null });
|
|
300
|
+
const lines = renderMetricsView(data, mockTheme, 80);
|
|
301
|
+
assertTrue(lines.some(l => l.includes("No metrics data")), "shows no-data message");
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ─── renderTimelineView ─────────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
console.log("\n=== renderTimelineView ===");
|
|
307
|
+
|
|
308
|
+
{
|
|
309
|
+
const now = Date.now();
|
|
310
|
+
const data = makeVisualizerData({
|
|
311
|
+
units: [
|
|
312
|
+
{
|
|
313
|
+
type: "execute-task",
|
|
314
|
+
id: "M001/S01/T01",
|
|
315
|
+
model: "claude-opus-4-6",
|
|
316
|
+
startedAt: now - 120000,
|
|
317
|
+
finishedAt: now - 60000,
|
|
318
|
+
tokens: { input: 500, output: 200, cacheRead: 100, cacheWrite: 50, total: 850 },
|
|
319
|
+
cost: 0.42,
|
|
320
|
+
toolCalls: 5,
|
|
321
|
+
assistantMessages: 3,
|
|
322
|
+
userMessages: 1,
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
type: "plan-slice",
|
|
326
|
+
id: "M001/S02",
|
|
327
|
+
model: "claude-opus-4-6",
|
|
328
|
+
startedAt: now - 60000,
|
|
329
|
+
finishedAt: now - 30000,
|
|
330
|
+
tokens: { input: 300, output: 150, cacheRead: 50, cacheWrite: 25, total: 525 },
|
|
331
|
+
cost: 0.18,
|
|
332
|
+
toolCalls: 2,
|
|
333
|
+
assistantMessages: 2,
|
|
334
|
+
userMessages: 1,
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Wide terminal — Gantt view
|
|
340
|
+
const ganttLines = renderTimelineView(data, mockTheme, 120);
|
|
341
|
+
assertTrue(ganttLines.length >= 2, "gantt view produces lines for each unit");
|
|
342
|
+
|
|
343
|
+
// Narrow terminal — list view
|
|
344
|
+
const listLines = renderTimelineView(data, mockTheme, 80);
|
|
345
|
+
assertTrue(listLines.length >= 2, "list view produces lines for each unit");
|
|
346
|
+
assertTrue(listLines.some(l => l.includes("execute-task")), "shows unit type");
|
|
347
|
+
assertTrue(listLines.some(l => l.includes("M001/S01/T01")), "shows unit id");
|
|
348
|
+
assertTrue(listLines.some(l => l.includes("$0.42")), "shows unit cost");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
{
|
|
352
|
+
const data = makeVisualizerData({ units: [] });
|
|
353
|
+
const lines = renderTimelineView(data, mockTheme, 80);
|
|
354
|
+
assertTrue(lines.some(l => l.includes("No execution history")), "shows empty message");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ─── renderAgentView ────────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
console.log("\n=== renderAgentView ===");
|
|
360
|
+
|
|
361
|
+
{
|
|
362
|
+
const now = Date.now();
|
|
363
|
+
const data = makeVisualizerData({
|
|
364
|
+
agentActivity: {
|
|
365
|
+
currentUnit: { type: "execute-task", id: "M001/S02/T03", startedAt: now - 60000 },
|
|
366
|
+
elapsed: 60000,
|
|
367
|
+
completedUnits: 8,
|
|
368
|
+
totalSlices: 15,
|
|
369
|
+
completionRate: 2.4,
|
|
370
|
+
active: true,
|
|
371
|
+
sessionCost: 1.23,
|
|
372
|
+
sessionTokens: 45200,
|
|
373
|
+
},
|
|
374
|
+
units: [
|
|
375
|
+
{
|
|
376
|
+
type: "execute-task", id: "M001/S01/T01", model: "claude-opus-4-6",
|
|
377
|
+
startedAt: now - 300000, finishedAt: now - 240000,
|
|
378
|
+
tokens: { input: 500, output: 200, cacheRead: 100, cacheWrite: 50, total: 850 },
|
|
379
|
+
cost: 0.12, toolCalls: 5, assistantMessages: 3, userMessages: 1,
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const lines = renderAgentView(data, mockTheme, 80);
|
|
385
|
+
assertTrue(lines.length > 0, "agent view produces output");
|
|
386
|
+
assertTrue(lines.some(l => l.includes("ACTIVE")), "shows active status");
|
|
387
|
+
assertTrue(lines.some(l => l.includes("M001/S02/T03")), "shows current unit");
|
|
388
|
+
assertTrue(lines.some(l => l.includes("8/15")), "shows progress fraction");
|
|
389
|
+
assertTrue(lines.some(l => l.includes("2.4 units/hr")), "shows completion rate");
|
|
390
|
+
assertTrue(lines.some(l => l.includes("$1.23")), "shows session cost");
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
{
|
|
394
|
+
const data = makeVisualizerData({ agentActivity: null });
|
|
395
|
+
const lines = renderAgentView(data, mockTheme, 80);
|
|
396
|
+
assertTrue(lines.some(l => l.includes("No agent activity")), "shows no-activity message");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
{
|
|
400
|
+
const data = makeVisualizerData({
|
|
401
|
+
agentActivity: {
|
|
402
|
+
currentUnit: null,
|
|
403
|
+
elapsed: 0,
|
|
404
|
+
completedUnits: 5,
|
|
405
|
+
totalSlices: 10,
|
|
406
|
+
completionRate: 1.5,
|
|
407
|
+
active: false,
|
|
408
|
+
sessionCost: 0.50,
|
|
409
|
+
sessionTokens: 20000,
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const lines = renderAgentView(data, mockTheme, 80);
|
|
414
|
+
assertTrue(lines.some(l => l.includes("IDLE")), "shows idle status");
|
|
415
|
+
assertTrue(lines.some(l => l.includes("Not in auto mode")), "shows not-in-auto message");
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ─── renderChangelogView ────────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
console.log("\n=== renderChangelogView ===");
|
|
421
|
+
|
|
422
|
+
{
|
|
423
|
+
const data = makeVisualizerData({
|
|
424
|
+
changelog: {
|
|
425
|
+
entries: [
|
|
426
|
+
{
|
|
427
|
+
milestoneId: "M001",
|
|
428
|
+
sliceId: "S01",
|
|
429
|
+
title: "Core Authentication Setup",
|
|
430
|
+
oneLiner: "Added JWT-based auth with refresh token rotation",
|
|
431
|
+
filesModified: [
|
|
432
|
+
{ path: "src/auth/jwt.ts", description: "JWT token generation and validation" },
|
|
433
|
+
{ path: "src/auth/middleware.ts", description: "Express middleware for auth checks" },
|
|
434
|
+
],
|
|
435
|
+
completedAt: "2026-03-15T14:30:00Z",
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const lines = renderChangelogView(data, mockTheme, 80);
|
|
442
|
+
assertTrue(lines.length > 0, "changelog view produces output");
|
|
443
|
+
assertTrue(lines.some(l => l.includes("M001/S01")), "shows slice reference");
|
|
444
|
+
assertTrue(lines.some(l => l.includes("Core Authentication Setup")), "shows entry title");
|
|
445
|
+
assertTrue(lines.some(l => l.includes("JWT-based auth")), "shows one-liner");
|
|
446
|
+
assertTrue(lines.some(l => l.includes("src/auth/jwt.ts")), "shows modified file");
|
|
447
|
+
assertTrue(lines.some(l => l.includes("2026-03-15")), "shows completed date");
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
{
|
|
451
|
+
const data = makeVisualizerData({ changelog: { entries: [] } });
|
|
452
|
+
const lines = renderChangelogView(data, mockTheme, 80);
|
|
453
|
+
assertTrue(lines.some(l => l.includes("No completed slices")), "shows empty state");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ─── renderExportView ───────────────────────────────────────────────────────
|
|
457
|
+
|
|
458
|
+
console.log("\n=== renderExportView ===");
|
|
459
|
+
|
|
460
|
+
{
|
|
461
|
+
const data = makeVisualizerData();
|
|
462
|
+
const lines = renderExportView(data, mockTheme, 80);
|
|
463
|
+
assertTrue(lines.some(l => l.includes("Export Options")), "shows export header");
|
|
464
|
+
assertTrue(lines.some(l => l.includes("[m]")), "shows markdown option");
|
|
465
|
+
assertTrue(lines.some(l => l.includes("[j]")), "shows json option");
|
|
466
|
+
assertTrue(lines.some(l => l.includes("[s]")), "shows snapshot option");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
{
|
|
470
|
+
const data = makeVisualizerData();
|
|
471
|
+
const lines = renderExportView(data, mockTheme, 80, "/tmp/export-2026.md");
|
|
472
|
+
assertTrue(lines.some(l => l.includes("Last export:")), "shows last export path");
|
|
473
|
+
assertTrue(lines.some(l => l.includes("/tmp/export-2026.md")), "shows specific export path");
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ─── Report ─────────────────────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
report();
|