gsd-pi 2.19.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-prompts.ts +103 -24
- package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/dist/resources/extensions/gsd/auto.ts +424 -30
- package/dist/resources/extensions/gsd/commands.ts +518 -36
- 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 +41 -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 +39 -3
- package/dist/resources/extensions/gsd/notifications.ts +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +70 -1
- package/dist/resources/extensions/gsd/preferences.ts +125 -150
- 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/system.md +2 -1
- 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/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/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/model-isolation.test.ts +99 -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 +262 -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/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/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 +92 -0
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +228 -5
- 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/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 +352 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +166 -22
- package/dist/resources/extensions/gsd/visualizer-views.ts +464 -2
- 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 +2 -4
- package/dist/resources/extensions/remote-questions/format.ts +154 -8
- package/dist/resources/extensions/remote-questions/manager.ts +9 -7
- 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-prompts.ts +103 -24
- package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/src/resources/extensions/gsd/auto.ts +424 -30
- package/src/resources/extensions/gsd/commands.ts +518 -36
- 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 +41 -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 +39 -3
- package/src/resources/extensions/gsd/notifications.ts +0 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +70 -1
- package/src/resources/extensions/gsd/preferences.ts +125 -150
- 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/system.md +2 -1
- 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/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/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/model-isolation.test.ts +99 -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 +262 -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/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/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 +92 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +228 -5
- 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/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 +352 -1
- package/src/resources/extensions/gsd/visualizer-overlay.ts +166 -22
- package/src/resources/extensions/gsd/visualizer-views.ts +464 -2
- 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 +2 -4
- package/src/resources/extensions/remote-questions/format.ts +154 -8
- package/src/resources/extensions/remote-questions/manager.ts +9 -7
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdtempSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import {
|
|
@@ -65,6 +65,30 @@ console.log("\n=== runtime record cleanup ===");
|
|
|
65
65
|
assertEq(loaded, null, "record removed");
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
console.log("\n=== hook unit type sanitization (slash in unitType) ===");
|
|
69
|
+
{
|
|
70
|
+
// Hook units have unitType like "hook/code-review" with a slash
|
|
71
|
+
// This should NOT create a subdirectory - the slash must be sanitized
|
|
72
|
+
const hookRecord = writeUnitRuntimeRecord(base, "hook/code-review", "M100/S02/T10", 2000, { phase: "dispatched" });
|
|
73
|
+
assertEq(hookRecord.unitType, "hook/code-review", "unitType preserved in record");
|
|
74
|
+
assertEq(hookRecord.unitId, "M100/S02/T10", "unitId preserved in record");
|
|
75
|
+
|
|
76
|
+
const loaded = readUnitRuntimeRecord(base, "hook/code-review", "M100/S02/T10");
|
|
77
|
+
assertTrue(loaded !== null, "hook record readable");
|
|
78
|
+
assertEq(loaded!.phase, "dispatched", "hook phase correct");
|
|
79
|
+
|
|
80
|
+
// Verify the file is in the units dir, not in a subdirectory
|
|
81
|
+
const unitsDir = join(base, ".gsd", "runtime", "units");
|
|
82
|
+
const files = readdirSync(unitsDir);
|
|
83
|
+
const hookFile = files.find((f: string) => f.includes("hook-code-review"));
|
|
84
|
+
assertTrue(hookFile !== undefined, "hook file exists with sanitized name");
|
|
85
|
+
assertTrue(!files.some((f: string) => f === "hook"), "no 'hook' subdirectory created");
|
|
86
|
+
|
|
87
|
+
clearUnitRuntimeRecord(base, "hook/code-review", "M100/S02/T10");
|
|
88
|
+
const cleared = readUnitRuntimeRecord(base, "hook/code-review", "M100/S02/T10");
|
|
89
|
+
assertEq(cleared, null, "hook record removed");
|
|
90
|
+
}
|
|
91
|
+
|
|
68
92
|
// ─── Must-have durability integration tests ───────────────────────────────
|
|
69
93
|
|
|
70
94
|
// Create a separate temp base for must-have tests to avoid interference
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Tests for critical path algorithm.
|
|
2
|
+
// Tests computeCriticalPath with known DAG structures.
|
|
3
|
+
|
|
4
|
+
import { computeCriticalPath } from "../visualizer-data.js";
|
|
5
|
+
import type { VisualizerMilestone } from "../visualizer-data.js";
|
|
6
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
7
|
+
|
|
8
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
9
|
+
|
|
10
|
+
function makeMs(id: string, status: "complete" | "active" | "pending", dependsOn: string[], slices: any[] = []): VisualizerMilestone {
|
|
11
|
+
return { id, title: id, status, dependsOn, slices };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function makeSlice(id: string, done: boolean, depends: string[] = []) {
|
|
15
|
+
return { id, title: id, done, active: false, risk: "low", depends, tasks: [] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ─── Linear chain ───────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
console.log("\n=== Critical Path: Linear Chain ===");
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
// M001 -> M002 -> M003
|
|
24
|
+
const milestones = [
|
|
25
|
+
makeMs("M001", "complete", []),
|
|
26
|
+
makeMs("M002", "active", ["M001"], [
|
|
27
|
+
makeSlice("S01", true),
|
|
28
|
+
makeSlice("S02", false, ["S01"]),
|
|
29
|
+
]),
|
|
30
|
+
makeMs("M003", "pending", ["M002"]),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const cp = computeCriticalPath(milestones);
|
|
34
|
+
assertTrue(cp.milestonePath.length > 0, "linear chain has critical path");
|
|
35
|
+
assertTrue(cp.milestonePath.includes("M002"), "M002 is on critical path");
|
|
36
|
+
assertTrue(cp.milestonePath.includes("M003"), "M003 is on critical path");
|
|
37
|
+
assertEq(cp.milestoneSlack.get("M002"), 0, "M002 has zero slack");
|
|
38
|
+
assertEq(cp.milestoneSlack.get("M003"), 0, "M003 has zero slack");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── Diamond DAG ────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
console.log("\n=== Critical Path: Diamond DAG ===");
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
// M001 -> M002 -> M004
|
|
47
|
+
// M001 -> M003 -> M004
|
|
48
|
+
// M002 has 3 incomplete slices, M003 has 1 incomplete slice
|
|
49
|
+
const milestones = [
|
|
50
|
+
makeMs("M001", "complete", []),
|
|
51
|
+
makeMs("M002", "active", ["M001"], [
|
|
52
|
+
makeSlice("S01", false),
|
|
53
|
+
makeSlice("S02", false),
|
|
54
|
+
makeSlice("S03", false),
|
|
55
|
+
]),
|
|
56
|
+
makeMs("M003", "pending", ["M001"], [
|
|
57
|
+
makeSlice("S01", false),
|
|
58
|
+
]),
|
|
59
|
+
makeMs("M004", "pending", ["M002", "M003"]),
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const cp = computeCriticalPath(milestones);
|
|
63
|
+
assertTrue(cp.milestonePath.length >= 2, "diamond DAG has critical path");
|
|
64
|
+
// M002 has weight 3 (3 incomplete), M003 has weight 1
|
|
65
|
+
// Critical path should go through M002 (longer)
|
|
66
|
+
assertTrue(cp.milestonePath.includes("M002"), "M002 (heavier) is on critical path");
|
|
67
|
+
|
|
68
|
+
// M003 should have non-zero slack since it's lighter
|
|
69
|
+
const m003Slack = cp.milestoneSlack.get("M003") ?? -1;
|
|
70
|
+
assertTrue(m003Slack > 0, "M003 has positive slack (lighter branch)");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Independent branches ───────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
console.log("\n=== Critical Path: Independent Branches ===");
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
// M001 (no deps), M002 (no deps), M003 (no deps)
|
|
79
|
+
const milestones = [
|
|
80
|
+
makeMs("M001", "active", [], [makeSlice("S01", false)]),
|
|
81
|
+
makeMs("M002", "pending", [], [makeSlice("S01", false), makeSlice("S02", false)]),
|
|
82
|
+
makeMs("M003", "pending", [], [makeSlice("S01", false)]),
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const cp = computeCriticalPath(milestones);
|
|
86
|
+
assertTrue(cp.milestonePath.length >= 1, "independent branches have at least one critical node");
|
|
87
|
+
// M002 has the most incomplete slices, should be critical
|
|
88
|
+
assertTrue(cp.milestonePath.includes("M002"), "M002 (longest) is on critical path");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ─── Slice-level critical path ──────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
console.log("\n=== Critical Path: Slice-level ===");
|
|
94
|
+
|
|
95
|
+
{
|
|
96
|
+
// Active milestone with slice dependencies: S01 -> S02 -> S04, S01 -> S03
|
|
97
|
+
const milestones = [
|
|
98
|
+
makeMs("M001", "active", [], [
|
|
99
|
+
makeSlice("S01", true),
|
|
100
|
+
makeSlice("S02", false, ["S01"]),
|
|
101
|
+
makeSlice("S03", false, ["S01"]),
|
|
102
|
+
makeSlice("S04", false, ["S02"]),
|
|
103
|
+
]),
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const cp = computeCriticalPath(milestones);
|
|
107
|
+
assertTrue(cp.slicePath.length > 0, "has slice-level critical path");
|
|
108
|
+
assertTrue(cp.slicePath.includes("S02"), "S02 is on slice critical path");
|
|
109
|
+
assertTrue(cp.slicePath.includes("S04"), "S04 is on slice critical path");
|
|
110
|
+
|
|
111
|
+
// S03 should have non-zero slack (it's a shorter branch)
|
|
112
|
+
const s03Slack = cp.sliceSlack.get("S03") ?? -1;
|
|
113
|
+
assertTrue(s03Slack > 0, "S03 has positive slack (shorter branch)");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── Empty milestones ───────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
console.log("\n=== Critical Path: Empty ===");
|
|
119
|
+
|
|
120
|
+
{
|
|
121
|
+
const cp = computeCriticalPath([]);
|
|
122
|
+
assertEq(cp.milestonePath.length, 0, "empty milestones produce empty path");
|
|
123
|
+
assertEq(cp.slicePath.length, 0, "empty milestones produce empty slice path");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ─── Single milestone ───────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
console.log("\n=== Critical Path: Single Milestone ===");
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
const milestones = [
|
|
132
|
+
makeMs("M001", "active", [], [
|
|
133
|
+
makeSlice("S01", false),
|
|
134
|
+
makeSlice("S02", false),
|
|
135
|
+
]),
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const cp = computeCriticalPath(milestones);
|
|
139
|
+
assertTrue(cp.milestonePath.length === 1, "single milestone is its own critical path");
|
|
140
|
+
assertEq(cp.milestonePath[0], "M001", "M001 is the critical node");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ─── Report ─────────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
report();
|
|
@@ -35,12 +35,38 @@ assertTrue(
|
|
|
35
35
|
"exports VisualizerTask interface",
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
+
// New interfaces
|
|
39
|
+
assertTrue(
|
|
40
|
+
dataSrc.includes("export interface CriticalPathInfo"),
|
|
41
|
+
"exports CriticalPathInfo interface",
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
assertTrue(
|
|
45
|
+
dataSrc.includes("export interface AgentActivityInfo"),
|
|
46
|
+
"exports AgentActivityInfo interface",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
assertTrue(
|
|
50
|
+
dataSrc.includes("export interface ChangelogEntry"),
|
|
51
|
+
"exports ChangelogEntry interface",
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
assertTrue(
|
|
55
|
+
dataSrc.includes("export interface ChangelogInfo"),
|
|
56
|
+
"exports ChangelogInfo interface",
|
|
57
|
+
);
|
|
58
|
+
|
|
38
59
|
// Function export
|
|
39
60
|
assertTrue(
|
|
40
61
|
dataSrc.includes("export async function loadVisualizerData"),
|
|
41
62
|
"exports loadVisualizerData function",
|
|
42
63
|
);
|
|
43
64
|
|
|
65
|
+
assertTrue(
|
|
66
|
+
dataSrc.includes("export function computeCriticalPath"),
|
|
67
|
+
"exports computeCriticalPath function",
|
|
68
|
+
);
|
|
69
|
+
|
|
44
70
|
// Data source usage
|
|
45
71
|
assertTrue(
|
|
46
72
|
dataSrc.includes("deriveState"),
|
|
@@ -62,6 +88,11 @@ assertTrue(
|
|
|
62
88
|
"uses parsePlan for plan parsing",
|
|
63
89
|
);
|
|
64
90
|
|
|
91
|
+
assertTrue(
|
|
92
|
+
dataSrc.includes("parseSummary"),
|
|
93
|
+
"uses parseSummary for changelog parsing",
|
|
94
|
+
);
|
|
95
|
+
|
|
65
96
|
assertTrue(
|
|
66
97
|
dataSrc.includes("getLedger"),
|
|
67
98
|
"uses getLedger for in-memory metrics",
|
|
@@ -113,6 +144,27 @@ assertTrue(
|
|
|
113
144
|
"VisualizerData has units array",
|
|
114
145
|
);
|
|
115
146
|
|
|
147
|
+
// New data model fields
|
|
148
|
+
assertTrue(
|
|
149
|
+
dataSrc.includes("criticalPath: CriticalPathInfo"),
|
|
150
|
+
"VisualizerData has criticalPath field",
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
assertTrue(
|
|
154
|
+
dataSrc.includes("remainingSliceCount: number"),
|
|
155
|
+
"VisualizerData has remainingSliceCount field",
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
assertTrue(
|
|
159
|
+
dataSrc.includes("agentActivity: AgentActivityInfo | null"),
|
|
160
|
+
"VisualizerData has agentActivity field",
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
assertTrue(
|
|
164
|
+
dataSrc.includes("changelog: ChangelogInfo"),
|
|
165
|
+
"VisualizerData has changelog field",
|
|
166
|
+
);
|
|
167
|
+
|
|
116
168
|
// Verify overlay source exists and imports data module
|
|
117
169
|
const overlayPath = join(__dirname, "..", "visualizer-overlay.ts");
|
|
118
170
|
const overlaySrc = readFileSync(overlayPath, "utf-8");
|
|
@@ -149,6 +201,21 @@ assertTrue(
|
|
|
149
201
|
"overlay delegates to renderTimelineView",
|
|
150
202
|
);
|
|
151
203
|
|
|
204
|
+
assertTrue(
|
|
205
|
+
overlaySrc.includes("renderAgentView"),
|
|
206
|
+
"overlay delegates to renderAgentView",
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
assertTrue(
|
|
210
|
+
overlaySrc.includes("renderChangelogView"),
|
|
211
|
+
"overlay delegates to renderChangelogView",
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
assertTrue(
|
|
215
|
+
overlaySrc.includes("renderExportView"),
|
|
216
|
+
"overlay delegates to renderExportView",
|
|
217
|
+
);
|
|
218
|
+
|
|
152
219
|
assertTrue(
|
|
153
220
|
overlaySrc.includes("handleInput"),
|
|
154
221
|
"overlay has handleInput method",
|
|
@@ -174,6 +241,31 @@ assertTrue(
|
|
|
174
241
|
"overlay tracks per-tab scroll offsets",
|
|
175
242
|
);
|
|
176
243
|
|
|
244
|
+
assertTrue(
|
|
245
|
+
overlaySrc.includes("filterMode"),
|
|
246
|
+
"overlay has filterMode state",
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
assertTrue(
|
|
250
|
+
overlaySrc.includes("filterText"),
|
|
251
|
+
"overlay has filterText state",
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
assertTrue(
|
|
255
|
+
overlaySrc.includes("filterField"),
|
|
256
|
+
"overlay has filterField state",
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
assertTrue(
|
|
260
|
+
overlaySrc.includes("TAB_COUNT"),
|
|
261
|
+
"overlay defines TAB_COUNT",
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
assertTrue(
|
|
265
|
+
overlaySrc.includes("7 Export"),
|
|
266
|
+
"overlay has 7 tab labels",
|
|
267
|
+
);
|
|
268
|
+
|
|
177
269
|
// Verify commands.ts integration
|
|
178
270
|
const commandsPath = join(__dirname, "..", "commands.ts");
|
|
179
271
|
const commandsSrc = readFileSync(commandsPath, "utf-8");
|
|
@@ -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();
|