gsd-pi 2.18.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/cli.js +3 -3
- package/dist/onboarding.d.ts +3 -1
- package/dist/onboarding.js +77 -3
- package/dist/remote-questions-config.d.ts +1 -1
- package/dist/resources/extensions/google-search/index.ts +164 -47
- package/dist/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/dist/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/dist/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/dist/resources/extensions/gsd/auto.ts +690 -39
- package/dist/resources/extensions/gsd/captures.ts +384 -0
- package/dist/resources/extensions/gsd/commands.ts +654 -36
- package/dist/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/dist/resources/extensions/gsd/context-budget.ts +243 -0
- package/dist/resources/extensions/gsd/context-store.ts +195 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/dist/resources/extensions/gsd/db-writer.ts +341 -0
- package/dist/resources/extensions/gsd/debug-logger.ts +178 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/dist/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/dist/resources/extensions/gsd/doctor.ts +283 -2
- package/dist/resources/extensions/gsd/export.ts +81 -2
- package/dist/resources/extensions/gsd/files.ts +39 -9
- package/dist/resources/extensions/gsd/git-service.ts +6 -0
- package/dist/resources/extensions/gsd/gsd-db.ts +752 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +26 -1
- package/dist/resources/extensions/gsd/history.ts +0 -1
- package/dist/resources/extensions/gsd/index.ts +277 -1
- package/dist/resources/extensions/gsd/md-importer.ts +526 -0
- package/dist/resources/extensions/gsd/metrics.ts +84 -0
- package/dist/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/dist/resources/extensions/gsd/model-router.ts +256 -0
- package/dist/resources/extensions/gsd/notifications.ts +0 -1
- package/dist/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/dist/resources/extensions/gsd/preferences.ts +198 -150
- package/dist/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/dist/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/dist/resources/extensions/gsd/prompts/system.md +2 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/dist/resources/extensions/gsd/quick.ts +156 -0
- package/dist/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/dist/resources/extensions/gsd/skill-health.ts +417 -0
- package/dist/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/dist/resources/extensions/gsd/state.ts +30 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/dist/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/dist/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/dist/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/dist/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/dist/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/dist/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/dist/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/dist/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/dist/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/dist/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/dist/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/dist/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/dist/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/dist/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/dist/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/dist/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/dist/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/dist/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/dist/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/dist/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/dist/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/dist/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/dist/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/dist/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +175 -0
- package/dist/resources/extensions/gsd/types.ts +29 -0
- package/dist/resources/extensions/gsd/undo.ts +0 -1
- package/dist/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/dist/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/dist/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/dist/resources/extensions/gsd/worktree-command.ts +18 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/dist/resources/extensions/remote-questions/config.ts +4 -2
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/dist/resources/extensions/remote-questions/format.ts +166 -14
- package/dist/resources/extensions/remote-questions/manager.ts +14 -4
- package/dist/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/dist/resources/extensions/remote-questions/types.ts +2 -1
- package/dist/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/dist/resources/extensions/voice/index.ts +4 -3
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +12 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +25 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +106 -3
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +35 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/types.js +6 -0
- package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/utils.js +45 -0
- package/packages/pi-coding-agent/dist/core/lsp/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +6 -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 +43 -11
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +7 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.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 -0
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.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 +5 -0
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +13 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +6 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +26 -0
- package/packages/pi-coding-agent/src/core/lsp/index.ts +157 -2
- package/packages/pi-coding-agent/src/core/lsp/lsp.md +6 -0
- package/packages/pi-coding-agent/src/core/lsp/types.ts +53 -0
- package/packages/pi-coding-agent/src/core/lsp/utils.ts +56 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +41 -11
- package/packages/pi-coding-agent/src/core/system-prompt.ts +7 -1
- package/packages/pi-coding-agent/src/core/tools/edit.ts +3 -0
- package/packages/pi-coding-agent/src/core/tools/write.ts +3 -0
- package/src/resources/extensions/google-search/index.ts +164 -47
- package/src/resources/extensions/gsd/auto-dashboard.ts +14 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +148 -39
- package/src/resources/extensions/gsd/auto-worktree.ts +93 -9
- package/src/resources/extensions/gsd/auto.ts +690 -39
- package/src/resources/extensions/gsd/captures.ts +384 -0
- package/src/resources/extensions/gsd/commands.ts +654 -36
- package/src/resources/extensions/gsd/complexity-classifier.ts +322 -0
- package/src/resources/extensions/gsd/context-budget.ts +243 -0
- package/src/resources/extensions/gsd/context-store.ts +195 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +51 -3
- package/src/resources/extensions/gsd/db-writer.ts +341 -0
- package/src/resources/extensions/gsd/debug-logger.ts +178 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +0 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +54 -0
- package/src/resources/extensions/gsd/doctor-proactive.ts +286 -0
- package/src/resources/extensions/gsd/doctor.ts +283 -2
- package/src/resources/extensions/gsd/export.ts +81 -2
- package/src/resources/extensions/gsd/files.ts +39 -9
- package/src/resources/extensions/gsd/git-service.ts +6 -0
- package/src/resources/extensions/gsd/gsd-db.ts +752 -0
- package/src/resources/extensions/gsd/guided-flow.ts +26 -1
- package/src/resources/extensions/gsd/history.ts +0 -1
- package/src/resources/extensions/gsd/index.ts +277 -1
- package/src/resources/extensions/gsd/md-importer.ts +526 -0
- package/src/resources/extensions/gsd/metrics.ts +84 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +65 -0
- package/src/resources/extensions/gsd/model-router.ts +256 -0
- package/src/resources/extensions/gsd/notifications.ts +0 -1
- package/src/resources/extensions/gsd/post-unit-hooks.ts +72 -2
- package/src/resources/extensions/gsd/preferences.ts +198 -150
- package/src/resources/extensions/gsd/prompt-loader.ts +45 -9
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -5
- package/src/resources/extensions/gsd/prompts/heal-skill.md +45 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +48 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +8 -0
- package/src/resources/extensions/gsd/prompts/system.md +2 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +62 -0
- package/src/resources/extensions/gsd/quick.ts +156 -0
- package/src/resources/extensions/gsd/skill-discovery.ts +5 -3
- package/src/resources/extensions/gsd/skill-health.ts +417 -0
- package/src/resources/extensions/gsd/skill-telemetry.ts +127 -0
- package/src/resources/extensions/gsd/state.ts +30 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/captures.test.ts +438 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +462 -0
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +204 -0
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +346 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +602 -0
- package/src/resources/extensions/gsd/tests/debug-logger.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +406 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +22 -0
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +244 -0
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +303 -0
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +434 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +353 -0
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +326 -0
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +228 -0
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +411 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +144 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/parsers.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +41 -1
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +464 -0
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +385 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +488 -1
- package/src/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +17 -29
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +2 -8
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +215 -62
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +126 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +31 -8
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +366 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +224 -0
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +215 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +290 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +478 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-post-create-hook.test.ts +165 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +200 -0
- package/src/resources/extensions/gsd/triage-ui.ts +175 -0
- package/src/resources/extensions/gsd/types.ts +29 -0
- package/src/resources/extensions/gsd/undo.ts +0 -1
- package/src/resources/extensions/gsd/unit-runtime.ts +5 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +505 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +337 -0
- package/src/resources/extensions/gsd/visualizer-views.ts +755 -0
- package/src/resources/extensions/gsd/worktree-command.ts +18 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +11 -4
- package/src/resources/extensions/remote-questions/config.ts +4 -2
- package/src/resources/extensions/remote-questions/discord-adapter.ts +35 -4
- package/src/resources/extensions/remote-questions/format.ts +166 -14
- package/src/resources/extensions/remote-questions/manager.ts +14 -4
- package/src/resources/extensions/remote-questions/remote-command.ts +100 -4
- package/src/resources/extensions/remote-questions/slack-adapter.ts +58 -2
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +161 -0
- package/src/resources/extensions/remote-questions/types.ts +2 -1
- package/src/resources/extensions/ttsr/ttsr-manager.ts +26 -0
- package/src/resources/extensions/voice/index.ts +4 -3
|
@@ -8,12 +8,15 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent
|
|
|
8
8
|
import { AuthStorage } from "@gsd/pi-coding-agent";
|
|
9
9
|
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
10
10
|
import { join, dirname } from "node:path";
|
|
11
|
+
import { enableDebug, isDebugEnabled } from "./debug-logger.js";
|
|
11
12
|
import { fileURLToPath } from "node:url";
|
|
12
13
|
import { deriveState } from "./state.js";
|
|
13
14
|
import { GSDDashboardOverlay } from "./dashboard-overlay.js";
|
|
15
|
+
import { GSDVisualizerOverlay } from "./visualizer-overlay.js";
|
|
14
16
|
import { showQueue, showDiscuss } from "./guided-flow.js";
|
|
15
17
|
import { startAuto, stopAuto, pauseAuto, isAutoActive, isAutoPaused, isStepMode, stopAutoRemote } from "./auto.js";
|
|
16
18
|
import { resolveProjectRoot } from "./worktree.js";
|
|
19
|
+
import { appendCapture, hasPendingCaptures, loadPendingCaptures } from "./captures.js";
|
|
17
20
|
import {
|
|
18
21
|
getGlobalGSDPreferencesPath,
|
|
19
22
|
getLegacyGlobalGSDPreferencesPath,
|
|
@@ -34,12 +37,13 @@ import {
|
|
|
34
37
|
import { loadPrompt } from "./prompt-loader.js";
|
|
35
38
|
|
|
36
39
|
import { handleRemote } from "../remote-questions/remote-command.js";
|
|
40
|
+
import { handleQuick } from "./quick.js";
|
|
37
41
|
import { handleHistory } from "./history.js";
|
|
38
42
|
import { handleUndo } from "./undo.js";
|
|
39
43
|
import { handleExport } from "./export.js";
|
|
40
44
|
import { nativeBranchList, nativeDetectMainBranch, nativeBranchListMerged, nativeBranchDelete, nativeForEachRef, nativeUpdateRef } from "./native-git-bridge.js";
|
|
41
45
|
|
|
42
|
-
function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined, reportText: string, structuredIssues: string): void {
|
|
46
|
+
export function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined, reportText: string, structuredIssues: string): void {
|
|
43
47
|
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".pi", "GSD-WORKFLOW.md");
|
|
44
48
|
const workflow = readFileSync(workflowPath, "utf-8");
|
|
45
49
|
const prompt = loadPrompt("doctor-heal", {
|
|
@@ -64,12 +68,13 @@ function projectRoot(): string {
|
|
|
64
68
|
|
|
65
69
|
export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
66
70
|
pi.registerCommand("gsd", {
|
|
67
|
-
description: "GSD — Get Shit Done: /gsd next|auto|stop|pause|status|queue|history|undo|skip|export|cleanup|prefs|config|hooks|doctor|migrate|remote|steer|knowledge",
|
|
71
|
+
description: "GSD — Get Shit Done: /gsd help|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|history|undo|skip|export|cleanup|mode|prefs|config|hooks|run-hook|skill-health|doctor|migrate|remote|steer|knowledge",
|
|
68
72
|
getArgumentCompletions: (prefix: string) => {
|
|
69
73
|
const subcommands = [
|
|
70
|
-
"next", "auto", "stop", "pause", "status", "queue", "discuss",
|
|
71
|
-
"
|
|
72
|
-
"
|
|
74
|
+
"help", "next", "auto", "stop", "pause", "status", "visualize", "queue", "quick", "discuss",
|
|
75
|
+
"capture", "triage",
|
|
76
|
+
"history", "undo", "skip", "export", "cleanup", "mode", "prefs",
|
|
77
|
+
"config", "hooks", "run-hook", "skill-health", "doctor", "migrate", "remote", "steer", "inspect", "knowledge",
|
|
73
78
|
];
|
|
74
79
|
const parts = prefix.trim().split(/\s+/);
|
|
75
80
|
|
|
@@ -81,11 +86,18 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
81
86
|
|
|
82
87
|
if (parts[0] === "auto" && parts.length <= 2) {
|
|
83
88
|
const flagPrefix = parts[1] ?? "";
|
|
84
|
-
return ["--verbose"]
|
|
89
|
+
return ["--verbose", "--debug"]
|
|
85
90
|
.filter((f) => f.startsWith(flagPrefix))
|
|
86
91
|
.map((f) => ({ value: `auto ${f}`, label: f }));
|
|
87
92
|
}
|
|
88
93
|
|
|
94
|
+
if (parts[0] === "mode" && parts.length <= 2) {
|
|
95
|
+
const subPrefix = parts[1] ?? "";
|
|
96
|
+
return ["global", "project"]
|
|
97
|
+
.filter((cmd) => cmd.startsWith(subPrefix))
|
|
98
|
+
.map((cmd) => ({ value: `mode ${cmd}`, label: cmd }));
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
if (parts[0] === "prefs" && parts.length <= 2) {
|
|
90
102
|
const subPrefix = parts[1] ?? "";
|
|
91
103
|
return ["global", "project", "status", "wizard", "setup"]
|
|
@@ -158,11 +170,30 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
158
170
|
async handler(args: string, ctx: ExtensionCommandContext) {
|
|
159
171
|
const trimmed = (typeof args === "string" ? args : "").trim();
|
|
160
172
|
|
|
173
|
+
if (trimmed === "help" || trimmed === "h" || trimmed === "?") {
|
|
174
|
+
showHelp(ctx);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
161
178
|
if (trimmed === "status") {
|
|
162
179
|
await handleStatus(ctx);
|
|
163
180
|
return;
|
|
164
181
|
}
|
|
165
182
|
|
|
183
|
+
if (trimmed === "visualize") {
|
|
184
|
+
await handleVisualize(ctx);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (trimmed === "mode" || trimmed.startsWith("mode ")) {
|
|
189
|
+
const modeArgs = trimmed.replace(/^mode\s*/, "").trim();
|
|
190
|
+
const scope = modeArgs === "project" ? "project" : "global";
|
|
191
|
+
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
192
|
+
await ensurePreferencesFile(path, ctx, scope);
|
|
193
|
+
await handlePrefsMode(ctx, scope);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
166
197
|
if (trimmed === "prefs" || trimmed.startsWith("prefs ")) {
|
|
167
198
|
await handlePrefs(trimmed.replace(/^prefs\s*/, "").trim(), ctx);
|
|
168
199
|
return;
|
|
@@ -179,12 +210,16 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
179
210
|
return;
|
|
180
211
|
}
|
|
181
212
|
const verboseMode = trimmed.includes("--verbose");
|
|
213
|
+
const debugMode = trimmed.includes("--debug");
|
|
214
|
+
if (debugMode) enableDebug(projectRoot());
|
|
182
215
|
await startAuto(ctx, pi, projectRoot(), verboseMode, { step: true });
|
|
183
216
|
return;
|
|
184
217
|
}
|
|
185
218
|
|
|
186
219
|
if (trimmed === "auto" || trimmed.startsWith("auto ")) {
|
|
187
220
|
const verboseMode = trimmed.includes("--verbose");
|
|
221
|
+
const debugMode = trimmed.includes("--debug");
|
|
222
|
+
if (debugMode) enableDebug(projectRoot());
|
|
188
223
|
await startAuto(ctx, pi, projectRoot(), verboseMode);
|
|
189
224
|
return;
|
|
190
225
|
}
|
|
@@ -259,6 +294,21 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
259
294
|
return;
|
|
260
295
|
}
|
|
261
296
|
|
|
297
|
+
if (trimmed.startsWith("capture ") || trimmed === "capture") {
|
|
298
|
+
await handleCapture(trimmed.replace(/^capture\s*/, "").trim(), ctx);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (trimmed === "triage") {
|
|
303
|
+
await handleTriage(ctx, pi, process.cwd());
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (trimmed === "quick" || trimmed.startsWith("quick ")) {
|
|
308
|
+
await handleQuick(trimmed.replace(/^quick\s*/, "").trim(), ctx, pi);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
262
312
|
if (trimmed === "config") {
|
|
263
313
|
await handleConfig(ctx);
|
|
264
314
|
return;
|
|
@@ -270,6 +320,32 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
270
320
|
return;
|
|
271
321
|
}
|
|
272
322
|
|
|
323
|
+
// ─── Skill Health ────────────────────────────────────────────
|
|
324
|
+
if (trimmed === "skill-health" || trimmed.startsWith("skill-health ")) {
|
|
325
|
+
await handleSkillHealth(trimmed.replace(/^skill-health\s*/, "").trim(), ctx);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (trimmed.startsWith("run-hook ")) {
|
|
330
|
+
await handleRunHook(trimmed.replace(/^run-hook\s*/, "").trim(), ctx, pi);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (trimmed === "run-hook") {
|
|
334
|
+
ctx.ui.notify(`Usage: /gsd run-hook <hook-name> <unit-type> <unit-id>
|
|
335
|
+
|
|
336
|
+
Unit types:
|
|
337
|
+
execute-task - Task execution (unit-id: M001/S01/T01)
|
|
338
|
+
plan-slice - Slice planning (unit-id: M001/S01)
|
|
339
|
+
research-milestone - Milestone research (unit-id: M001)
|
|
340
|
+
complete-slice - Slice completion (unit-id: M001/S01)
|
|
341
|
+
complete-milestone - Milestone completion (unit-id: M001)
|
|
342
|
+
|
|
343
|
+
Examples:
|
|
344
|
+
/gsd run-hook code-review execute-task M001/S01/T01
|
|
345
|
+
/gsd run-hook lint-check plan-slice M001/S01`, "warning");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
273
349
|
if (trimmed.startsWith("steer ")) {
|
|
274
350
|
await handleSteer(trimmed.replace(/^steer\s+/, "").trim(), ctx, pi);
|
|
275
351
|
return;
|
|
@@ -299,6 +375,11 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
299
375
|
return;
|
|
300
376
|
}
|
|
301
377
|
|
|
378
|
+
if (trimmed === "inspect") {
|
|
379
|
+
await handleInspect(ctx);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
302
383
|
if (trimmed === "") {
|
|
303
384
|
// Bare /gsd defaults to step mode
|
|
304
385
|
await startAuto(ctx, pi, projectRoot(), false, { step: true });
|
|
@@ -306,13 +387,57 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
306
387
|
}
|
|
307
388
|
|
|
308
389
|
ctx.ui.notify(
|
|
309
|
-
`Unknown: /gsd ${trimmed}.
|
|
390
|
+
`Unknown: /gsd ${trimmed}. Run /gsd help for available commands.`,
|
|
310
391
|
"warning",
|
|
311
392
|
);
|
|
312
393
|
},
|
|
313
394
|
});
|
|
314
395
|
}
|
|
315
396
|
|
|
397
|
+
function showHelp(ctx: ExtensionCommandContext): void {
|
|
398
|
+
const lines = [
|
|
399
|
+
"GSD — Get Shit Done\n",
|
|
400
|
+
"WORKFLOW",
|
|
401
|
+
" /gsd Run next unit in step mode (same as /gsd next)",
|
|
402
|
+
" /gsd next Execute next task, then pause [--dry-run] [--verbose]",
|
|
403
|
+
" /gsd auto Run all queued units continuously [--verbose]",
|
|
404
|
+
" /gsd stop Stop auto-mode gracefully",
|
|
405
|
+
" /gsd pause Pause auto-mode (preserves state, /gsd auto to resume)",
|
|
406
|
+
" /gsd discuss Start guided milestone/slice discussion",
|
|
407
|
+
"",
|
|
408
|
+
"VISIBILITY",
|
|
409
|
+
" /gsd status Show progress dashboard (Ctrl+Alt+G)",
|
|
410
|
+
" /gsd visualize Interactive 7-tab TUI (progress, deps, metrics, timeline, agent, changes, export)",
|
|
411
|
+
" /gsd queue Show queued/dispatched units and execution order",
|
|
412
|
+
" /gsd history View execution history [--cost] [--phase] [--model] [N]",
|
|
413
|
+
"",
|
|
414
|
+
"COURSE CORRECTION",
|
|
415
|
+
" /gsd steer <desc> Apply user override to active work",
|
|
416
|
+
" /gsd capture <text> Quick-capture a thought to CAPTURES.md",
|
|
417
|
+
" /gsd triage Classify and route pending captures",
|
|
418
|
+
" /gsd skip <unit> Prevent a unit from auto-mode dispatch",
|
|
419
|
+
" /gsd undo Revert last completed unit [--force]",
|
|
420
|
+
"",
|
|
421
|
+
"PROJECT KNOWLEDGE",
|
|
422
|
+
" /gsd knowledge <type> <text> Add rule, pattern, or lesson to KNOWLEDGE.md",
|
|
423
|
+
"",
|
|
424
|
+
"CONFIGURATION",
|
|
425
|
+
" /gsd mode Set workflow mode (solo/team) [global|project]",
|
|
426
|
+
" /gsd prefs Manage preferences [global|project|status|wizard|setup]",
|
|
427
|
+
" /gsd config Set API keys for external tools",
|
|
428
|
+
" /gsd hooks Show post-unit hook configuration",
|
|
429
|
+
"",
|
|
430
|
+
"MAINTENANCE",
|
|
431
|
+
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
432
|
+
" /gsd export Export milestone/slice results [--json|--markdown]",
|
|
433
|
+
" /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
|
|
434
|
+
" /gsd migrate Upgrade .gsd/ structures to new format",
|
|
435
|
+
" /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
|
|
436
|
+
" /gsd inspect Show SQLite DB diagnostics (schema, row counts, recent entries)",
|
|
437
|
+
];
|
|
438
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
439
|
+
}
|
|
440
|
+
|
|
316
441
|
async function handleStatus(ctx: ExtensionCommandContext): Promise<void> {
|
|
317
442
|
const basePath = projectRoot();
|
|
318
443
|
const state = await deriveState(basePath);
|
|
@@ -344,6 +469,28 @@ export async function fireStatusViaCommand(
|
|
|
344
469
|
await handleStatus(ctx as ExtensionCommandContext);
|
|
345
470
|
}
|
|
346
471
|
|
|
472
|
+
async function handleVisualize(ctx: ExtensionCommandContext): Promise<void> {
|
|
473
|
+
if (!ctx.hasUI) {
|
|
474
|
+
ctx.ui.notify("Visualizer requires an interactive terminal.", "warning");
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
await ctx.ui.custom<void>(
|
|
479
|
+
(tui, theme, _kb, done) => {
|
|
480
|
+
return new GSDVisualizerOverlay(tui, theme, () => done());
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
overlay: true,
|
|
484
|
+
overlayOptions: {
|
|
485
|
+
width: "80%",
|
|
486
|
+
minWidth: 80,
|
|
487
|
+
maxHeight: "90%",
|
|
488
|
+
anchor: "center",
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
347
494
|
async function handlePrefs(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
348
495
|
const trimmed = args.trim();
|
|
349
496
|
|
|
@@ -393,6 +540,36 @@ async function handlePrefs(args: string, ctx: ExtensionCommandContext): Promise<
|
|
|
393
540
|
ctx.ui.notify("Usage: /gsd prefs [global|project|status|wizard|setup]", "info");
|
|
394
541
|
}
|
|
395
542
|
|
|
543
|
+
async function handlePrefsMode(ctx: ExtensionCommandContext, scope: "global" | "project"): Promise<void> {
|
|
544
|
+
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
545
|
+
const existing = scope === "project" ? loadProjectGSDPreferences() : loadGlobalGSDPreferences();
|
|
546
|
+
const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
|
|
547
|
+
|
|
548
|
+
await configureMode(ctx, prefs);
|
|
549
|
+
|
|
550
|
+
// Serialize and save
|
|
551
|
+
prefs.version = prefs.version || 1;
|
|
552
|
+
const frontmatter = serializePreferencesToFrontmatter(prefs);
|
|
553
|
+
|
|
554
|
+
let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
|
|
555
|
+
if (existsSync(path)) {
|
|
556
|
+
const existingContent = readFileSync(path, "utf-8");
|
|
557
|
+
const closingIdx = existingContent.indexOf("\n---", existingContent.indexOf("---"));
|
|
558
|
+
if (closingIdx !== -1) {
|
|
559
|
+
const afterFrontmatter = existingContent.slice(closingIdx + 4);
|
|
560
|
+
if (afterFrontmatter.trim()) {
|
|
561
|
+
body = afterFrontmatter;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const content = `---\n${frontmatter}---${body}`;
|
|
567
|
+
await saveFile(path, content);
|
|
568
|
+
await ctx.waitForIdle();
|
|
569
|
+
await ctx.reload();
|
|
570
|
+
ctx.ui.notify(`Saved ${scope} preferences to ${path}`, "info");
|
|
571
|
+
}
|
|
572
|
+
|
|
396
573
|
async function handleDoctor(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
397
574
|
const trimmed = args.trim();
|
|
398
575
|
const parts = trimmed ? trimmed.split(/\s+/) : [];
|
|
@@ -431,19 +608,220 @@ async function handleDoctor(args: string, ctx: ExtensionCommandContext, pi: Exte
|
|
|
431
608
|
}
|
|
432
609
|
}
|
|
433
610
|
|
|
611
|
+
// ─── Inspect ──────────────────────────────────────────────────────────────────
|
|
612
|
+
|
|
613
|
+
export interface InspectData {
|
|
614
|
+
schemaVersion: number | null;
|
|
615
|
+
counts: { decisions: number; requirements: number; artifacts: number };
|
|
616
|
+
recentDecisions: Array<{ id: string; decision: string; choice: string }>;
|
|
617
|
+
recentRequirements: Array<{ id: string; status: string; description: string }>;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export function formatInspectOutput(data: InspectData): string {
|
|
621
|
+
const lines: string[] = [];
|
|
622
|
+
lines.push("=== GSD Database Inspect ===");
|
|
623
|
+
lines.push(`Schema version: ${data.schemaVersion ?? "unknown"}`);
|
|
624
|
+
lines.push("");
|
|
625
|
+
lines.push(`Decisions: ${data.counts.decisions}`);
|
|
626
|
+
lines.push(`Requirements: ${data.counts.requirements}`);
|
|
627
|
+
lines.push(`Artifacts: ${data.counts.artifacts}`);
|
|
628
|
+
|
|
629
|
+
if (data.recentDecisions.length > 0) {
|
|
630
|
+
lines.push("");
|
|
631
|
+
lines.push("Recent decisions:");
|
|
632
|
+
for (const d of data.recentDecisions) {
|
|
633
|
+
lines.push(` ${d.id}: ${d.decision} → ${d.choice}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (data.recentRequirements.length > 0) {
|
|
638
|
+
lines.push("");
|
|
639
|
+
lines.push("Recent requirements:");
|
|
640
|
+
for (const r of data.recentRequirements) {
|
|
641
|
+
lines.push(` ${r.id} [${r.status}]: ${r.description}`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return lines.join("\n");
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async function handleInspect(ctx: ExtensionCommandContext): Promise<void> {
|
|
649
|
+
try {
|
|
650
|
+
const { isDbAvailable, _getAdapter } = await import("./gsd-db.js");
|
|
651
|
+
|
|
652
|
+
if (!isDbAvailable()) {
|
|
653
|
+
ctx.ui.notify("No GSD database available. Run /gsd auto to create one.", "info");
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const adapter = _getAdapter();
|
|
658
|
+
if (!adapter) {
|
|
659
|
+
ctx.ui.notify("No GSD database available. Run /gsd auto to create one.", "info");
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const versionRow = adapter.prepare("SELECT MAX(version) as v FROM schema_version").get();
|
|
664
|
+
const schemaVersion = versionRow ? (versionRow["v"] as number | null) : null;
|
|
665
|
+
|
|
666
|
+
const dCount = adapter.prepare("SELECT count(*) as cnt FROM decisions").get();
|
|
667
|
+
const rCount = adapter.prepare("SELECT count(*) as cnt FROM requirements").get();
|
|
668
|
+
const aCount = adapter.prepare("SELECT count(*) as cnt FROM artifacts").get();
|
|
669
|
+
|
|
670
|
+
const recentDecisions = adapter
|
|
671
|
+
.prepare("SELECT id, decision, choice FROM decisions ORDER BY seq DESC LIMIT 5")
|
|
672
|
+
.all() as Array<{ id: string; decision: string; choice: string }>;
|
|
673
|
+
|
|
674
|
+
const recentRequirements = adapter
|
|
675
|
+
.prepare("SELECT id, status, description FROM requirements ORDER BY id DESC LIMIT 5")
|
|
676
|
+
.all() as Array<{ id: string; status: string; description: string }>;
|
|
677
|
+
|
|
678
|
+
const data: InspectData = {
|
|
679
|
+
schemaVersion,
|
|
680
|
+
counts: {
|
|
681
|
+
decisions: (dCount?.["cnt"] as number) ?? 0,
|
|
682
|
+
requirements: (rCount?.["cnt"] as number) ?? 0,
|
|
683
|
+
artifacts: (aCount?.["cnt"] as number) ?? 0,
|
|
684
|
+
},
|
|
685
|
+
recentDecisions,
|
|
686
|
+
recentRequirements,
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
ctx.ui.notify(formatInspectOutput(data), "info");
|
|
690
|
+
} catch (err) {
|
|
691
|
+
process.stderr.write(`gsd-db: /gsd inspect failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
692
|
+
ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// ─── Skill Health ─────────────────────────────────────────────────────────────
|
|
697
|
+
|
|
698
|
+
async function handleSkillHealth(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
699
|
+
const {
|
|
700
|
+
generateSkillHealthReport,
|
|
701
|
+
formatSkillHealthReport,
|
|
702
|
+
formatSkillDetail,
|
|
703
|
+
} = await import("./skill-health.js");
|
|
704
|
+
|
|
705
|
+
const basePath = projectRoot();
|
|
706
|
+
|
|
707
|
+
// /gsd skill-health <skill-name> — detail view
|
|
708
|
+
if (args && !args.startsWith("--")) {
|
|
709
|
+
const detail = formatSkillDetail(basePath, args);
|
|
710
|
+
ctx.ui.notify(detail, "info");
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Parse flags
|
|
715
|
+
const staleMatch = args.match(/--stale\s+(\d+)/);
|
|
716
|
+
const staleDays = staleMatch ? parseInt(staleMatch[1], 10) : undefined;
|
|
717
|
+
const decliningOnly = args.includes("--declining");
|
|
718
|
+
|
|
719
|
+
const report = generateSkillHealthReport(basePath, staleDays);
|
|
720
|
+
|
|
721
|
+
if (decliningOnly) {
|
|
722
|
+
if (report.decliningSkills.length === 0) {
|
|
723
|
+
ctx.ui.notify("No skills flagged for declining performance.", "info");
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
const filtered = {
|
|
727
|
+
...report,
|
|
728
|
+
skills: report.skills.filter(s => s.flagged),
|
|
729
|
+
};
|
|
730
|
+
ctx.ui.notify(formatSkillHealthReport(filtered), "info");
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
ctx.ui.notify(formatSkillHealthReport(report), "info");
|
|
735
|
+
}
|
|
736
|
+
|
|
434
737
|
// ─── Preferences Wizard ───────────────────────────────────────────────────────
|
|
435
738
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
739
|
+
/** Build short summary strings for each preference category. */
|
|
740
|
+
function buildCategorySummaries(prefs: Record<string, unknown>): Record<string, string> {
|
|
741
|
+
// Mode
|
|
742
|
+
const mode = prefs.mode as string | undefined;
|
|
743
|
+
const modeSummary = mode ?? "(not set)";
|
|
744
|
+
|
|
745
|
+
// Models
|
|
746
|
+
const models = prefs.models as Record<string, string> | undefined;
|
|
747
|
+
let modelsSummary = "(not configured)";
|
|
748
|
+
if (models && Object.keys(models).length > 0) {
|
|
749
|
+
const parts = Object.entries(models).map(([phase, model]) => `${phase}: ${model}`);
|
|
750
|
+
modelsSummary = parts.join(", ");
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Timeouts
|
|
754
|
+
const autoSup = prefs.auto_supervisor as Record<string, unknown> | undefined;
|
|
755
|
+
let timeoutsSummary = "(defaults)";
|
|
756
|
+
if (autoSup && Object.keys(autoSup).length > 0) {
|
|
757
|
+
const soft = autoSup.soft_timeout_minutes ?? "20";
|
|
758
|
+
const idle = autoSup.idle_timeout_minutes ?? "10";
|
|
759
|
+
const hard = autoSup.hard_timeout_minutes ?? "30";
|
|
760
|
+
timeoutsSummary = `soft: ${soft}m, idle: ${idle}m, hard: ${hard}m`;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Git
|
|
764
|
+
const git = prefs.git as Record<string, unknown> | undefined;
|
|
765
|
+
let gitSummary = "(defaults)";
|
|
766
|
+
if (git && Object.keys(git).length > 0) {
|
|
767
|
+
const branch = git.main_branch ?? "main";
|
|
768
|
+
const push = git.auto_push ? "on" : "off";
|
|
769
|
+
gitSummary = `main: ${branch}, push: ${push}`;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Skills
|
|
773
|
+
const discovery = prefs.skill_discovery as string | undefined;
|
|
774
|
+
const uat = prefs.uat_dispatch;
|
|
775
|
+
let skillsSummary = "(not configured)";
|
|
776
|
+
if (discovery || uat !== undefined) {
|
|
777
|
+
const parts: string[] = [];
|
|
778
|
+
if (discovery) parts.push(`discovery: ${discovery}`);
|
|
779
|
+
if (uat !== undefined) parts.push(`uat: ${uat}`);
|
|
780
|
+
skillsSummary = parts.join(", ");
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Budget
|
|
784
|
+
const ceiling = prefs.budget_ceiling;
|
|
785
|
+
const enforcement = prefs.budget_enforcement as string | undefined;
|
|
786
|
+
let budgetSummary = "(no limit)";
|
|
787
|
+
if (ceiling !== undefined) {
|
|
788
|
+
budgetSummary = `$${ceiling}`;
|
|
789
|
+
if (enforcement) budgetSummary += ` / ${enforcement}`;
|
|
790
|
+
} else if (enforcement) {
|
|
791
|
+
budgetSummary = enforcement;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Notifications
|
|
795
|
+
const notif = prefs.notifications as Record<string, boolean> | undefined;
|
|
796
|
+
let notifSummary = "(defaults)";
|
|
797
|
+
if (notif && Object.keys(notif).length > 0) {
|
|
798
|
+
const allKeys = ["enabled", "on_complete", "on_error", "on_budget", "on_milestone", "on_attention"];
|
|
799
|
+
const enabledCount = allKeys.filter(k => notif[k] !== false).length;
|
|
800
|
+
notifSummary = `${enabledCount}/${allKeys.length} enabled`;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Advanced
|
|
804
|
+
const uniqueIds = prefs.unique_milestone_ids;
|
|
805
|
+
let advancedSummary = "(defaults)";
|
|
806
|
+
if (uniqueIds !== undefined) {
|
|
807
|
+
advancedSummary = `unique IDs: ${uniqueIds ? "on" : "off"}`;
|
|
808
|
+
}
|
|
443
809
|
|
|
444
|
-
|
|
810
|
+
return {
|
|
811
|
+
mode: modeSummary,
|
|
812
|
+
models: modelsSummary,
|
|
813
|
+
timeouts: timeoutsSummary,
|
|
814
|
+
git: gitSummary,
|
|
815
|
+
skills: skillsSummary,
|
|
816
|
+
budget: budgetSummary,
|
|
817
|
+
notifications: notifSummary,
|
|
818
|
+
advanced: advancedSummary,
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// ─── Category configuration functions ────────────────────────────────────────
|
|
445
823
|
|
|
446
|
-
|
|
824
|
+
async function configureModels(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
447
825
|
const modelPhases = ["research", "planning", "execution", "completion"] as const;
|
|
448
826
|
const models: Record<string, string> = (prefs.models as Record<string, string>) ?? {};
|
|
449
827
|
|
|
@@ -466,7 +844,6 @@ async function handlePrefsWizard(
|
|
|
466
844
|
}
|
|
467
845
|
}
|
|
468
846
|
} else {
|
|
469
|
-
// No authenticated models available — fall back to text input
|
|
470
847
|
for (const phase of modelPhases) {
|
|
471
848
|
const current = models[phase] ?? "";
|
|
472
849
|
const input = await ctx.ui.input(
|
|
@@ -486,8 +863,9 @@ async function handlePrefsWizard(
|
|
|
486
863
|
if (Object.keys(models).length > 0) {
|
|
487
864
|
prefs.models = models;
|
|
488
865
|
}
|
|
866
|
+
}
|
|
489
867
|
|
|
490
|
-
|
|
868
|
+
async function configureTimeouts(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
491
869
|
const autoSup: Record<string, unknown> = (prefs.auto_supervisor as Record<string, unknown>) ?? {};
|
|
492
870
|
const timeoutFields = [
|
|
493
871
|
{ key: "soft_timeout_minutes", label: "Soft timeout (minutes)", defaultVal: "20" },
|
|
@@ -516,8 +894,9 @@ async function handlePrefsWizard(
|
|
|
516
894
|
if (Object.keys(autoSup).length > 0) {
|
|
517
895
|
prefs.auto_supervisor = autoSup;
|
|
518
896
|
}
|
|
897
|
+
}
|
|
519
898
|
|
|
520
|
-
|
|
899
|
+
async function configureGit(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
521
900
|
const git: Record<string, unknown> = (prefs.git as Record<string, unknown>) ?? {};
|
|
522
901
|
|
|
523
902
|
// main_branch
|
|
@@ -618,7 +997,7 @@ async function handlePrefsWizard(
|
|
|
618
997
|
git.isolation = isolationChoice;
|
|
619
998
|
}
|
|
620
999
|
|
|
621
|
-
//
|
|
1000
|
+
// commit_docs
|
|
622
1001
|
const currentCommitDocs = git.commit_docs;
|
|
623
1002
|
const commitDocsChoice = await ctx.ui.select(
|
|
624
1003
|
`Track .gsd/ planning docs in git${currentCommitDocs !== undefined ? ` (current: ${currentCommitDocs})` : ""}:`,
|
|
@@ -631,8 +1010,10 @@ async function handlePrefsWizard(
|
|
|
631
1010
|
if (Object.keys(git).length > 0) {
|
|
632
1011
|
prefs.git = git;
|
|
633
1012
|
}
|
|
1013
|
+
}
|
|
634
1014
|
|
|
635
|
-
|
|
1015
|
+
async function configureSkills(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1016
|
+
// Skill discovery mode
|
|
636
1017
|
const currentDiscovery = (prefs.skill_discovery as string) ?? "";
|
|
637
1018
|
const discoveryChoice = await ctx.ui.select(
|
|
638
1019
|
`Skill discovery mode${currentDiscovery ? ` (current: ${currentDiscovery})` : ""}:`,
|
|
@@ -642,17 +1023,18 @@ async function handlePrefsWizard(
|
|
|
642
1023
|
prefs.skill_discovery = discoveryChoice;
|
|
643
1024
|
}
|
|
644
1025
|
|
|
645
|
-
//
|
|
646
|
-
const
|
|
647
|
-
const
|
|
648
|
-
`
|
|
1026
|
+
// UAT dispatch
|
|
1027
|
+
const currentUat = prefs.uat_dispatch;
|
|
1028
|
+
const uatChoice = await ctx.ui.select(
|
|
1029
|
+
`UAT dispatch mode${currentUat !== undefined ? ` (current: ${currentUat})` : " (default: false)"}:`,
|
|
649
1030
|
["true", "false", "(keep current)"],
|
|
650
1031
|
);
|
|
651
|
-
if (
|
|
652
|
-
prefs.
|
|
1032
|
+
if (uatChoice && uatChoice !== "(keep current)") {
|
|
1033
|
+
prefs.uat_dispatch = uatChoice === "true";
|
|
653
1034
|
}
|
|
1035
|
+
}
|
|
654
1036
|
|
|
655
|
-
|
|
1037
|
+
async function configureBudget(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
656
1038
|
const currentCeiling = prefs.budget_ceiling;
|
|
657
1039
|
const ceilingStr = currentCeiling !== undefined ? String(currentCeiling) : "";
|
|
658
1040
|
const ceilingInput = await ctx.ui.input(
|
|
@@ -698,8 +1080,9 @@ async function handlePrefsWizard(
|
|
|
698
1080
|
ctx.ui.notify(`Invalid context pause threshold "${val}" — must be 0-100. Keeping previous value.`, "warning");
|
|
699
1081
|
}
|
|
700
1082
|
}
|
|
1083
|
+
}
|
|
701
1084
|
|
|
702
|
-
|
|
1085
|
+
async function configureNotifications(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
703
1086
|
const notif: Record<string, boolean> = (prefs.notifications as Record<string, boolean>) ?? {};
|
|
704
1087
|
const notifFields = [
|
|
705
1088
|
{ key: "enabled", label: "Notifications enabled (master toggle)", defaultVal: true },
|
|
@@ -724,15 +1107,88 @@ async function handlePrefsWizard(
|
|
|
724
1107
|
if (Object.keys(notif).length > 0) {
|
|
725
1108
|
prefs.notifications = notif;
|
|
726
1109
|
}
|
|
1110
|
+
}
|
|
727
1111
|
|
|
728
|
-
|
|
729
|
-
const
|
|
730
|
-
const
|
|
731
|
-
`
|
|
1112
|
+
async function configureMode(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1113
|
+
const currentMode = prefs.mode as string | undefined;
|
|
1114
|
+
const modeChoice = await ctx.ui.select(
|
|
1115
|
+
`Workflow mode${currentMode ? ` (current: ${currentMode})` : ""}:`,
|
|
1116
|
+
[
|
|
1117
|
+
"solo — auto-push, squash, simple IDs (personal projects)",
|
|
1118
|
+
"team — unique IDs, push branches, pre-merge checks (shared repos)",
|
|
1119
|
+
"(none) — configure everything manually",
|
|
1120
|
+
"(keep current)",
|
|
1121
|
+
],
|
|
1122
|
+
);
|
|
1123
|
+
const modeStr = typeof modeChoice === "string" ? modeChoice : "";
|
|
1124
|
+
if (modeStr && modeStr !== "(keep current)") {
|
|
1125
|
+
if (modeStr.startsWith("solo")) {
|
|
1126
|
+
prefs.mode = "solo";
|
|
1127
|
+
ctx.ui.notify(
|
|
1128
|
+
"Mode: solo — defaults: auto_push=true, push_branches=false, pre_merge_check=false, merge_strategy=squash, isolation=worktree, commit_docs=true, unique_milestone_ids=false",
|
|
1129
|
+
"info",
|
|
1130
|
+
);
|
|
1131
|
+
} else if (modeStr.startsWith("team")) {
|
|
1132
|
+
prefs.mode = "team";
|
|
1133
|
+
ctx.ui.notify(
|
|
1134
|
+
"Mode: team — defaults: auto_push=false, push_branches=true, pre_merge_check=true, merge_strategy=squash, isolation=worktree, commit_docs=true, unique_milestone_ids=true",
|
|
1135
|
+
"info",
|
|
1136
|
+
);
|
|
1137
|
+
} else {
|
|
1138
|
+
delete prefs.mode;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
async function configureAdvanced(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1144
|
+
const currentUnique = prefs.unique_milestone_ids;
|
|
1145
|
+
const uniqueChoice = await ctx.ui.select(
|
|
1146
|
+
`Unique milestone IDs${currentUnique !== undefined ? ` (current: ${currentUnique})` : ""}:`,
|
|
732
1147
|
["true", "false", "(keep current)"],
|
|
733
1148
|
);
|
|
734
|
-
if (
|
|
735
|
-
prefs.
|
|
1149
|
+
if (uniqueChoice && uniqueChoice !== "(keep current)") {
|
|
1150
|
+
prefs.unique_milestone_ids = uniqueChoice === "true";
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// ─── Main wizard with category menu ─────────────────────────────────────────
|
|
1155
|
+
|
|
1156
|
+
async function handlePrefsWizard(
|
|
1157
|
+
ctx: ExtensionCommandContext,
|
|
1158
|
+
scope: "global" | "project",
|
|
1159
|
+
): Promise<void> {
|
|
1160
|
+
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
1161
|
+
const existing = scope === "project" ? loadProjectGSDPreferences() : loadGlobalGSDPreferences();
|
|
1162
|
+
const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
|
|
1163
|
+
|
|
1164
|
+
ctx.ui.notify(`GSD preferences (${scope}) — pick a category to configure.`, "info");
|
|
1165
|
+
|
|
1166
|
+
while (true) {
|
|
1167
|
+
const summaries = buildCategorySummaries(prefs);
|
|
1168
|
+
const options = [
|
|
1169
|
+
`Workflow Mode ${summaries.mode}`,
|
|
1170
|
+
`Models ${summaries.models}`,
|
|
1171
|
+
`Timeouts ${summaries.timeouts}`,
|
|
1172
|
+
`Git ${summaries.git}`,
|
|
1173
|
+
`Skills ${summaries.skills}`,
|
|
1174
|
+
`Budget ${summaries.budget}`,
|
|
1175
|
+
`Notifications ${summaries.notifications}`,
|
|
1176
|
+
`Advanced ${summaries.advanced}`,
|
|
1177
|
+
`── Save & Exit ──`,
|
|
1178
|
+
];
|
|
1179
|
+
|
|
1180
|
+
const raw = await ctx.ui.select("GSD Preferences", options);
|
|
1181
|
+
const choice = typeof raw === "string" ? raw : "";
|
|
1182
|
+
if (!choice || choice.includes("Save & Exit")) break;
|
|
1183
|
+
|
|
1184
|
+
if (choice.startsWith("Workflow Mode")) await configureMode(ctx, prefs);
|
|
1185
|
+
else if (choice.startsWith("Models")) await configureModels(ctx, prefs);
|
|
1186
|
+
else if (choice.startsWith("Timeouts")) await configureTimeouts(ctx, prefs);
|
|
1187
|
+
else if (choice.startsWith("Git")) await configureGit(ctx, prefs);
|
|
1188
|
+
else if (choice.startsWith("Skills")) await configureSkills(ctx, prefs);
|
|
1189
|
+
else if (choice.startsWith("Budget")) await configureBudget(ctx, prefs);
|
|
1190
|
+
else if (choice.startsWith("Notifications")) await configureNotifications(ctx, prefs);
|
|
1191
|
+
else if (choice.startsWith("Advanced")) await configureAdvanced(ctx, prefs);
|
|
736
1192
|
}
|
|
737
1193
|
|
|
738
1194
|
// ─── Serialize to frontmatter ───────────────────────────────────────────
|
|
@@ -823,7 +1279,7 @@ function serializePreferencesToFrontmatter(prefs: Record<string, unknown>): stri
|
|
|
823
1279
|
|
|
824
1280
|
// Ordered keys for consistent output
|
|
825
1281
|
const orderedKeys = [
|
|
826
|
-
"version", "always_use_skills", "prefer_skills", "avoid_skills",
|
|
1282
|
+
"version", "mode", "always_use_skills", "prefer_skills", "avoid_skills",
|
|
827
1283
|
"skill_rules", "custom_instructions", "models", "skill_discovery",
|
|
828
1284
|
"auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
|
829
1285
|
"budget_ceiling", "budget_enforcement", "context_pause_threshold",
|
|
@@ -1195,6 +1651,102 @@ async function handleKnowledge(args: string, ctx: ExtensionCommandContext): Prom
|
|
|
1195
1651
|
ctx.ui.notify(`Added ${type} to KNOWLEDGE.md: "${entryText}"`, "success");
|
|
1196
1652
|
}
|
|
1197
1653
|
|
|
1654
|
+
// ─── Capture Command ──────────────────────────────────────────────────────────
|
|
1655
|
+
|
|
1656
|
+
/**
|
|
1657
|
+
* Handle `/gsd capture "..."` — fire-and-forget thought capture.
|
|
1658
|
+
* Appends to `.gsd/CAPTURES.md` without interrupting auto-mode.
|
|
1659
|
+
* Works in all modes: auto running, paused, stopped, no project.
|
|
1660
|
+
*/
|
|
1661
|
+
async function handleCapture(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
1662
|
+
// Strip surrounding quotes from the argument
|
|
1663
|
+
let text = args.trim();
|
|
1664
|
+
if (!text) {
|
|
1665
|
+
ctx.ui.notify('Usage: /gsd capture "your thought here"', "warning");
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
// Remove wrapping quotes (single or double)
|
|
1669
|
+
if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) {
|
|
1670
|
+
text = text.slice(1, -1);
|
|
1671
|
+
}
|
|
1672
|
+
if (!text) {
|
|
1673
|
+
ctx.ui.notify('Usage: /gsd capture "your thought here"', "warning");
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
const basePath = process.cwd();
|
|
1678
|
+
|
|
1679
|
+
// Ensure .gsd/ exists — capture should work even without a milestone
|
|
1680
|
+
const gsdDir = join(basePath, ".gsd");
|
|
1681
|
+
if (!existsSync(gsdDir)) {
|
|
1682
|
+
mkdirSync(gsdDir, { recursive: true });
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
const id = appendCapture(basePath, text);
|
|
1686
|
+
ctx.ui.notify(`Captured: ${id} — "${text.length > 60 ? text.slice(0, 57) + "..." : text}"`, "info");
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
// ─── Triage Command ───────────────────────────────────────────────────────────
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* Handle `/gsd triage` — manually trigger triage of pending captures.
|
|
1693
|
+
* Dispatches the triage prompt to the LLM for classification.
|
|
1694
|
+
* Triage result handling (confirmation UI) is wired in T03.
|
|
1695
|
+
*/
|
|
1696
|
+
async function handleTriage(ctx: ExtensionCommandContext, pi: ExtensionAPI, basePath: string): Promise<void> {
|
|
1697
|
+
if (!hasPendingCaptures(basePath)) {
|
|
1698
|
+
ctx.ui.notify("No pending captures to triage.", "info");
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
const pending = loadPendingCaptures(basePath);
|
|
1703
|
+
ctx.ui.notify(`Triaging ${pending.length} pending capture${pending.length === 1 ? "" : "s"}...`, "info");
|
|
1704
|
+
|
|
1705
|
+
// Build context for the triage prompt
|
|
1706
|
+
const state = await deriveState(basePath);
|
|
1707
|
+
let currentPlan = "";
|
|
1708
|
+
let roadmapContext = "";
|
|
1709
|
+
|
|
1710
|
+
if (state.activeMilestone && state.activeSlice) {
|
|
1711
|
+
const { resolveSliceFile, resolveMilestoneFile } = await import("./paths.js");
|
|
1712
|
+
const planFile = resolveSliceFile(basePath, state.activeMilestone.id, state.activeSlice.id, "PLAN");
|
|
1713
|
+
if (planFile) {
|
|
1714
|
+
const { loadFile: load } = await import("./files.js");
|
|
1715
|
+
currentPlan = (await load(planFile)) ?? "";
|
|
1716
|
+
}
|
|
1717
|
+
const roadmapFile = resolveMilestoneFile(basePath, state.activeMilestone.id, "ROADMAP");
|
|
1718
|
+
if (roadmapFile) {
|
|
1719
|
+
const { loadFile: load } = await import("./files.js");
|
|
1720
|
+
roadmapContext = (await load(roadmapFile)) ?? "";
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// Format pending captures for the prompt
|
|
1725
|
+
const capturesList = pending.map(c =>
|
|
1726
|
+
`- **${c.id}**: "${c.text}" (captured: ${c.timestamp})`
|
|
1727
|
+
).join("\n");
|
|
1728
|
+
|
|
1729
|
+
// Dispatch triage prompt
|
|
1730
|
+
const { loadPrompt } = await import("./prompt-loader.js");
|
|
1731
|
+
const prompt = loadPrompt("triage-captures", {
|
|
1732
|
+
pendingCaptures: capturesList,
|
|
1733
|
+
currentPlan: currentPlan || "(no active slice plan)",
|
|
1734
|
+
roadmapContext: roadmapContext || "(no active roadmap)",
|
|
1735
|
+
});
|
|
1736
|
+
|
|
1737
|
+
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".pi", "GSD-WORKFLOW.md");
|
|
1738
|
+
const workflow = readFileSync(workflowPath, "utf-8");
|
|
1739
|
+
|
|
1740
|
+
pi.sendMessage(
|
|
1741
|
+
{
|
|
1742
|
+
customType: "gsd-triage",
|
|
1743
|
+
content: `Read the following GSD workflow protocol and execute exactly.\n\n${workflow}\n\n## Your Task\n\n${prompt}`,
|
|
1744
|
+
display: false,
|
|
1745
|
+
},
|
|
1746
|
+
{ triggerTurn: true },
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1198
1750
|
async function handleSteer(change: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
1199
1751
|
const basePath = process.cwd();
|
|
1200
1752
|
const state = await deriveState(basePath);
|
|
@@ -1237,3 +1789,69 @@ async function handleSteer(change: string, ctx: ExtensionCommandContext, pi: Ext
|
|
|
1237
1789
|
ctx.ui.notify(`Override registered: "${change}". Update plan documents to reflect this change.`, "info");
|
|
1238
1790
|
}
|
|
1239
1791
|
}
|
|
1792
|
+
|
|
1793
|
+
async function handleRunHook(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
1794
|
+
const parts = args.trim().split(/\s+/);
|
|
1795
|
+
if (parts.length < 3) {
|
|
1796
|
+
ctx.ui.notify(`Usage: /gsd run-hook <hook-name> <unit-type> <unit-id>
|
|
1797
|
+
|
|
1798
|
+
Unit types:
|
|
1799
|
+
execute-task - Task execution (unit-id: M001/S01/T01)
|
|
1800
|
+
plan-slice - Slice planning (unit-id: M001/S01)
|
|
1801
|
+
research-milestone - Milestone research (unit-id: M001)
|
|
1802
|
+
complete-slice - Slice completion (unit-id: M001/S01)
|
|
1803
|
+
complete-milestone - Milestone completion (unit-id: M001)
|
|
1804
|
+
|
|
1805
|
+
Examples:
|
|
1806
|
+
/gsd run-hook code-review execute-task M001/S01/T01
|
|
1807
|
+
/gsd run-hook lint-check plan-slice M001/S01`, "warning");
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
const [hookName, unitType, unitId] = parts;
|
|
1812
|
+
const basePath = projectRoot();
|
|
1813
|
+
|
|
1814
|
+
// Import the hook trigger function
|
|
1815
|
+
const { triggerHookManually, formatHookStatus, getHookStatus } = await import("./post-unit-hooks.js");
|
|
1816
|
+
const { dispatchHookUnit } = await import("./auto.js");
|
|
1817
|
+
|
|
1818
|
+
// Check if the hook exists
|
|
1819
|
+
const hooks = getHookStatus();
|
|
1820
|
+
const hookExists = hooks.some(h => h.name === hookName);
|
|
1821
|
+
if (!hookExists) {
|
|
1822
|
+
ctx.ui.notify(`Hook "${hookName}" not found. Configured hooks:\n${formatHookStatus()}`, "error");
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// Validate unit ID format
|
|
1827
|
+
const unitIdPattern = /^M\d{3}\/S\d{2,3}\/T\d{2,3}$/;
|
|
1828
|
+
if (!unitIdPattern.test(unitId)) {
|
|
1829
|
+
ctx.ui.notify(`Invalid unit ID format: "${unitId}". Expected format: M004/S04/T03`, "warning");
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
// Trigger the hook manually
|
|
1834
|
+
const hookUnit = triggerHookManually(hookName, unitType, unitId, basePath);
|
|
1835
|
+
if (!hookUnit) {
|
|
1836
|
+
ctx.ui.notify(`Failed to trigger hook "${hookName}". The hook may be disabled or not configured for unit type "${unitType}".`, "error");
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
ctx.ui.notify(`Manually triggering hook: ${hookName} for ${unitType} ${unitId}`, "info");
|
|
1841
|
+
|
|
1842
|
+
// Dispatch the hook unit directly, bypassing normal pre-dispatch hooks
|
|
1843
|
+
const success = await dispatchHookUnit(
|
|
1844
|
+
ctx,
|
|
1845
|
+
pi,
|
|
1846
|
+
hookName,
|
|
1847
|
+
unitType,
|
|
1848
|
+
unitId,
|
|
1849
|
+
hookUnit.prompt,
|
|
1850
|
+
hookUnit.model,
|
|
1851
|
+
basePath,
|
|
1852
|
+
);
|
|
1853
|
+
|
|
1854
|
+
if (!success) {
|
|
1855
|
+
ctx.ui.notify("Failed to dispatch hook. Auto-mode may have been cancelled.", "error");
|
|
1856
|
+
}
|
|
1857
|
+
}
|