@opengsd/gsd-pi 1.0.2-dev.e70300c → 1.0.2-dev.fb7ddf1
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 +63 -12
- package/dist/headless-answers.js +2 -1
- package/dist/headless-events.d.ts +1 -0
- package/dist/headless-events.js +8 -1
- package/dist/onboarding.js +22 -3
- package/dist/resource-loader.d.ts +7 -0
- package/dist/resource-loader.js +44 -9
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +34 -11
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/get-secrets-from-user.js +16 -16
- package/dist/resources/extensions/google-cli/index.js +30 -0
- package/dist/resources/extensions/google-cli/models.js +55 -0
- package/dist/resources/extensions/google-cli/package.json +11 -0
- package/dist/resources/extensions/google-cli/readiness.js +12 -0
- package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
- package/dist/resources/extensions/gsd/auto/loop.js +81 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +38 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +8 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +17 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +65 -16
- package/dist/resources/extensions/gsd/auto-prompts.js +5 -236
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -1
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +34 -1
- package/dist/resources/extensions/gsd/auto.js +40 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -2
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +39 -5
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +107 -27
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -27
- package/dist/resources/extensions/gsd/bootstrap/tool-search-shim.js +4 -4
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -0
- package/dist/resources/extensions/gsd/commands-usage.js +105 -1
- package/dist/resources/extensions/gsd/config-overlay.js +20 -14
- package/dist/resources/extensions/gsd/context-overlay.js +22 -16
- package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +87 -0
- package/dist/resources/extensions/gsd/doctor-git-checks.js +70 -5
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/doctor.js +7 -2
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/guided-flow.js +5 -6
- package/dist/resources/extensions/gsd/key-manager.js +45 -13
- package/dist/resources/extensions/gsd/mcp-filter.js +57 -18
- package/dist/resources/extensions/gsd/mcp-project-config.js +15 -9
- package/dist/resources/extensions/gsd/migration-auto-check.js +5 -1
- package/dist/resources/extensions/gsd/milestone-actions.js +3 -0
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +28 -0
- package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
- package/dist/resources/extensions/gsd/parallel-merge.js +6 -4
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/post-execution-checks.js +5 -4
- package/dist/resources/extensions/gsd/preferences-skills.js +11 -4
- package/dist/resources/extensions/gsd/preferences.js +14 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +3 -20
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/repo-identity.js +36 -6
- package/dist/resources/extensions/gsd/repository-registry.js +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +13 -6
- package/dist/resources/extensions/gsd/skill-activation.js +233 -0
- package/dist/resources/extensions/gsd/skill-catalog.data.js +820 -0
- package/dist/resources/extensions/gsd/skill-catalog.install.js +179 -0
- package/dist/resources/extensions/gsd/skill-catalog.js +5 -1028
- package/dist/resources/extensions/gsd/skill-discovery.js +121 -79
- package/dist/resources/extensions/gsd/skill-scope.js +52 -0
- package/dist/resources/extensions/gsd/skill-telemetry.js +6 -39
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +1 -1
- package/dist/resources/extensions/gsd/skills.js +60 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +351 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +4 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +42 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +63 -2
- package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +35 -26
- package/dist/resources/extensions/gsd/user-input-boundary.js +1 -1
- package/dist/resources/extensions/gsd/vision-ask.js +22 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/gsd/worktree-state-projection.js +29 -0
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/extensions/shared/confirm-ui.js +9 -6
- package/dist/resources/extensions/shared/dialog-frame.js +42 -0
- package/dist/resources/extensions/shared/interview-ui.js +42 -30
- package/dist/resources/extensions/shared/next-action-ui.js +6 -6
- package/dist/resources/extensions/subagent/index.js +8 -15
- package/dist/resources/shared/package-manager-detection.js +36 -0
- package/dist/resources/skills/agent-browser/SKILL.md +1 -1
- package/dist/resources/skills/api-design/SKILL.md +1 -1
- package/dist/resources/skills/code-optimizer/SKILL.md +6 -11
- package/dist/resources/skills/create-gsd-extension/SKILL.md +1 -1
- package/dist/resources/skills/create-mcp-server/SKILL.md +1 -1
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +2 -10
- package/dist/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
- package/dist/resources/skills/decompose-into-slices/SKILL.md +3 -3
- package/dist/resources/skills/dependency-upgrade/SKILL.md +1 -1
- package/dist/resources/skills/forensics/SKILL.md +2 -2
- package/dist/resources/skills/grill-me/SKILL.md +1 -1
- package/dist/resources/skills/handoff/SKILL.md +1 -1
- package/dist/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
- package/dist/resources/skills/observability/SKILL.md +1 -1
- package/dist/resources/skills/security-review/SKILL.md +1 -1
- package/dist/resources/skills/spike-wrap-up/SKILL.md +1 -1
- package/dist/resources/skills/tdd/SKILL.md +1 -1
- package/dist/resources/skills/write-docs/SKILL.md +1 -1
- package/dist/resources/skills/write-milestone-brief/SKILL.md +1 -1
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +7 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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.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/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
- package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-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/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +5 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.test.js +5 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +15 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/dist/workflow.test.js +1 -0
- package/packages/contracts/dist/workflow.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +22 -8
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- 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 +3 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -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 +2 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +7 -1
- 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 +47 -8
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +16 -14
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/skills.js +6 -0
- package/packages/pi-agent-core/dist/harness/skills.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/system-prompt.js +7 -0
- package/packages/pi-agent-core/dist/harness/system-prompt.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +48 -206
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +67 -220
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses-shared.js +28 -4
- package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/tool-search-shim.test.js +29 -1
- package/packages/pi-ai/dist/utils/tests/tool-search-shim.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.d.ts +4 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/tool-search-shim.js +58 -10
- package/packages/pi-ai/dist/utils/tool-search-shim.js.map +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.d.ts +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/tool-shims.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +8 -2
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +3 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +5 -7
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/read.js +5 -4
- package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +0 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +8 -8
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/detect-existing.js +17 -3
- package/scripts/install/npm-global.js +103 -33
- package/scripts/install.js +1 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +36 -11
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +86 -19
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/get-secrets-from-user.ts +17 -16
- package/src/resources/extensions/google-cli/index.ts +34 -0
- package/src/resources/extensions/google-cli/models.ts +57 -0
- package/src/resources/extensions/google-cli/package.json +11 -0
- package/src/resources/extensions/google-cli/readiness.ts +15 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
- package/src/resources/extensions/gsd/auto/loop.ts +96 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +47 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +10 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +31 -11
- package/src/resources/extensions/gsd/auto-post-unit.ts +101 -18
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -284
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -7
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +3 -1
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +45 -1
- package/src/resources/extensions/gsd/auto.ts +50 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +9 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +42 -5
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +124 -25
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -28
- package/src/resources/extensions/gsd/bootstrap/tool-search-shim.ts +4 -4
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
- package/src/resources/extensions/gsd/commands-usage.ts +110 -5
- package/src/resources/extensions/gsd/config-overlay.ts +19 -16
- package/src/resources/extensions/gsd/context-overlay.ts +24 -19
- package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +99 -0
- package/src/resources/extensions/gsd/doctor-git-checks.ts +72 -5
- package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +7 -2
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/guided-flow.ts +5 -6
- package/src/resources/extensions/gsd/key-manager.ts +57 -14
- package/src/resources/extensions/gsd/mcp-filter.ts +64 -17
- package/src/resources/extensions/gsd/mcp-project-config.ts +24 -9
- package/src/resources/extensions/gsd/migration-auto-check.ts +6 -0
- package/src/resources/extensions/gsd/milestone-actions.ts +2 -0
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +28 -0
- package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
- package/src/resources/extensions/gsd/parallel-merge.ts +6 -4
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/post-execution-checks.ts +7 -4
- package/src/resources/extensions/gsd/preferences-skills.ts +11 -4
- package/src/resources/extensions/gsd/preferences.ts +17 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +3 -20
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/repo-identity.ts +35 -7
- package/src/resources/extensions/gsd/repository-registry.ts +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +13 -6
- package/src/resources/extensions/gsd/skill-activation.ts +292 -0
- package/src/resources/extensions/gsd/skill-catalog.data.ts +858 -0
- package/src/resources/extensions/gsd/skill-catalog.install.ts +205 -0
- package/src/resources/extensions/gsd/skill-catalog.ts +16 -1087
- package/src/resources/extensions/gsd/skill-discovery.ts +134 -78
- package/src/resources/extensions/gsd/skill-scope.ts +63 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +6 -40
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +1 -1
- package/src/resources/extensions/gsd/skills.ts +75 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +499 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +40 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +8 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +328 -2
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +28 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +40 -3
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +71 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +22 -3
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +56 -1
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +127 -10
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/project-relocation-recovery.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +116 -11
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +30 -1
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +111 -0
- package/src/resources/extensions/gsd/tests/skill-scope-auto.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/skills.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +67 -1
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +42 -10
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +82 -5
- package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +37 -26
- package/src/resources/extensions/gsd/user-input-boundary.ts +1 -1
- package/src/resources/extensions/gsd/vision-ask.ts +28 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/gsd/worktree-state-projection.ts +33 -0
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/extensions/shared/confirm-ui.ts +8 -12
- package/src/resources/extensions/shared/dialog-frame.ts +71 -0
- package/src/resources/extensions/shared/interview-ui.ts +43 -42
- package/src/resources/extensions/shared/next-action-ui.ts +6 -6
- package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
- package/src/resources/extensions/subagent/index.ts +8 -15
- package/src/resources/shared/package-manager-detection.ts +39 -0
- package/src/resources/skills/agent-browser/SKILL.md +1 -1
- package/src/resources/skills/api-design/SKILL.md +1 -1
- package/src/resources/skills/code-optimizer/SKILL.md +6 -11
- package/src/resources/skills/create-gsd-extension/SKILL.md +1 -1
- package/src/resources/skills/create-mcp-server/SKILL.md +1 -1
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +1 -1
- package/src/resources/skills/create-skill/workflows/verify-skill.md +2 -10
- package/src/resources/skills/debug-like-expert/references/when-to-research.md +1 -5
- package/src/resources/skills/decompose-into-slices/SKILL.md +3 -3
- package/src/resources/skills/dependency-upgrade/SKILL.md +1 -1
- package/src/resources/skills/forensics/SKILL.md +2 -2
- package/src/resources/skills/grill-me/SKILL.md +1 -1
- package/src/resources/skills/handoff/SKILL.md +1 -1
- package/src/resources/skills/make-interfaces-feel-better/SKILL.md +1 -1
- package/src/resources/skills/observability/SKILL.md +1 -1
- package/src/resources/skills/security-review/SKILL.md +1 -1
- package/src/resources/skills/spike-wrap-up/SKILL.md +1 -1
- package/src/resources/skills/tdd/SKILL.md +1 -1
- package/src/resources/skills/write-docs/SKILL.md +1 -1
- package/src/resources/skills/write-milestone-brief/SKILL.md +1 -1
- /package/dist/web/standalone/.next/static/{szb-HAt0IoSx3docUZO-E → tH1tnDYt1E0hK9Ien73Z0}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{szb-HAt0IoSx3docUZO-E → tH1tnDYt1E0hK9Ien73Z0}/_ssgManifest.js +0 -0
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Shows current LLM context window usage and session token totals.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ExtensionCommandContext, ContextUsage, SessionEntry } from "@gsd/pi-coding-agent";
|
|
7
|
+
import type { ExtensionCommandContext, ContextUsage, SessionEntry, Theme } from "@gsd/pi-coding-agent";
|
|
8
|
+
import { Key, matchesKey } from "@gsd/pi-tui";
|
|
8
9
|
|
|
9
10
|
import { formatCost, formatPercent, formatTokenCount } from "./metrics.js";
|
|
10
11
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
12
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
11
13
|
|
|
12
14
|
export interface SessionTokenTotals {
|
|
13
15
|
input: number;
|
|
@@ -160,6 +162,101 @@ export function formatUsageReport(options: {
|
|
|
160
162
|
return lines.join("\n");
|
|
161
163
|
}
|
|
162
164
|
|
|
165
|
+
async function showUsageDialog(
|
|
166
|
+
ctx: ExtensionCommandContext,
|
|
167
|
+
reportText: string,
|
|
168
|
+
): Promise<boolean | undefined> {
|
|
169
|
+
return ctx.ui.custom<boolean>((tui, theme: Theme, _kb, done) => {
|
|
170
|
+
let cachedLines: string[] | undefined;
|
|
171
|
+
let cachedWidth: number | undefined;
|
|
172
|
+
let cachedRows: number | undefined;
|
|
173
|
+
let cachedScrollOffset: number | undefined;
|
|
174
|
+
let scrollOffset = 0;
|
|
175
|
+
let lastMaxScroll = 0;
|
|
176
|
+
let lastVisibleRows = 1;
|
|
177
|
+
|
|
178
|
+
function render(width: number): string[] {
|
|
179
|
+
const terminalRows = process.stdout.rows || 0;
|
|
180
|
+
if (
|
|
181
|
+
cachedLines &&
|
|
182
|
+
cachedWidth === width &&
|
|
183
|
+
cachedRows === terminalRows &&
|
|
184
|
+
cachedScrollOffset === scrollOffset
|
|
185
|
+
) {
|
|
186
|
+
return cachedLines;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const contentWidth = Math.max(1, width - 4);
|
|
190
|
+
const body = reportText.split("\n");
|
|
191
|
+
if (body[0] === "Context Usage") body.shift();
|
|
192
|
+
while (body[0] === "") body.shift();
|
|
193
|
+
const maxOverlayRows = terminalRows > 0 ? Math.max(5, Math.floor(terminalRows * 0.8)) : 24;
|
|
194
|
+
const frameRows = 4;
|
|
195
|
+
const visibleRows = Math.max(1, maxOverlayRows - frameRows);
|
|
196
|
+
const maxScroll = Math.max(0, body.length - visibleRows);
|
|
197
|
+
scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
|
|
198
|
+
lastMaxScroll = maxScroll;
|
|
199
|
+
lastVisibleRows = visibleRows;
|
|
200
|
+
const visible = body.slice(scrollOffset, scrollOffset + visibleRows);
|
|
201
|
+
const scrollable = body.length > visibleRows;
|
|
202
|
+
|
|
203
|
+
cachedLines = renderDialogFrame(theme, "Context Usage", visible, width, {
|
|
204
|
+
footer: renderKeyHints(theme, scrollable ? ["↑↓ scroll", "any key close"] : ["any key close"], contentWidth),
|
|
205
|
+
scroll: { offset: scrollOffset, visibleRows, totalRows: body.length },
|
|
206
|
+
});
|
|
207
|
+
cachedWidth = width;
|
|
208
|
+
cachedRows = terminalRows;
|
|
209
|
+
cachedScrollOffset = scrollOffset;
|
|
210
|
+
return cachedLines;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function scrollBy(delta: number): boolean {
|
|
214
|
+
if (lastMaxScroll <= 0) return false;
|
|
215
|
+
const nextOffset = Math.min(Math.max(scrollOffset + delta, 0), lastMaxScroll);
|
|
216
|
+
if (nextOffset !== scrollOffset) {
|
|
217
|
+
scrollOffset = nextOffset;
|
|
218
|
+
cachedLines = undefined;
|
|
219
|
+
cachedScrollOffset = undefined;
|
|
220
|
+
tui.requestRender();
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
render,
|
|
227
|
+
invalidate: () => {
|
|
228
|
+
cachedLines = undefined;
|
|
229
|
+
cachedWidth = undefined;
|
|
230
|
+
cachedRows = undefined;
|
|
231
|
+
cachedScrollOffset = undefined;
|
|
232
|
+
},
|
|
233
|
+
handleInput: (data: string) => {
|
|
234
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
235
|
+
if (scrollBy(1)) return;
|
|
236
|
+
}
|
|
237
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
238
|
+
if (scrollBy(-1)) return;
|
|
239
|
+
}
|
|
240
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
241
|
+
if (scrollBy(lastVisibleRows)) return;
|
|
242
|
+
}
|
|
243
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
244
|
+
if (scrollBy(-lastVisibleRows)) return;
|
|
245
|
+
}
|
|
246
|
+
done(true);
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}, {
|
|
250
|
+
overlay: true,
|
|
251
|
+
overlayOptions: {
|
|
252
|
+
width: "70%",
|
|
253
|
+
minWidth: 64,
|
|
254
|
+
maxHeight: "80%",
|
|
255
|
+
anchor: "center",
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
163
260
|
export async function handleUsage(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
164
261
|
const contextUsage = ctx.getContextUsage?.();
|
|
165
262
|
const sessionTotals = scanSessionTokenTotals(ctx.sessionManager.getEntries());
|
|
@@ -187,8 +284,16 @@ export async function handleUsage(args: string, ctx: ExtensionCommandContext): P
|
|
|
187
284
|
return;
|
|
188
285
|
}
|
|
189
286
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
287
|
+
const reportText = formatUsageReport({ modelLabel, contextUsage, sessionTotals });
|
|
288
|
+
|
|
289
|
+
if (ctx.hasUI) {
|
|
290
|
+
try {
|
|
291
|
+
const result = await showUsageDialog(ctx, reportText);
|
|
292
|
+
if (result !== undefined) return;
|
|
293
|
+
} catch {
|
|
294
|
+
// Fall back to text notify below when custom overlays are unavailable.
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
ctx.ui.notify(reportText, "info");
|
|
194
299
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type { Theme } from "@gsd/pi-coding-agent";
|
|
11
11
|
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
12
12
|
|
|
13
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
13
14
|
import {
|
|
14
15
|
loadEffectiveGSDPreferences,
|
|
15
16
|
loadGlobalGSDPreferences,
|
|
@@ -231,6 +232,7 @@ export class GSDConfigOverlay {
|
|
|
231
232
|
private onClose: () => void;
|
|
232
233
|
private sections: ConfigSection[];
|
|
233
234
|
private cachedLines?: string[];
|
|
235
|
+
private cachedWidth?: number;
|
|
234
236
|
private scrollOffset = 0;
|
|
235
237
|
private disposed = false;
|
|
236
238
|
|
|
@@ -247,6 +249,7 @@ export class GSDConfigOverlay {
|
|
|
247
249
|
|
|
248
250
|
invalidate(): void {
|
|
249
251
|
this.cachedLines = undefined;
|
|
252
|
+
this.cachedWidth = undefined;
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
dispose(): void {
|
|
@@ -286,16 +289,13 @@ export class GSDConfigOverlay {
|
|
|
286
289
|
}
|
|
287
290
|
|
|
288
291
|
render(width: number): string[] {
|
|
289
|
-
if (this.cachedLines) return this.cachedLines;
|
|
292
|
+
if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
|
|
290
293
|
|
|
291
294
|
const t = this.theme;
|
|
292
|
-
const w = Math.max(
|
|
295
|
+
const w = Math.max(1, width);
|
|
296
|
+
const contentWidth = Math.max(1, w - 4);
|
|
293
297
|
const allLines: string[] = [];
|
|
294
298
|
|
|
295
|
-
// Header
|
|
296
|
-
allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
|
|
297
|
-
allLines.push(t.fg("muted", "\u2500".repeat(w)));
|
|
298
|
-
|
|
299
299
|
// Find max label width for alignment
|
|
300
300
|
let maxLabel = 0;
|
|
301
301
|
for (const section of this.sections) {
|
|
@@ -306,26 +306,29 @@ export class GSDConfigOverlay {
|
|
|
306
306
|
const labelPad = Math.min(maxLabel + 2, 24);
|
|
307
307
|
|
|
308
308
|
for (const section of this.sections) {
|
|
309
|
-
allLines.push("");
|
|
309
|
+
if (allLines.length > 0) allLines.push("");
|
|
310
310
|
allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
|
|
311
311
|
|
|
312
312
|
for (const row of section.rows) {
|
|
313
313
|
const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
|
|
314
314
|
const value = row.accent ? t.bold(row.value) : row.value;
|
|
315
|
-
allLines.push(truncateToWidth(`${label}${value}`,
|
|
315
|
+
allLines.push(truncateToWidth(`${label}${value}`, contentWidth));
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
allLines.push("");
|
|
320
|
-
allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
|
|
321
|
-
allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
|
|
322
|
-
|
|
323
319
|
// Apply scroll
|
|
324
|
-
const
|
|
320
|
+
const terminalRows = process.stdout.rows || 32;
|
|
321
|
+
const maxBodyRows = Math.max(1, Math.min(allLines.length, terminalRows - 12));
|
|
322
|
+
const maxScroll = Math.max(0, allLines.length - maxBodyRows);
|
|
325
323
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
326
|
-
const visible = allLines.slice(this.scrollOffset);
|
|
324
|
+
const visible = allLines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
|
|
325
|
+
const footer = renderKeyHints(t, ["esc/q close", "\u2191\u2193/jk scroll", "/gsd prefs to edit"], contentWidth);
|
|
327
326
|
|
|
328
|
-
this.cachedLines = visible
|
|
329
|
-
|
|
327
|
+
this.cachedLines = renderDialogFrame(t, "GSD Configuration", visible, w, {
|
|
328
|
+
footer,
|
|
329
|
+
scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: allLines.length },
|
|
330
|
+
});
|
|
331
|
+
this.cachedWidth = width;
|
|
332
|
+
return this.cachedLines;
|
|
330
333
|
}
|
|
331
334
|
}
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { Theme, ThemeColor } from "@gsd/pi-coding-agent";
|
|
6
|
-
import { matchesKey, Key, truncateToWidth
|
|
6
|
+
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
7
7
|
|
|
8
8
|
import type { ContextBreakdownReport, ContextSectionBreakdown } from "./commands-context.js";
|
|
9
9
|
import { formatTokenCount } from "./metrics.js";
|
|
10
|
-
import { renderProgressBar, rightAlign } from "./tui/render-kit.js";
|
|
10
|
+
import { renderDialogFrame, renderKeyHints, renderProgressBar, rightAlign } from "./tui/render-kit.js";
|
|
11
11
|
|
|
12
12
|
const SECTION_COLORS: ThemeColor[] = ["accent", "success", "warning", "borderAccent", "text"];
|
|
13
13
|
|
|
@@ -70,6 +70,7 @@ export class GSDContextOverlay {
|
|
|
70
70
|
private onClose: () => void;
|
|
71
71
|
private report: ContextBreakdownReport;
|
|
72
72
|
private cachedLines?: string[];
|
|
73
|
+
private cachedWidth?: number;
|
|
73
74
|
private scrollOffset = 0;
|
|
74
75
|
private disposed = false;
|
|
75
76
|
|
|
@@ -87,6 +88,7 @@ export class GSDContextOverlay {
|
|
|
87
88
|
|
|
88
89
|
invalidate(): void {
|
|
89
90
|
this.cachedLines = undefined;
|
|
91
|
+
this.cachedWidth = undefined;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
dispose(): void {
|
|
@@ -125,24 +127,22 @@ export class GSDContextOverlay {
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
render(width: number): string[] {
|
|
128
|
-
if (this.cachedLines) return this.cachedLines;
|
|
130
|
+
if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;
|
|
129
131
|
|
|
130
132
|
const theme = this.theme;
|
|
131
|
-
const w = Math.max(
|
|
133
|
+
const w = Math.max(1, width);
|
|
134
|
+
const contentWidth = Math.max(1, w - 4);
|
|
132
135
|
const totals = getContextChartTotals(this.report);
|
|
133
136
|
const chartTotal = Math.max(totals.inContext, totals.estimated, 1);
|
|
134
137
|
const lines: string[] = [];
|
|
135
138
|
|
|
136
|
-
lines.push(theme.bold(theme.fg("accent", " Context Breakdown ")));
|
|
137
|
-
lines.push(theme.fg("muted", "─".repeat(w)));
|
|
138
|
-
|
|
139
139
|
if (this.report.modelLabel) {
|
|
140
|
-
lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel),
|
|
140
|
+
lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), contentWidth));
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
lines.push("");
|
|
144
144
|
if (totals.window != null) {
|
|
145
|
-
const usageBarWidth = Math.max(
|
|
145
|
+
const usageBarWidth = Math.max(8, contentWidth - 28);
|
|
146
146
|
const usageBar = renderProgressBar(theme, totals.inContext, totals.window, usageBarWidth, {
|
|
147
147
|
filledColor: totals.inContext / totals.window > 0.85 ? "warning" : "accent",
|
|
148
148
|
});
|
|
@@ -151,7 +151,7 @@ export class GSDContextOverlay {
|
|
|
151
151
|
lines.push(` ${theme.fg("muted", "Estimated")} ${theme.fg("text", formatTokenCount(chartTotal))}`);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
const splitWidth = Math.max(
|
|
154
|
+
const splitWidth = Math.max(8, Math.floor((contentWidth - 8) / 2));
|
|
155
155
|
const systemBar = renderProgressBar(theme, totals.systemTokens, chartTotal, splitWidth, { filledColor: "accent" });
|
|
156
156
|
const convBar = renderProgressBar(theme, totals.conversationTokens, chartTotal, splitWidth, { filledColor: "success" });
|
|
157
157
|
lines.push("");
|
|
@@ -160,11 +160,11 @@ export class GSDContextOverlay {
|
|
|
160
160
|
|
|
161
161
|
lines.push("");
|
|
162
162
|
lines.push(theme.bold(theme.fg("accent", " System prompt")));
|
|
163
|
-
lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal,
|
|
163
|
+
lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, contentWidth, 22));
|
|
164
164
|
|
|
165
165
|
lines.push("");
|
|
166
166
|
lines.push(theme.bold(theme.fg("accent", " Conversation")));
|
|
167
|
-
lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal,
|
|
167
|
+
lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, contentWidth, 22));
|
|
168
168
|
|
|
169
169
|
lines.push("");
|
|
170
170
|
lines.push(theme.bold(theme.fg("accent", " Skills")));
|
|
@@ -172,7 +172,7 @@ export class GSDContextOverlay {
|
|
|
172
172
|
if (skills.available.length > 0) {
|
|
173
173
|
lines.push(` ${theme.fg("muted", "Available")} ${theme.fg("text", `${skills.available.length}`)}`);
|
|
174
174
|
const preview = skills.available.slice(0, 8).join(", ");
|
|
175
|
-
lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`,
|
|
175
|
+
lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, contentWidth));
|
|
176
176
|
} else {
|
|
177
177
|
lines.push(theme.fg("dim", " none in prompt"));
|
|
178
178
|
}
|
|
@@ -187,13 +187,18 @@ export class GSDContextOverlay {
|
|
|
187
187
|
lines.push(theme.bold(theme.fg("accent", " Agents")));
|
|
188
188
|
lines.push(` ${theme.fg("muted", "Subagent spawns")} ${theme.fg("text", String(this.report.subagentSpawns))}`);
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const maxScroll = Math.max(0, lines.length - 24);
|
|
190
|
+
const terminalRows = process.stdout.rows || 32;
|
|
191
|
+
const maxBodyRows = Math.max(1, Math.min(lines.length, terminalRows - 12));
|
|
192
|
+
const maxScroll = Math.max(0, lines.length - maxBodyRows);
|
|
195
193
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
196
|
-
|
|
194
|
+
const visible = lines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
|
|
195
|
+
const footer = renderKeyHints(theme, ["esc/q close", "↑↓ scroll", "/gsd context --open"], contentWidth);
|
|
196
|
+
|
|
197
|
+
this.cachedLines = renderDialogFrame(theme, "Context Breakdown", visible, w, {
|
|
198
|
+
footer,
|
|
199
|
+
scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: lines.length },
|
|
200
|
+
});
|
|
201
|
+
this.cachedWidth = width;
|
|
197
202
|
return this.cachedLines;
|
|
198
203
|
}
|
|
199
204
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { Theme } from "@gsd/pi-coding-agent";
|
|
11
|
-
import { truncateToWidth,
|
|
11
|
+
import { truncateToWidth, matchesKey, Key } from "@gsd/pi-tui";
|
|
12
12
|
import { deriveState } from "./state.js";
|
|
13
13
|
import { loadFile } from "./files.js";
|
|
14
14
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
@@ -29,6 +29,7 @@ import { estimateTimeRemaining } from "./auto-dashboard.js";
|
|
|
29
29
|
import { computeProgressScore, formatProgressLine } from "./progress-score.js";
|
|
30
30
|
import { runEnvironmentChecks, type EnvironmentCheckResult } from "./doctor-environment.js";
|
|
31
31
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
32
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
32
33
|
|
|
33
34
|
export function unitLabel(type: string): string {
|
|
34
35
|
switch (type) {
|
|
@@ -258,35 +259,26 @@ export class GSDDashboardOverlay {
|
|
|
258
259
|
|
|
259
260
|
const content = this.buildContentLines(width);
|
|
260
261
|
const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
|
|
261
|
-
const
|
|
262
|
-
const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
|
|
262
|
+
const visibleContentRows = Math.max(1, viewportHeight - 4);
|
|
263
263
|
const maxScroll = Math.max(0, content.length - visibleContentRows);
|
|
264
264
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
265
265
|
const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
|
|
266
|
-
|
|
267
|
-
const
|
|
266
|
+
const contentWidth = Math.max(1, width - 4);
|
|
267
|
+
const footer = renderKeyHints(
|
|
268
|
+
this.theme,
|
|
269
|
+
["↑↓ scroll", "g/G top/end", `Esc/${formattedShortcutPair("dashboard")} close`],
|
|
270
|
+
contentWidth,
|
|
271
|
+
);
|
|
272
|
+
const lines = renderDialogFrame(this.theme, "GSD Dashboard", visibleContent, width, {
|
|
273
|
+
footer,
|
|
274
|
+
scroll: { offset: this.scrollOffset, visibleRows: visibleContentRows, totalRows: content.length },
|
|
275
|
+
});
|
|
268
276
|
|
|
269
277
|
this.cachedWidth = width;
|
|
270
278
|
this.cachedLines = lines;
|
|
271
279
|
return lines;
|
|
272
280
|
}
|
|
273
281
|
|
|
274
|
-
private wrapInBox(inner: string[], width: number): string[] {
|
|
275
|
-
const th = this.theme;
|
|
276
|
-
const border = (s: string) => th.fg("borderAccent", s);
|
|
277
|
-
const innerWidth = width - 4;
|
|
278
|
-
const lines: string[] = [];
|
|
279
|
-
|
|
280
|
-
lines.push(border("╭" + "─".repeat(width - 2) + "╮"));
|
|
281
|
-
for (const line of inner) {
|
|
282
|
-
const truncated = truncateToWidth(line, innerWidth);
|
|
283
|
-
const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
|
|
284
|
-
lines.push(border("│") + " " + truncated + " ".repeat(padWidth) + " " + border("│"));
|
|
285
|
-
}
|
|
286
|
-
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
287
|
-
return lines;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
282
|
private buildContentLines(width: number): string[] {
|
|
291
283
|
const th = this.theme;
|
|
292
284
|
const shellWidth = width - 4;
|
|
@@ -303,7 +295,6 @@ export class GSDDashboardOverlay {
|
|
|
303
295
|
const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
|
|
304
296
|
const centered = (content: string) => row(centerLine(content, contentWidth));
|
|
305
297
|
|
|
306
|
-
const title = th.fg("accent", th.bold("GSD Dashboard"));
|
|
307
298
|
const isRemote = !!this.dashData.remoteSession;
|
|
308
299
|
const status = this.dashData.active
|
|
309
300
|
? `${Date.now() % 2000 < 1000 ? th.fg("success", "●") : th.fg("dim", "○")} ${th.fg("success", "AUTO")}`
|
|
@@ -328,7 +319,7 @@ export class GSDDashboardOverlay {
|
|
|
328
319
|
} else if (isRemote) {
|
|
329
320
|
elapsedParts = th.fg("dim", `since ${this.dashData.remoteSession!.startedAt.replace("T", " ").slice(0, 19)}`);
|
|
330
321
|
}
|
|
331
|
-
lines.push(row(joinColumns(`${
|
|
322
|
+
lines.push(row(joinColumns(`${status}${worktreeTag}`, elapsedParts, contentWidth)));
|
|
332
323
|
|
|
333
324
|
// Progress score — traffic light indicator (#1221)
|
|
334
325
|
if (this.dashData.active || this.dashData.paused) {
|
|
@@ -610,10 +601,6 @@ export class GSDDashboardOverlay {
|
|
|
610
601
|
}
|
|
611
602
|
}
|
|
612
603
|
|
|
613
|
-
lines.push(blank());
|
|
614
|
-
lines.push(hr());
|
|
615
|
-
lines.push(centered(th.fg("dim", `↑↓ scroll · g/G top/end · Esc/${formattedShortcutPair("dashboard")} close`)));
|
|
616
|
-
|
|
617
604
|
return lines;
|
|
618
605
|
}
|
|
619
606
|
|
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import type { DoctorIssue } from "./doctor-types.js";
|
|
5
5
|
import { isDbAvailable, _getAdapter } from "./gsd-db.js";
|
|
6
|
+
import { isAfter, latestExplicitReopenAt } from "./milestone-reopen-events.js";
|
|
6
7
|
import { resolveGsdPathContract, resolveMilestoneFile } from "./paths.js";
|
|
7
8
|
import { deriveState } from "./state.js";
|
|
8
9
|
import { readEvents } from "./workflow-events.js";
|
|
@@ -151,6 +152,104 @@ export async function checkEngineHealth(
|
|
|
151
152
|
} catch {
|
|
152
153
|
// Non-fatal — duplicate ID check failed
|
|
153
154
|
}
|
|
155
|
+
|
|
156
|
+
// e. Completed milestone dispatch history but DB reopened without an explicit reopen event.
|
|
157
|
+
try {
|
|
158
|
+
const reopened = adapter
|
|
159
|
+
.prepare(
|
|
160
|
+
`SELECT m.id, m.status, ud.started_at, ud.ended_at
|
|
161
|
+
FROM milestones m
|
|
162
|
+
JOIN unit_dispatches ud ON ud.milestone_id = m.id
|
|
163
|
+
WHERE m.status NOT IN ('complete', 'done', 'skipped', 'closed')
|
|
164
|
+
AND ud.unit_type = 'complete-milestone'
|
|
165
|
+
AND ud.unit_id = m.id
|
|
166
|
+
AND ud.status = 'completed'
|
|
167
|
+
AND ud.id = (
|
|
168
|
+
SELECT latest.id
|
|
169
|
+
FROM unit_dispatches latest
|
|
170
|
+
WHERE latest.milestone_id = m.id
|
|
171
|
+
AND latest.unit_type = 'complete-milestone'
|
|
172
|
+
AND latest.unit_id = m.id
|
|
173
|
+
AND latest.status = 'completed'
|
|
174
|
+
ORDER BY COALESCE(latest.ended_at, latest.started_at) DESC, latest.id DESC
|
|
175
|
+
LIMIT 1
|
|
176
|
+
)
|
|
177
|
+
ORDER BY m.id`,
|
|
178
|
+
)
|
|
179
|
+
.all() as Array<{ id: string; status: string; started_at: string | null; ended_at: string | null }>;
|
|
180
|
+
|
|
181
|
+
for (const row of reopened) {
|
|
182
|
+
const completedAt = row.ended_at ?? row.started_at ?? null;
|
|
183
|
+
const reopenAt = latestExplicitReopenAt(basePath, row.id);
|
|
184
|
+
if (reopenAt && (!completedAt || Date.parse(reopenAt) > Date.parse(completedAt))) continue;
|
|
185
|
+
issues.push({
|
|
186
|
+
severity: "error",
|
|
187
|
+
code: "completed_milestone_reopened",
|
|
188
|
+
scope: "milestone",
|
|
189
|
+
unitId: row.id,
|
|
190
|
+
message: `Milestone ${row.id} has completed complete-milestone dispatch history but DB status is ${row.status}. Explicitly reopen or recover before planning it again.`,
|
|
191
|
+
fixable: false,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
} catch {
|
|
195
|
+
// Non-fatal — completed-milestone reopen check failed
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// f. Completion artifacts disagree with open DB hierarchy rows.
|
|
199
|
+
try {
|
|
200
|
+
const rows = adapter
|
|
201
|
+
.prepare(
|
|
202
|
+
`SELECT a.path, a.artifact_type, a.milestone_id, a.slice_id, a.task_id, a.imported_at,
|
|
203
|
+
m.status AS milestone_status,
|
|
204
|
+
s.status AS slice_status,
|
|
205
|
+
t.status AS task_status,
|
|
206
|
+
(SELECT COUNT(*) FROM tasks tt WHERE tt.milestone_id = a.milestone_id AND tt.slice_id = a.slice_id) AS task_count
|
|
207
|
+
FROM artifacts a
|
|
208
|
+
JOIN milestones m ON m.id = a.milestone_id
|
|
209
|
+
LEFT JOIN slices s ON s.milestone_id = a.milestone_id AND s.id = a.slice_id
|
|
210
|
+
LEFT JOIN tasks t ON t.milestone_id = a.milestone_id AND t.slice_id = a.slice_id AND t.id = a.task_id
|
|
211
|
+
WHERE a.artifact_type = 'SUMMARY'
|
|
212
|
+
AND m.status NOT IN ('complete', 'done', 'skipped', 'closed')`,
|
|
213
|
+
)
|
|
214
|
+
.all() as Array<{
|
|
215
|
+
path: string;
|
|
216
|
+
milestone_id: string;
|
|
217
|
+
slice_id: string | null;
|
|
218
|
+
task_id: string | null;
|
|
219
|
+
imported_at: string | null;
|
|
220
|
+
slice_status: string | null;
|
|
221
|
+
task_status: string | null;
|
|
222
|
+
task_count: number;
|
|
223
|
+
}>;
|
|
224
|
+
|
|
225
|
+
const seen = new Set<string>();
|
|
226
|
+
for (const row of rows) {
|
|
227
|
+
const reopenAt = latestExplicitReopenAt(basePath, row.milestone_id);
|
|
228
|
+
if (!isAfter(row.imported_at, reopenAt)) continue;
|
|
229
|
+
const isSliceSummary = row.slice_id && !row.task_id && row.slice_status && !["complete", "done", "skipped", "closed"].includes(row.slice_status);
|
|
230
|
+
const isTaskSummary = row.slice_id && row.task_id && (!row.task_status || !["complete", "done", "skipped", "closed"].includes(row.task_status));
|
|
231
|
+
const isTaskArtifactWithoutDbTasks = row.slice_id && row.task_id && Number(row.task_count) === 0;
|
|
232
|
+
if (!isSliceSummary && !isTaskSummary && !isTaskArtifactWithoutDbTasks) continue;
|
|
233
|
+
|
|
234
|
+
const unitId = row.task_id
|
|
235
|
+
? `${row.milestone_id}/${row.slice_id}/${row.task_id}`
|
|
236
|
+
: row.slice_id
|
|
237
|
+
? `${row.milestone_id}/${row.slice_id}`
|
|
238
|
+
: row.milestone_id;
|
|
239
|
+
if (seen.has(unitId)) continue;
|
|
240
|
+
seen.add(unitId);
|
|
241
|
+
issues.push({
|
|
242
|
+
severity: "error",
|
|
243
|
+
code: "artifact_db_status_divergence",
|
|
244
|
+
scope: row.task_id ? "task" : row.slice_id ? "slice" : "milestone",
|
|
245
|
+
unitId,
|
|
246
|
+
message: `Completion artifact ${row.path} exists while DB state for ${unitId} is still open or missing. Runtime will not import it silently; run explicit recovery/repair after review.`,
|
|
247
|
+
fixable: false,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
// Non-fatal — artifact/DB status drift check failed
|
|
252
|
+
}
|
|
154
253
|
}
|
|
155
254
|
} catch {
|
|
156
255
|
// Non-fatal — DB constraint checks failed entirely
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// gsd-pi doctor git health checks
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { existsSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
|
|
6
6
|
import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
|
|
7
7
|
import { loadFile } from "./files.js";
|
|
@@ -56,11 +56,47 @@ function isSameOrNestedPath(candidate: string, container: string): boolean {
|
|
|
56
56
|
normalizedCandidate.startsWith(`${normalizedContainer}/`);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function
|
|
59
|
+
function normalizeGitPath(path: string): string {
|
|
60
|
+
return path.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isProjectContentPath(path: string): boolean {
|
|
64
|
+
const normalized = normalizeGitPath(path);
|
|
65
|
+
if (!normalized || normalized.endsWith("/")) return false;
|
|
66
|
+
if (normalized === ".gitignore" || normalized === ".gitattributes") return false;
|
|
67
|
+
if (normalized.endsWith(".DS_Store")) return false;
|
|
68
|
+
const parts = normalized.split("/");
|
|
69
|
+
return !parts.some(part => part === ".git" || part === ".gsd");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function gitLines(basePath: string, args: string[]): string[] {
|
|
73
|
+
const result = spawnSync("git", args, {
|
|
74
|
+
cwd: basePath,
|
|
75
|
+
encoding: "utf-8",
|
|
76
|
+
});
|
|
77
|
+
if (result.status !== 0) return [];
|
|
78
|
+
return result.stdout
|
|
79
|
+
.split("\n")
|
|
80
|
+
.map(line => normalizeGitPath(line.trim()))
|
|
81
|
+
.filter(isProjectContentPath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function listProjectContentFiles(basePath: string): string[] {
|
|
85
|
+
return [...new Set([
|
|
86
|
+
...gitLines(basePath, ["ls-files"]),
|
|
87
|
+
...gitLines(basePath, ["ls-files", "--others", "--exclude-standard"]),
|
|
88
|
+
])];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hasMaterializedProjectContentFallback(dirPath: string): boolean {
|
|
60
92
|
try {
|
|
61
93
|
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
62
|
-
if (entry.name
|
|
94
|
+
if (!isProjectContentPath(entry.name)) continue;
|
|
63
95
|
if (entry.name === ".DS_Store") continue;
|
|
96
|
+
if (entry.isDirectory()) {
|
|
97
|
+
if (hasMaterializedProjectContentFallback(join(dirPath, entry.name))) return true;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
64
100
|
return true;
|
|
65
101
|
}
|
|
66
102
|
} catch {
|
|
@@ -69,6 +105,27 @@ function hasProjectContentOnDisk(dirPath: string): boolean {
|
|
|
69
105
|
return false;
|
|
70
106
|
}
|
|
71
107
|
|
|
108
|
+
function hasProjectContentOnDisk(dirPath: string): boolean {
|
|
109
|
+
const gitProjectFiles = listProjectContentFiles(dirPath);
|
|
110
|
+
if (gitProjectFiles.length > 0) {
|
|
111
|
+
return gitProjectFiles.some(file => existsSync(join(dirPath, file)));
|
|
112
|
+
}
|
|
113
|
+
return hasMaterializedProjectContentFallback(dirPath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function copyProjectRootContentIntoWorktree(projectRoot: string, worktreeRoot: string): number {
|
|
117
|
+
let copied = 0;
|
|
118
|
+
for (const relPath of listProjectContentFiles(projectRoot)) {
|
|
119
|
+
const src = join(projectRoot, relPath);
|
|
120
|
+
if (!existsSync(src)) continue;
|
|
121
|
+
const dst = join(worktreeRoot, relPath);
|
|
122
|
+
mkdirSync(dirname(dst), { recursive: true });
|
|
123
|
+
cpSync(src, dst, { recursive: true, force: true });
|
|
124
|
+
copied++;
|
|
125
|
+
}
|
|
126
|
+
return copied;
|
|
127
|
+
}
|
|
128
|
+
|
|
72
129
|
function getSnapshotDiffCheckFailure(basePath: string): string | null {
|
|
73
130
|
const failures: string[] = [];
|
|
74
131
|
|
|
@@ -176,7 +233,17 @@ export async function checkGitHealth(
|
|
|
176
233
|
if (reset.status !== 0) {
|
|
177
234
|
throw new Error(reset.stderr || reset.error?.message || "git reset --hard failed");
|
|
178
235
|
}
|
|
179
|
-
|
|
236
|
+
const copied = !hasProjectContentOnDisk(recreated.path) && hasProjectContentOnDisk(basePath)
|
|
237
|
+
? copyProjectRootContentIntoWorktree(basePath, recreated.path)
|
|
238
|
+
: 0;
|
|
239
|
+
if (!hasProjectContentOnDisk(recreated.path) && hasProjectContentOnDisk(basePath)) {
|
|
240
|
+
throw new Error("recreated worktree still has no project content");
|
|
241
|
+
}
|
|
242
|
+
fixesApplied.push(
|
|
243
|
+
copied > 0
|
|
244
|
+
? `recreated empty worktree ${wt.path} and copied ${copied} project file${copied === 1 ? "" : "s"} from project root`
|
|
245
|
+
: `recreated empty worktree ${wt.path}`,
|
|
246
|
+
);
|
|
180
247
|
} catch {
|
|
181
248
|
fixesApplied.push(`failed to recreate empty worktree ${wt.path}`);
|
|
182
249
|
}
|