gsd-pi 2.82.0 → 3.0.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 +51 -32
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +19 -6
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +90 -31
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +246 -133
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +45 -26
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +178 -63
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +17 -3
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +87 -7
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +16 -9
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/paths.js +4 -0
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/state.js +3 -3
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +9 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +10 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +87 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- 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 +5 -5
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- 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/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/8359.65b24fac92188a6b.js +10 -0
- package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-b23b3f6858dc6dc8.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-855d616060cb6e59.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- 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 +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +25 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +24 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +22 -6
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +104 -38
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +279 -144
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +58 -36
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +187 -61
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +20 -4
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +42 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +89 -7
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +16 -9
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/paths.ts +5 -0
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/state.ts +3 -3
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +9 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +10 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +151 -12
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +18 -6
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +378 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +251 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +103 -7
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +97 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/ttsr/ttsr-manager.ts +5 -1
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +0 -10
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-9ecfd95f343793f0.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
// ADR-013 Stage 2b — KNOWLEDGE.md backfill + hybrid projection tests.
|
|
2
|
+
//
|
|
3
|
+
// Covers four behaviors:
|
|
4
|
+
// 1. parser: splits cells correctly, skips header/separator rows, respects
|
|
5
|
+
// section boundaries
|
|
6
|
+
// 2. backfill: Patterns -> memories(category=pattern), Lessons ->
|
|
7
|
+
// memories(category=gotcha), Rules NOT migrated, idempotent
|
|
8
|
+
// 3. projection: hybrid output preserves manual Rules verbatim while
|
|
9
|
+
// projecting Patterns + Lessons from memories
|
|
10
|
+
// 4. bootstrap path: backfill + projection round-trip produces a stable
|
|
11
|
+
// file that re-reading reconstitutes the same memory set
|
|
12
|
+
|
|
13
|
+
import test from "node:test";
|
|
14
|
+
import assert from "node:assert/strict";
|
|
15
|
+
import {
|
|
16
|
+
existsSync,
|
|
17
|
+
mkdirSync,
|
|
18
|
+
mkdtempSync,
|
|
19
|
+
readFileSync,
|
|
20
|
+
rmSync,
|
|
21
|
+
writeFileSync,
|
|
22
|
+
} from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import { tmpdir } from "node:os";
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
_getAdapter,
|
|
28
|
+
closeDatabase,
|
|
29
|
+
openDatabase,
|
|
30
|
+
} from "../gsd-db.ts";
|
|
31
|
+
import { backfillKnowledgeToMemories } from "../knowledge-backfill.ts";
|
|
32
|
+
import {
|
|
33
|
+
knowledgeMdPath,
|
|
34
|
+
parseKnowledgeRows,
|
|
35
|
+
splitPipeRow,
|
|
36
|
+
} from "../knowledge-parser.ts";
|
|
37
|
+
import { renderKnowledgeProjection } from "../knowledge-projection.ts";
|
|
38
|
+
|
|
39
|
+
function makeTmpBase(): string {
|
|
40
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-knowledge-stage2b-"));
|
|
41
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
42
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
43
|
+
return base;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function cleanup(base: string): void {
|
|
47
|
+
try {
|
|
48
|
+
closeDatabase();
|
|
49
|
+
} catch {
|
|
50
|
+
/* noop */
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
rmSync(base, { recursive: true, force: true });
|
|
54
|
+
} catch {
|
|
55
|
+
/* noop */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function writeKnowledgeMd(base: string, body: string): void {
|
|
60
|
+
writeFileSync(join(base, ".gsd", "KNOWLEDGE.md"), body, "utf-8");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const FIXTURE = `# Project Knowledge
|
|
64
|
+
|
|
65
|
+
Append-only register of project-specific rules, patterns, and lessons learned.
|
|
66
|
+
Agents read this before every unit. Add entries when you discover something worth remembering.
|
|
67
|
+
|
|
68
|
+
## Rules
|
|
69
|
+
|
|
70
|
+
| # | Scope | Rule | Why | Added |
|
|
71
|
+
|---|-------|------|-----|-------|
|
|
72
|
+
| K001 | project | All timestamps in UTC | clarity | 2026-01-01 |
|
|
73
|
+
| K002 | M001 | Never trust user input | safety | 2026-01-02 |
|
|
74
|
+
|
|
75
|
+
## Patterns
|
|
76
|
+
|
|
77
|
+
| # | Pattern | Where | Notes |
|
|
78
|
+
|---|---------|-------|-------|
|
|
79
|
+
| P001 | Repository pattern | services/ | guards |
|
|
80
|
+
| P002 | Adapter at the seam | packages/pi-ai/ | observability |
|
|
81
|
+
|
|
82
|
+
## Lessons Learned
|
|
83
|
+
|
|
84
|
+
| # | What Happened | Root Cause | Fix | Scope |
|
|
85
|
+
|---|--------------|------------|-----|-------|
|
|
86
|
+
| L001 | Cache poisoning | reused key | versioned key | project |
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
// ─── splitPipeRow ──────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
test("splitPipeRow extracts cells from a standard table row", () => {
|
|
92
|
+
const cells = splitPipeRow("| K001 | project | All timestamps in UTC | clarity | 2026-01-01 |");
|
|
93
|
+
assert.deepEqual(cells, ["K001", "project", "All timestamps in UTC", "clarity", "2026-01-01"]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("splitPipeRow preserves escaped pipes inside a cell", () => {
|
|
97
|
+
const cells = splitPipeRow(`| K001 | project | Use A \\| B operator | safety | 2026-01-01 |`);
|
|
98
|
+
assert.equal(cells[2], "Use A | B operator");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// ─── parseKnowledgeRows ────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
test("parseKnowledgeRows returns rows per section with the correct table tag", () => {
|
|
104
|
+
const rows = parseKnowledgeRows(FIXTURE);
|
|
105
|
+
assert.equal(rows.length, 5, "two rules + two patterns + one lesson");
|
|
106
|
+
const tables = rows.map((r) => r.table);
|
|
107
|
+
assert.deepEqual(tables, ["rules", "rules", "patterns", "patterns", "lessons"]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("parseKnowledgeRows captures cell values aligned with the section schema", () => {
|
|
111
|
+
const rows = parseKnowledgeRows(FIXTURE);
|
|
112
|
+
const p1 = rows.find((r) => r.id === "P001");
|
|
113
|
+
assert.ok(p1);
|
|
114
|
+
assert.equal(p1.cells[1], "Repository pattern");
|
|
115
|
+
assert.equal(p1.cells[2], "services/");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ─── backfillKnowledgeToMemories ───────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
test("backfill migrates Patterns + Lessons but skips Rules", () => {
|
|
121
|
+
const base = makeTmpBase();
|
|
122
|
+
try {
|
|
123
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
124
|
+
const written = backfillKnowledgeToMemories(base);
|
|
125
|
+
assert.equal(written, 3, "P001 + P002 + L001 should migrate; K rows skipped");
|
|
126
|
+
|
|
127
|
+
const adapter = _getAdapter();
|
|
128
|
+
assert.ok(adapter);
|
|
129
|
+
|
|
130
|
+
const knowledgeMemories = adapter
|
|
131
|
+
.prepare(
|
|
132
|
+
"SELECT category, structured_fields FROM memories WHERE structured_fields LIKE '%\"sourceKnowledgeId\":\"%' ORDER BY seq",
|
|
133
|
+
)
|
|
134
|
+
.all() as Array<{ category: string; structured_fields: string }>;
|
|
135
|
+
|
|
136
|
+
assert.equal(knowledgeMemories.length, 3);
|
|
137
|
+
const categoriesById: Record<string, string> = {};
|
|
138
|
+
for (const m of knowledgeMemories) {
|
|
139
|
+
const sf = JSON.parse(m.structured_fields) as { sourceKnowledgeId: string };
|
|
140
|
+
categoriesById[sf.sourceKnowledgeId] = m.category;
|
|
141
|
+
}
|
|
142
|
+
assert.equal(categoriesById["P001"], "pattern");
|
|
143
|
+
assert.equal(categoriesById["P002"], "pattern");
|
|
144
|
+
assert.equal(categoriesById["L001"], "gotcha");
|
|
145
|
+
assert.equal(categoriesById["K001"], undefined, "K001 must NOT be in memories");
|
|
146
|
+
} finally {
|
|
147
|
+
cleanup(base);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("backfill is idempotent — second run on the same file is a no-op", () => {
|
|
152
|
+
const base = makeTmpBase();
|
|
153
|
+
try {
|
|
154
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
155
|
+
const first = backfillKnowledgeToMemories(base);
|
|
156
|
+
assert.equal(first, 3);
|
|
157
|
+
const second = backfillKnowledgeToMemories(base);
|
|
158
|
+
assert.equal(second, 0, "already-migrated rows must not be re-inserted");
|
|
159
|
+
} finally {
|
|
160
|
+
cleanup(base);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("backfill returns 0 when KNOWLEDGE.md is absent", () => {
|
|
165
|
+
const base = makeTmpBase();
|
|
166
|
+
try {
|
|
167
|
+
assert.equal(backfillKnowledgeToMemories(base), 0);
|
|
168
|
+
} finally {
|
|
169
|
+
cleanup(base);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// ─── renderKnowledgeProjection ─────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
test("projection preserves the manual Rules section verbatim", () => {
|
|
176
|
+
const base = makeTmpBase();
|
|
177
|
+
try {
|
|
178
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
179
|
+
backfillKnowledgeToMemories(base);
|
|
180
|
+
renderKnowledgeProjection(base);
|
|
181
|
+
|
|
182
|
+
const rendered = readFileSync(knowledgeMdPath(base), "utf-8");
|
|
183
|
+
// Both K-rows must appear unchanged.
|
|
184
|
+
assert.match(rendered, /\| K001 \| project \| All timestamps in UTC \| clarity \| 2026-01-01 \|/);
|
|
185
|
+
assert.match(rendered, /\| K002 \| M001 \| Never trust user input \| safety \| 2026-01-02 \|/);
|
|
186
|
+
} finally {
|
|
187
|
+
cleanup(base);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("projection renders Patterns + Lessons from memories", () => {
|
|
192
|
+
const base = makeTmpBase();
|
|
193
|
+
try {
|
|
194
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
195
|
+
backfillKnowledgeToMemories(base);
|
|
196
|
+
// Wipe the original Patterns/Lessons table rows from the file so the
|
|
197
|
+
// projection's output can ONLY come from memories. Keep Rules intact.
|
|
198
|
+
writeKnowledgeMd(
|
|
199
|
+
base,
|
|
200
|
+
`# Project Knowledge
|
|
201
|
+
|
|
202
|
+
## Rules
|
|
203
|
+
|
|
204
|
+
| # | Scope | Rule | Why | Added |
|
|
205
|
+
|---|-------|------|-----|-------|
|
|
206
|
+
| K001 | project | All timestamps in UTC | clarity | 2026-01-01 |
|
|
207
|
+
| K002 | M001 | Never trust user input | safety | 2026-01-02 |
|
|
208
|
+
`,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
renderKnowledgeProjection(base);
|
|
212
|
+
const rendered = readFileSync(knowledgeMdPath(base), "utf-8");
|
|
213
|
+
|
|
214
|
+
assert.match(rendered, /\| P001 \| Repository pattern \| services\/ \| guards \|/);
|
|
215
|
+
assert.match(rendered, /\| P002 \| Adapter at the seam \| packages\/pi-ai\/ \| observability \|/);
|
|
216
|
+
assert.match(rendered, /\| L001 \| Cache poisoning \| reused key \| versioned key \| project \|/);
|
|
217
|
+
|
|
218
|
+
// Section structure must still be the canonical three headings, in order.
|
|
219
|
+
const rulesIdx = rendered.indexOf("## Rules");
|
|
220
|
+
const patternsIdx = rendered.indexOf("## Patterns");
|
|
221
|
+
const lessonsIdx = rendered.indexOf("## Lessons Learned");
|
|
222
|
+
assert.ok(rulesIdx >= 0 && patternsIdx > rulesIdx && lessonsIdx > patternsIdx, "headings must appear in canonical order");
|
|
223
|
+
} finally {
|
|
224
|
+
cleanup(base);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("projection is idempotent when nothing has changed", () => {
|
|
229
|
+
const base = makeTmpBase();
|
|
230
|
+
try {
|
|
231
|
+
// Seed a file the projection will *change* (no canonical headers yet, so
|
|
232
|
+
// the first render must rewrite to add structure).
|
|
233
|
+
writeKnowledgeMd(
|
|
234
|
+
base,
|
|
235
|
+
`# Project Knowledge
|
|
236
|
+
|
|
237
|
+
## Rules
|
|
238
|
+
|
|
239
|
+
| # | Scope | Rule | Why | Added |
|
|
240
|
+
|---|-------|------|-----|-------|
|
|
241
|
+
| K001 | project | manual rule | reason | 2026-01-01 |
|
|
242
|
+
`,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const first = renderKnowledgeProjection(base);
|
|
246
|
+
assert.equal(first.written, true, "first render adds the missing Patterns + Lessons section scaffolding");
|
|
247
|
+
|
|
248
|
+
const second = renderKnowledgeProjection(base);
|
|
249
|
+
assert.equal(second.written, false, "second render is a no-op when content already matches");
|
|
250
|
+
} finally {
|
|
251
|
+
cleanup(base);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("projection emits empty section tables when no rows exist for that category", () => {
|
|
256
|
+
const base = makeTmpBase();
|
|
257
|
+
try {
|
|
258
|
+
writeKnowledgeMd(
|
|
259
|
+
base,
|
|
260
|
+
`# Project Knowledge
|
|
261
|
+
|
|
262
|
+
## Rules
|
|
263
|
+
|
|
264
|
+
| # | Scope | Rule | Why | Added |
|
|
265
|
+
|---|-------|------|-----|-------|
|
|
266
|
+
`,
|
|
267
|
+
);
|
|
268
|
+
renderKnowledgeProjection(base);
|
|
269
|
+
const rendered = readFileSync(knowledgeMdPath(base), "utf-8");
|
|
270
|
+
|
|
271
|
+
assert.match(rendered, /## Patterns/);
|
|
272
|
+
assert.match(rendered, /## Lessons Learned/);
|
|
273
|
+
// The empty-table headers must be present.
|
|
274
|
+
assert.match(rendered, /\| # \| Pattern \| Where \| Notes \|/);
|
|
275
|
+
assert.match(rendered, /\| # \| What Happened \| Root Cause \| Fix \| Scope \|/);
|
|
276
|
+
} finally {
|
|
277
|
+
cleanup(base);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test("projection escapes pipes in memory content", () => {
|
|
282
|
+
const base = makeTmpBase();
|
|
283
|
+
try {
|
|
284
|
+
writeKnowledgeMd(
|
|
285
|
+
base,
|
|
286
|
+
`## Patterns
|
|
287
|
+
|
|
288
|
+
| # | Pattern | Where | Notes |
|
|
289
|
+
|---|---------|-------|-------|
|
|
290
|
+
| P001 | Use A \\| B fallback | adapters/ | watch out |
|
|
291
|
+
`,
|
|
292
|
+
);
|
|
293
|
+
backfillKnowledgeToMemories(base);
|
|
294
|
+
renderKnowledgeProjection(base);
|
|
295
|
+
const rendered = readFileSync(knowledgeMdPath(base), "utf-8");
|
|
296
|
+
|
|
297
|
+
// Pipe MUST stay escaped in the rendered output so the table doesn't break.
|
|
298
|
+
assert.match(rendered, /\| P001 \| Use A \\\| B fallback \| adapters\/ \| watch out \|/);
|
|
299
|
+
} finally {
|
|
300
|
+
cleanup(base);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// ─── End-to-end round-trip ─────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
test("backfill + projection round-trip: re-running backfill on rendered file is a no-op", () => {
|
|
307
|
+
const base = makeTmpBase();
|
|
308
|
+
try {
|
|
309
|
+
writeKnowledgeMd(base, FIXTURE);
|
|
310
|
+
const initial = backfillKnowledgeToMemories(base);
|
|
311
|
+
assert.equal(initial, 3);
|
|
312
|
+
|
|
313
|
+
renderKnowledgeProjection(base);
|
|
314
|
+
assert.ok(existsSync(knowledgeMdPath(base)));
|
|
315
|
+
|
|
316
|
+
// The rendered file contains the same P/L IDs as the source. A second
|
|
317
|
+
// backfill pass must NOT re-insert them.
|
|
318
|
+
const second = backfillKnowledgeToMemories(base);
|
|
319
|
+
assert.equal(second, 0, "round-trip rendered file must remain idempotent for backfill");
|
|
320
|
+
} finally {
|
|
321
|
+
cleanup(base);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// ADR-013 Stage 2c — /gsd knowledge write-side redirect tests.
|
|
2
|
+
//
|
|
3
|
+
// Locks in four properties of captureKnowledgeEntry / nextKnowledgeId:
|
|
4
|
+
// 1. Pattern entries write a memory row with category="pattern" and a
|
|
5
|
+
// sourceKnowledgeId marker — but do NOT touch KNOWLEDGE.md.
|
|
6
|
+
// 2. Lesson entries write a memory row with category="gotcha" — same
|
|
7
|
+
// file-vs-memory split.
|
|
8
|
+
// 3. Next-ID is monotonic across both surfaces: a P004 in the file plus a
|
|
9
|
+
// P007 in memories yields P008 next.
|
|
10
|
+
// 4. The legacy appendKnowledge stays the canonical path for Rules
|
|
11
|
+
// (covered indirectly via no-memory side effect on type="rule").
|
|
12
|
+
|
|
13
|
+
import test from "node:test";
|
|
14
|
+
import assert from "node:assert/strict";
|
|
15
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
_getAdapter,
|
|
21
|
+
closeDatabase,
|
|
22
|
+
openDatabase,
|
|
23
|
+
} from "../gsd-db.ts";
|
|
24
|
+
import { captureKnowledgeEntry, nextKnowledgeId } from "../knowledge-capture.ts";
|
|
25
|
+
import { knowledgeMdPath } from "../knowledge-parser.ts";
|
|
26
|
+
|
|
27
|
+
function makeTmpBase(): string {
|
|
28
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-knowledge-capture-"));
|
|
29
|
+
mkdirSync(join(base, ".gsd"), { recursive: true });
|
|
30
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
31
|
+
return base;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function cleanup(base: string): void {
|
|
35
|
+
try {
|
|
36
|
+
closeDatabase();
|
|
37
|
+
} catch {
|
|
38
|
+
/* noop */
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
rmSync(base, { recursive: true, force: true });
|
|
42
|
+
} catch {
|
|
43
|
+
/* noop */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readMemoriesWithMarker(prefix: "P" | "L"): Array<{ category: string; sf: Record<string, unknown> }> {
|
|
48
|
+
const adapter = _getAdapter();
|
|
49
|
+
if (!adapter) return [];
|
|
50
|
+
const rows = adapter
|
|
51
|
+
.prepare(
|
|
52
|
+
"SELECT category, structured_fields FROM memories WHERE structured_fields LIKE :pattern ORDER BY seq",
|
|
53
|
+
)
|
|
54
|
+
.all({ ":pattern": `%"sourceKnowledgeId":"${prefix}%` }) as Array<{
|
|
55
|
+
category: string;
|
|
56
|
+
structured_fields: string;
|
|
57
|
+
}>;
|
|
58
|
+
return rows.map((r) => ({ category: r.category, sf: JSON.parse(r.structured_fields) }));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ─── Pattern path ───────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
test("pattern entry creates a memory and assigns the next P### id", () => {
|
|
64
|
+
const base = makeTmpBase();
|
|
65
|
+
try {
|
|
66
|
+
const result = captureKnowledgeEntry(base, "pattern", "Repository pattern at the seam", "M001");
|
|
67
|
+
assert.equal(result.id, "P001", "first pattern on a fresh project should be P001");
|
|
68
|
+
assert.equal(result.written, true);
|
|
69
|
+
|
|
70
|
+
const memories = readMemoriesWithMarker("P");
|
|
71
|
+
assert.equal(memories.length, 1);
|
|
72
|
+
assert.equal(memories[0]?.category, "pattern");
|
|
73
|
+
assert.equal(memories[0]?.sf.sourceKnowledgeId, "P001");
|
|
74
|
+
assert.equal(memories[0]?.sf.pattern, "Repository pattern at the seam");
|
|
75
|
+
assert.equal(memories[0]?.sf.where, "");
|
|
76
|
+
assert.equal(memories[0]?.sf.notes, "");
|
|
77
|
+
} finally {
|
|
78
|
+
cleanup(base);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("pattern entry does NOT write to KNOWLEDGE.md (memory-only)", () => {
|
|
83
|
+
const base = makeTmpBase();
|
|
84
|
+
try {
|
|
85
|
+
captureKnowledgeEntry(base, "pattern", "Adapter at the seam", "project");
|
|
86
|
+
assert.equal(
|
|
87
|
+
existsSync(knowledgeMdPath(base)),
|
|
88
|
+
false,
|
|
89
|
+
"KNOWLEDGE.md should remain untouched — projection re-renders on next session start",
|
|
90
|
+
);
|
|
91
|
+
} finally {
|
|
92
|
+
cleanup(base);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("repeated pattern captures advance the ID monotonically", () => {
|
|
97
|
+
const base = makeTmpBase();
|
|
98
|
+
try {
|
|
99
|
+
const a = captureKnowledgeEntry(base, "pattern", "First", "project");
|
|
100
|
+
const b = captureKnowledgeEntry(base, "pattern", "Second", "project");
|
|
101
|
+
const c = captureKnowledgeEntry(base, "pattern", "Third", "project");
|
|
102
|
+
assert.deepEqual([a.id, b.id, c.id], ["P001", "P002", "P003"]);
|
|
103
|
+
} finally {
|
|
104
|
+
cleanup(base);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// ─── Lesson path ────────────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
test("lesson entry creates a memory with category=gotcha and L### id", () => {
|
|
111
|
+
const base = makeTmpBase();
|
|
112
|
+
try {
|
|
113
|
+
const result = captureKnowledgeEntry(base, "lesson", "Cache poisoning via reused key", "M001/S01");
|
|
114
|
+
assert.equal(result.id, "L001");
|
|
115
|
+
assert.equal(result.written, true);
|
|
116
|
+
|
|
117
|
+
const memories = readMemoriesWithMarker("L");
|
|
118
|
+
assert.equal(memories.length, 1);
|
|
119
|
+
assert.equal(memories[0]?.category, "gotcha");
|
|
120
|
+
assert.equal(memories[0]?.sf.sourceKnowledgeId, "L001");
|
|
121
|
+
assert.equal(memories[0]?.sf.whatHappened, "Cache poisoning via reused key");
|
|
122
|
+
assert.equal(memories[0]?.sf.scopeText, "M001/S01");
|
|
123
|
+
} finally {
|
|
124
|
+
cleanup(base);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ─── Empty input ────────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
test("empty entry text does NOT create a memory but still assigns an id", () => {
|
|
131
|
+
const base = makeTmpBase();
|
|
132
|
+
try {
|
|
133
|
+
const result = captureKnowledgeEntry(base, "pattern", " ", "project");
|
|
134
|
+
assert.equal(result.written, false);
|
|
135
|
+
assert.equal(readMemoriesWithMarker("P").length, 0);
|
|
136
|
+
} finally {
|
|
137
|
+
cleanup(base);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// ─── nextKnowledgeId — cross-surface monotonicity ───────────────────────────
|
|
142
|
+
|
|
143
|
+
test("nextKnowledgeId takes max of file and memory surfaces", () => {
|
|
144
|
+
const base = makeTmpBase();
|
|
145
|
+
try {
|
|
146
|
+
// Pre-existing patterns in KNOWLEDGE.md and one new pattern in memories.
|
|
147
|
+
// The legacy appendKnowledge format starts P at 001 — we simulate higher
|
|
148
|
+
// existing IDs to verify the take-max-then-+1 rule.
|
|
149
|
+
writeFileSync(
|
|
150
|
+
knowledgeMdPath(base),
|
|
151
|
+
`## Patterns
|
|
152
|
+
|
|
153
|
+
| # | Pattern | Where | Notes |
|
|
154
|
+
|---|---------|-------|-------|
|
|
155
|
+
| P004 | Legacy pattern | services/ | preserved |
|
|
156
|
+
`,
|
|
157
|
+
"utf-8",
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Capture jumps the memory ID forward.
|
|
161
|
+
captureKnowledgeEntry(base, "pattern", "Memory-only pattern", "project");
|
|
162
|
+
captureKnowledgeEntry(base, "pattern", "Another memory-only pattern", "project");
|
|
163
|
+
captureKnowledgeEntry(base, "pattern", "And another", "project");
|
|
164
|
+
|
|
165
|
+
// After: file has P004 (max=4); memories have P005, P006, P007 (max=7).
|
|
166
|
+
// Next must be P008.
|
|
167
|
+
assert.equal(nextKnowledgeId(base, "P"), "P008");
|
|
168
|
+
} finally {
|
|
169
|
+
cleanup(base);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("nextKnowledgeId works per-prefix without cross-talk", () => {
|
|
174
|
+
const base = makeTmpBase();
|
|
175
|
+
try {
|
|
176
|
+
captureKnowledgeEntry(base, "pattern", "P entry", "project");
|
|
177
|
+
captureKnowledgeEntry(base, "pattern", "P entry 2", "project");
|
|
178
|
+
captureKnowledgeEntry(base, "lesson", "L entry", "project");
|
|
179
|
+
|
|
180
|
+
assert.equal(nextKnowledgeId(base, "P"), "P003");
|
|
181
|
+
assert.equal(nextKnowledgeId(base, "L"), "L002");
|
|
182
|
+
// K has no entries on this project — first one should be K001.
|
|
183
|
+
assert.equal(nextKnowledgeId(base, "K"), "K001");
|
|
184
|
+
} finally {
|
|
185
|
+
cleanup(base);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("nextKnowledgeId pads to three digits even at the rollover", () => {
|
|
190
|
+
const base = makeTmpBase();
|
|
191
|
+
try {
|
|
192
|
+
writeFileSync(
|
|
193
|
+
knowledgeMdPath(base),
|
|
194
|
+
`## Patterns
|
|
195
|
+
|
|
196
|
+
| # | Pattern | Where | Notes |
|
|
197
|
+
|---|---------|-------|-------|
|
|
198
|
+
| P099 | high water mark | — | — |
|
|
199
|
+
`,
|
|
200
|
+
"utf-8",
|
|
201
|
+
);
|
|
202
|
+
assert.equal(nextKnowledgeId(base, "P"), "P100");
|
|
203
|
+
} finally {
|
|
204
|
+
cleanup(base);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ─── Sanity: file-side reads still see existing rows after capture ─────────
|
|
209
|
+
|
|
210
|
+
test("after pattern capture, KNOWLEDGE.md untouched but next id reflects memory state", () => {
|
|
211
|
+
const base = makeTmpBase();
|
|
212
|
+
try {
|
|
213
|
+
captureKnowledgeEntry(base, "pattern", "First", "project");
|
|
214
|
+
// KNOWLEDGE.md still absent.
|
|
215
|
+
assert.equal(existsSync(knowledgeMdPath(base)), false);
|
|
216
|
+
// Next-ID logic sees the new memory.
|
|
217
|
+
assert.equal(nextKnowledgeId(base, "P"), "P002");
|
|
218
|
+
} finally {
|
|
219
|
+
cleanup(base);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("rule writes still flow through appendKnowledge (file-canonical) — memory unchanged", async () => {
|
|
224
|
+
const base = makeTmpBase();
|
|
225
|
+
try {
|
|
226
|
+
// We invoke the legacy file path directly here; the command handler
|
|
227
|
+
// dispatch is verified separately at the integration level. The point
|
|
228
|
+
// of this test is to lock in that captureKnowledgeEntry is NOT the
|
|
229
|
+
// rule path — rules must go through appendKnowledge.
|
|
230
|
+
const { appendKnowledge } = await import("../files.ts");
|
|
231
|
+
await appendKnowledge(base, "rule", "Always pin SQLite version", "project");
|
|
232
|
+
|
|
233
|
+
const md = readFileSync(knowledgeMdPath(base), "utf-8");
|
|
234
|
+
assert.match(md, /\| K001 \| project \| Always pin SQLite version /);
|
|
235
|
+
|
|
236
|
+
// No pattern/lesson memories should exist as a side effect.
|
|
237
|
+
assert.equal(readMemoriesWithMarker("P").length, 0);
|
|
238
|
+
assert.equal(readMemoriesWithMarker("L").length, 0);
|
|
239
|
+
} finally {
|
|
240
|
+
cleanup(base);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
@@ -187,7 +187,7 @@ test('loadKnowledgeBlock: uses project knowledge alone when no global file', ()
|
|
|
187
187
|
writeFileSync(join(cwd, '.gsd', 'KNOWLEDGE.md'), 'K001: Use real DB');
|
|
188
188
|
|
|
189
189
|
const result = loadKnowledgeBlock(gsdHome, cwd);
|
|
190
|
-
assert.ok(result.block.includes('[KNOWLEDGE — Rules
|
|
190
|
+
assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
|
|
191
191
|
assert.ok(result.block.includes('## Project Knowledge'));
|
|
192
192
|
assert.ok(result.block.includes('K001: Use real DB'));
|
|
193
193
|
assert.ok(!result.block.includes('## Global Knowledge'));
|
|
@@ -205,7 +205,7 @@ test('loadKnowledgeBlock: uses global knowledge alone when no project file', ()
|
|
|
205
205
|
writeFileSync(join(gsdHome, 'agent', 'KNOWLEDGE.md'), 'G001: Respond in English');
|
|
206
206
|
|
|
207
207
|
const result = loadKnowledgeBlock(gsdHome, cwd);
|
|
208
|
-
assert.ok(result.block.includes('[KNOWLEDGE — Rules
|
|
208
|
+
assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
|
|
209
209
|
assert.ok(result.block.includes('## Global Knowledge'));
|
|
210
210
|
assert.ok(result.block.includes('G001: Respond in English'));
|
|
211
211
|
assert.ok(!result.block.includes('## Project Knowledge'));
|
|
@@ -234,6 +234,51 @@ test('loadKnowledgeBlock: merges global before project when both exist', () => {
|
|
|
234
234
|
rmSync(tmp, { recursive: true, force: true });
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
test('loadKnowledgeBlock: strips patterns and lessons from project knowledge', () => {
|
|
238
|
+
const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-strip-')));
|
|
239
|
+
const gsdHome = join(tmp, 'home');
|
|
240
|
+
const cwd = join(tmp, 'project');
|
|
241
|
+
mkdirSync(join(cwd, '.gsd'), { recursive: true });
|
|
242
|
+
mkdirSync(join(gsdHome, 'agent'), { recursive: true });
|
|
243
|
+
writeFileSync(
|
|
244
|
+
join(cwd, '.gsd', 'KNOWLEDGE.md'),
|
|
245
|
+
[
|
|
246
|
+
'# Project Knowledge',
|
|
247
|
+
'',
|
|
248
|
+
'Intro note that should stay with manual rules.',
|
|
249
|
+
'',
|
|
250
|
+
'## Rules',
|
|
251
|
+
'',
|
|
252
|
+
'| ID | Rule | Notes |',
|
|
253
|
+
'|---|---|---|',
|
|
254
|
+
'| K001 | Use real DB | - |',
|
|
255
|
+
'',
|
|
256
|
+
'## Patterns',
|
|
257
|
+
'',
|
|
258
|
+
'| ID | Pattern | Where | Notes |',
|
|
259
|
+
'|---|---|---|---|',
|
|
260
|
+
'| P001 | Prefer async | server | - |',
|
|
261
|
+
'',
|
|
262
|
+
'## Lessons Learned',
|
|
263
|
+
'',
|
|
264
|
+
'| ID | What Happened | Root Cause | Fix | Scope |',
|
|
265
|
+
'|---|---|---|---|---|',
|
|
266
|
+
'| L001 | Missed cache | N/A | Add TTL | project |',
|
|
267
|
+
].join('\n'),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const result = loadKnowledgeBlock(gsdHome, cwd);
|
|
271
|
+
assert.ok(result.block.includes('[KNOWLEDGE — Rules from KNOWLEDGE.md'));
|
|
272
|
+
assert.ok(result.block.includes('Intro note that should stay with manual rules.'));
|
|
273
|
+
assert.ok(result.block.includes('K001'), 'rules entry should be present');
|
|
274
|
+
assert.ok(!result.block.includes('P001'), 'patterns should be stripped and injected via memories');
|
|
275
|
+
assert.ok(!result.block.includes('L001'), 'lessons should be stripped and injected via memories');
|
|
276
|
+
assert.ok(!result.block.includes('## Patterns'), 'Patterns heading should not appear');
|
|
277
|
+
assert.ok(!result.block.includes('## Lessons Learned'), 'Lessons heading should not appear');
|
|
278
|
+
|
|
279
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
280
|
+
});
|
|
281
|
+
|
|
237
282
|
test('loadKnowledgeBlock: reports globalSizeKb above 4KB threshold', () => {
|
|
238
283
|
const tmp = realpathSync(mkdtempSync(join(tmpdir(), 'gsd-kb-')));
|
|
239
284
|
const gsdHome = join(tmp, 'home');
|