@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.965d1788
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 +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -19
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
- package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +5 -4
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/json-persistence.js +20 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
- package/dist/resources/extensions/gsd/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
- package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
- package/dist/resources/extensions/gsd/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
- package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
- package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
- package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
- package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
- package/dist/resources/extensions/gsd/state.js +12 -611
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +32 -4
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- package/dist/resources/extensions/gsd/verification-gate.js +7 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +4 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
- 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 +12 -12
- 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 +9 -9
- 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_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 +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/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- 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 +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +3 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts +2 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +2 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
- package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
- package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +34 -20
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +3 -2
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +11 -7
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme-schema.d.ts +75 -75
- package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/theme/theme-schema.js +1 -1
- package/pkg/dist/theme/theme-schema.js.map +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +11 -7
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -19
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +6 -5
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/json-persistence.ts +20 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
- package/src/resources/extensions/gsd/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
- package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
- package/src/resources/extensions/gsd/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
- package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
- package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
- package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
- package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
- package/src/resources/extensions/gsd/state.ts +32 -732
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +130 -3
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +32 -4
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- package/src/resources/extensions/gsd/verification-gate.ts +8 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → -ji77QJck2IKIwrGza1Bs}/_ssgManifest.js +0 -0
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
// File Purpose: Tests the one-time migration from nested to flat-phase layout.
|
|
3
3
|
import test, { afterEach } from "node:test";
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
|
-
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, readdirSync, readFileSync } from "node:fs";
|
|
5
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, readdirSync, readFileSync, utimesSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
migrateToFlatPhase,
|
|
12
|
+
needsFlatPhaseMigration,
|
|
13
|
+
pruneStaleFlatPhaseBackups,
|
|
14
|
+
} from "../flat-phase-migration.ts";
|
|
11
15
|
import { openDatabase, closeDatabase, insertMilestone, insertSlice, insertTask, getAllMilestones, getMilestoneSlices, getSliceTasks } from "../gsd-db.ts";
|
|
12
16
|
|
|
13
17
|
const tmpDirs: string[] = [];
|
|
@@ -112,3 +116,34 @@ test("migrateToFlatPhase preserves slice sidecar artifacts and skips recovery pl
|
|
|
112
116
|
"recovery placeholder PLAN should not be promoted when no DB tasks can render a real plan",
|
|
113
117
|
);
|
|
114
118
|
});
|
|
119
|
+
|
|
120
|
+
test("pruneStaleFlatPhaseBackups removes migrate-* dirs older than retention window", async () => {
|
|
121
|
+
const base = makeTmp();
|
|
122
|
+
await migrateToFlatPhase(base);
|
|
123
|
+
|
|
124
|
+
const backupRoot = join(base, ".gsd-backups");
|
|
125
|
+
assert.ok(existsSync(backupRoot), "backup should exist immediately after migration");
|
|
126
|
+
|
|
127
|
+
const staleDir = join(backupRoot, "migrate-stale");
|
|
128
|
+
mkdirSync(staleDir, { recursive: true });
|
|
129
|
+
writeFileSync(join(staleDir, "marker.txt"), "old backup\n", "utf-8");
|
|
130
|
+
const staleDate = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000);
|
|
131
|
+
utimesSync(staleDir, staleDate, staleDate);
|
|
132
|
+
|
|
133
|
+
const removed = pruneStaleFlatPhaseBackups(base);
|
|
134
|
+
assert.equal(removed, 1, "stale migrate-* dir should be pruned");
|
|
135
|
+
assert.equal(existsSync(staleDir), false, "stale backup dir should be gone");
|
|
136
|
+
assert.ok(existsSync(backupRoot), "fresh migration backup should remain");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("pruneStaleFlatPhaseBackups is a no-op while flat-phase migration is still needed", () => {
|
|
140
|
+
const base = makeTmp();
|
|
141
|
+
const backupRoot = join(base, ".gsd-backups", "migrate-stale");
|
|
142
|
+
mkdirSync(backupRoot, { recursive: true });
|
|
143
|
+
writeFileSync(join(backupRoot, "marker.txt"), "old backup\n", "utf-8");
|
|
144
|
+
const staleDate = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000);
|
|
145
|
+
utimesSync(backupRoot, staleDate, staleDate);
|
|
146
|
+
|
|
147
|
+
assert.equal(pruneStaleFlatPhaseBackups(base), 0, "must not prune while migration is pending");
|
|
148
|
+
assert.ok(existsSync(backupRoot), "backup must remain until migration completes");
|
|
149
|
+
});
|
|
@@ -119,3 +119,91 @@ describe("extractTrace error filtering (#2539)", () => {
|
|
|
119
119
|
assert.equal(trace.errors.length, 1, "lint error with output should be counted");
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
|
+
|
|
123
|
+
describe("extractTrace pending tool calls (#945)", () => {
|
|
124
|
+
test("tool call without a toolResult is counted as an error", () => {
|
|
125
|
+
const entries = [
|
|
126
|
+
{
|
|
127
|
+
type: "message",
|
|
128
|
+
message: {
|
|
129
|
+
role: "assistant",
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "toolCall",
|
|
133
|
+
id: "toolu_missing",
|
|
134
|
+
name: "gsd_summary_save",
|
|
135
|
+
arguments: { content: "unfinished summary" },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
const trace = extractTrace(entries);
|
|
143
|
+
|
|
144
|
+
assert.equal(trace.toolCalls.length, 1);
|
|
145
|
+
assert.equal(trace.toolCalls[0]?.name, "gsd_summary_save");
|
|
146
|
+
assert.equal(trace.toolCalls[0]?.isError, true);
|
|
147
|
+
assert.equal(trace.toolCalls[0]?.result, "missing tool result (stream/tool-call abort before execution)");
|
|
148
|
+
assert.equal(trace.errors.length, 1);
|
|
149
|
+
assert.equal(trace.errors[0], "Tool call gsd_summary_save started but no toolResult was recorded");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("pending bash call with no toolResult marks commandsRun entry as failed", () => {
|
|
153
|
+
// A bash tool call that was initiated but never got a toolResult (stream abort).
|
|
154
|
+
const entries = [
|
|
155
|
+
{
|
|
156
|
+
type: "message",
|
|
157
|
+
message: {
|
|
158
|
+
role: "assistant",
|
|
159
|
+
content: [
|
|
160
|
+
{
|
|
161
|
+
type: "toolCall",
|
|
162
|
+
id: "toolu_bash_missing",
|
|
163
|
+
name: "bash",
|
|
164
|
+
arguments: { command: "npm run build" },
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
const trace = extractTrace(entries);
|
|
172
|
+
|
|
173
|
+
// The tool call should be recorded as an error.
|
|
174
|
+
assert.equal(trace.toolCalls.length, 1);
|
|
175
|
+
assert.equal(trace.toolCalls[0]?.name, "bash");
|
|
176
|
+
assert.equal(trace.toolCalls[0]?.isError, true);
|
|
177
|
+
|
|
178
|
+
// The commandsRun entry must be consistent: failed: true, not failed: false.
|
|
179
|
+
assert.equal(trace.commandsRun.length, 1);
|
|
180
|
+
assert.equal(trace.commandsRun[0]?.command, "npm run build");
|
|
181
|
+
assert.equal(trace.commandsRun[0]?.failed, true,
|
|
182
|
+
"commandsRun entry should be failed when its bash call never returned a result");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("pending bg_shell call with no toolResult marks commandsRun entry as failed", () => {
|
|
186
|
+
const entries = [
|
|
187
|
+
{
|
|
188
|
+
type: "message",
|
|
189
|
+
message: {
|
|
190
|
+
role: "assistant",
|
|
191
|
+
content: [
|
|
192
|
+
{
|
|
193
|
+
type: "toolCall",
|
|
194
|
+
id: "toolu_bg_missing",
|
|
195
|
+
name: "bg_shell",
|
|
196
|
+
arguments: { command: "sleep 30" },
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
const trace = extractTrace(entries);
|
|
204
|
+
|
|
205
|
+
assert.equal(trace.commandsRun.length, 1);
|
|
206
|
+
assert.equal(trace.commandsRun[0]?.failed, true,
|
|
207
|
+
"bg_shell commandsRun entry should be failed when no toolResult was recorded");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -40,6 +40,10 @@ describe('ensureGitignore writes .bg-shell/ baseline (#4902)', () => {
|
|
|
40
40
|
lines.has('.bg-shell/'),
|
|
41
41
|
`.gitignore should include .bg-shell/. Got:\n${ignore}`,
|
|
42
42
|
);
|
|
43
|
+
assert.ok(
|
|
44
|
+
lines.has('.gsd-backups/'),
|
|
45
|
+
`.gitignore should include .gsd-backups/. Got:\n${ignore}`,
|
|
46
|
+
);
|
|
43
47
|
} finally {
|
|
44
48
|
cleanup(dir);
|
|
45
49
|
}
|
package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts
CHANGED
|
@@ -86,3 +86,45 @@ test("guided milestone prompt builder preloads milestone planning context", asyn
|
|
|
86
86
|
rmSync(base, { recursive: true, force: true });
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
|
+
|
|
90
|
+
test("guided milestone prompt builder caps prior draft seed before interpolation", async () => {
|
|
91
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-guided-milestone-draft-cap-"));
|
|
92
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
93
|
+
process.env.GSD_HOME = join(base, ".gsd-home");
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const currentDir = join(base, ".gsd", "milestones", "M001");
|
|
97
|
+
mkdirSync(currentDir, { recursive: true });
|
|
98
|
+
|
|
99
|
+
const draftPath = join(currentDir, "M001-CONTEXT-DRAFT.md");
|
|
100
|
+
writeFileSync(draftPath, "# Draft\n\nSMALL-DRAFT-SIGNAL", "utf-8");
|
|
101
|
+
const smallPrompt = await buildDiscussMilestonePrompt("M001", "Draft Resume", base, "true", {
|
|
102
|
+
includeContextMode: false,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
writeFileSync(
|
|
106
|
+
draftPath,
|
|
107
|
+
["# Draft", "", "SMALL-DRAFT-SIGNAL", "", "A".repeat(200_000), "", "OVERSIZED-DRAFT-TAIL-SIGNAL"].join("\n"),
|
|
108
|
+
"utf-8",
|
|
109
|
+
);
|
|
110
|
+
const largePrompt = await buildDiscussMilestonePrompt("M001", "Draft Resume", base, "true", {
|
|
111
|
+
includeContextMode: false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const addedChars = largePrompt.length - smallPrompt.length;
|
|
115
|
+
|
|
116
|
+
assert.match(largePrompt, /## Prior Discussion \(Draft Seed\)/);
|
|
117
|
+
assert.match(largePrompt, /### Prior Discussion Draft/);
|
|
118
|
+
assert.match(largePrompt, /SMALL-DRAFT-SIGNAL/);
|
|
119
|
+
assert.doesNotMatch(largePrompt, /OVERSIZED-DRAFT-TAIL-SIGNAL/);
|
|
120
|
+
assert.match(
|
|
121
|
+
largePrompt,
|
|
122
|
+
/Draft seed truncated; read the full draft at `\.gsd\/milestones\/M001\/M001-CONTEXT-DRAFT\.md` if needed\./,
|
|
123
|
+
);
|
|
124
|
+
assert.ok(addedChars < 25_000, `large draft should add bounded seed chars, added ${addedChars}`);
|
|
125
|
+
} finally {
|
|
126
|
+
if (previousGsdHome === undefined) delete process.env.GSD_HOME;
|
|
127
|
+
else process.env.GSD_HOME = previousGsdHome;
|
|
128
|
+
rmSync(base, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import test from "node:test";
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
import { chmodSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { performance } from "node:perf_hooks";
|
|
9
|
+
import { delimiter, join } from "node:path";
|
|
8
10
|
import { tmpdir } from "node:os";
|
|
9
11
|
import {
|
|
10
12
|
buildHealthLines,
|
|
@@ -12,8 +14,9 @@ import {
|
|
|
12
14
|
formatRelativeTime,
|
|
13
15
|
type HealthWidgetData,
|
|
14
16
|
} from "../health-widget-core.ts";
|
|
15
|
-
import { HEALTH_WIDGET_ACTIVE_HINTS } from "../health-widget.ts";
|
|
17
|
+
import { HEALTH_WIDGET_ACTIVE_HINTS, getCachedProjectState, initHealthWidget } from "../health-widget.ts";
|
|
16
18
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
19
|
+
import { GIT_NO_PROMPT_ENV } from "../git-constants.ts";
|
|
17
20
|
|
|
18
21
|
function makeTempDir(prefix: string): string {
|
|
19
22
|
const dir = join(
|
|
@@ -32,6 +35,58 @@ function cleanup(dir: string): void {
|
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
function runGit(cwd: string, ...args: string[]): string {
|
|
39
|
+
return execFileSync("git", args, {
|
|
40
|
+
cwd,
|
|
41
|
+
encoding: "utf-8",
|
|
42
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
43
|
+
}).trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function makeTempRepo(prefix: string): string {
|
|
47
|
+
const dir = makeTempDir(prefix);
|
|
48
|
+
runGit(dir, "init");
|
|
49
|
+
runGit(dir, "config", "user.email", "test@test.com");
|
|
50
|
+
runGit(dir, "config", "user.name", "Test");
|
|
51
|
+
writeFileSync(join(dir, "README.md"), "# test\n", "utf-8");
|
|
52
|
+
runGit(dir, "add", "README.md");
|
|
53
|
+
runGit(dir, "commit", "-m", "initial commit");
|
|
54
|
+
return dir;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function installSlowGitLogShim(binDir: string): void {
|
|
58
|
+
writeFileSync(
|
|
59
|
+
join(binDir, "git"),
|
|
60
|
+
[
|
|
61
|
+
"#!/bin/sh",
|
|
62
|
+
'if [ "$1" = "log" ]; then sleep 1; fi',
|
|
63
|
+
'PATH="$GSD_REAL_PATH"',
|
|
64
|
+
"export PATH",
|
|
65
|
+
'exec git "$@"',
|
|
66
|
+
"",
|
|
67
|
+
].join("\n"),
|
|
68
|
+
"utf-8",
|
|
69
|
+
);
|
|
70
|
+
chmodSync(join(binDir, "git"), 0o755);
|
|
71
|
+
|
|
72
|
+
writeFileSync(
|
|
73
|
+
join(binDir, "git.cmd"),
|
|
74
|
+
[
|
|
75
|
+
"@echo off",
|
|
76
|
+
'if "%1"=="log" powershell -NoProfile -Command "Start-Sleep -Seconds 1"',
|
|
77
|
+
'set "PATH=%GSD_REAL_PATH%"',
|
|
78
|
+
"git %*",
|
|
79
|
+
"",
|
|
80
|
+
].join("\r\n"),
|
|
81
|
+
"utf-8",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type HealthWidgetFactory = (
|
|
86
|
+
tui: { requestRender(): void },
|
|
87
|
+
theme: { fg(style: string, text: string): string },
|
|
88
|
+
) => { dispose(): void };
|
|
89
|
+
|
|
35
90
|
function activeData(overrides: Partial<HealthWidgetData> = {}): HealthWidgetData {
|
|
36
91
|
return {
|
|
37
92
|
projectState: "active",
|
|
@@ -70,6 +125,86 @@ test("detectHealthWidgetProjectState: milestone without metrics returns active",
|
|
|
70
125
|
assert.equal(detectHealthWidgetProjectState(dir), "active");
|
|
71
126
|
});
|
|
72
127
|
|
|
128
|
+
test("getCachedProjectState: reuses project state until the refresh TTL expires", (t) => {
|
|
129
|
+
const dir = makeTempDir("cached-state");
|
|
130
|
+
t.after(() => { cleanup(dir); });
|
|
131
|
+
|
|
132
|
+
let now = 1_000_000;
|
|
133
|
+
const dateNow = t.mock.method(Date, "now", () => now);
|
|
134
|
+
t.after(() => { dateNow.mock.restore(); });
|
|
135
|
+
|
|
136
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
137
|
+
assert.equal(getCachedProjectState(dir), "initialized");
|
|
138
|
+
|
|
139
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
140
|
+
assert.equal(getCachedProjectState(dir), "initialized");
|
|
141
|
+
|
|
142
|
+
now += 60_000;
|
|
143
|
+
assert.equal(getCachedProjectState(dir), "initialized");
|
|
144
|
+
|
|
145
|
+
now += 1;
|
|
146
|
+
assert.equal(getCachedProjectState(dir), "active");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("getCachedProjectState: force=true bypasses TTL and returns fresh state within TTL window", (t) => {
|
|
150
|
+
const dir = makeTempDir("forced-state");
|
|
151
|
+
t.after(() => { cleanup(dir); });
|
|
152
|
+
|
|
153
|
+
let now = 2_000_000;
|
|
154
|
+
const dateNow = t.mock.method(Date, "now", () => now);
|
|
155
|
+
t.after(() => { dateNow.mock.restore(); });
|
|
156
|
+
|
|
157
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
158
|
+
// Prime the cache with "initialized".
|
|
159
|
+
assert.equal(getCachedProjectState(dir), "initialized");
|
|
160
|
+
|
|
161
|
+
// Disk changes within the TTL window.
|
|
162
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
163
|
+
now += 1_000; // well within 60s TTL
|
|
164
|
+
|
|
165
|
+
// Normal call still returns stale cached value.
|
|
166
|
+
assert.equal(getCachedProjectState(dir), "initialized");
|
|
167
|
+
|
|
168
|
+
// force=true bypasses TTL and returns the fresh disk state.
|
|
169
|
+
assert.equal(getCachedProjectState(dir, true), "active");
|
|
170
|
+
|
|
171
|
+
// Subsequent non-forced call also reflects the freshened cache.
|
|
172
|
+
assert.equal(getCachedProjectState(dir), "active");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("initHealthWidget: re-init paints fresh project state within cache TTL", (t) => {
|
|
176
|
+
const dir = makeTempDir("reinit-state");
|
|
177
|
+
t.after(() => { cleanup(dir); });
|
|
178
|
+
|
|
179
|
+
let now = 3_000_000;
|
|
180
|
+
const dateNow = t.mock.method(Date, "now", () => now);
|
|
181
|
+
t.after(() => { dateNow.mock.restore(); });
|
|
182
|
+
|
|
183
|
+
const originalCwd = process.cwd();
|
|
184
|
+
process.chdir(dir);
|
|
185
|
+
t.after(() => { process.chdir(originalCwd); });
|
|
186
|
+
|
|
187
|
+
const initialLineSets: string[][] = [];
|
|
188
|
+
const ctx = {
|
|
189
|
+
hasUI: true,
|
|
190
|
+
ui: {
|
|
191
|
+
setWidget: (_key: string, value: unknown) => {
|
|
192
|
+
if (Array.isArray(value)) initialLineSets.push(value as string[]);
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
} as any;
|
|
196
|
+
|
|
197
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
198
|
+
initHealthWidget(ctx);
|
|
199
|
+
assert.equal(initialLineSets.at(-1)?.[0], " GSD Project Initialized");
|
|
200
|
+
|
|
201
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
202
|
+
now += 1_000;
|
|
203
|
+
|
|
204
|
+
initHealthWidget(ctx);
|
|
205
|
+
assert.match(initialLineSets.at(-1)?.[0] ?? "", /System OK/);
|
|
206
|
+
});
|
|
207
|
+
|
|
73
208
|
test("buildHealthLines: none state shows single onboarding line pointing at /gsd", (t) => {
|
|
74
209
|
const lines = buildHealthLines(activeData({ projectState: "none" }));
|
|
75
210
|
assert.equal(lines.length, 1, "renders exactly one line");
|
|
@@ -101,6 +236,136 @@ test("health widget active hints include visualization and notifications", () =>
|
|
|
101
236
|
assert.match(HEALTH_WIDGET_ACTIVE_HINTS, /\/gsd help/);
|
|
102
237
|
});
|
|
103
238
|
|
|
239
|
+
test("health widget async refresh does not block timers while git log is slow", async (t) => {
|
|
240
|
+
const dir = makeTempRepo("slow-git-log");
|
|
241
|
+
const binDir = makeTempDir("slow-git-log-bin");
|
|
242
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
243
|
+
installSlowGitLogShim(binDir);
|
|
244
|
+
|
|
245
|
+
const originalCwd = process.cwd();
|
|
246
|
+
const originalProcessPath = process.env.PATH;
|
|
247
|
+
const originalEnvPath = GIT_NO_PROMPT_ENV.PATH;
|
|
248
|
+
const originalEnvRealPath = GIT_NO_PROMPT_ENV.GSD_REAL_PATH;
|
|
249
|
+
const shimmedPath = `${binDir}${delimiter}${originalProcessPath ?? ""}`;
|
|
250
|
+
|
|
251
|
+
process.chdir(dir);
|
|
252
|
+
process.env.PATH = shimmedPath;
|
|
253
|
+
GIT_NO_PROMPT_ENV.PATH = shimmedPath;
|
|
254
|
+
GIT_NO_PROMPT_ENV.GSD_REAL_PATH = originalProcessPath ?? "";
|
|
255
|
+
|
|
256
|
+
let factory: HealthWidgetFactory | null = null;
|
|
257
|
+
let resolveRefresh: (() => void) | undefined;
|
|
258
|
+
const refreshed = new Promise<void>((resolve) => { resolveRefresh = resolve; });
|
|
259
|
+
const gaps: number[] = [];
|
|
260
|
+
let lastTick = performance.now();
|
|
261
|
+
let heartbeat: NodeJS.Timeout | undefined;
|
|
262
|
+
let refreshTimeout: NodeJS.Timeout | undefined;
|
|
263
|
+
let widget: { dispose(): void } | undefined;
|
|
264
|
+
|
|
265
|
+
t.after(() => {
|
|
266
|
+
if (widget) widget.dispose();
|
|
267
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
268
|
+
if (refreshTimeout) clearTimeout(refreshTimeout);
|
|
269
|
+
process.chdir(originalCwd);
|
|
270
|
+
if (originalProcessPath === undefined) delete process.env.PATH;
|
|
271
|
+
else process.env.PATH = originalProcessPath;
|
|
272
|
+
if (originalEnvPath === undefined) delete GIT_NO_PROMPT_ENV.PATH;
|
|
273
|
+
else GIT_NO_PROMPT_ENV.PATH = originalEnvPath;
|
|
274
|
+
if (originalEnvRealPath === undefined) delete GIT_NO_PROMPT_ENV.GSD_REAL_PATH;
|
|
275
|
+
else GIT_NO_PROMPT_ENV.GSD_REAL_PATH = originalEnvRealPath;
|
|
276
|
+
cleanup(binDir);
|
|
277
|
+
cleanup(dir);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
initHealthWidget({
|
|
281
|
+
hasUI: true,
|
|
282
|
+
ui: {
|
|
283
|
+
setWidget: (_key: string, value: unknown) => {
|
|
284
|
+
if (typeof value === "function") factory = value as HealthWidgetFactory;
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
} as any);
|
|
288
|
+
|
|
289
|
+
assert.ok(factory, "health widget factory is registered");
|
|
290
|
+
|
|
291
|
+
heartbeat = setInterval(() => {
|
|
292
|
+
const now = performance.now();
|
|
293
|
+
gaps.push(now - lastTick);
|
|
294
|
+
lastTick = now;
|
|
295
|
+
}, 25);
|
|
296
|
+
|
|
297
|
+
// assert.ok above guards at runtime; double-cast is needed because TypeScript
|
|
298
|
+
// cannot track the factory assignment through the `as any` closure call.
|
|
299
|
+
widget = (factory as unknown as HealthWidgetFactory)(
|
|
300
|
+
{ requestRender: () => { resolveRefresh?.(); } },
|
|
301
|
+
{ fg: (_style: string, text: string) => text },
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
await Promise.race([
|
|
305
|
+
refreshed,
|
|
306
|
+
new Promise<never>((_, reject) => {
|
|
307
|
+
refreshTimeout = setTimeout(() => reject(new Error("health widget refresh did not complete")), 4_000);
|
|
308
|
+
}),
|
|
309
|
+
]);
|
|
310
|
+
if (refreshTimeout) clearTimeout(refreshTimeout);
|
|
311
|
+
|
|
312
|
+
assert.ok(gaps.length > 0, "heartbeat ran while refresh was in flight");
|
|
313
|
+
const maxGap = Math.max(...gaps);
|
|
314
|
+
assert.ok(maxGap < 750, `slow git log must not starve timers; max gap was ${Math.round(maxGap)}ms`);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("initHealthWidget: synchronous first-paint render never contains last-commit info (regression #964)", (t) => {
|
|
318
|
+
// Before the fix, loadHealthWidgetData with includeChecks:true called
|
|
319
|
+
// loadLastCommitInfo — synchronous native-git-bridge ops (nativeIsRepo,
|
|
320
|
+
// nativeGetCurrentBranch, nativeLastCommitEpoch, nativeCommitSubject) — which
|
|
321
|
+
// froze the TUI on slow repos. The fix removes that synchronous git path
|
|
322
|
+
// entirely: lastCommitEpoch/lastCommitMessage are now always null from the
|
|
323
|
+
// synchronous loader; only the async refresh (loadLastCommitInfoAsync) fills
|
|
324
|
+
// them in. This test guards that contract by verifying that the initial
|
|
325
|
+
// string-array setWidget call never contains "Last commit:" even on a real
|
|
326
|
+
// git repo where native git queries would succeed.
|
|
327
|
+
const dir = makeTempRepo("sync-last-commit-regression");
|
|
328
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
329
|
+
|
|
330
|
+
const originalCwd = process.cwd();
|
|
331
|
+
process.chdir(dir);
|
|
332
|
+
|
|
333
|
+
let widget: { dispose(): void } | undefined;
|
|
334
|
+
t.after(() => {
|
|
335
|
+
if (widget) widget.dispose();
|
|
336
|
+
process.chdir(originalCwd);
|
|
337
|
+
cleanup(dir);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const initialRenders: string[][] = [];
|
|
341
|
+
|
|
342
|
+
initHealthWidget({
|
|
343
|
+
hasUI: true,
|
|
344
|
+
ui: {
|
|
345
|
+
setWidget: (_key: string, value: unknown) => {
|
|
346
|
+
if (Array.isArray(value)) {
|
|
347
|
+
initialRenders.push(value as string[]);
|
|
348
|
+
} else if (typeof value === "function") {
|
|
349
|
+
// Instantiate the factory to satisfy dispose(), but do not await the
|
|
350
|
+
// async refresh — we are only inspecting the synchronous first-paint.
|
|
351
|
+
widget = (value as unknown as HealthWidgetFactory)(
|
|
352
|
+
{ requestRender: () => {} },
|
|
353
|
+
{ fg: (_style: string, text: string) => text },
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
} as any);
|
|
359
|
+
|
|
360
|
+
assert.ok(initialRenders.length > 0, "at least one synchronous setWidget call");
|
|
361
|
+
|
|
362
|
+
const combined = initialRenders.flat().join("\n");
|
|
363
|
+
assert.ok(
|
|
364
|
+
!combined.includes("Last commit:"),
|
|
365
|
+
"synchronous first-paint render must not contain 'Last commit:' — sync git path removed (regression #964)",
|
|
366
|
+
);
|
|
367
|
+
});
|
|
368
|
+
|
|
104
369
|
test("buildHealthLines: active state with budget ceiling shows percent summary", (t) => {
|
|
105
370
|
const lines = buildHealthLines(activeData({ budgetSpent: 2.5, budgetCeiling: 10 }));
|
|
106
371
|
assert.equal(lines.length, 1);
|