gsd-pi 2.66.1-dev.ed243f2 → 2.67.0-dev.43b0159
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/dist/claude-cli-check.d.ts +8 -0
- package/dist/claude-cli-check.js +36 -0
- package/dist/cli.js +40 -0
- package/dist/onboarding.js +19 -2
- package/dist/resources/extensions/ask-user-questions.js +79 -11
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +4 -3
- package/dist/resources/extensions/claude-code-cli/readiness.js +63 -12
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +10 -3
- package/dist/resources/extensions/gsd/auto/loop.js +13 -1
- package/dist/resources/extensions/gsd/auto/phases.js +22 -3
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/session.js +1 -1
- package/dist/resources/extensions/gsd/auto-dashboard.js +65 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +30 -28
- package/dist/resources/extensions/gsd/auto-model-selection.js +12 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +173 -25
- package/dist/resources/extensions/gsd/auto-recovery.js +11 -12
- package/dist/resources/extensions/gsd/auto.js +13 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +18 -6
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +59 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +8 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +186 -14
- package/dist/resources/extensions/gsd/codebase-generator.js +4 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/dispatcher.js +1 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +94 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +49 -9
- package/dist/resources/extensions/gsd/context-store.js +134 -2
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +3 -1
- package/dist/resources/extensions/gsd/detection.js +6 -0
- package/dist/resources/extensions/gsd/files.js +19 -2
- package/dist/resources/extensions/gsd/guided-flow.js +12 -8
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +2 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +3 -1
- package/dist/resources/extensions/gsd/preferences.js +6 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/dist/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/dist/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/dist/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +2 -1
- package/dist/resources/extensions/gsd/state.js +2 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.js +27 -26
- package/dist/resources/extensions/gsd/workflow-reconcile.js +46 -7
- package/dist/resources/extensions/remote-questions/manager.js +8 -0
- package/dist/resources/extensions/shared/interview-ui.js +10 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{6502.8874bcae249c02e1.js → 6502.b804e48b7919f55e.js} +3 -3
- package/dist/web/standalone/.next/static/chunks/{webpack-9fed74684e1c5bb1.js → webpack-65f0501b197d1c49.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -3
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/json-parse.js +11 -1
- package/packages/pi-ai/dist/utils/json-parse.js.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js +60 -1
- package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js +14 -0
- package/packages/pi-ai/dist/utils/tests/json-parse.test.js.map +1 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +10 -0
- package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +4 -3
- package/packages/pi-ai/src/utils/json-parse.ts +11 -1
- package/packages/pi-ai/src/utils/repair-tool-json.ts +69 -1
- package/packages/pi-ai/src/utils/tests/json-parse.test.ts +17 -0
- package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +13 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +16 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +58 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +58 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +9 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +4 -0
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +69 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +66 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +5 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +18 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +11 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +2 -2
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +13 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +35 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/tui.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +43 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +9 -7
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js +54 -0
- package/packages/pi-tui/dist/components/__tests__/editor.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +3 -1
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +14 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +6 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +8 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +15 -0
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +43 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +50 -0
- package/packages/pi-tui/src/autocomplete.ts +9 -7
- package/packages/pi-tui/src/components/__tests__/editor.test.ts +64 -0
- package/packages/pi-tui/src/components/editor.ts +14 -3
- package/packages/pi-tui/src/stdin-buffer.ts +7 -0
- package/packages/pi-tui/src/tui.ts +9 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +103 -11
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +4 -3
- package/src/resources/extensions/claude-code-cli/readiness.ts +67 -12
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +12 -3
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +17 -0
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +18 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop.ts +14 -1
- package/src/resources/extensions/gsd/auto/phases.ts +27 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +14 -2
- package/src/resources/extensions/gsd/auto/session.ts +1 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +76 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +36 -35
- package/src/resources/extensions/gsd/auto-model-selection.ts +12 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +195 -25
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -15
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +27 -6
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +67 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +11 -8
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +209 -16
- package/src/resources/extensions/gsd/codebase-generator.ts +4 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/dispatcher.ts +1 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +113 -8
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +49 -11
- package/src/resources/extensions/gsd/context-store.ts +167 -2
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +3 -1
- package/src/resources/extensions/gsd/detection.ts +6 -0
- package/src/resources/extensions/gsd/files.ts +21 -2
- package/src/resources/extensions/gsd/guided-flow.ts +15 -8
- package/src/resources/extensions/gsd/index.ts +6 -0
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +2 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +3 -1
- package/src/resources/extensions/gsd/preferences.ts +6 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +7 -7
- package/src/resources/extensions/gsd/prompts/discuss.md +3 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
- package/src/resources/extensions/gsd/prompts/rethink.md +6 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +11 -9
- package/src/resources/extensions/gsd/prompts/worktree-merge.md +3 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +4 -1
- package/src/resources/extensions/gsd/state.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +52 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +21 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/decision-scope-cascade.test.ts +370 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +53 -13
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/measurement.test.ts +531 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +71 -2
- package/src/resources/extensions/gsd/tests/parsers.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/queue-execution-guard.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/register-shortcuts.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +210 -35
- package/src/resources/extensions/gsd/visualizer-overlay.ts +31 -27
- package/src/resources/extensions/gsd/workflow-reconcile.ts +59 -8
- package/src/resources/extensions/remote-questions/manager.ts +9 -0
- package/src/resources/extensions/shared/interview-ui.ts +13 -0
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{HAq0VE4k68rhRvJbQL1VW → CrKrzIIxk55witDF1eS0L}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import { describe, test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import {
|
|
4
|
+
queryKnowledge,
|
|
5
|
+
formatRoadmapExcerpt,
|
|
6
|
+
} from '../context-store.ts';
|
|
7
|
+
|
|
8
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
9
|
+
// measurement.test.ts — Verify ≥40% context reduction from scoped injection
|
|
10
|
+
//
|
|
11
|
+
// Tests queryKnowledge() and formatRoadmapExcerpt() with realistic synthetic
|
|
12
|
+
// fixtures to confirm the context reduction target is met.
|
|
13
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
14
|
+
|
|
15
|
+
// ─── Synthetic KNOWLEDGE.md Fixture (~8KB, 9 H2 sections) ──────────────────
|
|
16
|
+
|
|
17
|
+
const syntheticKnowledge = `# Project Knowledge Base
|
|
18
|
+
|
|
19
|
+
## Database Patterns
|
|
20
|
+
SQLite is the primary persistence layer, using WAL mode for concurrent reads.
|
|
21
|
+
All queries use prepared statements for SQL injection prevention.
|
|
22
|
+
Connection pooling is handled by better-sqlite3's synchronous API.
|
|
23
|
+
Schema migrations are versioned and applied at startup.
|
|
24
|
+
|
|
25
|
+
Example patterns:
|
|
26
|
+
- Use transactions for multi-statement operations
|
|
27
|
+
- Prefer RETURNING clause for insert/update
|
|
28
|
+
- Index foreign keys for join performance
|
|
29
|
+
- Use CHECK constraints for data validation
|
|
30
|
+
|
|
31
|
+
Performance considerations:
|
|
32
|
+
- WAL checkpoint every 1000 writes
|
|
33
|
+
- Vacuum on shutdown for space reclamation
|
|
34
|
+
- Page size 4096 for SSD optimization
|
|
35
|
+
|
|
36
|
+
Database schema evolution:
|
|
37
|
+
- Migrations stored in migrations/ directory
|
|
38
|
+
- Each migration has up/down scripts
|
|
39
|
+
- Version table tracks applied migrations
|
|
40
|
+
- Rollback supported for last N migrations
|
|
41
|
+
|
|
42
|
+
Connection management:
|
|
43
|
+
- Single connection for write operations
|
|
44
|
+
- Read connections pooled for concurrency
|
|
45
|
+
- Connection timeout set to 5 seconds
|
|
46
|
+
- Busy timeout handles lock contention
|
|
47
|
+
|
|
48
|
+
Query patterns:
|
|
49
|
+
- Use prepared statements for parameterization
|
|
50
|
+
- Batch inserts via INSERT ... VALUES syntax
|
|
51
|
+
- Upserts via INSERT OR REPLACE
|
|
52
|
+
- Pagination via LIMIT/OFFSET or cursor
|
|
53
|
+
|
|
54
|
+
## API Design Principles
|
|
55
|
+
REST endpoints follow OpenAPI 3.0 specification.
|
|
56
|
+
Versioned paths use /v1/resource pattern.
|
|
57
|
+
Authentication uses Bearer tokens in Authorization header.
|
|
58
|
+
Rate limiting applies per-client with sliding window algorithm.
|
|
59
|
+
|
|
60
|
+
Response formats:
|
|
61
|
+
- Success: { data: T, meta?: { pagination } }
|
|
62
|
+
- Error: { error: { code, message, details? } }
|
|
63
|
+
- Pagination: cursor-based for large collections
|
|
64
|
+
|
|
65
|
+
Content negotiation:
|
|
66
|
+
- Accept: application/json (default)
|
|
67
|
+
- Accept: text/plain (for CLI consumers)
|
|
68
|
+
- Accept: text/event-stream (for SSE endpoints)
|
|
69
|
+
|
|
70
|
+
API versioning strategy:
|
|
71
|
+
- Major versions in URL path (/v1, /v2)
|
|
72
|
+
- Minor versions via Accept-Version header
|
|
73
|
+
- Deprecation warnings in response headers
|
|
74
|
+
- 12-month sunset period for old versions
|
|
75
|
+
|
|
76
|
+
Endpoint naming conventions:
|
|
77
|
+
- Nouns for resources (users, projects)
|
|
78
|
+
- Verbs only for non-CRUD actions (login, export)
|
|
79
|
+
- Plural form for collections
|
|
80
|
+
- Singular for singletons (me, config)
|
|
81
|
+
|
|
82
|
+
HTTP method semantics:
|
|
83
|
+
- GET: read-only, cacheable
|
|
84
|
+
- POST: create or non-idempotent action
|
|
85
|
+
- PUT: full replacement
|
|
86
|
+
- PATCH: partial update
|
|
87
|
+
- DELETE: remove resource
|
|
88
|
+
|
|
89
|
+
## Testing Strategy
|
|
90
|
+
Unit tests use node:test with strict assertions.
|
|
91
|
+
Integration tests mock external services via msw.
|
|
92
|
+
E2E tests use Playwright for browser automation.
|
|
93
|
+
Test coverage target is 80% line coverage.
|
|
94
|
+
|
|
95
|
+
Test organization:
|
|
96
|
+
- Unit tests adjacent to source files (*.test.ts)
|
|
97
|
+
- Integration tests in __tests__/integration/
|
|
98
|
+
- E2E tests in e2e/ directory
|
|
99
|
+
- Fixtures in __fixtures__/ subdirectories
|
|
100
|
+
|
|
101
|
+
Mocking guidelines:
|
|
102
|
+
- Prefer dependency injection over global mocks
|
|
103
|
+
- Use vi.mock() sparingly, only for ES module boundaries
|
|
104
|
+
- Reset mocks in afterEach hooks
|
|
105
|
+
|
|
106
|
+
Test data management:
|
|
107
|
+
- Factories generate realistic test data
|
|
108
|
+
- Seeds populate database for integration tests
|
|
109
|
+
- Snapshots capture expected output
|
|
110
|
+
- Golden files for complex comparisons
|
|
111
|
+
|
|
112
|
+
Assertion patterns:
|
|
113
|
+
- Use strict equality for primitives
|
|
114
|
+
- Deep equality for objects/arrays
|
|
115
|
+
- Regex matching for dynamic content
|
|
116
|
+
- Snapshot testing for UI components
|
|
117
|
+
|
|
118
|
+
Test isolation:
|
|
119
|
+
- Each test gets fresh database state
|
|
120
|
+
- Environment variables reset between tests
|
|
121
|
+
- File system operations use temp directories
|
|
122
|
+
- Network calls intercepted by mock server
|
|
123
|
+
|
|
124
|
+
## Error Handling
|
|
125
|
+
Errors are typed using discriminated unions.
|
|
126
|
+
Application errors extend BaseError class.
|
|
127
|
+
HTTP errors map to standard status codes.
|
|
128
|
+
Unhandled rejections trigger graceful shutdown.
|
|
129
|
+
|
|
130
|
+
Error codes follow domain prefixes:
|
|
131
|
+
- AUTH_xxx: Authentication/authorization errors
|
|
132
|
+
- DB_xxx: Database operation failures
|
|
133
|
+
- NET_xxx: Network/external service errors
|
|
134
|
+
- VAL_xxx: Validation errors
|
|
135
|
+
|
|
136
|
+
Logging integration:
|
|
137
|
+
- Error instances auto-serialize to JSON
|
|
138
|
+
- Stack traces included in development
|
|
139
|
+
- Correlation IDs propagate through request chain
|
|
140
|
+
|
|
141
|
+
Error recovery strategies:
|
|
142
|
+
- Retry with exponential backoff for transient errors
|
|
143
|
+
- Circuit breaker for external service failures
|
|
144
|
+
- Fallback values for non-critical operations
|
|
145
|
+
- Graceful degradation for partial failures
|
|
146
|
+
|
|
147
|
+
User-facing error messages:
|
|
148
|
+
- Generic messages for security-sensitive errors
|
|
149
|
+
- Actionable guidance for recoverable errors
|
|
150
|
+
- Reference codes for support escalation
|
|
151
|
+
- Localized messages via i18n
|
|
152
|
+
|
|
153
|
+
Error boundary patterns:
|
|
154
|
+
- Component-level boundaries in UI
|
|
155
|
+
- Route-level error handlers in API
|
|
156
|
+
- Global unhandled rejection handlers
|
|
157
|
+
- Process-level crash recovery
|
|
158
|
+
|
|
159
|
+
## Observability Patterns
|
|
160
|
+
Structured logging uses pino with JSON output.
|
|
161
|
+
Metrics collected via OpenTelemetry SDK.
|
|
162
|
+
Traces propagate context through async boundaries.
|
|
163
|
+
Health checks exposed at /health and /ready endpoints.
|
|
164
|
+
|
|
165
|
+
Log levels:
|
|
166
|
+
- ERROR: Unrecoverable failures
|
|
167
|
+
- WARN: Degraded operation
|
|
168
|
+
- INFO: Significant state changes
|
|
169
|
+
- DEBUG: Detailed diagnostic data
|
|
170
|
+
|
|
171
|
+
Metric types:
|
|
172
|
+
- Counters for request counts
|
|
173
|
+
- Histograms for latency distribution
|
|
174
|
+
- Gauges for resource utilization
|
|
175
|
+
|
|
176
|
+
Trace context propagation:
|
|
177
|
+
- W3C Trace Context headers
|
|
178
|
+
- Baggage for cross-service metadata
|
|
179
|
+
- Span attributes for searchability
|
|
180
|
+
- Events for significant moments
|
|
181
|
+
|
|
182
|
+
Dashboard design:
|
|
183
|
+
- SLO dashboards for reliability
|
|
184
|
+
- Request flow visualization
|
|
185
|
+
- Error rate trends
|
|
186
|
+
- Resource saturation alerts
|
|
187
|
+
|
|
188
|
+
Alerting strategy:
|
|
189
|
+
- Page for customer-impacting issues
|
|
190
|
+
- Ticket for degraded performance
|
|
191
|
+
- Notification for capacity planning
|
|
192
|
+
- Silence during maintenance windows
|
|
193
|
+
|
|
194
|
+
## Security Guidelines
|
|
195
|
+
Secrets never appear in logs or error messages.
|
|
196
|
+
Environment variables validated at startup.
|
|
197
|
+
CORS configured per-environment whitelist.
|
|
198
|
+
CSP headers enforced for web responses.
|
|
199
|
+
|
|
200
|
+
Input validation:
|
|
201
|
+
- Zod schemas for request body parsing
|
|
202
|
+
- Path parameters validated against patterns
|
|
203
|
+
- Query parameters have default/max values
|
|
204
|
+
|
|
205
|
+
Output encoding:
|
|
206
|
+
- HTML entities escaped in templates
|
|
207
|
+
- JSON stringification for API responses
|
|
208
|
+
- URL encoding for redirect targets
|
|
209
|
+
|
|
210
|
+
Authentication patterns:
|
|
211
|
+
- JWT tokens with short expiry
|
|
212
|
+
- Refresh token rotation
|
|
213
|
+
- Session invalidation on logout
|
|
214
|
+
- Multi-factor authentication support
|
|
215
|
+
|
|
216
|
+
Authorization model:
|
|
217
|
+
- Role-based access control (RBAC)
|
|
218
|
+
- Resource-level permissions
|
|
219
|
+
- Attribute-based policies (ABAC)
|
|
220
|
+
- Principle of least privilege
|
|
221
|
+
|
|
222
|
+
Secure communication:
|
|
223
|
+
- TLS 1.3 minimum
|
|
224
|
+
- Certificate pinning for mobile
|
|
225
|
+
- HSTS preload list
|
|
226
|
+
- Certificate transparency logging
|
|
227
|
+
|
|
228
|
+
## Performance Optimization
|
|
229
|
+
Critical paths target sub-10ms latency.
|
|
230
|
+
Database queries use covering indexes.
|
|
231
|
+
Response compression enabled for > 1KB bodies.
|
|
232
|
+
Static assets served with immutable caching.
|
|
233
|
+
|
|
234
|
+
Caching strategy:
|
|
235
|
+
- Redis for session data
|
|
236
|
+
- In-memory LRU for hot paths
|
|
237
|
+
- CDN for static assets
|
|
238
|
+
- Stale-while-revalidate for API responses
|
|
239
|
+
|
|
240
|
+
Memory management:
|
|
241
|
+
- Stream large payloads instead of buffering
|
|
242
|
+
- Weak references for disposable caches
|
|
243
|
+
- Manual GC hints for batch operations
|
|
244
|
+
|
|
245
|
+
Query optimization:
|
|
246
|
+
- Explain plans for complex queries
|
|
247
|
+
- Index usage analysis
|
|
248
|
+
- Query result caching
|
|
249
|
+
- Connection pooling tuning
|
|
250
|
+
|
|
251
|
+
Frontend performance:
|
|
252
|
+
- Code splitting for lazy loading
|
|
253
|
+
- Image optimization and lazy loading
|
|
254
|
+
- Critical CSS inlining
|
|
255
|
+
- Prefetching for likely navigations
|
|
256
|
+
|
|
257
|
+
Backend performance:
|
|
258
|
+
- Async I/O for non-blocking operations
|
|
259
|
+
- Worker threads for CPU-bound tasks
|
|
260
|
+
- Connection keep-alive
|
|
261
|
+
- Response streaming
|
|
262
|
+
|
|
263
|
+
## Deployment Architecture
|
|
264
|
+
Containers built with multi-stage Dockerfiles.
|
|
265
|
+
Kubernetes manifests in deploy/ directory.
|
|
266
|
+
Horizontal pod autoscaling on CPU/memory.
|
|
267
|
+
Rolling updates with zero-downtime.
|
|
268
|
+
|
|
269
|
+
Environment hierarchy:
|
|
270
|
+
- development: local Docker Compose
|
|
271
|
+
- staging: shared k8s namespace
|
|
272
|
+
- production: isolated k8s cluster
|
|
273
|
+
|
|
274
|
+
Configuration:
|
|
275
|
+
- ConfigMaps for non-sensitive config
|
|
276
|
+
- Secrets for credentials
|
|
277
|
+
- Environment-specific overlays via Kustomize
|
|
278
|
+
|
|
279
|
+
Container best practices:
|
|
280
|
+
- Non-root user in container
|
|
281
|
+
- Read-only filesystem where possible
|
|
282
|
+
- Resource limits and requests
|
|
283
|
+
- Liveness and readiness probes
|
|
284
|
+
|
|
285
|
+
Service mesh integration:
|
|
286
|
+
- Istio for traffic management
|
|
287
|
+
- mTLS for service-to-service auth
|
|
288
|
+
- Retry and timeout policies
|
|
289
|
+
- Circuit breaking configuration
|
|
290
|
+
|
|
291
|
+
Disaster recovery:
|
|
292
|
+
- Database replication across zones
|
|
293
|
+
- Point-in-time recovery capability
|
|
294
|
+
- Regular backup verification
|
|
295
|
+
- Documented runbooks
|
|
296
|
+
|
|
297
|
+
## Development Workflow
|
|
298
|
+
Feature branches follow conventional commits.
|
|
299
|
+
PRs require CI pass and code review.
|
|
300
|
+
Main branch deploys to staging automatically.
|
|
301
|
+
Release tags trigger production deployment.
|
|
302
|
+
|
|
303
|
+
CI pipeline stages:
|
|
304
|
+
1. Install dependencies
|
|
305
|
+
2. Lint and type check
|
|
306
|
+
3. Unit tests with coverage
|
|
307
|
+
4. Build artifacts
|
|
308
|
+
5. Integration tests
|
|
309
|
+
6. Security scan
|
|
310
|
+
|
|
311
|
+
Local development:
|
|
312
|
+
- pnpm for package management
|
|
313
|
+
- Turborepo for monorepo orchestration
|
|
314
|
+
- Docker Compose for service dependencies
|
|
315
|
+
|
|
316
|
+
Code review guidelines:
|
|
317
|
+
- Focus on correctness and clarity
|
|
318
|
+
- Security-sensitive changes require security review
|
|
319
|
+
- Performance-critical paths need benchmarks
|
|
320
|
+
- Breaking changes need migration guide
|
|
321
|
+
|
|
322
|
+
Branch strategy:
|
|
323
|
+
- main: production-ready code
|
|
324
|
+
- develop: integration branch (optional)
|
|
325
|
+
- feature/*: new functionality
|
|
326
|
+
- fix/*: bug fixes
|
|
327
|
+
- release/*: release preparation
|
|
328
|
+
|
|
329
|
+
Documentation requirements:
|
|
330
|
+
- README for project overview
|
|
331
|
+
- API docs auto-generated from OpenAPI
|
|
332
|
+
- Architecture decision records (ADRs)
|
|
333
|
+
- Runbooks for operational procedures
|
|
334
|
+
`;
|
|
335
|
+
|
|
336
|
+
// ─── Synthetic Roadmap Fixture (~1KB, 4 slices) ────────────────────────────
|
|
337
|
+
|
|
338
|
+
const syntheticRoadmap = `# M005: Tiered Context Injection
|
|
339
|
+
|
|
340
|
+
## Vision
|
|
341
|
+
Refactor prompt builders to inject relevance-scoped context instead of full files.
|
|
342
|
+
This reduces token consumption and improves agent focus on relevant information.
|
|
343
|
+
|
|
344
|
+
## Success Criteria
|
|
345
|
+
- [ ] 40% reduction in injected context size
|
|
346
|
+
- [ ] No regression in agent task completion rate
|
|
347
|
+
- [ ] Measurable test confirms reduction target
|
|
348
|
+
|
|
349
|
+
## Slice Overview
|
|
350
|
+
| ID | Slice | Risk | Depends | Done | After this |
|
|
351
|
+
|----|-------|------|---------|------|------------|
|
|
352
|
+
| S01 | Scope existing DB queries | low | — | ✅ | planSlice and researchSlice use milestone+slice filters for decisions/requirements. |
|
|
353
|
+
| S02 | KNOWLEDGE scoping + roadmap excerpt | medium | S01 | ⬜ | KNOWLEDGE sections filtered by keywords. Roadmap injected as excerpt. |
|
|
354
|
+
| S03 | Measurement test suite | low | S02 | ⬜ | Automated tests confirm 40% reduction vs baseline. |
|
|
355
|
+
| S04 | Documentation and rollout | low | S03 | ⬜ | Updated docs. Feature flag for gradual rollout. |
|
|
356
|
+
|
|
357
|
+
## Key Risks
|
|
358
|
+
1. Keyword extraction may miss relevant sections — mitigate with fallback to full content
|
|
359
|
+
2. Excerpt parsing fragile to roadmap format changes — mitigate with graceful degradation
|
|
360
|
+
|
|
361
|
+
## Definition of Done
|
|
362
|
+
- [ ] All slices complete with passing verification
|
|
363
|
+
- [ ] Measurement tests in CI
|
|
364
|
+
- [ ] No increase in prompt build latency
|
|
365
|
+
`;
|
|
366
|
+
|
|
367
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
368
|
+
// Measurement Tests
|
|
369
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
370
|
+
|
|
371
|
+
describe("measurement: context reduction verification", () => {
|
|
372
|
+
test("synthetic KNOWLEDGE fixture is ~8KB as specified", () => {
|
|
373
|
+
const sizeKB = syntheticKnowledge.length / 1024;
|
|
374
|
+
assert.ok(
|
|
375
|
+
sizeKB >= 7 && sizeKB <= 10,
|
|
376
|
+
`KNOWLEDGE fixture should be ~8KB, got ${sizeKB.toFixed(2)}KB`
|
|
377
|
+
);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("synthetic KNOWLEDGE has 9 H2 sections", () => {
|
|
381
|
+
const h2Count = (syntheticKnowledge.match(/^## /gm) || []).length;
|
|
382
|
+
assert.strictEqual(h2Count, 9, `KNOWLEDGE fixture should have 9 H2 sections, got ${h2Count}`);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("queryKnowledge achieves ≥40% reduction with targeted keywords", async () => {
|
|
386
|
+
// Keywords targeting 2 sections: "Database Patterns" and "Testing Strategy"
|
|
387
|
+
const keywords = ['database', 'testing'];
|
|
388
|
+
|
|
389
|
+
const scopedResult = await queryKnowledge(syntheticKnowledge, keywords);
|
|
390
|
+
|
|
391
|
+
const fullSize = syntheticKnowledge.length;
|
|
392
|
+
const scopedSize = scopedResult.length;
|
|
393
|
+
const reductionPct = ((fullSize - scopedSize) / fullSize) * 100;
|
|
394
|
+
|
|
395
|
+
// Verify we got matching sections
|
|
396
|
+
assert.match(scopedResult, /## Database Patterns/, 'should include Database section');
|
|
397
|
+
assert.match(scopedResult, /## Testing Strategy/, 'should include Testing section');
|
|
398
|
+
|
|
399
|
+
// Verify we excluded other sections
|
|
400
|
+
assert.ok(!scopedResult.includes('## API Design'), 'should exclude API section');
|
|
401
|
+
assert.ok(!scopedResult.includes('## Observability'), 'should exclude Observability section');
|
|
402
|
+
assert.ok(!scopedResult.includes('## Deployment'), 'should exclude Deployment section');
|
|
403
|
+
|
|
404
|
+
// Verify ≥40% reduction (2/9 sections = ~78% reduction expected)
|
|
405
|
+
assert.ok(
|
|
406
|
+
reductionPct >= 40,
|
|
407
|
+
`queryKnowledge should achieve ≥40% reduction, got ${reductionPct.toFixed(1)}% (${scopedSize} chars vs ${fullSize} chars)`
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
console.log(` → queryKnowledge: ${reductionPct.toFixed(1)}% reduction (${scopedSize} → ${fullSize} chars)`);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
test("queryKnowledge with single keyword achieves ≥40% reduction", async () => {
|
|
414
|
+
// Single keyword targeting 1 section
|
|
415
|
+
const keywords = ['security'];
|
|
416
|
+
|
|
417
|
+
const scopedResult = await queryKnowledge(syntheticKnowledge, keywords);
|
|
418
|
+
|
|
419
|
+
const fullSize = syntheticKnowledge.length;
|
|
420
|
+
const scopedSize = scopedResult.length;
|
|
421
|
+
const reductionPct = ((fullSize - scopedSize) / fullSize) * 100;
|
|
422
|
+
|
|
423
|
+
// Verify we got matching section
|
|
424
|
+
assert.match(scopedResult, /## Security Guidelines/, 'should include Security section');
|
|
425
|
+
|
|
426
|
+
// Verify ≥40% reduction (1/9 sections = ~89% reduction expected)
|
|
427
|
+
assert.ok(
|
|
428
|
+
reductionPct >= 40,
|
|
429
|
+
`single keyword should achieve ≥40% reduction, got ${reductionPct.toFixed(1)}%`
|
|
430
|
+
);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("formatRoadmapExcerpt achieves ≥40% reduction", () => {
|
|
434
|
+
const sliceId = 'S02';
|
|
435
|
+
|
|
436
|
+
const excerptResult = formatRoadmapExcerpt(syntheticRoadmap, sliceId, '.gsd/milestones/M005/M005-ROADMAP.md');
|
|
437
|
+
|
|
438
|
+
const fullSize = syntheticRoadmap.length;
|
|
439
|
+
const excerptSize = excerptResult.length;
|
|
440
|
+
const reductionPct = ((fullSize - excerptSize) / fullSize) * 100;
|
|
441
|
+
|
|
442
|
+
// Verify excerpt contains required elements
|
|
443
|
+
assert.match(excerptResult, /\| ID \| Slice \|/, 'should have table header');
|
|
444
|
+
assert.match(excerptResult, /\| S01 \|/, 'should have predecessor S01');
|
|
445
|
+
assert.match(excerptResult, /\| S02 \|/, 'should have target S02');
|
|
446
|
+
assert.match(excerptResult, /See full roadmap:/, 'should have reference directive');
|
|
447
|
+
|
|
448
|
+
// Verify we excluded other slices
|
|
449
|
+
assert.ok(!excerptResult.includes('| S03 |'), 'should exclude S03');
|
|
450
|
+
assert.ok(!excerptResult.includes('| S04 |'), 'should exclude S04');
|
|
451
|
+
|
|
452
|
+
// Verify ≥40% reduction (2 rows + overhead vs full roadmap = significant reduction)
|
|
453
|
+
assert.ok(
|
|
454
|
+
reductionPct >= 40,
|
|
455
|
+
`formatRoadmapExcerpt should achieve ≥40% reduction, got ${reductionPct.toFixed(1)}% (${excerptSize} chars vs ${fullSize} chars)`
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
console.log(` → formatRoadmapExcerpt: ${reductionPct.toFixed(1)}% reduction (${excerptSize} → ${fullSize} chars)`);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("combined KNOWLEDGE + roadmap reduction exceeds 40%", async () => {
|
|
462
|
+
// Simulate what happens in buildPlanSlicePrompt
|
|
463
|
+
const keywords = ['database', 'testing'];
|
|
464
|
+
|
|
465
|
+
const scopedKnowledge = await queryKnowledge(syntheticKnowledge, keywords);
|
|
466
|
+
const scopedRoadmap = formatRoadmapExcerpt(syntheticRoadmap, 'S02');
|
|
467
|
+
|
|
468
|
+
const fullKnowledgeSize = syntheticKnowledge.length;
|
|
469
|
+
const fullRoadmapSize = syntheticRoadmap.length;
|
|
470
|
+
const fullTotal = fullKnowledgeSize + fullRoadmapSize;
|
|
471
|
+
|
|
472
|
+
const scopedKnowledgeSize = scopedKnowledge.length;
|
|
473
|
+
const scopedRoadmapSize = scopedRoadmap.length;
|
|
474
|
+
const scopedTotal = scopedKnowledgeSize + scopedRoadmapSize;
|
|
475
|
+
|
|
476
|
+
const combinedReductionPct = ((fullTotal - scopedTotal) / fullTotal) * 100;
|
|
477
|
+
|
|
478
|
+
// Combined reduction should easily exceed 40%
|
|
479
|
+
assert.ok(
|
|
480
|
+
combinedReductionPct >= 40,
|
|
481
|
+
`combined reduction should be ≥40%, got ${combinedReductionPct.toFixed(1)}%`
|
|
482
|
+
);
|
|
483
|
+
|
|
484
|
+
console.log(` → Combined: ${combinedReductionPct.toFixed(1)}% reduction`);
|
|
485
|
+
console.log(` - KNOWLEDGE: ${fullKnowledgeSize} → ${scopedKnowledgeSize} chars`);
|
|
486
|
+
console.log(` - Roadmap: ${fullRoadmapSize} → ${scopedRoadmapSize} chars`);
|
|
487
|
+
console.log(` - Total: ${fullTotal} → ${scopedTotal} chars`);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe("measurement: edge cases maintain reduction target", () => {
|
|
492
|
+
test("three keywords still achieves ≥40% reduction", async () => {
|
|
493
|
+
// Even with 3 matching sections (3/9 = 33%), we should hit target
|
|
494
|
+
const keywords = ['database', 'api', 'security'];
|
|
495
|
+
|
|
496
|
+
const scopedResult = await queryKnowledge(syntheticKnowledge, keywords);
|
|
497
|
+
|
|
498
|
+
const fullSize = syntheticKnowledge.length;
|
|
499
|
+
const scopedSize = scopedResult.length;
|
|
500
|
+
const reductionPct = ((fullSize - scopedSize) / fullSize) * 100;
|
|
501
|
+
|
|
502
|
+
// Verify matches (3 sections)
|
|
503
|
+
assert.match(scopedResult, /## Database Patterns/, 'should include Database');
|
|
504
|
+
assert.match(scopedResult, /## API Design/, 'should include API');
|
|
505
|
+
assert.match(scopedResult, /## Security Guidelines/, 'should include Security');
|
|
506
|
+
|
|
507
|
+
// With 3/9 sections, reduction should be ~67%
|
|
508
|
+
assert.ok(
|
|
509
|
+
reductionPct >= 40,
|
|
510
|
+
`3 keywords should still achieve ≥40% reduction, got ${reductionPct.toFixed(1)}%`
|
|
511
|
+
);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
test("excerpt for S01 (no dependencies) achieves ≥40% reduction", () => {
|
|
515
|
+
const excerptResult = formatRoadmapExcerpt(syntheticRoadmap, 'S01');
|
|
516
|
+
|
|
517
|
+
const fullSize = syntheticRoadmap.length;
|
|
518
|
+
const excerptSize = excerptResult.length;
|
|
519
|
+
const reductionPct = ((fullSize - excerptSize) / fullSize) * 100;
|
|
520
|
+
|
|
521
|
+
// S01 has no predecessor, so just 1 row + header + reference
|
|
522
|
+
assert.match(excerptResult, /\| S01 \|/, 'should have S01');
|
|
523
|
+
assert.ok(!excerptResult.includes('| S02 |'), 'should not have S02');
|
|
524
|
+
|
|
525
|
+
// Single row should still achieve significant reduction
|
|
526
|
+
assert.ok(
|
|
527
|
+
reductionPct >= 40,
|
|
528
|
+
`S01 excerpt should achieve ≥40% reduction, got ${reductionPct.toFixed(1)}%`
|
|
529
|
+
);
|
|
530
|
+
});
|
|
531
|
+
});
|
|
@@ -273,9 +273,9 @@ test('Scenario 2: Fully complete project — deriveState phase', async () => {
|
|
|
273
273
|
invalidateAllCaches();
|
|
274
274
|
const state = await deriveState(base);
|
|
275
275
|
assert.deepStrictEqual(state.phase, 'complete', 'complete: deriveState phase is complete (validation + summary written by migration)');
|
|
276
|
-
|
|
277
|
-
assert.ok(state.
|
|
278
|
-
assert.deepStrictEqual(state.
|
|
276
|
+
assert.equal(state.activeMilestone, null, 'complete: deriveState has no activeMilestone');
|
|
277
|
+
assert.ok(state.lastCompletedMilestone !== null, 'complete: deriveState exposes lastCompletedMilestone');
|
|
278
|
+
assert.deepStrictEqual(state.lastCompletedMilestone!.id, 'M001', 'complete: deriveState lastCompletedMilestone is M001');
|
|
279
279
|
|
|
280
280
|
// generatePreview for complete project
|
|
281
281
|
const preview = generatePreview(project);
|
|
@@ -292,4 +292,3 @@ test('Scenario 2: Fully complete project — deriveState phase', async () => {
|
|
|
292
292
|
rmSync(base, { recursive: true, force: true });
|
|
293
293
|
}
|
|
294
294
|
});
|
|
295
|
-
|
|
@@ -57,4 +57,25 @@ describe("parallel-monitor-overlay", () => {
|
|
|
57
57
|
assert.ok(closed, "pressing q should trigger onClose");
|
|
58
58
|
overlay2.dispose();
|
|
59
59
|
});
|
|
60
|
+
|
|
61
|
+
it("ParallelMonitorOverlay clamps scrollOffset during render", async () => {
|
|
62
|
+
const mod = await import("../parallel-monitor-overlay.js");
|
|
63
|
+
|
|
64
|
+
const mockTui = { requestRender: () => {} };
|
|
65
|
+
const mockTheme = {
|
|
66
|
+
fg: (_color: string, text: string) => text,
|
|
67
|
+
bold: (text: string) => text,
|
|
68
|
+
};
|
|
69
|
+
const overlay = new mod.ParallelMonitorOverlay(
|
|
70
|
+
mockTui,
|
|
71
|
+
mockTheme as any,
|
|
72
|
+
() => {},
|
|
73
|
+
"/nonexistent/path",
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
(overlay as any).scrollOffset = 999;
|
|
77
|
+
overlay.render(80);
|
|
78
|
+
assert.equal((overlay as any).scrollOffset, 0, "empty overlays clamp scroll to zero");
|
|
79
|
+
overlay.dispose();
|
|
80
|
+
});
|
|
60
81
|
});
|
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
* Verifies the dispatch rule and prompt builder exist with correct structure.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import test from "node:test";
|
|
7
|
+
import test, { afterEach } from "node:test";
|
|
8
8
|
import assert from "node:assert/strict";
|
|
9
|
-
import { readFileSync } from "node:fs";
|
|
9
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { join, dirname } from "node:path";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
|
|
14
|
+
import { resolveDispatch } from "../auto-dispatch.ts";
|
|
15
|
+
|
|
13
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
17
|
|
|
15
18
|
const dispatchSrc = readFileSync(join(__dirname, "..", "auto-dispatch.ts"), "utf-8");
|
|
@@ -17,6 +20,47 @@ const promptsSrc = readFileSync(join(__dirname, "..", "auto-prompts.ts"), "utf-8
|
|
|
17
20
|
const templatePath = join(__dirname, "..", "prompts", "parallel-research-slices.md");
|
|
18
21
|
const templateSrc = readFileSync(templatePath, "utf-8");
|
|
19
22
|
|
|
23
|
+
const tmpDirs: string[] = [];
|
|
24
|
+
|
|
25
|
+
function makeTmpProject(): string {
|
|
26
|
+
const base = mkdtempSync(join(tmpdir(), "parallel-research-"));
|
|
27
|
+
tmpDirs.push(base);
|
|
28
|
+
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
29
|
+
mkdirSync(milestoneDir, { recursive: true });
|
|
30
|
+
writeFileSync(
|
|
31
|
+
join(milestoneDir, "M001-ROADMAP.md"),
|
|
32
|
+
[
|
|
33
|
+
"# M001: Parallel Research Milestone",
|
|
34
|
+
"",
|
|
35
|
+
"**Vision:** Research-ready slices.",
|
|
36
|
+
"",
|
|
37
|
+
"**Success Criteria:**",
|
|
38
|
+
"- Research both slices",
|
|
39
|
+
"",
|
|
40
|
+
"## Slices",
|
|
41
|
+
"",
|
|
42
|
+
"- [ ] **S01: Alpha** `risk:low` `depends:[]`",
|
|
43
|
+
"- [ ] **S02: Beta** `risk:low` `depends:[]`",
|
|
44
|
+
"",
|
|
45
|
+
"## Boundary Map",
|
|
46
|
+
"",
|
|
47
|
+
].join("\n"),
|
|
48
|
+
"utf-8",
|
|
49
|
+
);
|
|
50
|
+
return base;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
for (const dir of tmpDirs) {
|
|
55
|
+
try {
|
|
56
|
+
rmSync(dir, { recursive: true, force: true });
|
|
57
|
+
} catch {
|
|
58
|
+
// Best-effort cleanup only.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
tmpDirs.length = 0;
|
|
62
|
+
});
|
|
63
|
+
|
|
20
64
|
// ─── Dispatch rule ────────────────────────────────────────────────────────
|
|
21
65
|
|
|
22
66
|
test("dispatch: parallel-research-slices rule exists", () => {
|
|
@@ -75,3 +119,28 @@ test("template: validate-milestone uses parallel reviewers", () => {
|
|
|
75
119
|
"validate-milestone should dispatch 3 parallel reviewers",
|
|
76
120
|
);
|
|
77
121
|
});
|
|
122
|
+
|
|
123
|
+
test("resolveDispatch prefers parallel research when multiple slices are ready", async () => {
|
|
124
|
+
const base = makeTmpProject();
|
|
125
|
+
|
|
126
|
+
const action = await resolveDispatch({
|
|
127
|
+
basePath: base,
|
|
128
|
+
mid: "M001",
|
|
129
|
+
midTitle: "Parallel Research Milestone",
|
|
130
|
+
state: {
|
|
131
|
+
phase: "planning",
|
|
132
|
+
activeMilestone: { id: "M001", title: "Parallel Research Milestone", status: "active" },
|
|
133
|
+
activeSlice: { id: "S01", title: "Alpha" },
|
|
134
|
+
activeTask: null,
|
|
135
|
+
registry: [],
|
|
136
|
+
blockers: [],
|
|
137
|
+
} as any,
|
|
138
|
+
prefs: undefined,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
assert.equal(action.action, "dispatch");
|
|
142
|
+
if (action.action === "dispatch") {
|
|
143
|
+
assert.equal(action.unitType, "research-slice");
|
|
144
|
+
assert.equal(action.unitId, "M001/parallel-research");
|
|
145
|
+
}
|
|
146
|
+
});
|