@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.74e8dd1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
- package/dist/resources/extensions/gsd/auto/phases.js +4 -3
- package/dist/resources/extensions/gsd/auto-dashboard.js +15 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +39 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +113 -7
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
- package/dist/resources/extensions/gsd/auto-start.js +94 -15
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
- package/dist/resources/extensions/gsd/auto.js +22 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +79 -0
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +7 -3
- package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +107 -59
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
- package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +2 -1
- package/dist/resources/extensions/gsd/error-classifier.js +2 -1
- package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
- package/dist/resources/extensions/gsd/gsd-db.js +37 -4
- package/dist/resources/extensions/gsd/guided-flow.js +1 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
- package/dist/resources/extensions/gsd/mcp-project-config.js +67 -8
- package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
- package/dist/resources/extensions/gsd/prompts/run-uat.md +10 -4
- package/dist/resources/extensions/gsd/prompts/system.md +3 -1
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
- package/dist/resources/extensions/gsd/skill-activation.js +20 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
- package/dist/resources/extensions/gsd/state.js +15 -12
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +366 -3
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
- package/dist/resources/extensions/mcp-client/manager.js +31 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
- 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/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 +4 -4
- 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/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/package.json +2 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -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/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- 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 +72 -31
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
- 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 -1
- 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 +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +82 -0
- 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/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +15 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +338 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +412 -112
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/terminal.d.ts +1 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +8 -4
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
- package/src/resources/extensions/gsd/auto/phases.ts +5 -3
- package/src/resources/extensions/gsd/auto-dashboard.ts +16 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +48 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +138 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +9 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
- package/src/resources/extensions/gsd/auto-start.ts +112 -17
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
- package/src/resources/extensions/gsd/auto.ts +35 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +86 -0
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +7 -3
- package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +134 -57
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
- package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +2 -1
- package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
- package/src/resources/extensions/gsd/gsd-db.ts +41 -6
- package/src/resources/extensions/gsd/guided-flow.ts +1 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
- package/src/resources/extensions/gsd/mcp-project-config.ts +92 -10
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +10 -4
- package/src/resources/extensions/gsd/prompts/system.md +3 -1
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
- package/src/resources/extensions/gsd/skill-activation.ts +20 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
- package/src/resources/extensions/gsd/state.ts +16 -12
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
- package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +440 -2
- package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
- package/src/resources/extensions/mcp-client/manager.ts +33 -1
- package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_ssgManifest.js +0 -0
|
@@ -51,6 +51,7 @@ export function showHelp(ctx, args = "") {
|
|
|
51
51
|
" /gsd keys API key manager (LLM + tool keys)",
|
|
52
52
|
" /gsd doctor Diagnose and repair .gsd/ state",
|
|
53
53
|
" /gsd closeout Recover failed git closeout actions",
|
|
54
|
+
" /gsd rebuild Rebuild markdown projections from the DB [markdown]",
|
|
54
55
|
"",
|
|
55
56
|
"Use /gsd help full for the complete command reference.",
|
|
56
57
|
];
|
|
@@ -68,7 +69,7 @@ export function showHelp(ctx, args = "") {
|
|
|
68
69
|
" /gsd new-milestone Create milestone from headless context (used by gsd headless)",
|
|
69
70
|
" /gsd new-project Bootstrap a new project (use --deep for staged project-level discovery)",
|
|
70
71
|
" /gsd quick Execute a quick task without full planning overhead",
|
|
71
|
-
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|uat|replan]",
|
|
72
|
+
" /gsd dispatch Dispatch a specific phase directly [research|plan|execute|complete|validate|reassess|uat|replan]",
|
|
72
73
|
" /gsd verdict <v> Override milestone validation verdict [pass|needs-attention|needs-remediation] [--milestone Mxxx] [--rationale \"...\"]",
|
|
73
74
|
" /gsd parallel Parallel milestone orchestration [start|status|stop|pause|resume|merge|watch]",
|
|
74
75
|
" /gsd workflow Custom workflow lifecycle [new|run|list|validate|pause|resume]",
|
|
@@ -132,7 +133,7 @@ export function showHelp(ctx, args = "") {
|
|
|
132
133
|
" /gsd skill-health Skill lifecycle dashboard",
|
|
133
134
|
" /gsd extensions Manage extensions [list|enable|disable|info]",
|
|
134
135
|
" /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
|
|
135
|
-
" /gsd mcp MCP server management [status|check|test|enable|disable|import|delete|init]",
|
|
136
|
+
" /gsd mcp MCP server management [status|check|discover|test|enable|disable|import|delete|init]",
|
|
136
137
|
"",
|
|
137
138
|
"MAINTENANCE",
|
|
138
139
|
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
@@ -141,6 +142,9 @@ export function showHelp(ctx, args = "") {
|
|
|
141
142
|
" /gsd export Alias for /gsd report",
|
|
142
143
|
" /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
|
|
143
144
|
" /gsd closeout Recover failed git closeout actions [status|retry|resolve] [unit-id]",
|
|
145
|
+
" /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
|
|
146
|
+
" /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
|
|
147
|
+
" /gsd recover --confirm Import markdown into the DB after DB loss/corruption",
|
|
144
148
|
" /gsd worktree Manage worktrees from the TUI [list|merge|clean|remove]",
|
|
145
149
|
" /gsd migrate Migrate .planning/ (v1) to DB-backed .gsd/ with backup + audit",
|
|
146
150
|
" /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
|
|
@@ -4,7 +4,7 @@ import { handleDoctor, handleCapture, handleKnowledge, handleRunHook, handleSkil
|
|
|
4
4
|
import { handleInspect } from "../../commands-inspect.js";
|
|
5
5
|
import { handleLogs } from "../../commands-logs.js";
|
|
6
6
|
import { handleDebug } from "../../commands-debug.js";
|
|
7
|
-
import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover } from "../../commands-maintenance.js";
|
|
7
|
+
import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleCleanupProjects, handleCleanupWorktrees, handleRecover, handleRebuild } from "../../commands-maintenance.js";
|
|
8
8
|
import { handleExport } from "../../export.js";
|
|
9
9
|
import { handleHistory } from "../../history.js";
|
|
10
10
|
import { handleUndo } from "../../undo.js";
|
|
@@ -130,8 +130,12 @@ export async function handleOpsCommand(trimmed, ctx, pi) {
|
|
|
130
130
|
await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
|
|
131
131
|
return true;
|
|
132
132
|
}
|
|
133
|
-
if (trimmed === "recover") {
|
|
134
|
-
await handleRecover(ctx, projectRoot());
|
|
133
|
+
if (trimmed === "recover" || trimmed.startsWith("recover ")) {
|
|
134
|
+
await handleRecover(ctx, projectRoot(), trimmed.replace(/^recover\s*/, "").trim());
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (trimmed === "rebuild" || trimmed.startsWith("rebuild ")) {
|
|
138
|
+
await handleRebuild(ctx, projectRoot(), trimmed.replace(/^rebuild\s*/, "").trim());
|
|
135
139
|
return true;
|
|
136
140
|
}
|
|
137
141
|
if (trimmed === "closeout" || trimmed.startsWith("closeout ")) {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GSD Maintenance — cleanup, skip, dry-run, and recover handlers.
|
|
3
3
|
*
|
|
4
|
-
* Contains: handleCleanupBranches, handleCleanupSnapshots, handleCleanupWorktrees, handleSkip, handleDryRun, handleRecover
|
|
4
|
+
* Contains: handleCleanupBranches, handleCleanupSnapshots, handleCleanupWorktrees, handleSkip, handleDryRun, handleRecover, handleRebuild
|
|
5
5
|
*/
|
|
6
|
+
import { existsSync, mkdirSync, renameSync } from "node:fs";
|
|
7
|
+
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
6
8
|
import { deriveState } from "./state.js";
|
|
9
|
+
import { gsdProjectionRoot, gsdRoot } from "./paths.js";
|
|
7
10
|
import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
|
|
8
11
|
import { logWarning } from "./workflow-logger.js";
|
|
9
12
|
export async function handleCleanupBranches(ctx, basePath) {
|
|
@@ -439,6 +442,30 @@ export async function handleCleanupProjects(args, ctx) {
|
|
|
439
442
|
}
|
|
440
443
|
ctx.ui.notify(lines.join("\n"), "info");
|
|
441
444
|
}
|
|
445
|
+
function recoverConfirmed(args) {
|
|
446
|
+
return args
|
|
447
|
+
.split(/\s+/)
|
|
448
|
+
.map((part) => part.trim().toLowerCase())
|
|
449
|
+
.some((part) => part === "--confirm" || part === "--yes" || part === "confirm");
|
|
450
|
+
}
|
|
451
|
+
async function confirmRecover(ctx, args) {
|
|
452
|
+
if (recoverConfirmed(args))
|
|
453
|
+
return true;
|
|
454
|
+
const warning = [
|
|
455
|
+
"gsd recover imports markdown into the database.",
|
|
456
|
+
"It clears and reconstructs milestone, slice, and task hierarchy rows from rendered markdown.",
|
|
457
|
+
"Use /gsd rebuild markdown for normal DB-to-markdown realignment.",
|
|
458
|
+
].join("\n");
|
|
459
|
+
if (typeof ctx.ui.confirm === "function") {
|
|
460
|
+
const confirmed = await ctx.ui.confirm("Import markdown into the DB?", `${warning}\n\nContinue only if the DB is lost or corrupt and markdown is the source you intend to import.`);
|
|
461
|
+
if (confirmed)
|
|
462
|
+
return true;
|
|
463
|
+
ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
ctx.ui.notify(`${warning}\n\nNo database changes made. Re-run /gsd recover --confirm to proceed.`, "warning");
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
442
469
|
/**
|
|
443
470
|
* `gsd recover` — Reconstruct DB hierarchy state from rendered markdown on disk.
|
|
444
471
|
*
|
|
@@ -448,7 +475,7 @@ export async function handleCleanupProjects(args, ctx) {
|
|
|
448
475
|
*
|
|
449
476
|
* Prints counts of recovered items and the resulting project phase.
|
|
450
477
|
*/
|
|
451
|
-
export async function handleRecover(ctx, basePath) {
|
|
478
|
+
export async function handleRecover(ctx, basePath, args = "") {
|
|
452
479
|
const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction } = await import("./gsd-db.js");
|
|
453
480
|
const { migrateHierarchyToDb } = await import("./md-importer.js");
|
|
454
481
|
const { invalidateStateCache } = await import("./state.js");
|
|
@@ -456,6 +483,8 @@ export async function handleRecover(ctx, basePath) {
|
|
|
456
483
|
ctx.ui.notify("gsd recover: No database open. Run a GSD command first to initialize the DB.", "error");
|
|
457
484
|
return;
|
|
458
485
|
}
|
|
486
|
+
if (!(await confirmRecover(ctx, args)))
|
|
487
|
+
return;
|
|
459
488
|
try {
|
|
460
489
|
// 1. Delete + re-populate inside a single transaction for atomicity.
|
|
461
490
|
// clearEngineHierarchy() uses transaction() internally but transaction()
|
|
@@ -496,3 +525,144 @@ export async function handleRecover(ctx, basePath) {
|
|
|
496
525
|
ctx.ui.notify(`gsd recover failed: ${msg}`, "error");
|
|
497
526
|
}
|
|
498
527
|
}
|
|
528
|
+
function normalizeArtifactPath(value) {
|
|
529
|
+
return value.replace(/\\/g, "/");
|
|
530
|
+
}
|
|
531
|
+
function pathWithin(root, candidate) {
|
|
532
|
+
const rel = relative(root, candidate);
|
|
533
|
+
return rel.length === 0 || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
534
|
+
}
|
|
535
|
+
function artifactPathForDb(basePath, absPath) {
|
|
536
|
+
const projectionRoot = gsdProjectionRoot(basePath);
|
|
537
|
+
const root = pathWithin(projectionRoot, absPath) ? projectionRoot : gsdRoot(basePath);
|
|
538
|
+
return normalizeArtifactPath(relative(root, absPath));
|
|
539
|
+
}
|
|
540
|
+
function quarantineRelativePath(basePath, absPath) {
|
|
541
|
+
for (const root of [gsdProjectionRoot(basePath), gsdRoot(basePath)]) {
|
|
542
|
+
if (pathWithin(root, absPath)) {
|
|
543
|
+
return normalizeArtifactPath(relative(root, absPath));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return normalizeArtifactPath(absPath.replace(/^[/\\]+/, ""));
|
|
547
|
+
}
|
|
548
|
+
function uniquePath(path) {
|
|
549
|
+
if (!existsSync(path))
|
|
550
|
+
return path;
|
|
551
|
+
let idx = 2;
|
|
552
|
+
while (existsSync(`${path}.${idx}`))
|
|
553
|
+
idx++;
|
|
554
|
+
return `${path}.${idx}`;
|
|
555
|
+
}
|
|
556
|
+
function resolveDiskArtifactPath(basePath, artifactPath) {
|
|
557
|
+
if (isAbsolute(artifactPath))
|
|
558
|
+
return artifactPath;
|
|
559
|
+
const candidates = [
|
|
560
|
+
join(gsdProjectionRoot(basePath), artifactPath),
|
|
561
|
+
join(gsdRoot(basePath), artifactPath),
|
|
562
|
+
];
|
|
563
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
|
|
564
|
+
}
|
|
565
|
+
function quarantineProjectionFile(basePath, absPath, stamp) {
|
|
566
|
+
const rel = quarantineRelativePath(basePath, absPath);
|
|
567
|
+
const target = uniquePath(join(gsdProjectionRoot(basePath), "quarantine", "projections", stamp, rel));
|
|
568
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
569
|
+
renameSync(absPath, target);
|
|
570
|
+
return target;
|
|
571
|
+
}
|
|
572
|
+
function parseRebuildTarget(args) {
|
|
573
|
+
const trimmed = args.trim().toLowerCase();
|
|
574
|
+
if (!trimmed || trimmed === "markdown")
|
|
575
|
+
return "markdown";
|
|
576
|
+
if (trimmed === "database" || trimmed === "db")
|
|
577
|
+
return "database";
|
|
578
|
+
return "usage";
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* `gsd rebuild markdown` — Re-render markdown projections from the authoritative DB.
|
|
582
|
+
*
|
|
583
|
+
* This is the DB-first realignment command. It does not import markdown into
|
|
584
|
+
* the DB. Completion SUMMARY files that contradict open DB rows are preserved
|
|
585
|
+
* under `.gsd/quarantine/projections/` before DB projections are rendered.
|
|
586
|
+
*/
|
|
587
|
+
export async function handleRebuild(ctx, basePath, args = "") {
|
|
588
|
+
const { isDbAvailable: dbAvailable, deleteArtifactByPath } = await import("./gsd-db.js");
|
|
589
|
+
const { detectArtifactDbDrift } = await import("./state-reconciliation/drift/artifact-db.js");
|
|
590
|
+
const { renderAllFromDb } = await import("./markdown-renderer.js");
|
|
591
|
+
const { invalidateStateCache } = await import("./state.js");
|
|
592
|
+
const target = parseRebuildTarget(args);
|
|
593
|
+
if (target === "usage") {
|
|
594
|
+
ctx.ui.notify([
|
|
595
|
+
"Usage:",
|
|
596
|
+
" /gsd rebuild markdown Rebuild markdown projections from the canonical DB",
|
|
597
|
+
" /gsd rebuild database Reserved for DB-native rebuilds; does not import markdown",
|
|
598
|
+
].join("\n"), "warning");
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (target === "database") {
|
|
602
|
+
ctx.ui.notify([
|
|
603
|
+
"gsd rebuild database is reserved for DB-native rebuilds.",
|
|
604
|
+
"It will not import markdown projections into the DB.",
|
|
605
|
+
"For normal realignment, run /gsd rebuild markdown.",
|
|
606
|
+
"If the DB is lost or corrupt and markdown is the source to import, run /gsd recover --confirm.",
|
|
607
|
+
].join("\n"), "warning");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (!dbAvailable()) {
|
|
611
|
+
ctx.ui.notify("gsd rebuild markdown: No database open. Run a GSD command first to initialize the DB.", "error");
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
invalidateStateCache();
|
|
616
|
+
const state = await deriveState(basePath);
|
|
617
|
+
const drifts = detectArtifactDbDrift(state, { basePath, state });
|
|
618
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
619
|
+
const quarantined = [];
|
|
620
|
+
const seen = new Set();
|
|
621
|
+
for (const drift of drifts) {
|
|
622
|
+
if (drift.kind !== "artifact-db-status-divergence")
|
|
623
|
+
continue;
|
|
624
|
+
if (drift.artifactType !== "SUMMARY" || !drift.artifactPath)
|
|
625
|
+
continue;
|
|
626
|
+
const absPath = resolveDiskArtifactPath(basePath, drift.artifactPath);
|
|
627
|
+
if (seen.has(absPath) || !existsSync(absPath))
|
|
628
|
+
continue;
|
|
629
|
+
seen.add(absPath);
|
|
630
|
+
const artifactDbPath = artifactPathForDb(basePath, absPath);
|
|
631
|
+
const target = quarantineProjectionFile(basePath, absPath, stamp);
|
|
632
|
+
deleteArtifactByPath(artifactDbPath);
|
|
633
|
+
quarantined.push(target);
|
|
634
|
+
}
|
|
635
|
+
const rendered = await renderAllFromDb(basePath);
|
|
636
|
+
invalidateStateCache();
|
|
637
|
+
const lines = [
|
|
638
|
+
"gsd rebuild markdown: rebuilt markdown projections from the canonical DB",
|
|
639
|
+
` Rendered: ${rendered.rendered}`,
|
|
640
|
+
` Skipped: ${rendered.skipped}`,
|
|
641
|
+
` Quarantined: ${quarantined.length}`,
|
|
642
|
+
];
|
|
643
|
+
if (rendered.errors.length > 0) {
|
|
644
|
+
lines.push(` Errors: ${rendered.errors.length}`);
|
|
645
|
+
for (const err of rendered.errors.slice(0, 5)) {
|
|
646
|
+
lines.push(` - ${err}`);
|
|
647
|
+
}
|
|
648
|
+
if (rendered.errors.length > 5) {
|
|
649
|
+
lines.push(` - ${rendered.errors.length - 5} more`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (quarantined.length > 0) {
|
|
653
|
+
lines.push("", " Quarantine:");
|
|
654
|
+
for (const target of quarantined.slice(0, 5)) {
|
|
655
|
+
lines.push(` - ${target}`);
|
|
656
|
+
}
|
|
657
|
+
if (quarantined.length > 5) {
|
|
658
|
+
lines.push(` - ${quarantined.length - 5} more`);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
ctx.ui.notify(lines.join("\n"), rendered.errors.length > 0 ? "warning" : "success");
|
|
662
|
+
}
|
|
663
|
+
catch (err) {
|
|
664
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
665
|
+
logWarning("command", `rebuild failed: ${msg}`);
|
|
666
|
+
ctx.ui.notify(`gsd rebuild failed: ${msg}`, "error");
|
|
667
|
+
}
|
|
668
|
+
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* /gsd mcp — Overview of all servers (alias: /gsd mcp status)
|
|
8
8
|
* /gsd mcp status — Same as bare /gsd mcp
|
|
9
9
|
* /gsd mcp check <srv> — Detailed status for a specific server
|
|
10
|
+
* /gsd mcp discover [srv] — Connect and list tools for a server
|
|
10
11
|
* /gsd mcp test <srv> — Test handshake + tools/list for a server
|
|
11
12
|
* /gsd mcp enable <srv> / disable <srv> — Toggle local server exposure
|
|
12
13
|
* /gsd mcp import <srv> [as <name>] — Copy a discovered server into local config
|
|
@@ -15,6 +16,7 @@
|
|
|
15
16
|
import { resolve } from "node:path";
|
|
16
17
|
import { ensureProjectWorkflowMcpConfig } from "./mcp-project-config.js";
|
|
17
18
|
import { deleteProjectLocalMcpServer, readMcpManagementStatus, setProjectLocalMcpServerDisabled, testMcpServerConnection, upsertProjectLocalMcpServer, } from "../mcp-client/manager.js";
|
|
19
|
+
const MCP_STATUS_PROBE_TIMEOUT_MS = 10_000;
|
|
18
20
|
export function hasHostMcpTool(systemPrompt, serverName) {
|
|
19
21
|
const marker = `mcp__${serverName}__`;
|
|
20
22
|
return systemPrompt.includes(marker);
|
|
@@ -48,21 +50,23 @@ export function formatMcpStatusReport(servers) {
|
|
|
48
50
|
}
|
|
49
51
|
const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
|
|
50
52
|
for (const s of servers) {
|
|
51
|
-
const icon = s.disabled ? "⊘" : s.error ? "✗" : s.connected ? "✓" : "○";
|
|
53
|
+
const icon = s.disabled ? "⊘" : s.error ? "✗" : s.connected || s.available ? "✓" : "○";
|
|
52
54
|
const status = s.disabled
|
|
53
55
|
? "disabled"
|
|
54
56
|
: s.error
|
|
55
57
|
? `error: ${s.error}`
|
|
56
58
|
: s.connected
|
|
57
59
|
? `connected — ${s.toolCount} tools`
|
|
58
|
-
:
|
|
60
|
+
: s.available
|
|
61
|
+
? `available — ${s.toolCount} tools`
|
|
62
|
+
: "disconnected";
|
|
59
63
|
const warningText = s.envWarnings?.length ? ` — ${s.envWarnings.length} warning(s)` : "";
|
|
60
64
|
lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}${warningText}`);
|
|
61
65
|
}
|
|
62
66
|
lines.push("");
|
|
63
67
|
lines.push("Use /gsd mcp check <server> for details on a specific server.");
|
|
68
|
+
lines.push("Use /gsd mcp discover <server> to connect and list tools.");
|
|
64
69
|
lines.push("Use /gsd mcp test <server> to verify handshake and tool discovery.");
|
|
65
|
-
lines.push("Use mcp_discover to connect and list tools for a server.");
|
|
66
70
|
return lines.join("\n");
|
|
67
71
|
}
|
|
68
72
|
export function formatMcpServerDetail(server) {
|
|
@@ -77,8 +81,8 @@ export function formatMcpServerDetail(server) {
|
|
|
77
81
|
lines.push(` Status: error`);
|
|
78
82
|
lines.push(` Error: ${server.error}`);
|
|
79
83
|
}
|
|
80
|
-
else if (server.connected) {
|
|
81
|
-
lines.push(` Status: connected`);
|
|
84
|
+
else if (server.connected || server.available) {
|
|
85
|
+
lines.push(` Status: ${server.connected ? "connected" : "available"}`);
|
|
82
86
|
lines.push(` Tools: ${server.toolCount}`);
|
|
83
87
|
if (server.tools.length > 0) {
|
|
84
88
|
lines.push("");
|
|
@@ -91,7 +95,7 @@ export function formatMcpServerDetail(server) {
|
|
|
91
95
|
else {
|
|
92
96
|
lines.push(` Status: disconnected`);
|
|
93
97
|
lines.push("");
|
|
94
|
-
lines.push(` Run
|
|
98
|
+
lines.push(` Run /gsd mcp discover ${server.name} to connect and list tools.`);
|
|
95
99
|
}
|
|
96
100
|
if (server.envWarnings?.length) {
|
|
97
101
|
lines.push("");
|
|
@@ -120,9 +124,70 @@ export function formatMcpConnectionTestResult(result) {
|
|
|
120
124
|
...(result.warnings.length > 0 ? ["", "Warnings:", ...result.warnings.map((warning) => ` - ${warning}`)] : []),
|
|
121
125
|
].join("\n");
|
|
122
126
|
}
|
|
127
|
+
export function formatMcpDiscoveryResult(result) {
|
|
128
|
+
if (result.ok) {
|
|
129
|
+
return [
|
|
130
|
+
`MCP discovery completed for ${result.server}.`,
|
|
131
|
+
"",
|
|
132
|
+
`Transport: ${result.transport}`,
|
|
133
|
+
`Tools: ${result.toolCount}`,
|
|
134
|
+
...(result.tools.length > 0 ? ["", "Discovered tools:", ...result.tools.map((tool) => ` - ${tool}`)] : []),
|
|
135
|
+
"",
|
|
136
|
+
`Call with: mcp_call(server="${result.server}", tool="<tool_name>", args={...})`,
|
|
137
|
+
].join("\n");
|
|
138
|
+
}
|
|
139
|
+
return [
|
|
140
|
+
`MCP discovery failed for ${result.server}.`,
|
|
141
|
+
"",
|
|
142
|
+
`Transport: ${result.transport}`,
|
|
143
|
+
`Error: ${result.error ?? "Unknown error"}`,
|
|
144
|
+
...(result.warnings.length > 0 ? ["", "Warnings:", ...result.warnings.map((warning) => ` - ${warning}`)] : []),
|
|
145
|
+
].join("\n");
|
|
146
|
+
}
|
|
147
|
+
async function readLiveConnectionStatus(serverName) {
|
|
148
|
+
try {
|
|
149
|
+
const mcpClient = await import("../mcp-client/index.js");
|
|
150
|
+
const mod = mcpClient;
|
|
151
|
+
if (typeof mod.getConnectionStatus === "function") {
|
|
152
|
+
return mod.getConnectionStatus(serverName);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// mcp-client may not expose status helpers in some hosts.
|
|
157
|
+
}
|
|
158
|
+
return { connected: false, tools: [] };
|
|
159
|
+
}
|
|
160
|
+
function shouldProbeConfiguredServer(config) {
|
|
161
|
+
return !config.disabled && config.transport === "stdio" && (config.envWarnings?.length ?? 0) === 0;
|
|
162
|
+
}
|
|
163
|
+
async function resolveMcpRuntimeStatus(config, systemPrompt) {
|
|
164
|
+
const live = await readLiveConnectionStatus(config.name);
|
|
165
|
+
let connected = live.connected;
|
|
166
|
+
let tools = live.tools;
|
|
167
|
+
let error = live.error;
|
|
168
|
+
if (!connected && !error && hasHostMcpTool(systemPrompt, config.name))
|
|
169
|
+
connected = true;
|
|
170
|
+
if (!connected && !error && shouldProbeConfiguredServer(config)) {
|
|
171
|
+
const probed = await testMcpServerConnection(config.name, { timeoutMs: MCP_STATUS_PROBE_TIMEOUT_MS });
|
|
172
|
+
if (probed.ok) {
|
|
173
|
+
return {
|
|
174
|
+
connected: false,
|
|
175
|
+
available: true,
|
|
176
|
+
tools: probed.tools,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
error = probed.error;
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
connected,
|
|
183
|
+
available: false,
|
|
184
|
+
tools,
|
|
185
|
+
error,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
123
188
|
// ─── Command handler ────────────────────────────────────────────────────────
|
|
124
189
|
/**
|
|
125
|
-
* Handle `/gsd mcp [status|check <server
|
|
190
|
+
* Handle `/gsd mcp [status|check <server>|discover [server]|...]`.
|
|
126
191
|
*/
|
|
127
192
|
export async function handleMcpStatus(args, ctx) {
|
|
128
193
|
const trimmed = args.trim();
|
|
@@ -146,6 +211,24 @@ export async function handleMcpStatus(args, ctx) {
|
|
|
146
211
|
}
|
|
147
212
|
return;
|
|
148
213
|
}
|
|
214
|
+
// /gsd mcp discover [server]
|
|
215
|
+
if (lowered === "discover" || lowered.startsWith("discover ")) {
|
|
216
|
+
const requestedServerName = trimmed.slice("discover".length).trim();
|
|
217
|
+
let serverName = requestedServerName;
|
|
218
|
+
if (!serverName) {
|
|
219
|
+
if (configs.length === 1) {
|
|
220
|
+
serverName = configs[0].name;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
const available = configs.map((config) => config.name).join(", ") || "(none)";
|
|
224
|
+
ctx.ui.notify(`Usage: /gsd mcp discover <server>\n\nAvailable: ${available}`, "warning");
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const result = await testMcpServerConnection(serverName);
|
|
229
|
+
ctx.ui.notify(formatMcpDiscoveryResult(result), result.ok ? "info" : "warning");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
149
232
|
// /gsd mcp test <server>
|
|
150
233
|
if (lowered.startsWith("test ")) {
|
|
151
234
|
const serverName = trimmed.slice("test ".length).trim();
|
|
@@ -245,33 +328,15 @@ export async function handleMcpStatus(args, ctx) {
|
|
|
245
328
|
ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
|
|
246
329
|
return;
|
|
247
330
|
}
|
|
248
|
-
|
|
249
|
-
let connected = false;
|
|
250
|
-
let toolNames = [];
|
|
251
|
-
let error;
|
|
252
|
-
try {
|
|
253
|
-
const mcpClient = await import("../mcp-client/index.js");
|
|
254
|
-
// Access the module's connection state if exported; fall back gracefully
|
|
255
|
-
const mod = mcpClient;
|
|
256
|
-
if (typeof mod.getConnectionStatus === "function") {
|
|
257
|
-
const status = mod.getConnectionStatus(serverName);
|
|
258
|
-
connected = status.connected;
|
|
259
|
-
toolNames = status.tools;
|
|
260
|
-
error = status.error;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
catch {
|
|
264
|
-
// mcp-client may not expose status helpers — that's fine
|
|
265
|
-
}
|
|
266
|
-
if (!connected && !error && hasHostMcpTool(systemPrompt, serverName))
|
|
267
|
-
connected = true;
|
|
331
|
+
const runtime = await resolveMcpRuntimeStatus(config, systemPrompt);
|
|
268
332
|
ctx.ui.notify(formatMcpServerDetail({
|
|
269
333
|
name: config.name,
|
|
270
334
|
transport: config.transport,
|
|
271
|
-
connected,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
335
|
+
connected: runtime.connected,
|
|
336
|
+
available: runtime.available,
|
|
337
|
+
toolCount: runtime.tools.length,
|
|
338
|
+
tools: runtime.tools,
|
|
339
|
+
error: runtime.error,
|
|
275
340
|
disabled: config.disabled,
|
|
276
341
|
sourcePath: config.sourcePath,
|
|
277
342
|
envWarnings: config.envWarnings,
|
|
@@ -280,38 +345,20 @@ export async function handleMcpStatus(args, ctx) {
|
|
|
280
345
|
}
|
|
281
346
|
// /gsd mcp or /gsd mcp status
|
|
282
347
|
if (!lowered || lowered === "status") {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
let connected = false;
|
|
287
|
-
let toolCount = 0;
|
|
288
|
-
let error;
|
|
289
|
-
try {
|
|
290
|
-
const mcpClient = await import("../mcp-client/index.js");
|
|
291
|
-
const mod = mcpClient;
|
|
292
|
-
if (typeof mod.getConnectionStatus === "function") {
|
|
293
|
-
const status = mod.getConnectionStatus(config.name);
|
|
294
|
-
connected = status.connected;
|
|
295
|
-
toolCount = status.tools.length;
|
|
296
|
-
error = status.error;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
catch {
|
|
300
|
-
// Fall back to unknown state
|
|
301
|
-
}
|
|
302
|
-
if (!connected && !error && hasHostMcpTool(systemPrompt, config.name))
|
|
303
|
-
connected = true;
|
|
304
|
-
statuses.push({
|
|
348
|
+
const statuses = await Promise.all(configs.map(async (config) => {
|
|
349
|
+
const runtime = await resolveMcpRuntimeStatus(config, systemPrompt);
|
|
350
|
+
return {
|
|
305
351
|
name: config.name,
|
|
306
352
|
transport: config.transport,
|
|
307
|
-
connected,
|
|
308
|
-
|
|
309
|
-
|
|
353
|
+
connected: runtime.connected,
|
|
354
|
+
available: runtime.available,
|
|
355
|
+
toolCount: runtime.tools.length,
|
|
356
|
+
error: runtime.error,
|
|
310
357
|
disabled: config.disabled,
|
|
311
358
|
sourcePath: config.sourcePath,
|
|
312
359
|
envWarnings: config.envWarnings,
|
|
313
|
-
}
|
|
314
|
-
}
|
|
360
|
+
};
|
|
361
|
+
}));
|
|
315
362
|
const warningLines = [
|
|
316
363
|
...management.warnings,
|
|
317
364
|
...management.duplicates.map((dup) => `Duplicate "${dup.name}" from ${dup.shadowedSourcePath} is shadowed by ${dup.keptSourcePath}.`),
|
|
@@ -323,9 +370,10 @@ export async function handleMcpStatus(args, ctx) {
|
|
|
323
370
|
return;
|
|
324
371
|
}
|
|
325
372
|
// Unknown subcommand
|
|
326
|
-
ctx.ui.notify("Usage: /gsd mcp [status|check <server>|test <server>|enable <server>|disable <server>|delete <server> --confirm|import <server> [as <name>]|init [dir]]\n\n" +
|
|
373
|
+
ctx.ui.notify("Usage: /gsd mcp [status|check <server>|discover [server]|test <server>|enable <server>|disable <server>|delete <server> --confirm|import <server> [as <name>]|init [dir]]\n\n" +
|
|
327
374
|
" status Show all MCP server statuses (default)\n" +
|
|
328
375
|
" check <server> Detailed status for a specific server\n" +
|
|
376
|
+
" discover [server] Connect and list tools for a server\n" +
|
|
329
377
|
" test <server> Verify MCP handshake and tools/list\n" +
|
|
330
378
|
" enable <server> Enable a local GSD-managed server\n" +
|
|
331
379
|
" disable <server> Disable a local GSD-managed server\n" +
|
|
@@ -11,6 +11,8 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import { getGlobalGSDPreferencesPath, getLegacyGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, loadGlobalGSDPreferences, loadProjectGSDPreferences, loadEffectiveGSDPreferences, normalizePreferencesShape, resolveAllSkillReferences, } from "./preferences.js";
|
|
12
12
|
import { loadFile, saveFile, splitFrontmatter, parseFrontmatterMap } from "./files.js";
|
|
13
13
|
import { runClaudeImportFlow } from "./claude-import.js";
|
|
14
|
+
const DEFAULT_WIDGET_MODE = "small";
|
|
15
|
+
const WIDGET_MODE_OPTIONS = [DEFAULT_WIDGET_MODE, "full", "min", "off"];
|
|
14
16
|
/** Extract body content after frontmatter closing delimiter, or null if none. */
|
|
15
17
|
function extractBodyAfterFrontmatter(content) {
|
|
16
18
|
const closingIdx = content.indexOf("\n---", content.indexOf("---"));
|
|
@@ -1509,7 +1511,7 @@ async function configureAdvanced(ctx, prefs) {
|
|
|
1509
1511
|
else if (minRequestInterval !== undefined) {
|
|
1510
1512
|
prefs.min_request_interval_ms = minRequestInterval;
|
|
1511
1513
|
}
|
|
1512
|
-
const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode,
|
|
1514
|
+
const widget = await promptEnum(ctx, "Auto-mode widget display", prefs.widget_mode, WIDGET_MODE_OPTIONS, DEFAULT_WIDGET_MODE);
|
|
1513
1515
|
if (widget !== undefined)
|
|
1514
1516
|
prefs.widget_mode = widget;
|
|
1515
1517
|
const experimental = prefs.experimental ?? {};
|
|
@@ -166,6 +166,6 @@ export async function handleVerdict(rawArgs, ctx, basePath) {
|
|
|
166
166
|
ctx.ui.notify(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`, "success");
|
|
167
167
|
}
|
|
168
168
|
if (effectiveVerdict === "needs-remediation") {
|
|
169
|
-
ctx.ui.notify("Follow up with
|
|
169
|
+
ctx.ui.notify("Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.", "info");
|
|
170
170
|
}
|
|
171
171
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
10
10
|
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
11
11
|
import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, loadProjectGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, resolveDynamicRoutingConfig, resolveEffectiveProfile, resolveModelWithFallbacksForUnit, resolveAutoSupervisorConfig, } from "./preferences.js";
|
|
12
|
+
const DEFAULT_WIDGET_MODE = "small";
|
|
12
13
|
function collectConfigSections() {
|
|
13
14
|
const sections = [];
|
|
14
15
|
const globalPrefs = loadGlobalGSDPreferences();
|
|
@@ -157,7 +158,7 @@ function collectConfigSections() {
|
|
|
157
158
|
toggleRows.push({ label: "search_provider", value: prefs.search_provider });
|
|
158
159
|
if (prefs?.context_selection)
|
|
159
160
|
toggleRows.push({ label: "context_selection", value: prefs.context_selection });
|
|
160
|
-
if (prefs?.widget_mode && prefs.widget_mode !==
|
|
161
|
+
if (prefs?.widget_mode && prefs.widget_mode !== DEFAULT_WIDGET_MODE)
|
|
161
162
|
toggleRows.push({ label: "widget_mode", value: prefs.widget_mode });
|
|
162
163
|
if (prefs?.experimental?.rtk)
|
|
163
164
|
toggleRows.push({ label: "experimental.rtk", value: "on" });
|
|
@@ -21,9 +21,10 @@ export function resetRetryState(state) {
|
|
|
21
21
|
const PERMANENT_RE = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i;
|
|
22
22
|
// Include provider-specific quota-window phrasing like:
|
|
23
23
|
// - "You've hit your limit"
|
|
24
|
+
// - "You've reached your limit"
|
|
24
25
|
// - "usage limit" / "quota reached"
|
|
25
26
|
// - "out of extra usage"
|
|
26
|
-
const RATE_LIMIT_RE = /rate.?limit|too many requests|429|hit your limit|usage limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
|
|
27
|
+
const RATE_LIMIT_RE = /rate.?limit|too many requests|429|(?:hit|reached) your (?:\w+ )?limit|(?:usage|session|weekly|daily|monthly|quota) limit|out of extra usage|quota (?:reached|hit)|limit.*resets?/i;
|
|
27
28
|
// OpenRouter affordability-style quota errors should be treated as transient
|
|
28
29
|
// so core retry logic can lower maxTokens and continue in-session.
|
|
29
30
|
const AFFORDABILITY_RE = /requires more credits|can only afford|insufficient credits|not enough credits|fewer max_tokens/i;
|
|
@@ -247,6 +247,7 @@ function writeMeta(path, result, request, now) {
|
|
|
247
247
|
id: result.id,
|
|
248
248
|
runtime: result.runtime,
|
|
249
249
|
purpose: request.purpose ?? null,
|
|
250
|
+
...(request.metadata ? { metadata: request.metadata } : {}),
|
|
250
251
|
script_chars: request.script.length,
|
|
251
252
|
started_at: now.toISOString(),
|
|
252
253
|
finished_at: new Date(now.getTime() + result.duration_ms).toISOString(),
|
|
@@ -260,6 +261,7 @@ function writeMeta(path, result, request, now) {
|
|
|
260
261
|
stderr_truncated: result.stderr_truncated,
|
|
261
262
|
stdout_path: result.stdout_path,
|
|
262
263
|
stderr_path: result.stderr_path,
|
|
264
|
+
...(request.metadata ? { metadata: request.metadata } : {}),
|
|
263
265
|
};
|
|
264
266
|
writeFileSync(path, `${JSON.stringify(meta, null, 2)}\n`);
|
|
265
267
|
}
|