@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.738160b9
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/cli.js +17 -4
- package/dist/headless-answers.js +1 -1
- package/dist/headless-ui.d.ts +1 -1
- package/dist/headless-ui.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- 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 +11 -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-budget.js +5 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +34 -20
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -14
- package/dist/resources/extensions/gsd/auto-recovery.js +9 -510
- 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/auto.js +19 -10
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +39 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +11 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -21
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +96 -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/handlers/auto.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +17 -11
- package/dist/resources/extensions/gsd/commands-usage.js +1 -1
- 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/engine.js +4 -1
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
- 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 +53 -11
- 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 +61 -4
- package/dist/resources/extensions/gsd/gitignore.js +4 -1
- 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/migrate-external.js +11 -2
- 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-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
- 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/tools/plan-slice.js +59 -44
- package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
- 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 +36 -6
- 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 +126 -13
- 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 +10 -10
- 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 +10 -10
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- 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-client.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +23 -5
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- 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 +35 -21
- 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/dist/agent-loop.js +3 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +46 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +38 -0
- package/packages/pi-ai/dist/models.generated.js.map +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/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
- 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/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +14 -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-budget.ts +12 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +35 -24
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +41 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +13 -511
- 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/auto.ts +23 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +44 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +11 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -21
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +104 -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/handlers/auto.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -10
- package/src/resources/extensions/gsd/commands-usage.ts +1 -1
- 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/engine.ts +8 -1
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
- 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/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +56 -11
- 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 +69 -5
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- 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/migrate-external.ts +8 -2
- 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-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
- 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-budget-alerts.test.ts +14 -5
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +146 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
- 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/db-memory-fts-schema.test.ts +58 -3
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -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/doctor-scope-db-unavailable.test.ts +239 -2
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -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/memory-store.test.ts +48 -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/migrate-external-worktree.test.ts +57 -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 +4 -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/plan-slice.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
- 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/prompt-budget-enforcement.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
- 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/register-hooks-loop-guard-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +15 -3
- 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 +208 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +32 -3
- 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/uok-gitops-turn-action.test.ts +38 -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 +96 -15
- package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +6 -5
- 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/tools/plan-slice.ts +60 -47
- package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
- 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 +36 -6
- 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 +141 -7
- 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 → 2A_WqqCS-EoYZxN9_v3d2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → 2A_WqqCS-EoYZxN9_v3d2}/_ssgManifest.js +0 -0
|
@@ -11,7 +11,7 @@ import { spawn } from "node:child_process";
|
|
|
11
11
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { randomUUID } from "node:crypto";
|
|
13
13
|
import { resolve } from "node:path";
|
|
14
|
-
import { killProcessTree, SIGKILL_GRACE_MS, HARD_DEADLINE_MS } from "@gsd/pi-coding-agent";
|
|
14
|
+
import { getShellConfig, killProcessTree, SIGKILL_GRACE_MS, HARD_DEADLINE_MS } from "@gsd/pi-coding-agent";
|
|
15
15
|
const ALWAYS_FORWARD_ENV = ["PATH", "HOME"];
|
|
16
16
|
// SIGKILL_GRACE_MS / HARD_DEADLINE_MS are imported from @gsd/pi-coding-agent
|
|
17
17
|
// (shell.ts) — the single source of truth for the graceful-kill timing ladder —
|
|
@@ -60,7 +60,13 @@ function clampTimeout(request, opts) {
|
|
|
60
60
|
function resolveCommand(runtime) {
|
|
61
61
|
switch (runtime) {
|
|
62
62
|
case "bash":
|
|
63
|
-
|
|
63
|
+
try {
|
|
64
|
+
const { shell, args } = getShellConfig();
|
|
65
|
+
return { cmd: shell, args };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { cmd: "bash", args: ["-c"] };
|
|
69
|
+
}
|
|
64
70
|
case "node":
|
|
65
71
|
return { cmd: process.execPath, args: ["-e"] };
|
|
66
72
|
case "python":
|
|
@@ -180,10 +186,22 @@ export function runExecSandbox(request, opts) {
|
|
|
180
186
|
const effectiveGraceMs = opts.kill_grace_ms ?? SIGKILL_GRACE_MS;
|
|
181
187
|
const effectiveForceResolveDelay = opts.force_resolve_delay_ms ?? (effectiveGraceMs + HARD_DEADLINE_MS);
|
|
182
188
|
let timedOut = false;
|
|
189
|
+
let aborted = false;
|
|
183
190
|
let settled = false;
|
|
191
|
+
let killInitiated = false;
|
|
192
|
+
let timer;
|
|
184
193
|
let forceResolveTimer;
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
let abortListener;
|
|
195
|
+
const removeAbortListener = () => {
|
|
196
|
+
if (opts.signal && abortListener) {
|
|
197
|
+
opts.signal.removeEventListener("abort", abortListener);
|
|
198
|
+
abortListener = undefined;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const initiateKill = () => {
|
|
202
|
+
if (killInitiated)
|
|
203
|
+
return;
|
|
204
|
+
killInitiated = true;
|
|
187
205
|
// killProcessTree handles both platforms and kills the whole tree: on Unix
|
|
188
206
|
// it signals the process group (SIGTERM -> grace -> SIGKILL); on Windows it
|
|
189
207
|
// force-kills the tree via taskkill /F /T. Using child.kill("SIGTERM") here
|
|
@@ -201,14 +219,14 @@ export function runExecSandbox(request, opts) {
|
|
|
201
219
|
finalize(null, "SIGKILL", true);
|
|
202
220
|
}, effectiveForceResolveDelay);
|
|
203
221
|
forceResolveTimer.unref?.();
|
|
204
|
-
}
|
|
205
|
-
timer.unref?.();
|
|
222
|
+
};
|
|
206
223
|
const finalize = (exitCode, signal, forceResolved = false) => {
|
|
207
224
|
if (settled)
|
|
208
225
|
return;
|
|
209
226
|
settled = true;
|
|
210
227
|
clearTimeout(timer);
|
|
211
228
|
clearTimeout(forceResolveTimer);
|
|
229
|
+
removeAbortListener();
|
|
212
230
|
const duration = Date.now() - started;
|
|
213
231
|
const stdoutBuf = Buffer.concat(stdoutChunks);
|
|
214
232
|
const stderrBuf = Buffer.concat(stderrChunks);
|
|
@@ -219,17 +237,20 @@ export function runExecSandbox(request, opts) {
|
|
|
219
237
|
const digestBody = tail(stdoutBuf, opts.digest_chars);
|
|
220
238
|
const digest = digestBody.length > 0
|
|
221
239
|
? digestBody
|
|
222
|
-
:
|
|
223
|
-
? "[no stdout —
|
|
224
|
-
:
|
|
225
|
-
?
|
|
226
|
-
:
|
|
240
|
+
: aborted
|
|
241
|
+
? "[no stdout — aborted]"
|
|
242
|
+
: timedOut
|
|
243
|
+
? "[no stdout — timed out]"
|
|
244
|
+
: stderrBuf.length > 0
|
|
245
|
+
? `[no stdout — tail of stderr]\n${tail(stderrBuf, opts.digest_chars)}`
|
|
246
|
+
: "[no output]";
|
|
227
247
|
const result = {
|
|
228
248
|
id,
|
|
229
249
|
runtime: request.runtime,
|
|
230
250
|
exit_code: exitCode,
|
|
231
251
|
signal,
|
|
232
252
|
timed_out: timedOut,
|
|
253
|
+
aborted,
|
|
233
254
|
force_resolved: forceResolved,
|
|
234
255
|
duration_ms: duration,
|
|
235
256
|
stdout_bytes: stdoutBytes,
|
|
@@ -244,6 +265,26 @@ export function runExecSandbox(request, opts) {
|
|
|
244
265
|
writeMeta(metaPath, result, request, now);
|
|
245
266
|
resolveP(result);
|
|
246
267
|
};
|
|
268
|
+
timer = setTimeout(() => {
|
|
269
|
+
timedOut = true;
|
|
270
|
+
initiateKill();
|
|
271
|
+
}, timeoutMs);
|
|
272
|
+
timer.unref?.();
|
|
273
|
+
if (opts.signal) {
|
|
274
|
+
abortListener = () => {
|
|
275
|
+
if (settled || timedOut)
|
|
276
|
+
return;
|
|
277
|
+
aborted = true;
|
|
278
|
+
clearTimeout(timer);
|
|
279
|
+
initiateKill();
|
|
280
|
+
};
|
|
281
|
+
if (opts.signal.aborted) {
|
|
282
|
+
abortListener();
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
opts.signal.addEventListener("abort", abortListener, { once: true });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
247
288
|
child.on("error", (err) => {
|
|
248
289
|
const message = err instanceof Error ? err.message : String(err);
|
|
249
290
|
const line = `child error: ${message}\n`;
|
|
@@ -274,6 +315,7 @@ function writeMeta(path, result, request, now) {
|
|
|
274
315
|
exit_code: result.exit_code,
|
|
275
316
|
signal: result.signal,
|
|
276
317
|
timed_out: result.timed_out,
|
|
318
|
+
aborted: result.aborted === true,
|
|
277
319
|
force_resolved: result.force_resolved,
|
|
278
320
|
duration_ms: result.duration_ms,
|
|
279
321
|
stdout_bytes: result.stdout_bytes,
|
|
@@ -59,6 +59,51 @@ export function needsFlatPhaseMigration(basePath) {
|
|
|
59
59
|
// Resume an interrupted migration where the legacy tree was renamed aside.
|
|
60
60
|
return hasLegacyMilestoneSubdirs(legacyMigratingPath(basePath));
|
|
61
61
|
}
|
|
62
|
+
/** Retention window before flat-phase migration backups are auto-pruned. */
|
|
63
|
+
export const FLAT_PHASE_BACKUP_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
|
|
64
|
+
/**
|
|
65
|
+
* Remove stale flat-phase migration backups after the retention window.
|
|
66
|
+
* Only runs when migration is complete (.gsd/phases/ exists, legacy layout gone).
|
|
67
|
+
* Returns the number of migrate-* directories removed.
|
|
68
|
+
*/
|
|
69
|
+
export function pruneStaleFlatPhaseBackups(basePath) {
|
|
70
|
+
if (needsFlatPhaseMigration(basePath))
|
|
71
|
+
return 0;
|
|
72
|
+
const phasesPath = join(basePath, ".gsd", LAYOUT_SEGMENTS.level1);
|
|
73
|
+
if (!existsSync(phasesPath))
|
|
74
|
+
return 0;
|
|
75
|
+
const backupRoot = join(basePath, ".gsd-backups");
|
|
76
|
+
if (!existsSync(backupRoot))
|
|
77
|
+
return 0;
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
let removed = 0;
|
|
80
|
+
for (const entry of readdirSync(backupRoot)) {
|
|
81
|
+
if (!entry.startsWith("migrate-"))
|
|
82
|
+
continue;
|
|
83
|
+
const dirPath = join(backupRoot, entry);
|
|
84
|
+
try {
|
|
85
|
+
const st = statSync(dirPath);
|
|
86
|
+
if (!st.isDirectory())
|
|
87
|
+
continue;
|
|
88
|
+
if (now - st.mtimeMs < FLAT_PHASE_BACKUP_RETENTION_MS)
|
|
89
|
+
continue;
|
|
90
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
91
|
+
removed++;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Non-fatal: leave backup for manual recovery.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
if (readdirSync(backupRoot).length === 0) {
|
|
99
|
+
rmSync(backupRoot, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Non-fatal.
|
|
104
|
+
}
|
|
105
|
+
return removed;
|
|
106
|
+
}
|
|
62
107
|
/**
|
|
63
108
|
* Migrate from legacy nested .gsd/milestones/ to flat-phase .gsd/phases/.
|
|
64
109
|
*
|
|
@@ -22,8 +22,7 @@ import { deriveState } from "./state.js";
|
|
|
22
22
|
import { isAutoActive } from "./auto.js";
|
|
23
23
|
import { loadPrompt } from "./prompt-loader.js";
|
|
24
24
|
import { gsdRoot } from "./paths.js";
|
|
25
|
-
import { isDbAvailable,
|
|
26
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
25
|
+
import { isDbAvailable, getHierarchyCompletionCounts } from "./gsd-db.js";
|
|
27
26
|
import { formatDuration } from "../shared/format-utils.js";
|
|
28
27
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
29
28
|
import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
@@ -593,36 +592,7 @@ function loadCompletedKeys(basePath) {
|
|
|
593
592
|
function getDbCompletionCounts() {
|
|
594
593
|
if (!isDbAvailable())
|
|
595
594
|
return null;
|
|
596
|
-
|
|
597
|
-
let completedMilestones = 0;
|
|
598
|
-
let totalSlices = 0;
|
|
599
|
-
let completedSlices = 0;
|
|
600
|
-
let totalTasks = 0;
|
|
601
|
-
let completedTasks = 0;
|
|
602
|
-
for (const m of milestones) {
|
|
603
|
-
if (isClosedStatus(m.status))
|
|
604
|
-
completedMilestones++;
|
|
605
|
-
const slices = getMilestoneSlices(m.id);
|
|
606
|
-
for (const s of slices) {
|
|
607
|
-
totalSlices++;
|
|
608
|
-
if (isClosedStatus(s.status))
|
|
609
|
-
completedSlices++;
|
|
610
|
-
const tasks = getSliceTasks(m.id, s.id);
|
|
611
|
-
for (const t of tasks) {
|
|
612
|
-
totalTasks++;
|
|
613
|
-
if (isClosedStatus(t.status))
|
|
614
|
-
completedTasks++;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
return {
|
|
619
|
-
milestones: completedMilestones,
|
|
620
|
-
milestonesTotal: milestones.length,
|
|
621
|
-
slices: completedSlices,
|
|
622
|
-
slicesTotal: totalSlices,
|
|
623
|
-
tasks: completedTasks,
|
|
624
|
-
tasksTotal: totalTasks,
|
|
625
|
-
};
|
|
595
|
+
return getHierarchyCompletionCounts();
|
|
626
596
|
}
|
|
627
597
|
// ─── Anomaly Detectors ───────────────────────────────────────────────────────
|
|
628
598
|
/**
|
|
@@ -208,6 +208,7 @@ export class MergeConflictError extends GSDError {
|
|
|
208
208
|
*/
|
|
209
209
|
export const RUNTIME_EXCLUSION_PATHS = [
|
|
210
210
|
".gsd-worktrees/",
|
|
211
|
+
".gsd-backups/**",
|
|
211
212
|
".gsd/activity/",
|
|
212
213
|
".gsd/audit/",
|
|
213
214
|
".gsd/forensics/",
|
|
@@ -225,6 +226,7 @@ export const RUNTIME_EXCLUSION_PATHS = [
|
|
|
225
226
|
".gsd/event-log.jsonl",
|
|
226
227
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
227
228
|
];
|
|
229
|
+
const runtimeFilesCleanedUpRepos = new Set();
|
|
228
230
|
// ─── Integration Branch Metadata ───────────────────────────────────────────
|
|
229
231
|
/**
|
|
230
232
|
* Path to the milestone metadata file that stores the integration branch.
|
|
@@ -565,7 +567,8 @@ export class GitServiceImpl {
|
|
|
565
567
|
// and the worktree is torn down. This prevents a mid-execution behavioral
|
|
566
568
|
// discontinuity where the first half of a milestone has .gsd/ artifacts
|
|
567
569
|
// committed but the second half doesn't (#1326).
|
|
568
|
-
|
|
570
|
+
const cleanupRepoKey = resolve(this.basePath);
|
|
571
|
+
if (!runtimeFilesCleanedUpRepos.has(cleanupRepoKey)) {
|
|
569
572
|
let cleaned = false;
|
|
570
573
|
for (const exclusion of RUNTIME_EXCLUSION_PATHS) {
|
|
571
574
|
const removed = nativeRmCached(this.basePath, [exclusion]);
|
|
@@ -575,7 +578,7 @@ export class GitServiceImpl {
|
|
|
575
578
|
if (cleaned) {
|
|
576
579
|
nativeCommit(this.basePath, "chore: untrack .gsd/ runtime files from git index", { allowEmpty: false });
|
|
577
580
|
}
|
|
578
|
-
|
|
581
|
+
runtimeFilesCleanedUpRepos.add(cleanupRepoKey);
|
|
579
582
|
}
|
|
580
583
|
// Stage everything using pathspec exclusions so excluded paths are never
|
|
581
584
|
// hashed by git. The old approach of `git add -A` followed by unstaging
|
|
@@ -683,8 +686,6 @@ export class GitServiceImpl {
|
|
|
683
686
|
return false;
|
|
684
687
|
}
|
|
685
688
|
}
|
|
686
|
-
/** Tracks whether runtime file cleanup has run this session. */
|
|
687
|
-
_runtimeFilesCleanedUp = false;
|
|
688
689
|
/**
|
|
689
690
|
* Stage files (smart staging) and commit.
|
|
690
691
|
* Returns the commit message string on success, or null if nothing to commit.
|
|
@@ -1027,6 +1028,7 @@ function collectRepositoryDirtyStatus(basePath) {
|
|
|
1027
1028
|
const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
|
|
1028
1029
|
const registry = createRepositoryRegistryFromPreferences(basePath, preferences);
|
|
1029
1030
|
const dirtyByRepository = {};
|
|
1031
|
+
const registeredRoots = new Set(registry.repositories.map((repo) => resolve(repo.root)));
|
|
1030
1032
|
for (const repo of registry.repositories) {
|
|
1031
1033
|
try {
|
|
1032
1034
|
dirtyByRepository[repo.id] = runGit(repo.root, ["status", "--porcelain"]).length > 0;
|
|
@@ -1036,8 +1038,63 @@ function collectRepositoryDirtyStatus(basePath) {
|
|
|
1036
1038
|
dirtyByRepository[repo.id] = nativeHasChanges(repo.root);
|
|
1037
1039
|
}
|
|
1038
1040
|
}
|
|
1041
|
+
for (const repoRoot of findUndeclaredNestedGitRepositories(registry.projectRoot, registeredRoots)) {
|
|
1042
|
+
let dirty = false;
|
|
1043
|
+
try {
|
|
1044
|
+
dirty = runGit(repoRoot, ["status", "--porcelain"]).length > 0;
|
|
1045
|
+
}
|
|
1046
|
+
catch {
|
|
1047
|
+
dirty = nativeHasChanges(repoRoot);
|
|
1048
|
+
}
|
|
1049
|
+
if (!dirty)
|
|
1050
|
+
continue;
|
|
1051
|
+
const relPath = relative(registry.projectRoot, repoRoot).split(sep).join("/") || repoRoot;
|
|
1052
|
+
const label = `${relPath} (undeclared)`;
|
|
1053
|
+
dirtyByRepository[label] = true;
|
|
1054
|
+
logWarning("engine", `undeclared dirty nested git repo ${relPath}; declare it under workspace.repositories or commit manually`, { file: "git-service.ts" });
|
|
1055
|
+
}
|
|
1039
1056
|
return dirtyByRepository;
|
|
1040
1057
|
}
|
|
1058
|
+
const UNDECLARED_NESTED_REPO_SCAN_MAX_DEPTH = 4;
|
|
1059
|
+
const UNDECLARED_NESTED_REPO_SKIP_DIRS = new Set([
|
|
1060
|
+
".git",
|
|
1061
|
+
".gsd",
|
|
1062
|
+
".gsd-worktrees",
|
|
1063
|
+
"node_modules",
|
|
1064
|
+
"dist",
|
|
1065
|
+
"dist-test",
|
|
1066
|
+
]);
|
|
1067
|
+
function findUndeclaredNestedGitRepositories(projectRoot, registeredRoots) {
|
|
1068
|
+
const found = [];
|
|
1069
|
+
function visit(dir, depth) {
|
|
1070
|
+
if (depth >= UNDECLARED_NESTED_REPO_SCAN_MAX_DEPTH)
|
|
1071
|
+
return;
|
|
1072
|
+
let entries;
|
|
1073
|
+
try {
|
|
1074
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
1075
|
+
}
|
|
1076
|
+
catch {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
for (const entry of entries) {
|
|
1080
|
+
if (!entry.isDirectory())
|
|
1081
|
+
continue;
|
|
1082
|
+
if (UNDECLARED_NESTED_REPO_SKIP_DIRS.has(entry.name))
|
|
1083
|
+
continue;
|
|
1084
|
+
const child = join(dir, entry.name);
|
|
1085
|
+
const childRoot = resolve(child);
|
|
1086
|
+
const hasGitDir = existsSync(join(child, ".git"));
|
|
1087
|
+
const isRegistered = registeredRoots.has(childRoot);
|
|
1088
|
+
if (hasGitDir && !isRegistered) {
|
|
1089
|
+
found.push(childRoot);
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
visit(child, depth + 1);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
visit(projectRoot, 0);
|
|
1096
|
+
return found;
|
|
1097
|
+
}
|
|
1041
1098
|
function runPerRepositoryCommitAction(args) {
|
|
1042
1099
|
const preferences = loadEffectiveGSDPreferences(args.basePath)?.preferences;
|
|
1043
1100
|
const registry = createRepositoryRegistryFromPreferences(args.basePath, preferences);
|
|
@@ -22,8 +22,9 @@ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
|
22
22
|
* With external state (symlink), these are a no-op in most cases,
|
|
23
23
|
* but retained for backwards compatibility during migration.
|
|
24
24
|
*/
|
|
25
|
-
const GSD_RUNTIME_PATTERNS = [
|
|
25
|
+
export const GSD_RUNTIME_PATTERNS = [
|
|
26
26
|
".gsd-worktrees/",
|
|
27
|
+
".gsd-backups/",
|
|
27
28
|
".gsd/activity/",
|
|
28
29
|
".gsd/audit/",
|
|
29
30
|
".gsd/forensics/",
|
|
@@ -48,6 +49,8 @@ const BASELINE_PATTERNS = [
|
|
|
48
49
|
".gsd",
|
|
49
50
|
// Worktree container sibling — NOT covered by the ".gsd" pattern above.
|
|
50
51
|
".gsd-worktrees/",
|
|
52
|
+
// Flat-phase migration snapshots — NOT covered by the ".gsd" pattern above.
|
|
53
|
+
".gsd-backups/",
|
|
51
54
|
".gsd-id",
|
|
52
55
|
".mcp.json",
|
|
53
56
|
".bg-shell/",
|
|
@@ -12,7 +12,7 @@ import { loadFile } from "./files.js";
|
|
|
12
12
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
13
13
|
import { deriveState } from "./state.js";
|
|
14
14
|
import { invalidateAllCaches } from "./cache.js";
|
|
15
|
-
import { gsdRoot, resolveMilestoneFile, resolveGsdRootFile, relGsdRootFile, } from "./paths.js";
|
|
15
|
+
import { gsdRoot, resolveMilestoneFile, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, } from "./paths.js";
|
|
16
16
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
17
17
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
18
18
|
import { nativeAddPaths, nativeCommit } from "./native-git-bridge.js";
|
|
@@ -20,6 +20,9 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
20
20
|
import { saveQueueOrder } from "./queue-order.js";
|
|
21
21
|
import { findMilestoneIds, nextMilestoneId } from "./milestone-ids.js";
|
|
22
22
|
import { isFutureMilestoneStatus } from "./status-guards.js";
|
|
23
|
+
const QUEUE_ARTIFACT_EXCERPT_MAX_CHARS = 20_000;
|
|
24
|
+
const QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS = 120_000;
|
|
25
|
+
const QUEUE_CONTEXT_SECTION_SEPARATOR = "\n\n---\n\n";
|
|
23
26
|
// ─── Queue Entry Point ──────────────────────────────────────────────────────
|
|
24
27
|
/**
|
|
25
28
|
* Queue future milestones via conversational intake.
|
|
@@ -215,7 +218,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
215
218
|
if (contextFile) {
|
|
216
219
|
const content = await loadFile(contextFile);
|
|
217
220
|
if (content) {
|
|
218
|
-
parts.push(`\n**Context:**\n${content
|
|
221
|
+
parts.push(`\n**Context:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "CONTEXT"))}`);
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
224
|
else {
|
|
@@ -224,7 +227,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
224
227
|
if (draftFile) {
|
|
225
228
|
const draftContent = await loadFile(draftFile);
|
|
226
229
|
if (draftContent) {
|
|
227
|
-
parts.push(`\n**Draft context available:**\n${draftContent
|
|
230
|
+
parts.push(`\n**Draft context available:**\n${summarizeArtifactForQueue(draftContent, relMilestoneFile(basePath, mid, "CONTEXT-DRAFT"))}`);
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
}
|
|
@@ -235,7 +238,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
235
238
|
if (roadmapFile) {
|
|
236
239
|
const content = await loadFile(roadmapFile);
|
|
237
240
|
if (content) {
|
|
238
|
-
parts.push(`\n**Roadmap:**\n${content
|
|
241
|
+
parts.push(`\n**Roadmap:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "ROADMAP"))}`);
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
244
|
}
|
|
@@ -249,7 +252,65 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
249
252
|
sections.push(`### Previous Queue Entries\nSource: \`${relGsdRootFile("QUEUE")}\`\n\n${queueContent.trim()}`);
|
|
250
253
|
}
|
|
251
254
|
}
|
|
252
|
-
return sections
|
|
255
|
+
return capExistingMilestonesContext(sections);
|
|
256
|
+
}
|
|
257
|
+
function summarizeArtifactForQueue(content, sourcePath, cap = QUEUE_ARTIFACT_EXCERPT_MAX_CHARS) {
|
|
258
|
+
const trimmed = content.trim();
|
|
259
|
+
if (trimmed.length <= cap) {
|
|
260
|
+
return `Source: \`${sourcePath}\`\n\n${trimmed}`;
|
|
261
|
+
}
|
|
262
|
+
const excerpt = trimmed.slice(0, cap).trimEnd();
|
|
263
|
+
const omittedChars = trimmed.length - excerpt.length;
|
|
264
|
+
return [
|
|
265
|
+
`Source: \`${sourcePath}\``,
|
|
266
|
+
"",
|
|
267
|
+
excerpt,
|
|
268
|
+
"",
|
|
269
|
+
`[Truncated ${omittedChars} chars. Read \`${sourcePath}\` for full content.]`,
|
|
270
|
+
].join("\n");
|
|
271
|
+
}
|
|
272
|
+
function capExistingMilestonesContext(sections, cap = QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS) {
|
|
273
|
+
const fullContext = sections.join(QUEUE_CONTEXT_SECTION_SEPARATOR);
|
|
274
|
+
if (fullContext.length <= cap)
|
|
275
|
+
return fullContext;
|
|
276
|
+
const notice = `[Existing milestones context truncated to ${cap} chars. Read source paths in this prompt or the corresponding .gsd artifacts for full details.]`;
|
|
277
|
+
const noticeSuffix = `${QUEUE_CONTEXT_SECTION_SEPARATOR}${notice}`;
|
|
278
|
+
const selected = [];
|
|
279
|
+
for (const section of sections) {
|
|
280
|
+
const candidate = [...selected, section].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
281
|
+
if (candidate.length <= cap) {
|
|
282
|
+
selected.push(section);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
if (selected.length === sections.length) {
|
|
288
|
+
return selected.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
289
|
+
}
|
|
290
|
+
const compactTail = sections.slice(selected.length).map(compactSectionForQueueBudget);
|
|
291
|
+
const hybrid = [...selected, ...compactTail].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
292
|
+
if (hybrid.length <= cap)
|
|
293
|
+
return hybrid;
|
|
294
|
+
const compact = sections.map(compactSectionForQueueBudget);
|
|
295
|
+
const compactContext = compact.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
296
|
+
if (compactContext.length <= cap)
|
|
297
|
+
return compactContext;
|
|
298
|
+
return `${compactContext.slice(0, Math.max(0, cap - notice.length - 2)).trimEnd()}\n\n${notice}`;
|
|
299
|
+
}
|
|
300
|
+
function compactSectionForQueueBudget(section) {
|
|
301
|
+
const lines = section.split("\n");
|
|
302
|
+
const compact = [];
|
|
303
|
+
if (lines[0])
|
|
304
|
+
compact.push(lines[0]);
|
|
305
|
+
const statusLine = lines.find(line => line.startsWith("**Status:**"));
|
|
306
|
+
if (statusLine)
|
|
307
|
+
compact.push(statusLine);
|
|
308
|
+
const sourceLines = lines.filter(line => line.startsWith("Source: `"));
|
|
309
|
+
if (sourceLines.length > 0) {
|
|
310
|
+
compact.push("", "**Sources:**", ...sourceLines);
|
|
311
|
+
compact.push("", "[Artifact excerpts omitted due to total queue/rethink context budget.]");
|
|
312
|
+
}
|
|
313
|
+
return compact.join("\n");
|
|
253
314
|
}
|
|
254
315
|
// ─── Internal Helpers ───────────────────────────────────────────────────────
|
|
255
316
|
/**
|
|
@@ -1,29 +1,61 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Always-on ambient health signal rendered below the editor.
|
|
3
|
-
import {
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { runProviderChecks, runProviderChecksAsync, summariseProviderIssues } from "./doctor-providers.js";
|
|
4
5
|
import { runEnvironmentChecks, runEnvironmentChecksAsync } from "./doctor-environment.js";
|
|
5
6
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
6
|
-
import {
|
|
7
|
+
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
7
8
|
import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
|
|
8
9
|
import { projectRoot } from "./commands/context.js";
|
|
9
10
|
import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
|
|
10
11
|
export const HEALTH_WIDGET_ACTIVE_HINTS = " /gsd auto to run · /gsd status to inspect · /gsd report for snapshots · /gsd notifications for history · /gsd help";
|
|
12
|
+
const LAST_COMMIT_LOOKUP_TIMEOUT_MS = 3_000;
|
|
13
|
+
const REFRESH_INTERVAL_MS = 60_000;
|
|
14
|
+
const PROJECT_STATE_CACHE_TTL_MS = REFRESH_INTERVAL_MS;
|
|
11
15
|
// ── Data loader ────────────────────────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const projectStateCache = new Map();
|
|
17
|
+
export function getCachedProjectState(basePath, force) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const cached = projectStateCache.get(basePath);
|
|
20
|
+
if (!force && cached && now - cached.computedAt <= PROJECT_STATE_CACHE_TTL_MS) {
|
|
21
|
+
return cached.state;
|
|
22
|
+
}
|
|
23
|
+
const state = detectHealthWidgetProjectState(basePath);
|
|
24
|
+
projectStateCache.set(basePath, { state, computedAt: now });
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
|
+
function runHealthWidgetGit(basePath, args) {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
const child = execFile("git", args, {
|
|
30
|
+
cwd: basePath,
|
|
31
|
+
timeout: LAST_COMMIT_LOOKUP_TIMEOUT_MS,
|
|
32
|
+
encoding: "utf-8",
|
|
33
|
+
env: GIT_NO_PROMPT_ENV,
|
|
34
|
+
}, (err, stdout) => resolve(err ? null : String(stdout).trimEnd()));
|
|
35
|
+
child.on("error", () => resolve(null));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
async function loadLastCommitInfoAsync(basePath) {
|
|
16
39
|
try {
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
const epoch = nativeLastCommitEpoch(basePath, branch || "HEAD");
|
|
20
|
-
if (epoch > 0) {
|
|
21
|
-
return { epoch, message: nativeCommitSubject(basePath, branch || "HEAD") || null };
|
|
22
|
-
}
|
|
40
|
+
if ((await runHealthWidgetGit(basePath, ["rev-parse", "--git-dir"])) === null) {
|
|
41
|
+
return { epoch: null, message: null };
|
|
23
42
|
}
|
|
43
|
+
const branch = await runHealthWidgetGit(basePath, ["branch", "--show-current"]);
|
|
44
|
+
const ref = branch || "HEAD";
|
|
45
|
+
const raw = await runHealthWidgetGit(basePath, ["log", "-1", "--format=%ct%x00%s", ref]);
|
|
46
|
+
if (!raw)
|
|
47
|
+
return { epoch: null, message: null };
|
|
48
|
+
const separator = raw.indexOf("\0");
|
|
49
|
+
const epochText = separator >= 0 ? raw.slice(0, separator) : raw;
|
|
50
|
+
const epoch = parseInt(epochText.trim(), 10) || 0;
|
|
51
|
+
if (epoch <= 0)
|
|
52
|
+
return { epoch: null, message: null };
|
|
53
|
+
const message = separator >= 0 ? raw.slice(separator + 1).trim() : "";
|
|
54
|
+
return { epoch, message: message || null };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { epoch: null, message: null };
|
|
24
58
|
}
|
|
25
|
-
catch { /* non-fatal */ }
|
|
26
|
-
return { epoch: null, message: null };
|
|
27
59
|
}
|
|
28
60
|
function loadHealthWidgetData(basePath, options) {
|
|
29
61
|
// `includeChecks` gates the expensive subprocess-backed checks (provider +
|
|
@@ -38,7 +70,7 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
38
70
|
let environmentWarningCount = 0;
|
|
39
71
|
let lastCommitEpoch = null;
|
|
40
72
|
let lastCommitMessage = null;
|
|
41
|
-
const projectState =
|
|
73
|
+
const projectState = getCachedProjectState(basePath, options?.forceProjectState);
|
|
42
74
|
try {
|
|
43
75
|
const prefs = loadEffectiveGSDPreferences();
|
|
44
76
|
budgetCeiling = prefs?.preferences?.budget_ceiling;
|
|
@@ -66,12 +98,6 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
66
98
|
}
|
|
67
99
|
catch { /* non-fatal */ }
|
|
68
100
|
}
|
|
69
|
-
// ── Last commit info ── (git spawns — gated like the other expensive checks)
|
|
70
|
-
if (includeChecks) {
|
|
71
|
-
const commit = loadLastCommitInfo(basePath);
|
|
72
|
-
lastCommitEpoch = commit.epoch;
|
|
73
|
-
lastCommitMessage = commit.message;
|
|
74
|
-
}
|
|
75
101
|
return {
|
|
76
102
|
projectState,
|
|
77
103
|
budgetCeiling,
|
|
@@ -85,17 +111,15 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
85
111
|
};
|
|
86
112
|
}
|
|
87
113
|
// Non-blocking variant used by the widget's background refresh: the cheap fields
|
|
88
|
-
// come from the synchronous snapshot, then provider
|
|
89
|
-
// layered in off the event-loop critical path
|
|
90
|
-
// runEnvironmentChecksAsync). Keeps the always-on widget from stalling the UI on
|
|
91
|
-
// its initial enrichment or its 60s refresh.
|
|
114
|
+
// come from the synchronous snapshot, then provider, environment, and last-commit
|
|
115
|
+
// checks are layered in off the event-loop critical path.
|
|
92
116
|
async function loadHealthWidgetDataAsync(basePath) {
|
|
93
117
|
const data = loadHealthWidgetData(basePath, { includeChecks: false });
|
|
94
118
|
let providerIssue = data.providerIssue;
|
|
95
119
|
let environmentErrorCount = 0;
|
|
96
120
|
let environmentWarningCount = 0;
|
|
97
121
|
try {
|
|
98
|
-
providerIssue = summariseProviderIssues(
|
|
122
|
+
providerIssue = summariseProviderIssues(await runProviderChecksAsync());
|
|
99
123
|
}
|
|
100
124
|
catch { /* non-fatal */ }
|
|
101
125
|
try {
|
|
@@ -108,7 +132,7 @@ async function loadHealthWidgetDataAsync(basePath) {
|
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
catch { /* non-fatal */ }
|
|
111
|
-
const commit =
|
|
135
|
+
const commit = await loadLastCommitInfoAsync(basePath);
|
|
112
136
|
return {
|
|
113
137
|
...data,
|
|
114
138
|
providerIssue,
|
|
@@ -120,7 +144,6 @@ async function loadHealthWidgetDataAsync(basePath) {
|
|
|
120
144
|
};
|
|
121
145
|
}
|
|
122
146
|
// ── Widget init ────────────────────────────────────────────────────────────────
|
|
123
|
-
const REFRESH_INTERVAL_MS = 60_000;
|
|
124
147
|
/**
|
|
125
148
|
* Initialize the always-on gsd-health widget (belowEditor).
|
|
126
149
|
* Call once from the extension entry point after context is available.
|
|
@@ -129,13 +152,16 @@ export function initHealthWidget(ctx) {
|
|
|
129
152
|
if (!ctx.hasUI)
|
|
130
153
|
return;
|
|
131
154
|
const basePath = projectRoot();
|
|
155
|
+
// Re-init must reflect filesystem changes immediately; the TTL cache is for
|
|
156
|
+
// interval refreshes, not this one-off synchronous paint.
|
|
157
|
+
projectStateCache.delete(basePath);
|
|
132
158
|
// String-array fallback — used in RPC mode (factory is a no-op there).
|
|
133
159
|
// Skip the expensive provider/environment doctor checks here: this runs
|
|
134
160
|
// synchronously on the interactive-startup path, where running them would
|
|
135
161
|
// block first paint by ~0.9s (lsof/docker probes, otherwise run again
|
|
136
162
|
// immediately by the factory below). The factory's async refresh fills in
|
|
137
163
|
// real health once the screen is up.
|
|
138
|
-
const initialData = loadHealthWidgetData(basePath, { includeChecks: false });
|
|
164
|
+
const initialData = loadHealthWidgetData(basePath, { includeChecks: false, forceProjectState: true });
|
|
139
165
|
ctx.ui.setWidget("gsd-health", buildHealthLines(initialData), { placement: "belowEditor" });
|
|
140
166
|
// Factory-based widget for TUI mode — replaces the string-array above
|
|
141
167
|
ctx.ui.setWidget("gsd-health", (_tui, _theme) => {
|
|
@@ -56,6 +56,26 @@ export function saveJsonFile(filePath, data) {
|
|
|
56
56
|
// Non-fatal — don't let persistence failures break operation
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Save a JSON file atomically using compact serialization.
|
|
61
|
+
*
|
|
62
|
+
* Intended for machine-only ledgers where pretty-printing has no consumer.
|
|
63
|
+
* Keeps the same write-tmp-rename safety and non-fatal error behavior as
|
|
64
|
+
* saveJsonFile.
|
|
65
|
+
*/
|
|
66
|
+
export function saveJsonFileCompact(filePath, data) {
|
|
67
|
+
try {
|
|
68
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
69
|
+
// Use randomized tmp suffix to prevent concurrent-write data loss
|
|
70
|
+
const tmp = `${filePath}.tmp.${randomBytes(4).toString("hex")}`;
|
|
71
|
+
writeFileSync(tmp, JSON.stringify(data) + "\n", "utf-8");
|
|
72
|
+
renameSync(tmp, filePath);
|
|
73
|
+
// No cleanup needed — renameSync atomically removes tmp on success
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Non-fatal — don't let persistence failures break operation
|
|
77
|
+
}
|
|
78
|
+
}
|
|
59
79
|
/**
|
|
60
80
|
* Write a JSON file atomically (write to .tmp, then rename).
|
|
61
81
|
* Creates parent directories as needed. Non-fatal on error.
|