gsd-pi 2.27.0 → 2.28.0-dev.346ee62
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 +39 -12
- package/dist/cli.js +20 -21
- package/dist/extension-discovery.d.ts +16 -0
- package/dist/extension-discovery.js +66 -0
- package/dist/headless-answers.d.ts +51 -0
- package/dist/headless-answers.js +224 -0
- package/dist/headless-context.d.ts +18 -0
- package/dist/headless-context.js +44 -0
- package/dist/headless-events.d.ts +28 -0
- package/dist/headless-events.js +59 -0
- package/dist/headless-query.d.ts +40 -0
- package/dist/headless-query.js +77 -0
- package/dist/headless-ui.d.ts +23 -0
- package/dist/headless-ui.js +103 -0
- package/dist/headless.d.ts +2 -0
- package/dist/headless.js +67 -186
- package/dist/help-text.js +6 -0
- package/dist/loader.js +18 -59
- package/dist/onboarding.js +8 -7
- package/dist/remote-questions-config.js +8 -3
- package/dist/resource-loader.d.ts +1 -6
- package/dist/resource-loader.js +52 -95
- package/dist/resources/extensions/ask-user-questions.ts +3 -2
- package/dist/resources/extensions/bg-shell/bg-shell-command.ts +219 -0
- package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.ts +400 -0
- package/dist/resources/extensions/bg-shell/bg-shell-tool.ts +985 -0
- package/dist/resources/extensions/bg-shell/index.ts +17 -1561
- package/dist/resources/extensions/bg-shell/overlay.ts +4 -0
- package/dist/resources/extensions/bg-shell/utilities.ts +4 -16
- package/dist/resources/extensions/browser-tools/capture.ts +34 -2
- package/dist/resources/extensions/browser-tools/lifecycle.ts +5 -5
- package/dist/resources/extensions/browser-tools/settle.ts +1 -1
- package/dist/resources/extensions/browser-tools/state.ts +5 -5
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +1 -1
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +3 -3
- package/dist/resources/extensions/browser-tools/tools/assertions.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/device.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/extract.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/navigation.ts +6 -6
- package/dist/resources/extensions/browser-tools/tools/network-mock.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/pages.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.ts +28 -10
- package/dist/resources/extensions/browser-tools/tools/state-persistence.ts +1 -1
- package/dist/resources/extensions/browser-tools/tools/visual-diff.ts +1 -1
- package/dist/resources/extensions/browser-tools/utils.ts +5 -5
- package/dist/resources/extensions/get-secrets-from-user.ts +1 -1
- package/dist/resources/extensions/google-search/index.ts +21 -8
- package/dist/resources/extensions/gsd/activity-log.ts +2 -1
- package/dist/resources/extensions/gsd/atomic-write.ts +35 -0
- package/dist/resources/extensions/gsd/auto/session.ts +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +84 -3
- package/dist/resources/extensions/gsd/auto-idempotency.ts +150 -0
- package/dist/resources/extensions/gsd/auto-post-unit.ts +591 -0
- package/dist/resources/extensions/gsd/auto-prompts.ts +116 -22
- package/dist/resources/extensions/gsd/auto-recovery.ts +20 -9
- package/dist/resources/extensions/gsd/auto-start.ts +500 -0
- package/dist/resources/extensions/gsd/auto-stuck-detection.ts +220 -0
- package/dist/resources/extensions/gsd/auto-timers.ts +223 -0
- package/dist/resources/extensions/gsd/auto-unit-closeout.ts +3 -1
- package/dist/resources/extensions/gsd/auto-verification.ts +195 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +8 -31
- package/dist/resources/extensions/gsd/auto-worktree.ts +83 -67
- package/dist/resources/extensions/gsd/auto.ts +364 -1873
- package/dist/resources/extensions/gsd/commands-config.ts +102 -0
- package/dist/resources/extensions/gsd/commands-handlers.ts +402 -0
- package/dist/resources/extensions/gsd/commands-inspect.ts +90 -0
- package/dist/resources/extensions/gsd/commands-logs.ts +537 -0
- package/dist/resources/extensions/gsd/commands-maintenance.ts +206 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +747 -0
- package/dist/resources/extensions/gsd/commands.ts +378 -1431
- package/dist/resources/extensions/gsd/constants.ts +21 -0
- package/dist/resources/extensions/gsd/context-budget.ts +25 -2
- package/dist/resources/extensions/gsd/crash-recovery.ts +4 -2
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +13 -4
- package/dist/resources/extensions/gsd/db-writer.ts +21 -2
- package/dist/resources/extensions/gsd/detection.ts +469 -0
- package/dist/resources/extensions/gsd/diff-context.ts +2 -1
- package/dist/resources/extensions/gsd/dispatch-guard.ts +4 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +83 -0
- package/dist/resources/extensions/gsd/doctor-checks.ts +564 -0
- package/dist/resources/extensions/gsd/doctor-format.ts +78 -0
- package/dist/resources/extensions/gsd/doctor-types.ts +72 -0
- package/dist/resources/extensions/gsd/doctor.ts +64 -701
- package/dist/resources/extensions/gsd/errors.ts +0 -2
- package/dist/resources/extensions/gsd/export-html.ts +367 -11
- package/dist/resources/extensions/gsd/export.ts +119 -30
- package/dist/resources/extensions/gsd/files.ts +8 -126
- package/dist/resources/extensions/gsd/forensics.ts +2 -12
- package/dist/resources/extensions/gsd/git-constants.ts +11 -0
- package/dist/resources/extensions/gsd/git-service.ts +13 -9
- package/dist/resources/extensions/gsd/gsd-db.ts +26 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.ts +451 -0
- package/dist/resources/extensions/gsd/guided-flow.ts +231 -514
- package/dist/resources/extensions/gsd/history.ts +2 -20
- package/dist/resources/extensions/gsd/index.ts +206 -45
- package/dist/resources/extensions/gsd/init-wizard.ts +615 -0
- package/dist/resources/extensions/gsd/jsonl-utils.ts +21 -0
- package/dist/resources/extensions/gsd/key-manager.ts +995 -0
- package/dist/resources/extensions/gsd/metrics.ts +32 -5
- package/dist/resources/extensions/gsd/migrate/command.ts +1 -1
- package/dist/resources/extensions/gsd/migrate/parsers.ts +10 -95
- package/dist/resources/extensions/gsd/milestone-actions.ts +126 -0
- package/dist/resources/extensions/gsd/milestone-ids.ts +95 -0
- package/dist/resources/extensions/gsd/native-git-bridge.ts +5 -10
- package/dist/resources/extensions/gsd/parallel-eligibility.ts +3 -3
- package/dist/resources/extensions/gsd/paths.ts +1 -3
- package/dist/resources/extensions/gsd/plugin-importer.ts +3 -2
- package/dist/resources/extensions/gsd/preferences-hooks.ts +10 -0
- package/dist/resources/extensions/gsd/preferences-models.ts +323 -0
- package/dist/resources/extensions/gsd/preferences-skills.ts +169 -0
- package/dist/resources/extensions/gsd/preferences-types.ts +223 -0
- package/dist/resources/extensions/gsd/preferences-validation.ts +597 -0
- package/dist/resources/extensions/gsd/preferences.ts +219 -1305
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.ts +213 -0
- package/dist/resources/extensions/gsd/prompt-compressor.ts +508 -0
- package/dist/resources/extensions/gsd/prompt-loader.ts +4 -2
- package/dist/resources/extensions/gsd/prompt-ordering.ts +200 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -4
- package/dist/resources/extensions/gsd/prompts/discuss.md +13 -5
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -2
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +0 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -2
- package/dist/resources/extensions/gsd/prompts/queue.md +30 -0
- package/dist/resources/extensions/gsd/prompts/quick-task.md +0 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +0 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +0 -1
- package/dist/resources/extensions/gsd/prompts/system.md +5 -2
- package/dist/resources/extensions/gsd/provider-error-pause.ts +59 -10
- package/dist/resources/extensions/gsd/queue-order.ts +1 -1
- package/dist/resources/extensions/gsd/queue-reorder-ui.ts +15 -2
- package/dist/resources/extensions/gsd/quick.ts +18 -15
- package/dist/resources/extensions/gsd/reports.ts +1 -7
- package/dist/resources/extensions/gsd/safe-fs.ts +47 -0
- package/dist/resources/extensions/gsd/semantic-chunker.ts +336 -0
- package/dist/resources/extensions/gsd/session-forensics.ts +8 -23
- package/dist/resources/extensions/gsd/session-lock.ts +284 -0
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +80 -16
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +35 -6
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +7 -2
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +4 -13
- package/dist/resources/extensions/gsd/state.ts +54 -2
- package/dist/resources/extensions/gsd/structured-data-formatter.ts +144 -0
- package/dist/resources/extensions/gsd/summary-distiller.ts +258 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +34 -0
- package/dist/resources/extensions/gsd/tests/activity-log.test.ts +213 -0
- package/dist/resources/extensions/gsd/tests/agent-end-retry.test.ts +107 -0
- package/dist/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +197 -0
- package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +33 -39
- package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +108 -2
- package/dist/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +257 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +3 -0
- package/dist/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/dist/resources/extensions/gsd/tests/context-budget.test.ts +69 -0
- package/dist/resources/extensions/gsd/tests/detection.test.ts +398 -0
- package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +12 -24
- package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +118 -94
- package/dist/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +126 -0
- package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +7 -3
- package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +75 -0
- package/dist/resources/extensions/gsd/tests/doctor-git.test.ts +17 -55
- package/dist/resources/extensions/gsd/tests/export-html-all.test.ts +105 -0
- package/dist/resources/extensions/gsd/tests/export-html-enhancements.test.ts +375 -0
- package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +122 -0
- package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +3 -0
- package/dist/resources/extensions/gsd/tests/headless-answers.test.ts +340 -0
- package/dist/resources/extensions/gsd/tests/headless-query.test.ts +162 -0
- package/dist/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +24 -82
- package/dist/resources/extensions/gsd/tests/init-wizard.test.ts +197 -0
- package/dist/resources/extensions/gsd/tests/key-manager.test.ts +414 -0
- package/dist/resources/extensions/gsd/tests/metrics.test.ts +173 -305
- package/dist/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +3 -0
- package/dist/resources/extensions/gsd/tests/model-isolation.test.ts +59 -1
- package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +18 -61
- package/dist/resources/extensions/gsd/tests/none-mode-gates.test.ts +17 -8
- package/dist/resources/extensions/gsd/tests/parallel-merge.test.ts +3 -0
- package/dist/resources/extensions/gsd/tests/park-edge-cases.test.ts +276 -0
- package/dist/resources/extensions/gsd/tests/park-milestone.test.ts +401 -0
- package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +23 -47
- package/dist/resources/extensions/gsd/tests/preferences.test.ts +284 -0
- package/dist/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +314 -0
- package/dist/resources/extensions/gsd/tests/prompt-compressor.test.ts +529 -0
- package/dist/resources/extensions/gsd/tests/prompt-ordering.test.ts +296 -0
- package/dist/resources/extensions/gsd/tests/provider-errors.test.ts +338 -0
- package/dist/resources/extensions/gsd/tests/reassess-detection.test.ts +154 -0
- package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/remote-status.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +43 -60
- package/dist/resources/extensions/gsd/tests/semantic-chunker.test.ts +426 -0
- package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/dist/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +8 -5
- package/dist/resources/extensions/gsd/tests/structured-data-formatter.test.ts +365 -0
- package/dist/resources/extensions/gsd/tests/summary-distiller.test.ts +323 -0
- package/dist/resources/extensions/gsd/tests/token-counter.test.ts +129 -0
- package/dist/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +1272 -0
- package/dist/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +164 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/dist/resources/extensions/gsd/tests/triage-dispatch.test.ts +69 -73
- package/dist/resources/extensions/gsd/tests/update-command.test.ts +67 -0
- package/dist/resources/extensions/gsd/tests/validate-directory.test.ts +222 -0
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +115 -1
- package/dist/resources/extensions/gsd/tests/visualizer-overlay.test.ts +2 -2
- package/dist/resources/extensions/gsd/tests/visualizer-views.test.ts +2 -1
- package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +24 -61
- package/dist/resources/extensions/gsd/tests/worktree-e2e.test.ts +5 -2
- package/dist/resources/extensions/gsd/tests/write-gate.test.ts +132 -43
- package/dist/resources/extensions/gsd/token-counter.ts +20 -0
- package/dist/resources/extensions/gsd/triage-ui.ts +1 -1
- package/dist/resources/extensions/gsd/types.ts +4 -1
- package/dist/resources/extensions/gsd/validate-directory.ts +164 -0
- package/dist/resources/extensions/gsd/verification-evidence.ts +7 -4
- package/dist/resources/extensions/gsd/verification-gate.ts +70 -5
- package/dist/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/dist/resources/extensions/gsd/visualizer-overlay.ts +5 -2
- package/dist/resources/extensions/gsd/visualizer-views.ts +2 -3
- package/dist/resources/extensions/gsd/worktree-command.ts +4 -51
- package/dist/resources/extensions/gsd/worktree-manager.ts +7 -9
- package/dist/resources/extensions/gsd/worktree.ts +41 -1
- package/dist/resources/extensions/mcporter/index.ts +27 -14
- package/dist/resources/extensions/remote-questions/manager.ts +6 -24
- package/dist/resources/extensions/remote-questions/mod.ts +16 -0
- package/dist/resources/extensions/remote-questions/notify.ts +91 -0
- package/dist/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/dist/resources/extensions/remote-questions/store.ts +5 -1
- package/dist/resources/extensions/remote-questions/types.ts +26 -3
- package/dist/resources/extensions/search-the-web/native-search.ts +7 -0
- package/dist/resources/extensions/search-the-web/provider.ts +15 -3
- package/dist/resources/extensions/search-the-web/tool-llm-context.ts +1 -13
- package/dist/resources/extensions/search-the-web/tool-search.ts +1 -13
- package/dist/resources/extensions/shared/format-utils.ts +53 -0
- package/dist/resources/extensions/shared/frontmatter.ts +117 -0
- package/dist/resources/extensions/shared/mod.ts +30 -0
- package/dist/resources/extensions/shared/sanitize.ts +19 -0
- package/dist/resources/extensions/slash-commands/create-extension.ts +1 -1
- package/dist/resources/extensions/slash-commands/create-slash-command.ts +1 -1
- package/dist/resources/extensions/subagent/index.ts +1 -2
- package/dist/resources/extensions/ttsr/index.ts +5 -0
- package/dist/resources/extensions/ttsr/rule-loader.ts +4 -51
- package/dist/resources/extensions/universal-config/discovery.ts +37 -15
- package/dist/resources/extensions/voice/index.ts +1 -1
- package/dist/resources/skills/accessibility/SKILL.md +522 -0
- package/dist/resources/skills/accessibility/references/WCAG.md +162 -0
- package/dist/resources/skills/agent-browser/SKILL.md +517 -0
- package/dist/resources/skills/agent-browser/references/authentication.md +202 -0
- package/dist/resources/skills/agent-browser/references/commands.md +263 -0
- package/dist/resources/skills/agent-browser/references/profiling.md +120 -0
- package/dist/resources/skills/agent-browser/references/proxy-support.md +194 -0
- package/dist/resources/skills/agent-browser/references/session-management.md +193 -0
- package/dist/resources/skills/agent-browser/references/snapshot-refs.md +194 -0
- package/dist/resources/skills/agent-browser/references/video-recording.md +173 -0
- package/dist/resources/skills/agent-browser/templates/authenticated-session.sh +105 -0
- package/dist/resources/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/dist/resources/skills/agent-browser/templates/form-automation.sh +62 -0
- package/dist/resources/skills/best-practices/SKILL.md +583 -0
- package/dist/resources/skills/code-optimizer/SKILL.md +160 -0
- package/dist/resources/skills/code-optimizer/references/algorithmic-complexity.md +66 -0
- package/dist/resources/skills/code-optimizer/references/build-compilation.md +90 -0
- package/dist/resources/skills/code-optimizer/references/bundle-dependencies.md +82 -0
- package/dist/resources/skills/code-optimizer/references/caching-memoization.md +76 -0
- package/dist/resources/skills/code-optimizer/references/concurrency-async.md +80 -0
- package/dist/resources/skills/code-optimizer/references/config-infra.md +71 -0
- package/dist/resources/skills/code-optimizer/references/data-structures.md +80 -0
- package/dist/resources/skills/code-optimizer/references/database-queries.md +76 -0
- package/dist/resources/skills/code-optimizer/references/dead-code-redundancy.md +84 -0
- package/dist/resources/skills/code-optimizer/references/error-resilience.md +80 -0
- package/dist/resources/skills/code-optimizer/references/io-network.md +89 -0
- package/dist/resources/skills/code-optimizer/references/logging-observability.md +64 -0
- package/dist/resources/skills/code-optimizer/references/memory-resources.md +66 -0
- package/dist/resources/skills/code-optimizer/references/rendering-ui.md +90 -0
- package/dist/resources/skills/code-optimizer/references/security-performance.md +68 -0
- package/dist/resources/skills/core-web-vitals/SKILL.md +441 -0
- package/dist/resources/skills/core-web-vitals/references/LCP.md +208 -0
- package/dist/resources/skills/make-interfaces-feel-better/SKILL.md +122 -0
- package/dist/resources/skills/make-interfaces-feel-better/animations.md +379 -0
- package/dist/resources/skills/make-interfaces-feel-better/performance.md +88 -0
- package/dist/resources/skills/make-interfaces-feel-better/surfaces.md +247 -0
- package/dist/resources/skills/make-interfaces-feel-better/typography.md +123 -0
- package/dist/resources/skills/react-best-practices/README.md +123 -0
- package/dist/resources/skills/react-best-practices/SKILL.md +136 -0
- package/dist/resources/skills/react-best-practices/metadata.json +15 -0
- package/dist/resources/skills/react-best-practices/rules/_sections.md +46 -0
- package/dist/resources/skills/react-best-practices/rules/_template.md +28 -0
- package/dist/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/resources/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/dist/resources/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/dist/resources/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/resources/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/dist/resources/skills/react-best-practices/rules/async-dependencies.md +51 -0
- package/dist/resources/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/dist/resources/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/resources/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/dist/resources/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/resources/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/resources/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/resources/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/resources/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/resources/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/resources/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/resources/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/dist/resources/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/resources/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/resources/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/resources/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/resources/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/resources/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/resources/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/resources/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/resources/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/resources/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/resources/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/dist/resources/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/resources/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/dist/resources/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/resources/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/resources/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/dist/resources/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/resources/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/dist/resources/skills/userinterface-wiki/SKILL.md +253 -0
- package/dist/resources/skills/userinterface-wiki/rules/_sections.md +66 -0
- package/dist/resources/skills/userinterface-wiki/rules/_template.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md +30 -0
- package/dist/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md +30 -0
- package/dist/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md +36 -0
- package/dist/resources/skills/userinterface-wiki/rules/a11y-volume-control.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md +19 -0
- package/dist/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md +18 -0
- package/dist/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-callback-ref.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md +13 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-transition-delay.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md +35 -0
- package/dist/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md +48 -0
- package/dist/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/context-resume-suspended.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/context-reuse-single.md +30 -0
- package/dist/resources/skills/userinterface-wiki/rules/design-filter-for-character.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md +26 -0
- package/dist/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/duration-max-300ms.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/duration-press-hover.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/duration-small-state.md +15 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-for-state-change.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-natural-decay.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md +15 -0
- package/dist/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/exit-key-required.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/exit-matches-initial.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/exit-prop-required.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/impl-default-subtle.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/impl-preload-audio.md +34 -0
- package/dist/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md +26 -0
- package/dist/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-group-variants.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-three-lines.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/native-selection-styling.md +18 -0
- package/dist/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/nested-propagate-required.md +41 -0
- package/dist/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/none-high-frequency.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/param-click-duration.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/param-q-value-range.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/physics-active-state.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md +19 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md +34 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md +13 -0
- package/dist/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md +37 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-content-required.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md +37 -0
- package/dist/resources/skills/userinterface-wiki/rules/spring-for-gestures.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/spring-params-balanced.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/staging-dim-background.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/timing-consistent.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/timing-under-300ms.md +22 -0
- package/dist/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/transition-name-required.md +27 -0
- package/dist/resources/skills/userinterface-wiki/rules/transition-name-unique.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/transition-over-js-library.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md +18 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md +15 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-font-display-swap.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md +24 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md +18 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md +15 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-proper-fractions.md +15 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-slashed-zero.md +17 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md +21 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md +16 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-underline-offset.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md +49 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md +50 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md +30 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md +32 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md +45 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md +37 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md +36 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md +35 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md +45 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md +33 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md +41 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md +38 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-serial-position.md +31 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md +35 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md +28 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md +43 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md +36 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md +49 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md +49 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md +40 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md +35 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md +30 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md +25 -0
- package/dist/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md +23 -0
- package/dist/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md +29 -0
- package/dist/resources/skills/userinterface-wiki/rules/weight-match-action.md +32 -0
- package/dist/resources/skills/web-design-guidelines/SKILL.md +39 -0
- package/dist/resources/skills/web-quality-audit/SKILL.md +170 -0
- package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +91 -0
- package/dist/update-check.js +1 -1
- package/package.json +20 -8
- package/packages/native/package.json +28 -0
- package/packages/pi-agent-core/package.json +6 -0
- package/packages/pi-ai/dist/models.generated.d.ts +43 -11
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +34 -26
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +3 -2
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +14 -4
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -0
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +5 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +4 -0
- package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +6 -0
- package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/index.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/openai-codex.js +2 -0
- package/packages/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
- package/packages/pi-ai/oauth.d.ts +1 -0
- package/packages/pi-ai/oauth.js +1 -0
- package/packages/pi-ai/package.json +2 -2
- package/packages/pi-ai/src/models.generated.ts +42 -34
- package/packages/pi-ai/src/providers/anthropic.ts +3 -2
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +15 -4
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -0
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +5 -1
- package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +4 -0
- package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +6 -0
- package/packages/pi-ai/src/utils/oauth/index.ts +2 -2
- package/packages/pi-ai/src/utils/oauth/openai-codex.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +2 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js +23 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.js +50 -1
- package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js +2 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +3 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/constants.d.ts +29 -0
- package/packages/pi-coding-agent/dist/core/constants.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/constants.js +44 -0
- package/packages/pi-coding-agent/dist/core/constants.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +32 -10
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +77 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.js +12 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -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 +22 -2
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/index.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +13 -5
- package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +14 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js +12 -4
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +49 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +108 -14
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +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 +14 -5
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js +2 -1
- package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline-edit.js +4 -4
- package/packages/pi-coding-agent/dist/core/tools/hashline-edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline.js +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/hashline.test.js +8 -8
- package/packages/pi-coding-agent/dist/core/tools/hashline.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/path-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.js +1 -1
- package/packages/pi-coding-agent/dist/core/tools/path-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/truncate.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/truncate.js +2 -1
- package/packages/pi-coding-agent/dist/core/tools/truncate.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +2 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +3 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +6 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.d.ts +9 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js +47 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +4 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +30 -2
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +11 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +12 -2
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/pipeline.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/pipeline.js +25 -3
- package/packages/pi-coding-agent/dist/resources/extensions/memory/pipeline.js.map +1 -1
- package/packages/pi-coding-agent/package.json +0 -4
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.ts +2 -1
- package/packages/pi-coding-agent/src/core/bash-executor.ts +23 -1
- package/packages/pi-coding-agent/src/core/blob-store.ts +46 -1
- package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -2
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +2 -2
- package/packages/pi-coding-agent/src/core/constants.ts +59 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +1 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +84 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +31 -10
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +66 -0
- package/packages/pi-coding-agent/src/core/fs-utils.ts +12 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +22 -2
- package/packages/pi-coding-agent/src/core/lsp/index.ts +31 -5
- package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +13 -5
- package/packages/pi-coding-agent/src/core/model-resolver.ts +14 -0
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +58 -0
- package/packages/pi-coding-agent/src/core/resolve-config-value.ts +14 -4
- package/packages/pi-coding-agent/src/core/session-manager.ts +113 -18
- package/packages/pi-coding-agent/src/core/settings-manager.ts +22 -5
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/find.ts +2 -1
- package/packages/pi-coding-agent/src/core/tools/hashline-edit.ts +4 -4
- package/packages/pi-coding-agent/src/core/tools/hashline.test.ts +8 -8
- package/packages/pi-coding-agent/src/core/tools/hashline.ts +1 -1
- package/packages/pi-coding-agent/src/core/tools/index.ts +1 -1
- package/packages/pi-coding-agent/src/core/tools/path-utils.ts +1 -1
- package/packages/pi-coding-agent/src/core/tools/truncate.ts +3 -1
- package/packages/pi-coding-agent/src/index.ts +9 -0
- package/packages/pi-coding-agent/src/main.ts +7 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-selector.ts +49 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/index.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +32 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +12 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +11 -2
- package/packages/pi-coding-agent/src/resources/extensions/memory/pipeline.ts +23 -3
- package/packages/pi-tui/dist/__tests__/autocomplete.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +149 -0
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/fuzzy.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/fuzzy.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/fuzzy.test.js +94 -0
- package/packages/pi-tui/dist/__tests__/fuzzy.test.js.map +1 -0
- package/packages/pi-tui/dist/autocomplete.d.ts +5 -1
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +6 -2
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/package.json +8 -2
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +186 -0
- package/packages/pi-tui/src/__tests__/fuzzy.test.ts +112 -0
- package/packages/pi-tui/src/autocomplete.ts +8 -1
- package/src/resources/extensions/ask-user-questions.ts +3 -2
- package/src/resources/extensions/bg-shell/bg-shell-command.ts +219 -0
- package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +400 -0
- package/src/resources/extensions/bg-shell/bg-shell-tool.ts +985 -0
- package/src/resources/extensions/bg-shell/index.ts +17 -1561
- package/src/resources/extensions/bg-shell/overlay.ts +4 -0
- package/src/resources/extensions/bg-shell/utilities.ts +4 -16
- package/src/resources/extensions/browser-tools/capture.ts +34 -2
- package/src/resources/extensions/browser-tools/lifecycle.ts +5 -5
- package/src/resources/extensions/browser-tools/settle.ts +1 -1
- package/src/resources/extensions/browser-tools/state.ts +5 -5
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +1 -1
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +3 -3
- package/src/resources/extensions/browser-tools/tools/assertions.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/device.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/extract.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/navigation.ts +6 -6
- package/src/resources/extensions/browser-tools/tools/network-mock.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/pages.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +28 -10
- package/src/resources/extensions/browser-tools/tools/state-persistence.ts +1 -1
- package/src/resources/extensions/browser-tools/tools/visual-diff.ts +1 -1
- package/src/resources/extensions/browser-tools/utils.ts +5 -5
- package/src/resources/extensions/get-secrets-from-user.ts +1 -1
- package/src/resources/extensions/google-search/index.ts +21 -8
- package/src/resources/extensions/gsd/activity-log.ts +2 -1
- package/src/resources/extensions/gsd/atomic-write.ts +35 -0
- package/src/resources/extensions/gsd/auto/session.ts +12 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +84 -3
- package/src/resources/extensions/gsd/auto-idempotency.ts +150 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +591 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +116 -22
- package/src/resources/extensions/gsd/auto-recovery.ts +20 -9
- package/src/resources/extensions/gsd/auto-start.ts +500 -0
- package/src/resources/extensions/gsd/auto-stuck-detection.ts +220 -0
- package/src/resources/extensions/gsd/auto-timers.ts +223 -0
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +3 -1
- package/src/resources/extensions/gsd/auto-verification.ts +195 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +8 -31
- package/src/resources/extensions/gsd/auto-worktree.ts +83 -67
- package/src/resources/extensions/gsd/auto.ts +364 -1873
- package/src/resources/extensions/gsd/commands-config.ts +102 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +402 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +90 -0
- package/src/resources/extensions/gsd/commands-logs.ts +537 -0
- package/src/resources/extensions/gsd/commands-maintenance.ts +206 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +747 -0
- package/src/resources/extensions/gsd/commands.ts +378 -1431
- package/src/resources/extensions/gsd/constants.ts +21 -0
- package/src/resources/extensions/gsd/context-budget.ts +25 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +4 -2
- package/src/resources/extensions/gsd/dashboard-overlay.ts +13 -4
- package/src/resources/extensions/gsd/db-writer.ts +21 -2
- package/src/resources/extensions/gsd/detection.ts +469 -0
- package/src/resources/extensions/gsd/diff-context.ts +2 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +4 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +83 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +564 -0
- package/src/resources/extensions/gsd/doctor-format.ts +78 -0
- package/src/resources/extensions/gsd/doctor-types.ts +72 -0
- package/src/resources/extensions/gsd/doctor.ts +64 -701
- package/src/resources/extensions/gsd/errors.ts +0 -2
- package/src/resources/extensions/gsd/export-html.ts +367 -11
- package/src/resources/extensions/gsd/export.ts +119 -30
- package/src/resources/extensions/gsd/files.ts +8 -126
- package/src/resources/extensions/gsd/forensics.ts +2 -12
- package/src/resources/extensions/gsd/git-constants.ts +11 -0
- package/src/resources/extensions/gsd/git-service.ts +13 -9
- package/src/resources/extensions/gsd/gsd-db.ts +26 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +451 -0
- package/src/resources/extensions/gsd/guided-flow.ts +231 -514
- package/src/resources/extensions/gsd/history.ts +2 -20
- package/src/resources/extensions/gsd/index.ts +206 -45
- package/src/resources/extensions/gsd/init-wizard.ts +615 -0
- package/src/resources/extensions/gsd/jsonl-utils.ts +21 -0
- package/src/resources/extensions/gsd/key-manager.ts +995 -0
- package/src/resources/extensions/gsd/metrics.ts +32 -5
- package/src/resources/extensions/gsd/migrate/command.ts +1 -1
- package/src/resources/extensions/gsd/migrate/parsers.ts +10 -95
- package/src/resources/extensions/gsd/milestone-actions.ts +126 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +95 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -10
- package/src/resources/extensions/gsd/parallel-eligibility.ts +3 -3
- package/src/resources/extensions/gsd/paths.ts +1 -3
- package/src/resources/extensions/gsd/plugin-importer.ts +3 -2
- package/src/resources/extensions/gsd/preferences-hooks.ts +10 -0
- package/src/resources/extensions/gsd/preferences-models.ts +323 -0
- package/src/resources/extensions/gsd/preferences-skills.ts +169 -0
- package/src/resources/extensions/gsd/preferences-types.ts +223 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +597 -0
- package/src/resources/extensions/gsd/preferences.ts +219 -1305
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +213 -0
- package/src/resources/extensions/gsd/prompt-compressor.ts +508 -0
- package/src/resources/extensions/gsd/prompt-loader.ts +4 -2
- package/src/resources/extensions/gsd/prompt-ordering.ts +200 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -4
- package/src/resources/extensions/gsd/prompts/discuss.md +13 -5
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -2
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +0 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -2
- package/src/resources/extensions/gsd/prompts/queue.md +30 -0
- package/src/resources/extensions/gsd/prompts/quick-task.md +0 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +0 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +0 -1
- package/src/resources/extensions/gsd/prompts/system.md +5 -2
- package/src/resources/extensions/gsd/provider-error-pause.ts +59 -10
- package/src/resources/extensions/gsd/queue-order.ts +1 -1
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +15 -2
- package/src/resources/extensions/gsd/quick.ts +18 -15
- package/src/resources/extensions/gsd/reports.ts +1 -7
- package/src/resources/extensions/gsd/safe-fs.ts +47 -0
- package/src/resources/extensions/gsd/semantic-chunker.ts +336 -0
- package/src/resources/extensions/gsd/session-forensics.ts +8 -23
- package/src/resources/extensions/gsd/session-lock.ts +284 -0
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +80 -16
- package/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md +35 -6
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +7 -2
- package/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md +4 -13
- package/src/resources/extensions/gsd/state.ts +54 -2
- package/src/resources/extensions/gsd/structured-data-formatter.ts +144 -0
- package/src/resources/extensions/gsd/summary-distiller.ts +258 -0
- package/src/resources/extensions/gsd/templates/preferences.md +34 -0
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +213 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +33 -39
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +108 -2
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +257 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +398 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +12 -24
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +118 -94
- package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +126 -0
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +7 -3
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +17 -55
- package/src/resources/extensions/gsd/tests/export-html-all.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +375 -0
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +340 -0
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +24 -82
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +414 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +173 -305
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +59 -1
- package/src/resources/extensions/gsd/tests/next-milestone-id.test.ts +18 -61
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +17 -8
- package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +276 -0
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +401 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +23 -47
- package/src/resources/extensions/gsd/tests/preferences.test.ts +284 -0
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +314 -0
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +529 -0
- package/src/resources/extensions/gsd/tests/prompt-ordering.test.ts +296 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +338 -0
- package/src/resources/extensions/gsd/tests/reassess-detection.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/remote-status.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +43 -60
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +426 -0
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +8 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +365 -0
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +1272 -0
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +164 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +69 -73
- package/src/resources/extensions/gsd/tests/update-command.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/validate-directory.test.ts +222 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/workspace-index.test.ts +24 -61
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +132 -43
- package/src/resources/extensions/gsd/token-counter.ts +20 -0
- package/src/resources/extensions/gsd/triage-ui.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +4 -1
- package/src/resources/extensions/gsd/validate-directory.ts +164 -0
- package/src/resources/extensions/gsd/verification-evidence.ts +7 -4
- package/src/resources/extensions/gsd/verification-gate.ts +70 -5
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/gsd/visualizer-overlay.ts +5 -2
- package/src/resources/extensions/gsd/visualizer-views.ts +2 -3
- package/src/resources/extensions/gsd/worktree-command.ts +4 -51
- package/src/resources/extensions/gsd/worktree-manager.ts +7 -9
- package/src/resources/extensions/gsd/worktree.ts +41 -1
- package/src/resources/extensions/mcporter/index.ts +27 -14
- package/src/resources/extensions/remote-questions/manager.ts +6 -24
- package/src/resources/extensions/remote-questions/mod.ts +16 -0
- package/src/resources/extensions/remote-questions/notify.ts +91 -0
- package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/remote-questions/types.ts +26 -3
- package/src/resources/extensions/search-the-web/native-search.ts +7 -0
- package/src/resources/extensions/search-the-web/provider.ts +15 -3
- package/src/resources/extensions/search-the-web/tool-llm-context.ts +1 -13
- package/src/resources/extensions/search-the-web/tool-search.ts +1 -13
- package/src/resources/extensions/shared/format-utils.ts +53 -0
- package/src/resources/extensions/shared/frontmatter.ts +117 -0
- package/src/resources/extensions/shared/mod.ts +30 -0
- package/src/resources/extensions/shared/sanitize.ts +19 -0
- package/src/resources/extensions/slash-commands/create-extension.ts +1 -1
- package/src/resources/extensions/slash-commands/create-slash-command.ts +1 -1
- package/src/resources/extensions/subagent/index.ts +1 -2
- package/src/resources/extensions/ttsr/index.ts +5 -0
- package/src/resources/extensions/ttsr/rule-loader.ts +4 -51
- package/src/resources/extensions/universal-config/discovery.ts +37 -15
- package/src/resources/extensions/voice/index.ts +1 -1
- package/src/resources/skills/accessibility/SKILL.md +522 -0
- package/src/resources/skills/accessibility/references/WCAG.md +162 -0
- package/src/resources/skills/agent-browser/SKILL.md +517 -0
- package/src/resources/skills/agent-browser/references/authentication.md +202 -0
- package/src/resources/skills/agent-browser/references/commands.md +263 -0
- package/src/resources/skills/agent-browser/references/profiling.md +120 -0
- package/src/resources/skills/agent-browser/references/proxy-support.md +194 -0
- package/src/resources/skills/agent-browser/references/session-management.md +193 -0
- package/src/resources/skills/agent-browser/references/snapshot-refs.md +194 -0
- package/src/resources/skills/agent-browser/references/video-recording.md +173 -0
- package/src/resources/skills/agent-browser/templates/authenticated-session.sh +105 -0
- package/src/resources/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/src/resources/skills/agent-browser/templates/form-automation.sh +62 -0
- package/src/resources/skills/best-practices/SKILL.md +583 -0
- package/src/resources/skills/code-optimizer/SKILL.md +160 -0
- package/src/resources/skills/code-optimizer/references/algorithmic-complexity.md +66 -0
- package/src/resources/skills/code-optimizer/references/build-compilation.md +90 -0
- package/src/resources/skills/code-optimizer/references/bundle-dependencies.md +82 -0
- package/src/resources/skills/code-optimizer/references/caching-memoization.md +76 -0
- package/src/resources/skills/code-optimizer/references/concurrency-async.md +80 -0
- package/src/resources/skills/code-optimizer/references/config-infra.md +71 -0
- package/src/resources/skills/code-optimizer/references/data-structures.md +80 -0
- package/src/resources/skills/code-optimizer/references/database-queries.md +76 -0
- package/src/resources/skills/code-optimizer/references/dead-code-redundancy.md +84 -0
- package/src/resources/skills/code-optimizer/references/error-resilience.md +80 -0
- package/src/resources/skills/code-optimizer/references/io-network.md +89 -0
- package/src/resources/skills/code-optimizer/references/logging-observability.md +64 -0
- package/src/resources/skills/code-optimizer/references/memory-resources.md +66 -0
- package/src/resources/skills/code-optimizer/references/rendering-ui.md +90 -0
- package/src/resources/skills/code-optimizer/references/security-performance.md +68 -0
- package/src/resources/skills/core-web-vitals/SKILL.md +441 -0
- package/src/resources/skills/core-web-vitals/references/LCP.md +208 -0
- package/src/resources/skills/make-interfaces-feel-better/SKILL.md +122 -0
- package/src/resources/skills/make-interfaces-feel-better/animations.md +379 -0
- package/src/resources/skills/make-interfaces-feel-better/performance.md +88 -0
- package/src/resources/skills/make-interfaces-feel-better/surfaces.md +247 -0
- package/src/resources/skills/make-interfaces-feel-better/typography.md +123 -0
- package/src/resources/skills/react-best-practices/README.md +123 -0
- package/src/resources/skills/react-best-practices/SKILL.md +136 -0
- package/src/resources/skills/react-best-practices/metadata.json +15 -0
- package/src/resources/skills/react-best-practices/rules/_sections.md +46 -0
- package/src/resources/skills/react-best-practices/rules/_template.md +28 -0
- package/src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/src/resources/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/src/resources/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/src/resources/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/src/resources/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/src/resources/skills/react-best-practices/rules/async-dependencies.md +51 -0
- package/src/resources/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/src/resources/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/src/resources/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/src/resources/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/src/resources/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/src/resources/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/src/resources/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/src/resources/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/src/resources/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/src/resources/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/src/resources/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/src/resources/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/src/resources/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/src/resources/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/src/resources/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/src/resources/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/src/resources/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/src/resources/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/src/resources/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/src/resources/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/src/resources/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/src/resources/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/src/resources/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/src/resources/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/src/resources/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/src/resources/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/src/resources/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/src/resources/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/src/resources/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/src/resources/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/src/resources/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/src/resources/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/src/resources/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/src/resources/skills/userinterface-wiki/SKILL.md +253 -0
- package/src/resources/skills/userinterface-wiki/rules/_sections.md +66 -0
- package/src/resources/skills/userinterface-wiki/rules/_template.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md +30 -0
- package/src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md +30 -0
- package/src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md +36 -0
- package/src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md +19 -0
- package/src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md +18 -0
- package/src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/container-callback-ref.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md +13 -0
- package/src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/container-transition-delay.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md +35 -0
- package/src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md +48 -0
- package/src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/context-reuse-single.md +30 -0
- package/src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md +26 -0
- package/src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/duration-press-hover.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/duration-small-state.md +15 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md +15 -0
- package/src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/exit-key-required.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/exit-prop-required.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md +34 -0
- package/src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md +26 -0
- package/src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/native-selection-styling.md +18 -0
- package/src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md +41 -0
- package/src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/none-high-frequency.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/param-click-duration.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/param-q-value-range.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/physics-active-state.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md +19 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md +34 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md +13 -0
- package/src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md +37 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md +37 -0
- package/src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/staging-dim-background.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/timing-consistent.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md +22 -0
- package/src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/transition-name-required.md +27 -0
- package/src/resources/skills/userinterface-wiki/rules/transition-name-unique.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md +18 -0
- package/src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md +15 -0
- package/src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md +24 -0
- package/src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md +18 -0
- package/src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md +15 -0
- package/src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md +15 -0
- package/src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md +17 -0
- package/src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md +21 -0
- package/src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md +16 -0
- package/src/resources/skills/userinterface-wiki/rules/type-underline-offset.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md +49 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md +50 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md +30 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md +32 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md +45 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md +37 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md +36 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md +35 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md +45 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md +33 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md +41 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md +38 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-serial-position.md +31 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md +35 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md +28 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md +43 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md +36 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md +49 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md +49 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md +40 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md +35 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md +30 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md +25 -0
- package/src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md +23 -0
- package/src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md +29 -0
- package/src/resources/skills/userinterface-wiki/rules/weight-match-action.md +32 -0
- package/src/resources/skills/web-design-guidelines/SKILL.md +39 -0
- package/src/resources/skills/web-quality-audit/SKILL.md +170 -0
- package/src/resources/skills/web-quality-audit/scripts/analyze.sh +91 -0
- package/dist/resources/extensions/gsd/complexity.ts +0 -237
- package/dist/resources/extensions/gsd/github-client.ts +0 -235
- package/dist/resources/extensions/gsd/mcp-server.ts +0 -108
- package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +0 -297
- package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +0 -127
- package/dist/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +0 -110
- package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +0 -115
- package/dist/resources/extensions/gsd/tests/complexity-routing.test.ts +0 -294
- package/dist/resources/extensions/gsd/tests/marketplace-discovery.test.ts +0 -202
- package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +0 -176
- package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +0 -104
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +0 -120
- package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -226
- package/dist/resources/extensions/gsd/tests/preferences-mode.test.ts +0 -110
- package/dist/resources/extensions/gsd/tests/preferences-models.test.ts +0 -207
- package/dist/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +0 -183
- package/dist/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +0 -168
- package/dist/resources/extensions/shared/bundled-extension-paths.ts +0 -11
- package/src/resources/extensions/gsd/complexity.ts +0 -237
- package/src/resources/extensions/gsd/github-client.ts +0 -235
- package/src/resources/extensions/gsd/mcp-server.ts +0 -108
- package/src/resources/extensions/gsd/tests/activity-log-prune.test.ts +0 -297
- package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/agent-end-provider-error.test.ts +0 -110
- package/src/resources/extensions/gsd/tests/auto-draft-pause.test.ts +0 -115
- package/src/resources/extensions/gsd/tests/complexity-routing.test.ts +0 -294
- package/src/resources/extensions/gsd/tests/marketplace-discovery.test.ts +0 -202
- package/src/resources/extensions/gsd/tests/metrics-io.test.ts +0 -176
- package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +0 -104
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +0 -226
- package/src/resources/extensions/gsd/tests/preferences-mode.test.ts +0 -110
- package/src/resources/extensions/gsd/tests/preferences-models.test.ts +0 -207
- package/src/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +0 -183
- package/src/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +0 -168
- package/src/resources/extensions/shared/bundled-extension-paths.ts +0 -11
|
@@ -5,39 +5,25 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
8
|
-
import {
|
|
9
|
-
import { existsSync, readFileSync,
|
|
10
|
-
import { join
|
|
11
|
-
import { enableDebug
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
+
import type { GSDState } from "./types.js";
|
|
9
|
+
import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { enableDebug } from "./debug-logger.js";
|
|
13
12
|
import { deriveState } from "./state.js";
|
|
14
13
|
import { GSDDashboardOverlay } from "./dashboard-overlay.js";
|
|
15
14
|
import { GSDVisualizerOverlay } from "./visualizer-overlay.js";
|
|
16
15
|
import { showQueue, showDiscuss, showHeadlessMilestoneCreation } from "./guided-flow.js";
|
|
17
16
|
import { startAuto, stopAuto, pauseAuto, isAutoActive, isAutoPaused, isStepMode, stopAutoRemote, dispatchDirectPhase } from "./auto.js";
|
|
18
17
|
import { resolveProjectRoot } from "./worktree.js";
|
|
19
|
-
import {
|
|
18
|
+
import { assertSafeDirectory } from "./validate-directory.js";
|
|
20
19
|
import {
|
|
21
20
|
getGlobalGSDPreferencesPath,
|
|
22
|
-
getLegacyGlobalGSDPreferencesPath,
|
|
23
21
|
getProjectGSDPreferencesPath,
|
|
24
|
-
loadGlobalGSDPreferences,
|
|
25
|
-
loadProjectGSDPreferences,
|
|
26
22
|
loadEffectiveGSDPreferences,
|
|
27
|
-
resolveAllSkillReferences,
|
|
28
23
|
} from "./preferences.js";
|
|
29
|
-
import { loadFile, saveFile, appendOverride, appendKnowledge, splitFrontmatter, parseFrontmatterMap } from "./files.js";
|
|
30
|
-
import { runClaudeImportFlow } from "./claude-import.js";
|
|
31
|
-
import {
|
|
32
|
-
formatDoctorIssuesForPrompt,
|
|
33
|
-
formatDoctorReport,
|
|
34
|
-
runGSDDoctor,
|
|
35
|
-
selectDoctorScope,
|
|
36
|
-
filterDoctorIssues,
|
|
37
|
-
} from "./doctor.js";
|
|
38
24
|
import { loadPrompt } from "./prompt-loader.js";
|
|
39
25
|
|
|
40
|
-
import { handleRemote } from "../remote-questions/
|
|
26
|
+
import { handleRemote } from "../remote-questions/mod.js";
|
|
41
27
|
import { handleQuick } from "./quick.js";
|
|
42
28
|
import { handleHistory } from "./history.js";
|
|
43
29
|
import { handleUndo } from "./undo.js";
|
|
@@ -50,7 +36,21 @@ import {
|
|
|
50
36
|
import { formatEligibilityReport } from "./parallel-eligibility.js";
|
|
51
37
|
import { mergeAllCompleted, mergeCompletedMilestone, formatMergeResults } from "./parallel-merge.js";
|
|
52
38
|
import { resolveParallelConfig } from "./preferences.js";
|
|
53
|
-
|
|
39
|
+
|
|
40
|
+
// ─── Imports from extracted modules ──────────────────────────────────────────
|
|
41
|
+
import { handlePrefs, handlePrefsMode, handlePrefsWizard, ensurePreferencesFile } from "./commands-prefs-wizard.js";
|
|
42
|
+
import { handleConfig } from "./commands-config.js";
|
|
43
|
+
import { handleInspect } from "./commands-inspect.js";
|
|
44
|
+
import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleDryRun } from "./commands-maintenance.js";
|
|
45
|
+
import { handleDoctor, handleSteer, handleCapture, handleTriage, handleKnowledge, handleRunHook, handleUpdate, handleSkillHealth } from "./commands-handlers.js";
|
|
46
|
+
import { handleLogs } from "./commands-logs.js";
|
|
47
|
+
|
|
48
|
+
// ─── Re-exports (preserve public API surface) ───────────────────────────────
|
|
49
|
+
export { handlePrefs, handlePrefsMode, handlePrefsWizard, ensurePreferencesFile, handleImportClaude, buildCategorySummaries, serializePreferencesToFrontmatter, yamlSafeString, configureMode } from "./commands-prefs-wizard.js";
|
|
50
|
+
export { TOOL_KEYS, loadToolApiKeys, getConfigAuthStorage, handleConfig } from "./commands-config.js";
|
|
51
|
+
export { type InspectData, formatInspectOutput, handleInspect } from "./commands-inspect.js";
|
|
52
|
+
export { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleDryRun } from "./commands-maintenance.js";
|
|
53
|
+
export { handleDoctor, handleSteer, handleCapture, handleTriage, handleKnowledge, handleRunHook, handleUpdate, handleSkillHealth } from "./commands-handlers.js";
|
|
54
54
|
|
|
55
55
|
export function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined, reportText: string, structuredIssues: string): void {
|
|
56
56
|
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".pi", "GSD-WORKFLOW.md");
|
|
@@ -71,13 +71,15 @@ export function dispatchDoctorHeal(pi: ExtensionAPI, scope: string | undefined,
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/** Resolve the effective project root, accounting for worktree paths. */
|
|
74
|
-
function projectRoot(): string {
|
|
75
|
-
|
|
74
|
+
export function projectRoot(): string {
|
|
75
|
+
const root = resolveProjectRoot(process.cwd());
|
|
76
|
+
assertSafeDirectory(root);
|
|
77
|
+
return root;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
79
81
|
pi.registerCommand("gsd", {
|
|
80
|
-
description: "GSD — Get Shit Done: /gsd help|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|hooks|run-hook|skill-health|doctor|forensics|migrate|remote|steer|knowledge|new-milestone|parallel",
|
|
82
|
+
description: "GSD — Get Shit Done: /gsd help|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|migrate|remote|steer|knowledge|new-milestone|parallel|update",
|
|
81
83
|
getArgumentCompletions: (prefix: string) => {
|
|
82
84
|
const subcommands = [
|
|
83
85
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -101,11 +103,15 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
101
103
|
{ cmd: "mode", desc: "Switch workflow mode (solo/team)" },
|
|
102
104
|
{ cmd: "prefs", desc: "Manage preferences (model selection, timeouts, etc.)" },
|
|
103
105
|
{ cmd: "config", desc: "Set API keys for external tools" },
|
|
106
|
+
{ cmd: "keys", desc: "API key manager — list, add, remove, test, rotate, doctor" },
|
|
104
107
|
{ cmd: "hooks", desc: "Show configured post-unit and pre-dispatch hooks" },
|
|
105
108
|
{ cmd: "run-hook", desc: "Manually trigger a specific hook" },
|
|
106
109
|
{ cmd: "skill-health", desc: "Skill lifecycle dashboard" },
|
|
107
110
|
{ cmd: "doctor", desc: "Runtime health checks with auto-fix" },
|
|
111
|
+
{ cmd: "logs", desc: "Browse activity logs, debug logs, and metrics" },
|
|
108
112
|
{ cmd: "forensics", desc: "Examine execution logs" },
|
|
113
|
+
{ cmd: "init", desc: "Project init wizard — detect, configure, bootstrap .gsd/" },
|
|
114
|
+
{ cmd: "setup", desc: "Global setup status and configuration" },
|
|
109
115
|
{ cmd: "migrate", desc: "Migrate a v1 .planning directory to .gsd format" },
|
|
110
116
|
{ cmd: "remote", desc: "Control remote auto-mode" },
|
|
111
117
|
{ cmd: "steer", desc: "Hard-steer plan documents during execution" },
|
|
@@ -113,101 +119,206 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
113
119
|
{ cmd: "knowledge", desc: "Add persistent project knowledge (rule, pattern, or lesson)" },
|
|
114
120
|
{ cmd: "new-milestone", desc: "Create a milestone from a specification document (headless)" },
|
|
115
121
|
{ cmd: "parallel", desc: "Parallel milestone orchestration (start, status, stop, merge)" },
|
|
122
|
+
{ cmd: "park", desc: "Park a milestone — skip without deleting" },
|
|
123
|
+
{ cmd: "unpark", desc: "Reactivate a parked milestone" },
|
|
124
|
+
{ cmd: "update", desc: "Update GSD to the latest version" },
|
|
116
125
|
];
|
|
117
126
|
const parts = prefix.trim().split(/\s+/);
|
|
118
127
|
|
|
119
128
|
if (parts.length <= 1) {
|
|
120
129
|
return subcommands
|
|
121
130
|
.filter((item) => item.cmd.startsWith(parts[0] ?? ""))
|
|
122
|
-
.map((item) => ({
|
|
123
|
-
value: item.cmd,
|
|
124
|
-
label: item.cmd,
|
|
125
|
-
description: item.desc
|
|
131
|
+
.map((item) => ({
|
|
132
|
+
value: item.cmd,
|
|
133
|
+
label: item.cmd,
|
|
134
|
+
description: item.desc
|
|
126
135
|
}));
|
|
127
136
|
}
|
|
128
137
|
|
|
129
138
|
if (parts[0] === "auto" && parts.length <= 2) {
|
|
130
139
|
const flagPrefix = parts[1] ?? "";
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
const flags = [
|
|
141
|
+
{ flag: "--verbose", desc: "Show detailed execution output" },
|
|
142
|
+
{ flag: "--debug", desc: "Enable debug logging" },
|
|
143
|
+
];
|
|
144
|
+
return flags
|
|
145
|
+
.filter((f) => f.flag.startsWith(flagPrefix))
|
|
146
|
+
.map((f) => ({ value: `auto ${f.flag}`, label: f.flag, description: f.desc }));
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
if (parts[0] === "mode" && parts.length <= 2) {
|
|
137
150
|
const subPrefix = parts[1] ?? "";
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
151
|
+
const modes = [
|
|
152
|
+
{ cmd: "global", desc: "Edit global workflow mode" },
|
|
153
|
+
{ cmd: "project", desc: "Edit project-specific workflow mode" },
|
|
154
|
+
];
|
|
155
|
+
return modes
|
|
156
|
+
.filter((m) => m.cmd.startsWith(subPrefix))
|
|
157
|
+
.map((m) => ({ value: `mode ${m.cmd}`, label: m.cmd, description: m.desc }));
|
|
141
158
|
}
|
|
142
159
|
|
|
143
160
|
if (parts[0] === "parallel" && parts.length <= 2) {
|
|
144
161
|
const subPrefix = parts[1] ?? "";
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
const subs = [
|
|
163
|
+
{ cmd: "start", desc: "Start parallel milestone orchestration" },
|
|
164
|
+
{ cmd: "status", desc: "Show parallel worker statuses" },
|
|
165
|
+
{ cmd: "stop", desc: "Stop all parallel workers" },
|
|
166
|
+
{ cmd: "pause", desc: "Pause a specific worker" },
|
|
167
|
+
{ cmd: "resume", desc: "Resume a paused worker" },
|
|
168
|
+
{ cmd: "merge", desc: "Merge completed milestone branches" },
|
|
169
|
+
];
|
|
170
|
+
return subs
|
|
171
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
172
|
+
.map((s) => ({ value: `parallel ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (parts[0] === "setup" && parts.length <= 2) {
|
|
176
|
+
const subPrefix = parts[1] ?? "";
|
|
177
|
+
const subs = [
|
|
178
|
+
{ cmd: "llm", desc: "Configure LLM provider settings" },
|
|
179
|
+
{ cmd: "search", desc: "Configure web search provider" },
|
|
180
|
+
{ cmd: "remote", desc: "Configure remote integrations" },
|
|
181
|
+
{ cmd: "keys", desc: "Manage API keys" },
|
|
182
|
+
{ cmd: "prefs", desc: "Configure global preferences" },
|
|
183
|
+
];
|
|
184
|
+
return subs
|
|
185
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
186
|
+
.map((s) => ({ value: `setup ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (parts[0] === "logs" && parts.length <= 2) {
|
|
190
|
+
const subPrefix = parts[1] ?? "";
|
|
191
|
+
const subs = [
|
|
192
|
+
{ cmd: "debug", desc: "List or view debug log files" },
|
|
193
|
+
{ cmd: "tail", desc: "Show last N activity log summaries" },
|
|
194
|
+
{ cmd: "clear", desc: "Remove old activity and debug logs" },
|
|
195
|
+
];
|
|
196
|
+
return subs
|
|
197
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
198
|
+
.map((s) => ({ value: `logs ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (parts[0] === "keys" && parts.length <= 2) {
|
|
202
|
+
const subPrefix = parts[1] ?? "";
|
|
203
|
+
const subs = [
|
|
204
|
+
{ cmd: "list", desc: "Show key status dashboard" },
|
|
205
|
+
{ cmd: "add", desc: "Add a key for a provider" },
|
|
206
|
+
{ cmd: "remove", desc: "Remove a key" },
|
|
207
|
+
{ cmd: "test", desc: "Validate key(s) with API call" },
|
|
208
|
+
{ cmd: "rotate", desc: "Replace an existing key" },
|
|
209
|
+
{ cmd: "doctor", desc: "Health check all keys" },
|
|
210
|
+
];
|
|
211
|
+
return subs
|
|
212
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
213
|
+
.map((s) => ({ value: `keys ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
148
214
|
}
|
|
149
215
|
|
|
150
216
|
if (parts[0] === "prefs" && parts.length <= 2) {
|
|
151
217
|
const subPrefix = parts[1] ?? "";
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
218
|
+
const subs = [
|
|
219
|
+
{ cmd: "global", desc: "Edit global preferences file" },
|
|
220
|
+
{ cmd: "project", desc: "Edit project preferences file" },
|
|
221
|
+
{ cmd: "status", desc: "Show effective preferences" },
|
|
222
|
+
{ cmd: "wizard", desc: "Interactive preferences wizard" },
|
|
223
|
+
{ cmd: "setup", desc: "First-time preferences setup" },
|
|
224
|
+
{ cmd: "import-claude", desc: "Import settings from Claude Code" },
|
|
225
|
+
];
|
|
226
|
+
return subs
|
|
227
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
228
|
+
.map((s) => ({ value: `prefs ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
155
229
|
}
|
|
156
230
|
|
|
157
231
|
if (parts[0] === "remote" && parts.length <= 2) {
|
|
158
232
|
const subPrefix = parts[1] ?? "";
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
233
|
+
const subs = [
|
|
234
|
+
{ cmd: "slack", desc: "Configure Slack integration" },
|
|
235
|
+
{ cmd: "discord", desc: "Configure Discord integration" },
|
|
236
|
+
{ cmd: "status", desc: "Show remote connection status" },
|
|
237
|
+
{ cmd: "disconnect", desc: "Disconnect remote integrations" },
|
|
238
|
+
];
|
|
239
|
+
return subs
|
|
240
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
241
|
+
.map((s) => ({ value: `remote ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
162
242
|
}
|
|
163
243
|
|
|
164
244
|
if (parts[0] === "next" && parts.length <= 2) {
|
|
165
245
|
const flagPrefix = parts[1] ?? "";
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
246
|
+
const flags = [
|
|
247
|
+
{ flag: "--verbose", desc: "Show detailed step output" },
|
|
248
|
+
{ flag: "--dry-run", desc: "Preview next step without executing" },
|
|
249
|
+
];
|
|
250
|
+
return flags
|
|
251
|
+
.filter((f) => f.flag.startsWith(flagPrefix))
|
|
252
|
+
.map((f) => ({ value: `next ${f.flag}`, label: f.flag, description: f.desc }));
|
|
169
253
|
}
|
|
170
254
|
|
|
171
255
|
if (parts[0] === "history" && parts.length <= 2) {
|
|
172
256
|
const flagPrefix = parts[1] ?? "";
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
257
|
+
const flags = [
|
|
258
|
+
{ flag: "--cost", desc: "Show cost breakdown per entry" },
|
|
259
|
+
{ flag: "--phase", desc: "Filter by phase type" },
|
|
260
|
+
{ flag: "--model", desc: "Filter by model used" },
|
|
261
|
+
{ flag: "10", desc: "Show last 10 entries" },
|
|
262
|
+
{ flag: "20", desc: "Show last 20 entries" },
|
|
263
|
+
{ flag: "50", desc: "Show last 50 entries" },
|
|
264
|
+
];
|
|
265
|
+
return flags
|
|
266
|
+
.filter((f) => f.flag.startsWith(flagPrefix))
|
|
267
|
+
.map((f) => ({ value: `history ${f.flag}`, label: f.flag, description: f.desc }));
|
|
176
268
|
}
|
|
177
269
|
|
|
178
270
|
if (parts[0] === "undo" && parts.length <= 2) {
|
|
179
|
-
return [{ value: "undo --force", label: "--force" }];
|
|
271
|
+
return [{ value: "undo --force", label: "--force", description: "Skip confirmation prompt" }];
|
|
180
272
|
}
|
|
181
273
|
|
|
182
274
|
if (parts[0] === "export" && parts.length <= 2) {
|
|
183
275
|
const flagPrefix = parts[1] ?? "";
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
276
|
+
const flags = [
|
|
277
|
+
{ flag: "--json", desc: "Export as JSON" },
|
|
278
|
+
{ flag: "--markdown", desc: "Export as Markdown" },
|
|
279
|
+
{ flag: "--html", desc: "Export as HTML" },
|
|
280
|
+
{ flag: "--html --all", desc: "Export all milestones as HTML" },
|
|
281
|
+
];
|
|
282
|
+
return flags
|
|
283
|
+
.filter((f) => f.flag.startsWith(flagPrefix))
|
|
284
|
+
.map((f) => ({ value: `export ${f.flag}`, label: f.flag, description: f.desc }));
|
|
187
285
|
}
|
|
188
286
|
|
|
189
287
|
if (parts[0] === "cleanup" && parts.length <= 2) {
|
|
190
288
|
const subPrefix = parts[1] ?? "";
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
289
|
+
const subs = [
|
|
290
|
+
{ cmd: "branches", desc: "Remove merged milestone branches" },
|
|
291
|
+
{ cmd: "snapshots", desc: "Remove old execution snapshots" },
|
|
292
|
+
];
|
|
293
|
+
return subs
|
|
294
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
295
|
+
.map((s) => ({ value: `cleanup ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
194
296
|
}
|
|
195
297
|
|
|
196
298
|
if (parts[0] === "knowledge" && parts.length <= 2) {
|
|
197
299
|
const subPrefix = parts[1] ?? "";
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
300
|
+
const subs = [
|
|
301
|
+
{ cmd: "rule", desc: "Add a project rule (always/never do X)" },
|
|
302
|
+
{ cmd: "pattern", desc: "Add a code pattern to follow" },
|
|
303
|
+
{ cmd: "lesson", desc: "Record a lesson learned" },
|
|
304
|
+
];
|
|
305
|
+
return subs
|
|
306
|
+
.filter((s) => s.cmd.startsWith(subPrefix))
|
|
307
|
+
.map((s) => ({ value: `knowledge ${s.cmd}`, label: s.cmd, description: s.desc }));
|
|
201
308
|
}
|
|
202
309
|
|
|
203
310
|
if (parts[0] === "doctor") {
|
|
204
311
|
const modePrefix = parts[1] ?? "";
|
|
205
|
-
const modes = [
|
|
312
|
+
const modes = [
|
|
313
|
+
{ cmd: "fix", desc: "Auto-fix detected issues" },
|
|
314
|
+
{ cmd: "heal", desc: "AI-driven deep healing" },
|
|
315
|
+
{ cmd: "audit", desc: "Run health audit without fixing" },
|
|
316
|
+
];
|
|
206
317
|
|
|
207
318
|
if (parts.length <= 2) {
|
|
208
319
|
return modes
|
|
209
|
-
.filter((
|
|
210
|
-
.map((
|
|
320
|
+
.filter((m) => m.cmd.startsWith(modePrefix))
|
|
321
|
+
.map((m) => ({ value: `doctor ${m.cmd}`, label: m.cmd, description: m.desc }));
|
|
211
322
|
}
|
|
212
323
|
|
|
213
324
|
return [];
|
|
@@ -215,9 +326,18 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
215
326
|
|
|
216
327
|
if (parts[0] === "dispatch" && parts.length <= 2) {
|
|
217
328
|
const phasePrefix = parts[1] ?? "";
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
329
|
+
const phases = [
|
|
330
|
+
{ cmd: "research", desc: "Run research phase" },
|
|
331
|
+
{ cmd: "plan", desc: "Run planning phase" },
|
|
332
|
+
{ cmd: "execute", desc: "Run execution phase" },
|
|
333
|
+
{ cmd: "complete", desc: "Run completion phase" },
|
|
334
|
+
{ cmd: "reassess", desc: "Reassess current progress" },
|
|
335
|
+
{ cmd: "uat", desc: "Run user acceptance testing" },
|
|
336
|
+
{ cmd: "replan", desc: "Replan the current slice" },
|
|
337
|
+
];
|
|
338
|
+
return phases
|
|
339
|
+
.filter((p) => p.cmd.startsWith(phasePrefix))
|
|
340
|
+
.map((p) => ({ value: `dispatch ${p.cmd}`, label: p.cmd, description: p.desc }));
|
|
221
341
|
}
|
|
222
342
|
|
|
223
343
|
return [];
|
|
@@ -255,11 +375,42 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
255
375
|
return;
|
|
256
376
|
}
|
|
257
377
|
|
|
378
|
+
if (trimmed === "init") {
|
|
379
|
+
const { detectProjectState } = await import("./detection.js");
|
|
380
|
+
const { showProjectInit, handleReinit } = await import("./init-wizard.js");
|
|
381
|
+
const basePath = projectRoot();
|
|
382
|
+
const detection = detectProjectState(basePath);
|
|
383
|
+
if (detection.state === "v2-gsd" || detection.state === "v2-gsd-empty") {
|
|
384
|
+
await handleReinit(ctx, detection);
|
|
385
|
+
} else {
|
|
386
|
+
await showProjectInit(ctx, pi, basePath, detection);
|
|
387
|
+
}
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (trimmed === "keys" || trimmed.startsWith("keys ")) {
|
|
392
|
+
const { handleKeys } = await import("./key-manager.js");
|
|
393
|
+
const keysArgs = trimmed.replace(/^keys\s*/, "").trim();
|
|
394
|
+
await handleKeys(keysArgs, ctx);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (trimmed === "setup" || trimmed.startsWith("setup ")) {
|
|
399
|
+
const setupArgs = trimmed.replace(/^setup\s*/, "").trim();
|
|
400
|
+
await handleSetup(setupArgs, ctx);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
258
404
|
if (trimmed === "doctor" || trimmed.startsWith("doctor ")) {
|
|
259
405
|
await handleDoctor(trimmed.replace(/^doctor\s*/, "").trim(), ctx, pi);
|
|
260
406
|
return;
|
|
261
407
|
}
|
|
262
408
|
|
|
409
|
+
if (trimmed === "logs" || trimmed.startsWith("logs ")) {
|
|
410
|
+
await handleLogs(trimmed.replace(/^logs\s*/, "").trim(), ctx);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
263
414
|
if (trimmed === "forensics" || trimmed.startsWith("forensics ")) {
|
|
264
415
|
const { handleForensics } = await import("./forensics.js");
|
|
265
416
|
await handleForensics(trimmed.replace(/^forensics\s*/, "").trim(), ctx, pi);
|
|
@@ -464,6 +615,73 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
|
|
|
464
615
|
return;
|
|
465
616
|
}
|
|
466
617
|
|
|
618
|
+
if (trimmed === "park" || trimmed.startsWith("park ")) {
|
|
619
|
+
const basePath = projectRoot();
|
|
620
|
+
const arg = trimmed.replace(/^park\s*/, "").trim();
|
|
621
|
+
const { parkMilestone, isParked } = await import("./milestone-actions.js");
|
|
622
|
+
const { deriveState } = await import("./state.js");
|
|
623
|
+
|
|
624
|
+
let targetId = arg;
|
|
625
|
+
if (!targetId) {
|
|
626
|
+
// Park the current active milestone
|
|
627
|
+
const state = await deriveState(basePath);
|
|
628
|
+
if (!state.activeMilestone) {
|
|
629
|
+
ctx.ui.notify("No active milestone to park.", "warning");
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
targetId = state.activeMilestone.id;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (isParked(basePath, targetId)) {
|
|
636
|
+
ctx.ui.notify(`${targetId} is already parked. Use /gsd unpark ${targetId} to reactivate.`, "info");
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Extract reason from remaining args (e.g., /gsd park M002 "reason here")
|
|
641
|
+
const reasonParts = arg.replace(targetId, "").trim().replace(/^["']|["']$/g, "");
|
|
642
|
+
const reason = reasonParts || "Parked via /gsd park";
|
|
643
|
+
|
|
644
|
+
const success = parkMilestone(basePath, targetId, reason);
|
|
645
|
+
if (success) {
|
|
646
|
+
ctx.ui.notify(`Parked ${targetId}. Run /gsd unpark ${targetId} to reactivate.`, "info");
|
|
647
|
+
} else {
|
|
648
|
+
ctx.ui.notify(`Could not park ${targetId} — milestone not found.`, "warning");
|
|
649
|
+
}
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (trimmed === "unpark" || trimmed.startsWith("unpark ")) {
|
|
654
|
+
const basePath = projectRoot();
|
|
655
|
+
const arg = trimmed.replace(/^unpark\s*/, "").trim();
|
|
656
|
+
const { unparkMilestone } = await import("./milestone-actions.js");
|
|
657
|
+
const { deriveState } = await import("./state.js");
|
|
658
|
+
|
|
659
|
+
let targetId = arg;
|
|
660
|
+
if (!targetId) {
|
|
661
|
+
// List parked milestones and let user pick
|
|
662
|
+
const state = await deriveState(basePath);
|
|
663
|
+
const parkedEntries = state.registry.filter(e => e.status === "parked");
|
|
664
|
+
if (parkedEntries.length === 0) {
|
|
665
|
+
ctx.ui.notify("No parked milestones.", "info");
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
if (parkedEntries.length === 1) {
|
|
669
|
+
targetId = parkedEntries[0].id;
|
|
670
|
+
} else {
|
|
671
|
+
ctx.ui.notify(`Parked milestones: ${parkedEntries.map(e => e.id).join(", ")}. Specify which to unpark: /gsd unpark <id>`, "info");
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const success = unparkMilestone(basePath, targetId);
|
|
677
|
+
if (success) {
|
|
678
|
+
ctx.ui.notify(`Unparked ${targetId}. It will resume its normal position in the queue.`, "info");
|
|
679
|
+
} else {
|
|
680
|
+
ctx.ui.notify(`Could not unpark ${targetId} — milestone not found or not parked.`, "warning");
|
|
681
|
+
}
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
|
|
467
685
|
if (trimmed === "new-milestone") {
|
|
468
686
|
const basePath = projectRoot();
|
|
469
687
|
const headlessContextPath = join(basePath, ".gsd", "runtime", "headless-context.md");
|
|
@@ -575,6 +793,11 @@ Examples:
|
|
|
575
793
|
return;
|
|
576
794
|
}
|
|
577
795
|
|
|
796
|
+
if (trimmed === "update") {
|
|
797
|
+
await handleUpdate(ctx);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
|
|
578
801
|
if (trimmed === "") {
|
|
579
802
|
// Bare /gsd defaults to step mode
|
|
580
803
|
await startAuto(ctx, pi, projectRoot(), false, { step: true });
|
|
@@ -613,23 +836,29 @@ function showHelp(ctx: ExtensionCommandContext): void {
|
|
|
613
836
|
" /gsd triage Classify and route pending captures",
|
|
614
837
|
" /gsd skip <unit> Prevent a unit from auto-mode dispatch",
|
|
615
838
|
" /gsd undo Revert last completed unit [--force]",
|
|
839
|
+
" /gsd park [id] Park a milestone — skip without deleting [reason]",
|
|
840
|
+
" /gsd unpark [id] Reactivate a parked milestone",
|
|
616
841
|
"",
|
|
617
842
|
"PROJECT KNOWLEDGE",
|
|
618
843
|
" /gsd knowledge <type> <text> Add rule, pattern, or lesson to KNOWLEDGE.md",
|
|
619
844
|
"",
|
|
620
|
-
"CONFIGURATION",
|
|
845
|
+
"SETUP & CONFIGURATION",
|
|
846
|
+
" /gsd init Project init wizard — detect, configure, bootstrap .gsd/",
|
|
847
|
+
" /gsd setup Global setup status [llm|search|remote|keys|prefs]",
|
|
621
848
|
" /gsd mode Set workflow mode (solo/team) [global|project]",
|
|
622
849
|
" /gsd prefs Manage preferences [global|project|status|wizard|setup]",
|
|
623
850
|
" /gsd config Set API keys for external tools",
|
|
851
|
+
" /gsd keys API key manager [list|add|remove|test|rotate|doctor]",
|
|
624
852
|
" /gsd hooks Show post-unit hook configuration",
|
|
625
853
|
"",
|
|
626
854
|
"MAINTENANCE",
|
|
627
855
|
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
628
|
-
" /gsd export Export milestone/slice results [--json|--markdown|--html]",
|
|
856
|
+
" /gsd export Export milestone/slice results [--json|--markdown|--html] [--all]",
|
|
629
857
|
" /gsd cleanup Remove merged branches or snapshots [branches|snapshots]",
|
|
630
|
-
" /gsd migrate
|
|
858
|
+
" /gsd migrate Migrate .planning/ (v1) to .gsd/ (v2) format",
|
|
631
859
|
" /gsd remote Control remote auto-mode [slack|discord|status|disconnect]",
|
|
632
860
|
" /gsd inspect Show SQLite DB diagnostics (schema, row counts, recent entries)",
|
|
861
|
+
" /gsd update Update GSD to the latest version via npm",
|
|
633
862
|
];
|
|
634
863
|
ctx.ui.notify(lines.join("\n"), "info");
|
|
635
864
|
}
|
|
@@ -643,7 +872,7 @@ async function handleStatus(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
643
872
|
return;
|
|
644
873
|
}
|
|
645
874
|
|
|
646
|
-
await ctx.ui.custom<void>(
|
|
875
|
+
const result = await ctx.ui.custom<void>(
|
|
647
876
|
(tui, theme, _kb, done) => {
|
|
648
877
|
return new GSDDashboardOverlay(tui, theme, () => done());
|
|
649
878
|
},
|
|
@@ -657,6 +886,12 @@ async function handleStatus(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
657
886
|
},
|
|
658
887
|
},
|
|
659
888
|
);
|
|
889
|
+
|
|
890
|
+
// Fallback for RPC mode where ctx.ui.custom() returns undefined.
|
|
891
|
+
// Produce a text-based status summary so the turn is not empty.
|
|
892
|
+
if (result === undefined) {
|
|
893
|
+
ctx.ui.notify(formatTextStatus(state), "info");
|
|
894
|
+
}
|
|
660
895
|
}
|
|
661
896
|
|
|
662
897
|
export async function fireStatusViaCommand(
|
|
@@ -671,7 +906,7 @@ async function handleVisualize(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
671
906
|
return;
|
|
672
907
|
}
|
|
673
908
|
|
|
674
|
-
await ctx.ui.custom<void>(
|
|
909
|
+
const result = await ctx.ui.custom<void>(
|
|
675
910
|
(tui, theme, _kb, done) => {
|
|
676
911
|
return new GSDVisualizerOverlay(tui, theme, () => done());
|
|
677
912
|
},
|
|
@@ -685,1409 +920,121 @@ async function handleVisualize(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
685
920
|
},
|
|
686
921
|
},
|
|
687
922
|
);
|
|
923
|
+
|
|
924
|
+
// Fallback for RPC mode where ctx.ui.custom() returns undefined.
|
|
925
|
+
if (result === undefined) {
|
|
926
|
+
ctx.ui.notify("Visualizer requires an interactive terminal. Use /gsd status for a text-based overview.", "warning");
|
|
927
|
+
}
|
|
688
928
|
}
|
|
689
929
|
|
|
690
|
-
async function
|
|
691
|
-
const
|
|
930
|
+
async function handleSetup(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
931
|
+
const { detectProjectState, hasGlobalSetup } = await import("./detection.js");
|
|
692
932
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
await handlePrefsWizard(ctx, "global");
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
933
|
+
// Show current global setup status
|
|
934
|
+
const globalConfigured = hasGlobalSetup();
|
|
935
|
+
const detection = detectProjectState(projectRoot());
|
|
699
936
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
937
|
+
const statusLines = ["GSD Setup Status\n"];
|
|
938
|
+
statusLines.push(` Global preferences: ${globalConfigured ? "configured" : "not set"}`);
|
|
939
|
+
statusLines.push(` Project state: ${detection.state}`);
|
|
940
|
+
if (detection.projectSignals.primaryLanguage) {
|
|
941
|
+
statusLines.push(` Detected: ${detection.projectSignals.primaryLanguage}`);
|
|
704
942
|
}
|
|
705
943
|
|
|
706
|
-
if (
|
|
707
|
-
|
|
944
|
+
if (args === "llm" || args === "auth") {
|
|
945
|
+
ctx.ui.notify("Use /login to configure LLM authentication.", "info");
|
|
708
946
|
return;
|
|
709
947
|
}
|
|
710
948
|
|
|
711
|
-
if (
|
|
712
|
-
|
|
949
|
+
if (args === "search") {
|
|
950
|
+
ctx.ui.notify("Use /search-provider to configure web search.", "info");
|
|
713
951
|
return;
|
|
714
952
|
}
|
|
715
|
-
if (trimmed === "status") {
|
|
716
|
-
const globalPrefs = loadGlobalGSDPreferences();
|
|
717
|
-
const projectPrefs = loadProjectGSDPreferences();
|
|
718
|
-
const canonicalGlobal = getGlobalGSDPreferencesPath();
|
|
719
|
-
const legacyGlobal = getLegacyGlobalGSDPreferencesPath();
|
|
720
|
-
const globalStatus = globalPrefs
|
|
721
|
-
? `present: ${globalPrefs.path}${globalPrefs.path === legacyGlobal ? " (legacy fallback)" : ""}`
|
|
722
|
-
: `missing: ${canonicalGlobal}`;
|
|
723
|
-
const projectStatus = projectPrefs ? `present: ${projectPrefs.path}` : `missing: ${getProjectGSDPreferencesPath()}`;
|
|
724
|
-
|
|
725
|
-
const lines = [`GSD skill prefs — global ${globalStatus}; project ${projectStatus}`];
|
|
726
|
-
|
|
727
|
-
const effective = loadEffectiveGSDPreferences();
|
|
728
|
-
let hasUnresolved = false;
|
|
729
|
-
if (effective) {
|
|
730
|
-
const report = resolveAllSkillReferences(effective.preferences, process.cwd());
|
|
731
|
-
const resolved = [...report.resolutions.values()].filter(r => r.method !== "unresolved");
|
|
732
|
-
hasUnresolved = report.warnings.length > 0;
|
|
733
|
-
if (resolved.length > 0 || hasUnresolved) {
|
|
734
|
-
lines.push(`Skills: ${resolved.length} resolved, ${report.warnings.length} unresolved`);
|
|
735
|
-
}
|
|
736
|
-
if (hasUnresolved) {
|
|
737
|
-
lines.push(`Unresolved: ${report.warnings.join(", ")}`);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
953
|
|
|
741
|
-
|
|
954
|
+
if (args === "remote") {
|
|
955
|
+
ctx.ui.notify("Use /gsd remote to configure remote questions.", "info");
|
|
742
956
|
return;
|
|
743
957
|
}
|
|
744
958
|
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
async function handleImportClaude(ctx: ExtensionCommandContext, scope: "global" | "project"): Promise<void> {
|
|
749
|
-
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
750
|
-
if (!existsSync(path)) {
|
|
751
|
-
await ensurePreferencesFile(path, ctx, scope);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
const readPrefs = (): Record<string, unknown> => {
|
|
755
|
-
if (!existsSync(path)) return { version: 1 };
|
|
756
|
-
const content = readFileSync(path, "utf-8");
|
|
757
|
-
const [frontmatterLines] = splitFrontmatter(content);
|
|
758
|
-
return frontmatterLines ? parseFrontmatterMap(frontmatterLines) : { version: 1 };
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
const writePrefs = async (prefs: Record<string, unknown>): Promise<void> => {
|
|
762
|
-
prefs.version = prefs.version || 1;
|
|
763
|
-
const frontmatter = serializePreferencesToFrontmatter(prefs);
|
|
764
|
-
let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
|
|
765
|
-
if (existsSync(path)) {
|
|
766
|
-
const existingContent = readFileSync(path, "utf-8");
|
|
767
|
-
const closingIdx = existingContent.indexOf("\n---", existingContent.indexOf("---"));
|
|
768
|
-
if (closingIdx !== -1) {
|
|
769
|
-
const afterFrontmatter = existingContent.slice(closingIdx + 4);
|
|
770
|
-
if (afterFrontmatter.trim()) body = afterFrontmatter;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
await saveFile(path, `---\n${frontmatter}---${body}`);
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
await runClaudeImportFlow(ctx, scope, readPrefs, writePrefs);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
async function handlePrefsMode(ctx: ExtensionCommandContext, scope: "global" | "project"): Promise<void> {
|
|
780
|
-
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
781
|
-
const existing = scope === "project" ? loadProjectGSDPreferences() : loadGlobalGSDPreferences();
|
|
782
|
-
const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
|
|
783
|
-
|
|
784
|
-
await configureMode(ctx, prefs);
|
|
785
|
-
|
|
786
|
-
// Serialize and save
|
|
787
|
-
prefs.version = prefs.version || 1;
|
|
788
|
-
const frontmatter = serializePreferencesToFrontmatter(prefs);
|
|
789
|
-
|
|
790
|
-
let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
|
|
791
|
-
if (existsSync(path)) {
|
|
792
|
-
const existingContent = readFileSync(path, "utf-8");
|
|
793
|
-
const closingIdx = existingContent.indexOf("\n---", existingContent.indexOf("---"));
|
|
794
|
-
if (closingIdx !== -1) {
|
|
795
|
-
const afterFrontmatter = existingContent.slice(closingIdx + 4);
|
|
796
|
-
if (afterFrontmatter.trim()) {
|
|
797
|
-
body = afterFrontmatter;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
const content = `---\n${frontmatter}---${body}`;
|
|
803
|
-
await saveFile(path, content);
|
|
804
|
-
await ctx.waitForIdle();
|
|
805
|
-
await ctx.reload();
|
|
806
|
-
ctx.ui.notify(`Saved ${scope} preferences to ${path}`, "info");
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
async function handleDoctor(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
810
|
-
const trimmed = args.trim();
|
|
811
|
-
const parts = trimmed ? trimmed.split(/\s+/) : [];
|
|
812
|
-
const mode = parts[0] === "fix" || parts[0] === "heal" || parts[0] === "audit" ? parts[0] : "doctor";
|
|
813
|
-
const requestedScope = mode === "doctor" ? parts[0] : parts[1];
|
|
814
|
-
const scope = await selectDoctorScope(projectRoot(), requestedScope);
|
|
815
|
-
const effectiveScope = mode === "audit" ? requestedScope : scope;
|
|
816
|
-
const report = await runGSDDoctor(projectRoot(), {
|
|
817
|
-
fix: mode === "fix" || mode === "heal",
|
|
818
|
-
scope: effectiveScope,
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
const reportText = formatDoctorReport(report, {
|
|
822
|
-
scope: effectiveScope,
|
|
823
|
-
includeWarnings: mode === "audit",
|
|
824
|
-
maxIssues: mode === "audit" ? 50 : 12,
|
|
825
|
-
title: mode === "audit" ? "GSD doctor audit." : mode === "heal" ? "GSD doctor heal prep." : undefined,
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
ctx.ui.notify(reportText, report.ok ? "info" : "warning");
|
|
829
|
-
|
|
830
|
-
if (mode === "heal") {
|
|
831
|
-
const unresolved = filterDoctorIssues(report.issues, {
|
|
832
|
-
scope: effectiveScope,
|
|
833
|
-
includeWarnings: true,
|
|
834
|
-
});
|
|
835
|
-
const actionable = unresolved.filter(issue => issue.severity === "error" || issue.code === "all_tasks_done_missing_slice_uat" || issue.code === "slice_checked_missing_uat");
|
|
836
|
-
if (actionable.length === 0) {
|
|
837
|
-
ctx.ui.notify("Doctor heal found nothing actionable to hand off to the LLM.", "info");
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
const structuredIssues = formatDoctorIssuesForPrompt(actionable);
|
|
842
|
-
dispatchDoctorHeal(pi, effectiveScope, reportText, structuredIssues);
|
|
843
|
-
ctx.ui.notify(`Doctor heal dispatched ${actionable.length} issue(s) to the LLM.`, "info");
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// ─── Inspect ──────────────────────────────────────────────────────────────────
|
|
848
|
-
|
|
849
|
-
export interface InspectData {
|
|
850
|
-
schemaVersion: number | null;
|
|
851
|
-
counts: { decisions: number; requirements: number; artifacts: number };
|
|
852
|
-
recentDecisions: Array<{ id: string; decision: string; choice: string }>;
|
|
853
|
-
recentRequirements: Array<{ id: string; status: string; description: string }>;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
export function formatInspectOutput(data: InspectData): string {
|
|
857
|
-
const lines: string[] = [];
|
|
858
|
-
lines.push("=== GSD Database Inspect ===");
|
|
859
|
-
lines.push(`Schema version: ${data.schemaVersion ?? "unknown"}`);
|
|
860
|
-
lines.push("");
|
|
861
|
-
lines.push(`Decisions: ${data.counts.decisions}`);
|
|
862
|
-
lines.push(`Requirements: ${data.counts.requirements}`);
|
|
863
|
-
lines.push(`Artifacts: ${data.counts.artifacts}`);
|
|
864
|
-
|
|
865
|
-
if (data.recentDecisions.length > 0) {
|
|
866
|
-
lines.push("");
|
|
867
|
-
lines.push("Recent decisions:");
|
|
868
|
-
for (const d of data.recentDecisions) {
|
|
869
|
-
lines.push(` ${d.id}: ${d.decision} → ${d.choice}`);
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
if (data.recentRequirements.length > 0) {
|
|
874
|
-
lines.push("");
|
|
875
|
-
lines.push("Recent requirements:");
|
|
876
|
-
for (const r of data.recentRequirements) {
|
|
877
|
-
lines.push(` ${r.id} [${r.status}]: ${r.description}`);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
return lines.join("\n");
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
async function handleInspect(ctx: ExtensionCommandContext): Promise<void> {
|
|
885
|
-
try {
|
|
886
|
-
const { isDbAvailable, _getAdapter } = await import("./gsd-db.js");
|
|
887
|
-
|
|
888
|
-
if (!isDbAvailable()) {
|
|
889
|
-
ctx.ui.notify("No GSD database available. Run /gsd auto to create one.", "info");
|
|
890
|
-
return;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
const adapter = _getAdapter();
|
|
894
|
-
if (!adapter) {
|
|
895
|
-
ctx.ui.notify("No GSD database available. Run /gsd auto to create one.", "info");
|
|
896
|
-
return;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
const versionRow = adapter.prepare("SELECT MAX(version) as v FROM schema_version").get();
|
|
900
|
-
const schemaVersion = versionRow ? (versionRow["v"] as number | null) : null;
|
|
901
|
-
|
|
902
|
-
const dCount = adapter.prepare("SELECT count(*) as cnt FROM decisions").get();
|
|
903
|
-
const rCount = adapter.prepare("SELECT count(*) as cnt FROM requirements").get();
|
|
904
|
-
const aCount = adapter.prepare("SELECT count(*) as cnt FROM artifacts").get();
|
|
905
|
-
|
|
906
|
-
const recentDecisions = adapter
|
|
907
|
-
.prepare("SELECT id, decision, choice FROM decisions ORDER BY seq DESC LIMIT 5")
|
|
908
|
-
.all() as Array<{ id: string; decision: string; choice: string }>;
|
|
909
|
-
|
|
910
|
-
const recentRequirements = adapter
|
|
911
|
-
.prepare("SELECT id, status, description FROM requirements ORDER BY id DESC LIMIT 5")
|
|
912
|
-
.all() as Array<{ id: string; status: string; description: string }>;
|
|
913
|
-
|
|
914
|
-
const data: InspectData = {
|
|
915
|
-
schemaVersion,
|
|
916
|
-
counts: {
|
|
917
|
-
decisions: (dCount?.["cnt"] as number) ?? 0,
|
|
918
|
-
requirements: (rCount?.["cnt"] as number) ?? 0,
|
|
919
|
-
artifacts: (aCount?.["cnt"] as number) ?? 0,
|
|
920
|
-
},
|
|
921
|
-
recentDecisions,
|
|
922
|
-
recentRequirements,
|
|
923
|
-
};
|
|
924
|
-
|
|
925
|
-
ctx.ui.notify(formatInspectOutput(data), "info");
|
|
926
|
-
} catch (err) {
|
|
927
|
-
process.stderr.write(`gsd-db: /gsd inspect failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
928
|
-
ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
// ─── Skill Health ─────────────────────────────────────────────────────────────
|
|
933
|
-
|
|
934
|
-
async function handleSkillHealth(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
935
|
-
const {
|
|
936
|
-
generateSkillHealthReport,
|
|
937
|
-
formatSkillHealthReport,
|
|
938
|
-
formatSkillDetail,
|
|
939
|
-
} = await import("./skill-health.js");
|
|
940
|
-
|
|
941
|
-
const basePath = projectRoot();
|
|
942
|
-
|
|
943
|
-
// /gsd skill-health <skill-name> — detail view
|
|
944
|
-
if (args && !args.startsWith("--")) {
|
|
945
|
-
const detail = formatSkillDetail(basePath, args);
|
|
946
|
-
ctx.ui.notify(detail, "info");
|
|
959
|
+
if (args === "keys") {
|
|
960
|
+
const { handleKeys } = await import("./key-manager.js");
|
|
961
|
+
await handleKeys("", ctx);
|
|
947
962
|
return;
|
|
948
963
|
}
|
|
949
964
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
const decliningOnly = args.includes("--declining");
|
|
954
|
-
|
|
955
|
-
const report = generateSkillHealthReport(basePath, staleDays);
|
|
956
|
-
|
|
957
|
-
if (decliningOnly) {
|
|
958
|
-
if (report.decliningSkills.length === 0) {
|
|
959
|
-
ctx.ui.notify("No skills flagged for declining performance.", "info");
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
const filtered = {
|
|
963
|
-
...report,
|
|
964
|
-
skills: report.skills.filter(s => s.flagged),
|
|
965
|
-
};
|
|
966
|
-
ctx.ui.notify(formatSkillHealthReport(filtered), "info");
|
|
965
|
+
if (args === "prefs") {
|
|
966
|
+
await ensurePreferencesFile(getGlobalGSDPreferencesPath(), ctx, "global");
|
|
967
|
+
await handlePrefsWizard(ctx, "global");
|
|
967
968
|
return;
|
|
968
969
|
}
|
|
969
970
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
// Models
|
|
982
|
-
const models = prefs.models as Record<string, string> | undefined;
|
|
983
|
-
let modelsSummary = "(not configured)";
|
|
984
|
-
if (models && Object.keys(models).length > 0) {
|
|
985
|
-
const parts = Object.entries(models).map(([phase, model]) => `${phase}: ${model}`);
|
|
986
|
-
modelsSummary = parts.join(", ");
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// Timeouts
|
|
990
|
-
const autoSup = prefs.auto_supervisor as Record<string, unknown> | undefined;
|
|
991
|
-
let timeoutsSummary = "(defaults)";
|
|
992
|
-
if (autoSup && Object.keys(autoSup).length > 0) {
|
|
993
|
-
const soft = autoSup.soft_timeout_minutes ?? "20";
|
|
994
|
-
const idle = autoSup.idle_timeout_minutes ?? "10";
|
|
995
|
-
const hard = autoSup.hard_timeout_minutes ?? "30";
|
|
996
|
-
timeoutsSummary = `soft: ${soft}m, idle: ${idle}m, hard: ${hard}m`;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
// Git
|
|
1000
|
-
const git = prefs.git as Record<string, unknown> | undefined;
|
|
1001
|
-
let gitSummary = "(defaults)";
|
|
1002
|
-
if (git && Object.keys(git).length > 0) {
|
|
1003
|
-
const branch = git.main_branch ?? "main";
|
|
1004
|
-
const push = git.auto_push ? "on" : "off";
|
|
1005
|
-
gitSummary = `main: ${branch}, push: ${push}`;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
// Skills
|
|
1009
|
-
const discovery = prefs.skill_discovery as string | undefined;
|
|
1010
|
-
const uat = prefs.uat_dispatch;
|
|
1011
|
-
let skillsSummary = "(not configured)";
|
|
1012
|
-
if (discovery || uat !== undefined) {
|
|
1013
|
-
const parts: string[] = [];
|
|
1014
|
-
if (discovery) parts.push(`discovery: ${discovery}`);
|
|
1015
|
-
if (uat !== undefined) parts.push(`uat: ${uat}`);
|
|
1016
|
-
skillsSummary = parts.join(", ");
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// Budget
|
|
1020
|
-
const ceiling = prefs.budget_ceiling;
|
|
1021
|
-
const enforcement = prefs.budget_enforcement as string | undefined;
|
|
1022
|
-
let budgetSummary = "(no limit)";
|
|
1023
|
-
if (ceiling !== undefined) {
|
|
1024
|
-
budgetSummary = `$${ceiling}`;
|
|
1025
|
-
if (enforcement) budgetSummary += ` / ${enforcement}`;
|
|
1026
|
-
} else if (enforcement) {
|
|
1027
|
-
budgetSummary = enforcement;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
// Notifications
|
|
1031
|
-
const notif = prefs.notifications as Record<string, boolean> | undefined;
|
|
1032
|
-
let notifSummary = "(defaults)";
|
|
1033
|
-
if (notif && Object.keys(notif).length > 0) {
|
|
1034
|
-
const allKeys = ["enabled", "on_complete", "on_error", "on_budget", "on_milestone", "on_attention"];
|
|
1035
|
-
const enabledCount = allKeys.filter(k => notif[k] !== false).length;
|
|
1036
|
-
notifSummary = `${enabledCount}/${allKeys.length} enabled`;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// Advanced
|
|
1040
|
-
const uniqueIds = prefs.unique_milestone_ids;
|
|
1041
|
-
let advancedSummary = "(defaults)";
|
|
1042
|
-
if (uniqueIds !== undefined) {
|
|
1043
|
-
advancedSummary = `unique IDs: ${uniqueIds ? "on" : "off"}`;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
return {
|
|
1047
|
-
mode: modeSummary,
|
|
1048
|
-
models: modelsSummary,
|
|
1049
|
-
timeouts: timeoutsSummary,
|
|
1050
|
-
git: gitSummary,
|
|
1051
|
-
skills: skillsSummary,
|
|
1052
|
-
budget: budgetSummary,
|
|
1053
|
-
notifications: notifSummary,
|
|
1054
|
-
advanced: advancedSummary,
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// ─── Category configuration functions ────────────────────────────────────────
|
|
1059
|
-
|
|
1060
|
-
async function configureModels(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1061
|
-
const modelPhases = ["research", "planning", "execution", "completion"] as const;
|
|
1062
|
-
const models: Record<string, string> = (prefs.models as Record<string, string>) ?? {};
|
|
1063
|
-
|
|
1064
|
-
const availableModels = ctx.modelRegistry.getAvailable();
|
|
1065
|
-
if (availableModels.length > 0) {
|
|
1066
|
-
const modelOptions = availableModels.map(m => `${m.id} · ${m.provider}`);
|
|
1067
|
-
modelOptions.push("(keep current)", "(clear)");
|
|
1068
|
-
|
|
1069
|
-
for (const phase of modelPhases) {
|
|
1070
|
-
const current = models[phase] ?? "";
|
|
1071
|
-
const title = `Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`;
|
|
1072
|
-
const choice = await ctx.ui.select(title, modelOptions);
|
|
1073
|
-
|
|
1074
|
-
if (choice && typeof choice === "string" && choice !== "(keep current)") {
|
|
1075
|
-
if (choice === "(clear)") {
|
|
1076
|
-
delete models[phase];
|
|
1077
|
-
} else {
|
|
1078
|
-
models[phase] = choice.split(" · ")[0];
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
} else {
|
|
1083
|
-
for (const phase of modelPhases) {
|
|
1084
|
-
const current = models[phase] ?? "";
|
|
1085
|
-
const input = await ctx.ui.input(
|
|
1086
|
-
`Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`,
|
|
1087
|
-
current || "e.g. claude-sonnet-4-20250514",
|
|
1088
|
-
);
|
|
1089
|
-
if (input !== null && input !== undefined) {
|
|
1090
|
-
const val = input.trim();
|
|
1091
|
-
if (val) {
|
|
1092
|
-
models[phase] = val;
|
|
1093
|
-
} else if (current) {
|
|
1094
|
-
delete models[phase];
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
if (Object.keys(models).length > 0) {
|
|
1100
|
-
prefs.models = models;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
async function configureTimeouts(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1105
|
-
const autoSup: Record<string, unknown> = (prefs.auto_supervisor as Record<string, unknown>) ?? {};
|
|
1106
|
-
const timeoutFields = [
|
|
1107
|
-
{ key: "soft_timeout_minutes", label: "Soft timeout (minutes)", defaultVal: "20" },
|
|
1108
|
-
{ key: "idle_timeout_minutes", label: "Idle timeout (minutes)", defaultVal: "10" },
|
|
1109
|
-
{ key: "hard_timeout_minutes", label: "Hard timeout (minutes)", defaultVal: "30" },
|
|
1110
|
-
] as const;
|
|
1111
|
-
|
|
1112
|
-
for (const field of timeoutFields) {
|
|
1113
|
-
const current = autoSup[field.key];
|
|
1114
|
-
const currentStr = current !== undefined && current !== null ? String(current) : "";
|
|
1115
|
-
const input = await ctx.ui.input(
|
|
1116
|
-
`${field.label}${currentStr ? ` (current: ${currentStr})` : ` (default: ${field.defaultVal})`}:`,
|
|
1117
|
-
currentStr || field.defaultVal,
|
|
1118
|
-
);
|
|
1119
|
-
if (input !== null && input !== undefined) {
|
|
1120
|
-
const val = input.trim();
|
|
1121
|
-
if (val && /^\d+$/.test(val)) {
|
|
1122
|
-
autoSup[field.key] = Number(val);
|
|
1123
|
-
} else if (val && !/^\d+$/.test(val)) {
|
|
1124
|
-
ctx.ui.notify(`Invalid value "${val}" for ${field.label} — must be a whole number. Keeping previous value.`, "warning");
|
|
1125
|
-
} else if (!val && currentStr) {
|
|
1126
|
-
delete autoSup[field.key];
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
if (Object.keys(autoSup).length > 0) {
|
|
1131
|
-
prefs.auto_supervisor = autoSup;
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
async function configureGit(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1136
|
-
const git: Record<string, unknown> = (prefs.git as Record<string, unknown>) ?? {};
|
|
1137
|
-
|
|
1138
|
-
// main_branch
|
|
1139
|
-
const currentBranch = git.main_branch ? String(git.main_branch) : "";
|
|
1140
|
-
const branchInput = await ctx.ui.input(
|
|
1141
|
-
`Git main branch${currentBranch ? ` (current: ${currentBranch})` : ""}:`,
|
|
1142
|
-
currentBranch || "main",
|
|
1143
|
-
);
|
|
1144
|
-
if (branchInput !== null && branchInput !== undefined) {
|
|
1145
|
-
const val = branchInput.trim();
|
|
1146
|
-
if (val) {
|
|
1147
|
-
git.main_branch = val;
|
|
1148
|
-
} else if (currentBranch) {
|
|
1149
|
-
delete git.main_branch;
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// Boolean git toggles
|
|
1154
|
-
const gitBooleanFields = [
|
|
1155
|
-
{ key: "auto_push", label: "Auto-push commits after committing", defaultVal: false },
|
|
1156
|
-
{ key: "push_branches", label: "Push milestone branches to remote", defaultVal: false },
|
|
1157
|
-
{ key: "snapshots", label: "Create WIP snapshot commits during long tasks", defaultVal: false },
|
|
1158
|
-
] as const;
|
|
1159
|
-
|
|
1160
|
-
for (const field of gitBooleanFields) {
|
|
1161
|
-
const current = git[field.key];
|
|
1162
|
-
const currentStr = current !== undefined ? String(current) : "";
|
|
1163
|
-
const choice = await ctx.ui.select(
|
|
1164
|
-
`${field.label}${currentStr ? ` (current: ${currentStr})` : ` (default: ${field.defaultVal})`}:`,
|
|
1165
|
-
["true", "false", "(keep current)"],
|
|
1166
|
-
);
|
|
1167
|
-
if (choice && choice !== "(keep current)") {
|
|
1168
|
-
git[field.key] = choice === "true";
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
// remote
|
|
1173
|
-
const currentRemote = git.remote ? String(git.remote) : "";
|
|
1174
|
-
const remoteInput = await ctx.ui.input(
|
|
1175
|
-
`Git remote name${currentRemote ? ` (current: ${currentRemote})` : " (default: origin)"}:`,
|
|
1176
|
-
currentRemote || "origin",
|
|
1177
|
-
);
|
|
1178
|
-
if (remoteInput !== null && remoteInput !== undefined) {
|
|
1179
|
-
const val = remoteInput.trim();
|
|
1180
|
-
if (val && val !== "origin") {
|
|
1181
|
-
git.remote = val;
|
|
1182
|
-
} else if (!val && currentRemote) {
|
|
1183
|
-
delete git.remote;
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
// pre_merge_check
|
|
1188
|
-
const currentPreMerge = git.pre_merge_check !== undefined ? String(git.pre_merge_check) : "";
|
|
1189
|
-
const preMergeChoice = await ctx.ui.select(
|
|
1190
|
-
`Pre-merge check${currentPreMerge ? ` (current: ${currentPreMerge})` : " (default: false)"}:`,
|
|
1191
|
-
["true", "false", "auto", "(keep current)"],
|
|
1192
|
-
);
|
|
1193
|
-
if (preMergeChoice && preMergeChoice !== "(keep current)") {
|
|
1194
|
-
if (preMergeChoice === "auto") {
|
|
1195
|
-
git.pre_merge_check = "auto";
|
|
1196
|
-
} else {
|
|
1197
|
-
git.pre_merge_check = preMergeChoice === "true";
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
// commit_type
|
|
1202
|
-
const currentCommitType = git.commit_type ? String(git.commit_type) : "";
|
|
1203
|
-
const commitTypes = ["feat", "fix", "refactor", "docs", "test", "chore", "perf", "ci", "build", "style", "(inferred — default)", "(keep current)"];
|
|
1204
|
-
const commitChoice = await ctx.ui.select(
|
|
1205
|
-
`Default commit type${currentCommitType ? ` (current: ${currentCommitType})` : ""}:`,
|
|
1206
|
-
commitTypes,
|
|
1207
|
-
);
|
|
1208
|
-
if (commitChoice && typeof commitChoice === "string" && commitChoice !== "(keep current)") {
|
|
1209
|
-
if ((commitChoice as string).startsWith("(inferred")) {
|
|
1210
|
-
delete git.commit_type;
|
|
1211
|
-
} else {
|
|
1212
|
-
git.commit_type = commitChoice;
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
// merge_strategy
|
|
1217
|
-
const currentMerge = git.merge_strategy ? String(git.merge_strategy) : "";
|
|
1218
|
-
const mergeChoice = await ctx.ui.select(
|
|
1219
|
-
`Merge strategy${currentMerge ? ` (current: ${currentMerge})` : ""}:`,
|
|
1220
|
-
["squash", "merge", "(keep current)"],
|
|
1221
|
-
);
|
|
1222
|
-
if (mergeChoice && mergeChoice !== "(keep current)") {
|
|
1223
|
-
git.merge_strategy = mergeChoice;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
// isolation
|
|
1227
|
-
const currentIsolation = git.isolation ? String(git.isolation) : "";
|
|
1228
|
-
const isolationChoice = await ctx.ui.select(
|
|
1229
|
-
`Git isolation strategy${currentIsolation ? ` (current: ${currentIsolation})` : " (default: worktree)"}:`,
|
|
1230
|
-
["worktree", "branch", "none", "(keep current)"],
|
|
1231
|
-
);
|
|
1232
|
-
if (isolationChoice && isolationChoice !== "(keep current)") {
|
|
1233
|
-
git.isolation = isolationChoice;
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
// commit_docs
|
|
1237
|
-
const currentCommitDocs = git.commit_docs;
|
|
1238
|
-
const commitDocsChoice = await ctx.ui.select(
|
|
1239
|
-
`Track .gsd/ planning docs in git${currentCommitDocs !== undefined ? ` (current: ${currentCommitDocs})` : ""}:`,
|
|
1240
|
-
["true", "false", "(keep current)"],
|
|
1241
|
-
);
|
|
1242
|
-
if (commitDocsChoice && commitDocsChoice !== "(keep current)") {
|
|
1243
|
-
git.commit_docs = commitDocsChoice === "true";
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
if (Object.keys(git).length > 0) {
|
|
1247
|
-
prefs.git = git;
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
async function configureSkills(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1252
|
-
// Skill discovery mode
|
|
1253
|
-
const currentDiscovery = (prefs.skill_discovery as string) ?? "";
|
|
1254
|
-
const discoveryChoice = await ctx.ui.select(
|
|
1255
|
-
`Skill discovery mode${currentDiscovery ? ` (current: ${currentDiscovery})` : ""}:`,
|
|
1256
|
-
["auto", "suggest", "off", "(keep current)"],
|
|
1257
|
-
);
|
|
1258
|
-
if (discoveryChoice && discoveryChoice !== "(keep current)") {
|
|
1259
|
-
prefs.skill_discovery = discoveryChoice;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
// UAT dispatch
|
|
1263
|
-
const currentUat = prefs.uat_dispatch;
|
|
1264
|
-
const uatChoice = await ctx.ui.select(
|
|
1265
|
-
`UAT dispatch mode${currentUat !== undefined ? ` (current: ${currentUat})` : " (default: false)"}:`,
|
|
1266
|
-
["true", "false", "(keep current)"],
|
|
1267
|
-
);
|
|
1268
|
-
if (uatChoice && uatChoice !== "(keep current)") {
|
|
1269
|
-
prefs.uat_dispatch = uatChoice === "true";
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
async function configureBudget(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1274
|
-
const currentCeiling = prefs.budget_ceiling;
|
|
1275
|
-
const ceilingStr = currentCeiling !== undefined ? String(currentCeiling) : "";
|
|
1276
|
-
const ceilingInput = await ctx.ui.input(
|
|
1277
|
-
`Budget ceiling (USD)${ceilingStr ? ` (current: $${ceilingStr})` : " (default: no limit)"}:`,
|
|
1278
|
-
ceilingStr || "",
|
|
1279
|
-
);
|
|
1280
|
-
if (ceilingInput !== null && ceilingInput !== undefined) {
|
|
1281
|
-
const val = ceilingInput.trim().replace(/^\$/, "");
|
|
1282
|
-
if (val && !isNaN(Number(val)) && isFinite(Number(val))) {
|
|
1283
|
-
prefs.budget_ceiling = Number(val);
|
|
1284
|
-
} else if (val && (isNaN(Number(val)) || !isFinite(Number(val)))) {
|
|
1285
|
-
ctx.ui.notify(`Invalid budget ceiling "${val}" — must be a number. Keeping previous value.`, "warning");
|
|
1286
|
-
} else if (!val && ceilingStr) {
|
|
1287
|
-
delete prefs.budget_ceiling;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
const currentEnforcement = (prefs.budget_enforcement as string) ?? "";
|
|
1292
|
-
const enforcementChoice = await ctx.ui.select(
|
|
1293
|
-
`Budget enforcement${currentEnforcement ? ` (current: ${currentEnforcement})` : " (default: pause)"}:`,
|
|
1294
|
-
["warn", "pause", "halt", "(keep current)"],
|
|
1295
|
-
);
|
|
1296
|
-
if (enforcementChoice && enforcementChoice !== "(keep current)") {
|
|
1297
|
-
prefs.budget_enforcement = enforcementChoice;
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
const currentContextPause = prefs.context_pause_threshold;
|
|
1301
|
-
const contextPauseStr = currentContextPause !== undefined ? String(currentContextPause) : "";
|
|
1302
|
-
const contextPauseInput = await ctx.ui.input(
|
|
1303
|
-
`Context pause threshold (0-100%, 0=disabled)${contextPauseStr ? ` (current: ${contextPauseStr}%)` : " (default: 0)"}:`,
|
|
1304
|
-
contextPauseStr || "0",
|
|
1305
|
-
);
|
|
1306
|
-
if (contextPauseInput !== null && contextPauseInput !== undefined) {
|
|
1307
|
-
const val = contextPauseInput.trim().replace(/%$/, "");
|
|
1308
|
-
if (val && !isNaN(Number(val)) && Number(val) >= 0 && Number(val) <= 100) {
|
|
1309
|
-
const num = Number(val);
|
|
1310
|
-
if (num === 0) {
|
|
1311
|
-
delete prefs.context_pause_threshold;
|
|
1312
|
-
} else {
|
|
1313
|
-
prefs.context_pause_threshold = num;
|
|
1314
|
-
}
|
|
1315
|
-
} else if (val && (isNaN(Number(val)) || Number(val) < 0 || Number(val) > 100)) {
|
|
1316
|
-
ctx.ui.notify(`Invalid context pause threshold "${val}" — must be 0-100. Keeping previous value.`, "warning");
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
async function configureNotifications(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1322
|
-
const notif: Record<string, boolean> = (prefs.notifications as Record<string, boolean>) ?? {};
|
|
1323
|
-
const notifFields = [
|
|
1324
|
-
{ key: "enabled", label: "Notifications enabled (master toggle)", defaultVal: true },
|
|
1325
|
-
{ key: "on_complete", label: "Notify on unit completion", defaultVal: true },
|
|
1326
|
-
{ key: "on_error", label: "Notify on errors", defaultVal: true },
|
|
1327
|
-
{ key: "on_budget", label: "Notify on budget thresholds", defaultVal: true },
|
|
1328
|
-
{ key: "on_milestone", label: "Notify on milestone completion", defaultVal: true },
|
|
1329
|
-
{ key: "on_attention", label: "Notify when manual attention needed", defaultVal: true },
|
|
1330
|
-
] as const;
|
|
1331
|
-
|
|
1332
|
-
for (const field of notifFields) {
|
|
1333
|
-
const current = notif[field.key];
|
|
1334
|
-
const currentStr = current !== undefined && typeof current === "boolean" ? String(current) : "";
|
|
1335
|
-
const choice = await ctx.ui.select(
|
|
1336
|
-
`${field.label}${currentStr ? ` (current: ${currentStr})` : ` (default: ${field.defaultVal})`}:`,
|
|
1337
|
-
["true", "false", "(keep current)"],
|
|
1338
|
-
);
|
|
1339
|
-
if (choice && choice !== "(keep current)") {
|
|
1340
|
-
notif[field.key] = choice === "true";
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
if (Object.keys(notif).length > 0) {
|
|
1344
|
-
prefs.notifications = notif;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
async function configureMode(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1349
|
-
const currentMode = prefs.mode as string | undefined;
|
|
1350
|
-
const modeChoice = await ctx.ui.select(
|
|
1351
|
-
`Workflow mode${currentMode ? ` (current: ${currentMode})` : ""}:`,
|
|
1352
|
-
[
|
|
1353
|
-
"solo — auto-push, squash, simple IDs (personal projects)",
|
|
1354
|
-
"team — unique IDs, push branches, pre-merge checks (shared repos)",
|
|
1355
|
-
"(none) — configure everything manually",
|
|
1356
|
-
"(keep current)",
|
|
1357
|
-
],
|
|
1358
|
-
);
|
|
1359
|
-
const modeStr = typeof modeChoice === "string" ? modeChoice : "";
|
|
1360
|
-
if (modeStr && modeStr !== "(keep current)") {
|
|
1361
|
-
if (modeStr.startsWith("solo")) {
|
|
1362
|
-
prefs.mode = "solo";
|
|
1363
|
-
ctx.ui.notify(
|
|
1364
|
-
"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",
|
|
1365
|
-
"info",
|
|
1366
|
-
);
|
|
1367
|
-
} else if (modeStr.startsWith("team")) {
|
|
1368
|
-
prefs.mode = "team";
|
|
1369
|
-
ctx.ui.notify(
|
|
1370
|
-
"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",
|
|
1371
|
-
"info",
|
|
1372
|
-
);
|
|
1373
|
-
} else {
|
|
1374
|
-
delete prefs.mode;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
async function configureAdvanced(ctx: ExtensionCommandContext, prefs: Record<string, unknown>): Promise<void> {
|
|
1380
|
-
const currentUnique = prefs.unique_milestone_ids;
|
|
1381
|
-
const uniqueChoice = await ctx.ui.select(
|
|
1382
|
-
`Unique milestone IDs${currentUnique !== undefined ? ` (current: ${currentUnique})` : ""}:`,
|
|
1383
|
-
["true", "false", "(keep current)"],
|
|
971
|
+
// Full setup summary
|
|
972
|
+
ctx.ui.notify(statusLines.join("\n"), "info");
|
|
973
|
+
ctx.ui.notify(
|
|
974
|
+
"Available setup commands:\n" +
|
|
975
|
+
" /gsd setup llm — LLM authentication\n" +
|
|
976
|
+
" /gsd setup search — Web search provider\n" +
|
|
977
|
+
" /gsd setup remote — Remote questions (Discord/Slack/Telegram)\n" +
|
|
978
|
+
" /gsd setup keys — Tool API keys\n" +
|
|
979
|
+
" /gsd setup prefs — Global preferences wizard",
|
|
980
|
+
"info",
|
|
1384
981
|
);
|
|
1385
|
-
if (uniqueChoice && uniqueChoice !== "(keep current)") {
|
|
1386
|
-
prefs.unique_milestone_ids = uniqueChoice === "true";
|
|
1387
|
-
}
|
|
1388
982
|
}
|
|
1389
983
|
|
|
1390
|
-
// ───
|
|
1391
|
-
|
|
1392
|
-
async function handlePrefsWizard(
|
|
1393
|
-
ctx: ExtensionCommandContext,
|
|
1394
|
-
scope: "global" | "project",
|
|
1395
|
-
): Promise<void> {
|
|
1396
|
-
const path = scope === "project" ? getProjectGSDPreferencesPath() : getGlobalGSDPreferencesPath();
|
|
1397
|
-
const existing = scope === "project" ? loadProjectGSDPreferences() : loadGlobalGSDPreferences();
|
|
1398
|
-
const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
|
|
1399
|
-
|
|
1400
|
-
ctx.ui.notify(`GSD preferences (${scope}) — pick a category to configure.`, "info");
|
|
1401
|
-
|
|
1402
|
-
while (true) {
|
|
1403
|
-
const summaries = buildCategorySummaries(prefs);
|
|
1404
|
-
const options = [
|
|
1405
|
-
`Workflow Mode ${summaries.mode}`,
|
|
1406
|
-
`Models ${summaries.models}`,
|
|
1407
|
-
`Timeouts ${summaries.timeouts}`,
|
|
1408
|
-
`Git ${summaries.git}`,
|
|
1409
|
-
`Skills ${summaries.skills}`,
|
|
1410
|
-
`Budget ${summaries.budget}`,
|
|
1411
|
-
`Notifications ${summaries.notifications}`,
|
|
1412
|
-
`Advanced ${summaries.advanced}`,
|
|
1413
|
-
`── Save & Exit ──`,
|
|
1414
|
-
];
|
|
1415
|
-
|
|
1416
|
-
const raw = await ctx.ui.select("GSD Preferences", options);
|
|
1417
|
-
const choice = typeof raw === "string" ? raw : "";
|
|
1418
|
-
if (!choice || choice.includes("Save & Exit")) break;
|
|
1419
|
-
|
|
1420
|
-
if (choice.startsWith("Workflow Mode")) await configureMode(ctx, prefs);
|
|
1421
|
-
else if (choice.startsWith("Models")) await configureModels(ctx, prefs);
|
|
1422
|
-
else if (choice.startsWith("Timeouts")) await configureTimeouts(ctx, prefs);
|
|
1423
|
-
else if (choice.startsWith("Git")) await configureGit(ctx, prefs);
|
|
1424
|
-
else if (choice.startsWith("Skills")) await configureSkills(ctx, prefs);
|
|
1425
|
-
else if (choice.startsWith("Budget")) await configureBudget(ctx, prefs);
|
|
1426
|
-
else if (choice.startsWith("Notifications")) await configureNotifications(ctx, prefs);
|
|
1427
|
-
else if (choice.startsWith("Advanced")) await configureAdvanced(ctx, prefs);
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
// ─── Serialize to frontmatter ───────────────────────────────────────────
|
|
1431
|
-
prefs.version = prefs.version || 1;
|
|
1432
|
-
const frontmatter = serializePreferencesToFrontmatter(prefs);
|
|
1433
|
-
|
|
1434
|
-
// Preserve existing body content (everything after closing ---)
|
|
1435
|
-
let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
|
|
1436
|
-
if (existsSync(path)) {
|
|
1437
|
-
const existingContent = readFileSync(path, "utf-8");
|
|
1438
|
-
const closingIdx = existingContent.indexOf("\n---", existingContent.indexOf("---"));
|
|
1439
|
-
if (closingIdx !== -1) {
|
|
1440
|
-
const afterFrontmatter = existingContent.slice(closingIdx + 4); // skip past "\n---"
|
|
1441
|
-
if (afterFrontmatter.trim()) {
|
|
1442
|
-
body = afterFrontmatter;
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
const content = `---\n${frontmatter}---${body}`;
|
|
1448
|
-
|
|
1449
|
-
await saveFile(path, content);
|
|
1450
|
-
await ctx.waitForIdle();
|
|
1451
|
-
await ctx.reload();
|
|
1452
|
-
ctx.ui.notify(`Saved ${scope} preferences to ${path}`, "info");
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
/** Wrap a YAML value in double quotes if it contains special characters. */
|
|
1456
|
-
function yamlSafeString(val: unknown): string {
|
|
1457
|
-
if (typeof val !== "string") return String(val);
|
|
1458
|
-
if (/[:#{\[\]'"`,|>&*!?@%]/.test(val) || val.trim() !== val || val === "") {
|
|
1459
|
-
return `"${val.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1460
|
-
}
|
|
1461
|
-
return val;
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
function serializePreferencesToFrontmatter(prefs: Record<string, unknown>): string {
|
|
1465
|
-
const lines: string[] = [];
|
|
1466
|
-
|
|
1467
|
-
function serializeValue(key: string, value: unknown, indent: number): void {
|
|
1468
|
-
const prefix = " ".repeat(indent);
|
|
1469
|
-
if (value === null || value === undefined) return;
|
|
1470
|
-
|
|
1471
|
-
if (Array.isArray(value)) {
|
|
1472
|
-
if (value.length === 0) {
|
|
1473
|
-
return; // Omit empty arrays — avoids parse/serialize cycle bug with "[]" strings
|
|
1474
|
-
}
|
|
1475
|
-
lines.push(`${prefix}${key}:`);
|
|
1476
|
-
for (const item of value) {
|
|
1477
|
-
if (typeof item === "object" && item !== null) {
|
|
1478
|
-
const entries = Object.entries(item as Record<string, unknown>);
|
|
1479
|
-
if (entries.length > 0) {
|
|
1480
|
-
const [firstKey, firstVal] = entries[0];
|
|
1481
|
-
lines.push(`${prefix} - ${firstKey}: ${yamlSafeString(firstVal)}`);
|
|
1482
|
-
for (let i = 1; i < entries.length; i++) {
|
|
1483
|
-
const [k, v] = entries[i];
|
|
1484
|
-
if (Array.isArray(v)) {
|
|
1485
|
-
lines.push(`${prefix} ${k}:`);
|
|
1486
|
-
for (const arrItem of v) {
|
|
1487
|
-
lines.push(`${prefix} - ${yamlSafeString(arrItem)}`);
|
|
1488
|
-
}
|
|
1489
|
-
} else {
|
|
1490
|
-
lines.push(`${prefix} ${k}: ${yamlSafeString(v)}`);
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
} else {
|
|
1495
|
-
lines.push(`${prefix} - ${yamlSafeString(item)}`);
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
return;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
if (typeof value === "object") {
|
|
1502
|
-
const entries = Object.entries(value as Record<string, unknown>);
|
|
1503
|
-
if (entries.length === 0) {
|
|
1504
|
-
return; // Omit empty objects — avoids parse/serialize cycle bug with "{}" strings
|
|
1505
|
-
}
|
|
1506
|
-
lines.push(`${prefix}${key}:`);
|
|
1507
|
-
for (const [k, v] of entries) {
|
|
1508
|
-
serializeValue(k, v, indent + 1);
|
|
1509
|
-
}
|
|
1510
|
-
return;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
lines.push(`${prefix}${key}: ${yamlSafeString(value)}`);
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// Ordered keys for consistent output
|
|
1517
|
-
const orderedKeys = [
|
|
1518
|
-
"version", "mode", "always_use_skills", "prefer_skills", "avoid_skills",
|
|
1519
|
-
"skill_rules", "custom_instructions", "models", "skill_discovery",
|
|
1520
|
-
"auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
|
1521
|
-
"budget_ceiling", "budget_enforcement", "context_pause_threshold",
|
|
1522
|
-
"notifications", "remote_questions", "git",
|
|
1523
|
-
"post_unit_hooks", "pre_dispatch_hooks",
|
|
1524
|
-
];
|
|
1525
|
-
|
|
1526
|
-
const seen = new Set<string>();
|
|
1527
|
-
for (const key of orderedKeys) {
|
|
1528
|
-
if (key in prefs) {
|
|
1529
|
-
serializeValue(key, prefs[key], 0);
|
|
1530
|
-
seen.add(key);
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
// Any remaining keys not in the ordered list
|
|
1534
|
-
for (const [key, value] of Object.entries(prefs)) {
|
|
1535
|
-
if (!seen.has(key)) {
|
|
1536
|
-
serializeValue(key, value, 0);
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
return lines.join("\n") + "\n";
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
// ─── Tool Config Wizard ───────────────────────────────────────────────────────
|
|
984
|
+
// ─── Text-based status for RPC mode ────────────────────────────────────────
|
|
1544
985
|
|
|
1545
986
|
/**
|
|
1546
|
-
*
|
|
1547
|
-
*
|
|
1548
|
-
* and session startup to load keys from auth.json into environment variables.
|
|
987
|
+
* Generate a text-based status summary for non-TUI environments (RPC mode).
|
|
988
|
+
* Used as a fallback when the interactive dashboard overlay is unavailable.
|
|
1549
989
|
*/
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
{ id: "brave", env: "BRAVE_API_KEY", label: "Brave Search", hint: "brave.com/search/api" },
|
|
1553
|
-
{ id: "context7", env: "CONTEXT7_API_KEY", label: "Context7 Docs", hint: "context7.com/dashboard" },
|
|
1554
|
-
{ id: "jina", env: "JINA_API_KEY", label: "Jina Page Extract", hint: "jina.ai/api" },
|
|
1555
|
-
{ id: "groq", env: "GROQ_API_KEY", label: "Groq Voice", hint: "console.groq.com" },
|
|
1556
|
-
] as const;
|
|
1557
|
-
|
|
1558
|
-
/**
|
|
1559
|
-
* Load tool API keys from auth.json into environment variables.
|
|
1560
|
-
* Called at session startup to ensure tools have access to their credentials.
|
|
1561
|
-
*/
|
|
1562
|
-
export function loadToolApiKeys(): void {
|
|
1563
|
-
try {
|
|
1564
|
-
const authPath = join(process.env.HOME ?? "", ".gsd", "agent", "auth.json");
|
|
1565
|
-
if (!existsSync(authPath)) return;
|
|
1566
|
-
|
|
1567
|
-
const auth = AuthStorage.create(authPath);
|
|
1568
|
-
for (const tool of TOOL_KEYS) {
|
|
1569
|
-
const cred = auth.get(tool.id);
|
|
1570
|
-
if (cred && cred.type === "api_key" && cred.key && !process.env[tool.env]) {
|
|
1571
|
-
process.env[tool.env] = cred.key;
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
} catch {
|
|
1575
|
-
// Failed to load tool keys — ignore, they can still be set via env vars
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
function getConfigAuthStorage(): AuthStorage {
|
|
1580
|
-
const authPath = join(process.env.HOME ?? "", ".gsd", "agent", "auth.json");
|
|
1581
|
-
mkdirSync(dirname(authPath), { recursive: true });
|
|
1582
|
-
return AuthStorage.create(authPath);
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
async function handleConfig(ctx: ExtensionCommandContext): Promise<void> {
|
|
1586
|
-
const auth = getConfigAuthStorage();
|
|
1587
|
-
|
|
1588
|
-
// Show current status
|
|
1589
|
-
const statusLines = ["GSD Tool Configuration\n"];
|
|
1590
|
-
for (const tool of TOOL_KEYS) {
|
|
1591
|
-
const hasKey = !!process.env[tool.env] || !!(auth.get(tool.id) as { key?: string })?.key;
|
|
1592
|
-
statusLines.push(` ${hasKey ? "✓" : "✗"} ${tool.label}${hasKey ? "" : ` — get key at ${tool.hint}`}`);
|
|
1593
|
-
}
|
|
1594
|
-
ctx.ui.notify(statusLines.join("\n"), "info");
|
|
1595
|
-
|
|
1596
|
-
// Ask which tools to configure
|
|
1597
|
-
const options = TOOL_KEYS.map(t => {
|
|
1598
|
-
const hasKey = !!process.env[t.env] || !!(auth.get(t.id) as { key?: string })?.key;
|
|
1599
|
-
return `${t.label} ${hasKey ? "(configured ✓)" : "(not set)"}`;
|
|
1600
|
-
});
|
|
1601
|
-
options.push("(done)");
|
|
1602
|
-
|
|
1603
|
-
let changed = false;
|
|
1604
|
-
while (true) {
|
|
1605
|
-
const choice = await ctx.ui.select("Configure which tool? Press Escape when done.", options);
|
|
1606
|
-
if (!choice || typeof choice !== "string" || choice === "(done)") break;
|
|
1607
|
-
|
|
1608
|
-
const toolIdx = TOOL_KEYS.findIndex(t => choice.startsWith(t.label));
|
|
1609
|
-
if (toolIdx === -1) break;
|
|
1610
|
-
|
|
1611
|
-
const tool = TOOL_KEYS[toolIdx];
|
|
1612
|
-
const input = await ctx.ui.input(
|
|
1613
|
-
`API key for ${tool.label} (${tool.hint}):`,
|
|
1614
|
-
"paste your key here",
|
|
1615
|
-
);
|
|
1616
|
-
|
|
1617
|
-
if (input !== null && input !== undefined) {
|
|
1618
|
-
const key = input.trim();
|
|
1619
|
-
if (key) {
|
|
1620
|
-
auth.set(tool.id, { type: "api_key", key });
|
|
1621
|
-
process.env[tool.env] = key;
|
|
1622
|
-
ctx.ui.notify(`${tool.label} key saved and activated.`, "info");
|
|
1623
|
-
// Update option label
|
|
1624
|
-
options[toolIdx] = `${tool.label} (configured ✓)`;
|
|
1625
|
-
changed = true;
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
if (changed) {
|
|
1631
|
-
await ctx.waitForIdle();
|
|
1632
|
-
await ctx.reload();
|
|
1633
|
-
ctx.ui.notify("Configuration saved. Extensions reloaded with new keys.", "info");
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
async function ensurePreferencesFile(
|
|
1638
|
-
path: string,
|
|
1639
|
-
ctx: ExtensionCommandContext,
|
|
1640
|
-
scope: "global" | "project",
|
|
1641
|
-
): Promise<void> {
|
|
1642
|
-
if (!existsSync(path)) {
|
|
1643
|
-
const template = await loadFile(join(dirname(fileURLToPath(import.meta.url)), "templates", "preferences.md"));
|
|
1644
|
-
if (!template) {
|
|
1645
|
-
ctx.ui.notify("Could not load GSD preferences template.", "error");
|
|
1646
|
-
return;
|
|
1647
|
-
}
|
|
1648
|
-
await saveFile(path, template);
|
|
1649
|
-
ctx.ui.notify(`Created ${scope} GSD skill preferences at ${path}`, "info");
|
|
1650
|
-
} else {
|
|
1651
|
-
ctx.ui.notify(`Using existing ${scope} GSD skill preferences at ${path}`, "info");
|
|
1652
|
-
}
|
|
990
|
+
function formatTextStatus(state: GSDState): string {
|
|
991
|
+
const lines: string[] = ["GSD Status\n"];
|
|
1653
992
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
// ─── Skip handler ─────────────────────────────────────────────────────────────
|
|
993
|
+
// Phase
|
|
994
|
+
lines.push(`Phase: ${state.phase}`);
|
|
1657
995
|
|
|
1658
|
-
|
|
1659
|
-
if (
|
|
1660
|
-
|
|
1661
|
-
return;
|
|
996
|
+
// Active milestone
|
|
997
|
+
if (state.activeMilestone) {
|
|
998
|
+
lines.push(`Active milestone: ${state.activeMilestone.id} — ${state.activeMilestone.title}`);
|
|
1662
999
|
}
|
|
1663
1000
|
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
const completedKeysFile = pathJoin(basePath, ".gsd", "completed-units.json");
|
|
1668
|
-
let keys: string[] = [];
|
|
1669
|
-
try {
|
|
1670
|
-
if (fileExists(completedKeysFile)) {
|
|
1671
|
-
keys = JSON.parse(readFile(completedKeysFile, "utf-8"));
|
|
1672
|
-
}
|
|
1673
|
-
} catch { /* start fresh */ }
|
|
1674
|
-
|
|
1675
|
-
// Normalize: accept "execute-task/M001/S01/T03", "M001/S01/T03", or just "T03"
|
|
1676
|
-
let skipKey = unitArg;
|
|
1677
|
-
|
|
1678
|
-
if (!skipKey.includes("execute-task") && !skipKey.includes("plan-") && !skipKey.includes("research-") && !skipKey.includes("complete-")) {
|
|
1679
|
-
const state = await deriveState(basePath);
|
|
1680
|
-
const mid = state.activeMilestone?.id;
|
|
1681
|
-
const sid = state.activeSlice?.id;
|
|
1682
|
-
|
|
1683
|
-
if (unitArg.match(/^T\d+$/i) && mid && sid) {
|
|
1684
|
-
skipKey = `execute-task/${mid}/${sid}/${unitArg.toUpperCase()}`;
|
|
1685
|
-
} else if (unitArg.match(/^S\d+$/i) && mid) {
|
|
1686
|
-
skipKey = `plan-slice/${mid}/${unitArg.toUpperCase()}`;
|
|
1687
|
-
} else if (unitArg.includes("/")) {
|
|
1688
|
-
skipKey = `execute-task/${unitArg}`;
|
|
1689
|
-
}
|
|
1001
|
+
// Active slice / task
|
|
1002
|
+
if (state.activeSlice) {
|
|
1003
|
+
lines.push(`Active slice: ${state.activeSlice.id} — ${state.activeSlice.title}`);
|
|
1690
1004
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
ctx.ui.notify(`Already skipped: ${skipKey}`, "info");
|
|
1694
|
-
return;
|
|
1005
|
+
if (state.activeTask) {
|
|
1006
|
+
lines.push(`Active task: ${state.activeTask.id} — ${state.activeTask.title}`);
|
|
1695
1007
|
}
|
|
1696
1008
|
|
|
1697
|
-
|
|
1698
|
-
mkDir(pathJoin(basePath, ".gsd"), { recursive: true });
|
|
1699
|
-
writeFile(completedKeysFile, JSON.stringify(keys), "utf-8");
|
|
1700
|
-
|
|
1701
|
-
ctx.ui.notify(`Skipped: ${skipKey}. Will not be dispatched in auto-mode.`, "success");
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
// ─── Dry-run handler ──────────────────────────────────────────────────────────
|
|
1705
|
-
|
|
1706
|
-
async function handleDryRun(ctx: ExtensionCommandContext, basePath: string): Promise<void> {
|
|
1707
|
-
const state = await deriveState(basePath);
|
|
1708
|
-
|
|
1709
|
-
if (!state.activeMilestone) {
|
|
1710
|
-
ctx.ui.notify("No active milestone — nothing to dispatch.", "info");
|
|
1711
|
-
return;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
const { getLedger, getProjectTotals, formatCost, formatTokenCount, loadLedgerFromDisk } = await import("./metrics.js");
|
|
1715
|
-
const { loadEffectiveGSDPreferences: loadPrefs } = await import("./preferences.js");
|
|
1716
|
-
const { formatDuration } = await import("./history.js");
|
|
1717
|
-
|
|
1718
|
-
const ledger = getLedger();
|
|
1719
|
-
const units = ledger?.units ?? loadLedgerFromDisk(basePath)?.units ?? [];
|
|
1720
|
-
const prefs = loadPrefs()?.preferences;
|
|
1721
|
-
|
|
1722
|
-
let nextType = "unknown";
|
|
1723
|
-
let nextId = "unknown";
|
|
1724
|
-
|
|
1725
|
-
const mid = state.activeMilestone.id;
|
|
1726
|
-
const midTitle = state.activeMilestone.title;
|
|
1727
|
-
|
|
1728
|
-
if (state.phase === "pre-planning") {
|
|
1729
|
-
nextType = "research-milestone";
|
|
1730
|
-
nextId = mid;
|
|
1731
|
-
} else if (state.phase === "planning" && state.activeSlice) {
|
|
1732
|
-
nextType = "plan-slice";
|
|
1733
|
-
nextId = `${mid}/${state.activeSlice.id}`;
|
|
1734
|
-
} else if (state.phase === "executing" && state.activeTask && state.activeSlice) {
|
|
1735
|
-
nextType = "execute-task";
|
|
1736
|
-
nextId = `${mid}/${state.activeSlice.id}/${state.activeTask.id}`;
|
|
1737
|
-
} else if (state.phase === "summarizing" && state.activeSlice) {
|
|
1738
|
-
nextType = "complete-slice";
|
|
1739
|
-
nextId = `${mid}/${state.activeSlice.id}`;
|
|
1740
|
-
} else if (state.phase === "completing-milestone") {
|
|
1741
|
-
nextType = "complete-milestone";
|
|
1742
|
-
nextId = mid;
|
|
1743
|
-
} else {
|
|
1744
|
-
nextType = state.phase;
|
|
1745
|
-
nextId = mid;
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
const sameTypeUnits = units.filter(u => u.type === nextType);
|
|
1749
|
-
const avgCost = sameTypeUnits.length > 0
|
|
1750
|
-
? sameTypeUnits.reduce((s, u) => s + u.cost, 0) / sameTypeUnits.length
|
|
1751
|
-
: null;
|
|
1752
|
-
const avgDuration = sameTypeUnits.length > 0
|
|
1753
|
-
? sameTypeUnits.reduce((s, u) => s + (u.finishedAt - u.startedAt), 0) / sameTypeUnits.length
|
|
1754
|
-
: null;
|
|
1755
|
-
|
|
1756
|
-
const totals = units.length > 0 ? getProjectTotals(units) : null;
|
|
1757
|
-
const budgetRemaining = prefs?.budget_ceiling && totals
|
|
1758
|
-
? prefs.budget_ceiling - totals.cost
|
|
1759
|
-
: null;
|
|
1760
|
-
|
|
1761
|
-
const lines = [
|
|
1762
|
-
`Dry-run preview:`,
|
|
1763
|
-
``,
|
|
1764
|
-
` Next unit: ${nextType}`,
|
|
1765
|
-
` ID: ${nextId}`,
|
|
1766
|
-
` Milestone: ${mid}: ${midTitle}`,
|
|
1767
|
-
` Phase: ${state.phase}`,
|
|
1768
|
-
` Est. cost: ${avgCost !== null ? `${formatCost(avgCost)} (avg of ${sameTypeUnits.length} similar)` : "unknown (first of this type)"}`,
|
|
1769
|
-
` Est. duration: ${avgDuration !== null ? formatDuration(avgDuration) : "unknown"}`,
|
|
1770
|
-
` Spent so far: ${totals ? formatCost(totals.cost) : "$0"}`,
|
|
1771
|
-
` Budget left: ${budgetRemaining !== null ? formatCost(budgetRemaining) : "no ceiling set"}`,
|
|
1772
|
-
];
|
|
1773
|
-
|
|
1009
|
+
// Progress
|
|
1774
1010
|
if (state.progress) {
|
|
1775
|
-
const
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
// ─── Branch cleanup handler ──────────────────────────────────────────────────
|
|
1783
|
-
|
|
1784
|
-
async function handleCleanupBranches(ctx: ExtensionCommandContext, basePath: string): Promise<void> {
|
|
1785
|
-
let branches: string[];
|
|
1786
|
-
try {
|
|
1787
|
-
branches = nativeBranchList(basePath, "gsd/*");
|
|
1788
|
-
} catch {
|
|
1789
|
-
ctx.ui.notify("No GSD branches found.", "info");
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
if (branches.length === 0) {
|
|
1794
|
-
ctx.ui.notify("No GSD branches to clean up.", "info");
|
|
1795
|
-
return;
|
|
1796
|
-
}
|
|
1797
|
-
|
|
1798
|
-
const mainBranch = nativeDetectMainBranch(basePath);
|
|
1799
|
-
|
|
1800
|
-
let merged: string[];
|
|
1801
|
-
try {
|
|
1802
|
-
merged = nativeBranchListMerged(basePath, mainBranch, "gsd/*");
|
|
1803
|
-
} catch {
|
|
1804
|
-
merged = [];
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
if (merged.length === 0) {
|
|
1808
|
-
ctx.ui.notify(`${branches.length} GSD branches found, none are merged into ${mainBranch} yet.`, "info");
|
|
1809
|
-
return;
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
let deleted = 0;
|
|
1813
|
-
for (const branch of merged) {
|
|
1814
|
-
try {
|
|
1815
|
-
nativeBranchDelete(basePath, branch, false);
|
|
1816
|
-
deleted++;
|
|
1817
|
-
} catch { /* skip branches that can't be deleted */ }
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
ctx.ui.notify(`Cleaned up ${deleted} merged branches. ${branches.length - deleted} remain.`, "success");
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
|
-
// ─── Snapshot cleanup handler ─────────────────────────────────────────────────
|
|
1824
|
-
|
|
1825
|
-
async function handleCleanupSnapshots(ctx: ExtensionCommandContext, basePath: string): Promise<void> {
|
|
1826
|
-
let refs: string[];
|
|
1827
|
-
try {
|
|
1828
|
-
refs = nativeForEachRef(basePath, "refs/gsd/snapshots/");
|
|
1829
|
-
} catch {
|
|
1830
|
-
ctx.ui.notify("No snapshot refs found.", "info");
|
|
1831
|
-
return;
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
if (refs.length === 0) {
|
|
1835
|
-
ctx.ui.notify("No snapshot refs to clean up.", "info");
|
|
1836
|
-
return;
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
const byLabel = new Map<string, string[]>();
|
|
1840
|
-
for (const ref of refs) {
|
|
1841
|
-
const parts = ref.split("/");
|
|
1842
|
-
const label = parts.slice(0, -1).join("/");
|
|
1843
|
-
if (!byLabel.has(label)) byLabel.set(label, []);
|
|
1844
|
-
byLabel.get(label)!.push(ref);
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
|
-
let pruned = 0;
|
|
1848
|
-
for (const [, labelRefs] of byLabel) {
|
|
1849
|
-
const sorted = labelRefs.sort();
|
|
1850
|
-
for (const old of sorted.slice(0, -5)) {
|
|
1851
|
-
try {
|
|
1852
|
-
nativeUpdateRef(basePath, old);
|
|
1853
|
-
pruned++;
|
|
1854
|
-
} catch { /* skip */ }
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
ctx.ui.notify(`Pruned ${pruned} old snapshot refs. ${refs.length - pruned} remain.`, "success");
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
async function handleKnowledge(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
1862
|
-
const parts = args.split(/\s+/);
|
|
1863
|
-
const typeArg = parts[0]?.toLowerCase();
|
|
1864
|
-
|
|
1865
|
-
if (!typeArg || !["rule", "pattern", "lesson"].includes(typeArg)) {
|
|
1866
|
-
ctx.ui.notify(
|
|
1867
|
-
"Usage: /gsd knowledge <rule|pattern|lesson> <description>\nExample: /gsd knowledge rule Use real DB for integration tests",
|
|
1868
|
-
"warning",
|
|
1869
|
-
);
|
|
1870
|
-
return;
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
const entryText = parts.slice(1).join(" ").trim();
|
|
1874
|
-
if (!entryText) {
|
|
1875
|
-
ctx.ui.notify(`Usage: /gsd knowledge ${typeArg} <description>`, "warning");
|
|
1876
|
-
return;
|
|
1877
|
-
}
|
|
1878
|
-
|
|
1879
|
-
const type = typeArg as "rule" | "pattern" | "lesson";
|
|
1880
|
-
const basePath = process.cwd();
|
|
1881
|
-
const state = await deriveState(basePath);
|
|
1882
|
-
const scope = state.activeMilestone?.id
|
|
1883
|
-
? `${state.activeMilestone.id}${state.activeSlice ? `/${state.activeSlice.id}` : ""}`
|
|
1884
|
-
: "global";
|
|
1885
|
-
|
|
1886
|
-
await appendKnowledge(basePath, type, entryText, scope);
|
|
1887
|
-
ctx.ui.notify(`Added ${type} to KNOWLEDGE.md: "${entryText}"`, "success");
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
// ─── Capture Command ──────────────────────────────────────────────────────────
|
|
1891
|
-
|
|
1892
|
-
/**
|
|
1893
|
-
* Handle `/gsd capture "..."` — fire-and-forget thought capture.
|
|
1894
|
-
* Appends to `.gsd/CAPTURES.md` without interrupting auto-mode.
|
|
1895
|
-
* Works in all modes: auto running, paused, stopped, no project.
|
|
1896
|
-
*/
|
|
1897
|
-
async function handleCapture(args: string, ctx: ExtensionCommandContext): Promise<void> {
|
|
1898
|
-
// Strip surrounding quotes from the argument
|
|
1899
|
-
let text = args.trim();
|
|
1900
|
-
if (!text) {
|
|
1901
|
-
ctx.ui.notify('Usage: /gsd capture "your thought here"', "warning");
|
|
1902
|
-
return;
|
|
1903
|
-
}
|
|
1904
|
-
// Remove wrapping quotes (single or double)
|
|
1905
|
-
if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) {
|
|
1906
|
-
text = text.slice(1, -1);
|
|
1907
|
-
}
|
|
1908
|
-
if (!text) {
|
|
1909
|
-
ctx.ui.notify('Usage: /gsd capture "your thought here"', "warning");
|
|
1910
|
-
return;
|
|
1011
|
+
const { milestones, slices, tasks } = state.progress;
|
|
1012
|
+
const parts: string[] = [];
|
|
1013
|
+
parts.push(`milestones ${milestones.done}/${milestones.total}`);
|
|
1014
|
+
if (slices) parts.push(`slices ${slices.done}/${slices.total}`);
|
|
1015
|
+
if (tasks) parts.push(`tasks ${tasks.done}/${tasks.total}`);
|
|
1016
|
+
lines.push(`Progress: ${parts.join(", ")}`);
|
|
1911
1017
|
}
|
|
1912
1018
|
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
const gsdDir = join(basePath, ".gsd");
|
|
1917
|
-
if (!existsSync(gsdDir)) {
|
|
1918
|
-
mkdirSync(gsdDir, { recursive: true });
|
|
1019
|
+
// Next action
|
|
1020
|
+
if (state.nextAction) {
|
|
1021
|
+
lines.push(`Next: ${state.nextAction}`);
|
|
1919
1022
|
}
|
|
1920
1023
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
// ─── Triage Command ───────────────────────────────────────────────────────────
|
|
1926
|
-
|
|
1927
|
-
/**
|
|
1928
|
-
* Handle `/gsd triage` — manually trigger triage of pending captures.
|
|
1929
|
-
* Dispatches the triage prompt to the LLM for classification.
|
|
1930
|
-
* Triage result handling (confirmation UI) is wired in T03.
|
|
1931
|
-
*/
|
|
1932
|
-
async function handleTriage(ctx: ExtensionCommandContext, pi: ExtensionAPI, basePath: string): Promise<void> {
|
|
1933
|
-
if (!hasPendingCaptures(basePath)) {
|
|
1934
|
-
ctx.ui.notify("No pending captures to triage.", "info");
|
|
1935
|
-
return;
|
|
1024
|
+
// Blockers
|
|
1025
|
+
if (state.blockers.length > 0) {
|
|
1026
|
+
lines.push(`Blockers: ${state.blockers.join("; ")}`);
|
|
1936
1027
|
}
|
|
1937
1028
|
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
if (state.activeMilestone && state.activeSlice) {
|
|
1947
|
-
const { resolveSliceFile, resolveMilestoneFile } = await import("./paths.js");
|
|
1948
|
-
const planFile = resolveSliceFile(basePath, state.activeMilestone.id, state.activeSlice.id, "PLAN");
|
|
1949
|
-
if (planFile) {
|
|
1950
|
-
const { loadFile: load } = await import("./files.js");
|
|
1951
|
-
currentPlan = (await load(planFile)) ?? "";
|
|
1952
|
-
}
|
|
1953
|
-
const roadmapFile = resolveMilestoneFile(basePath, state.activeMilestone.id, "ROADMAP");
|
|
1954
|
-
if (roadmapFile) {
|
|
1955
|
-
const { loadFile: load } = await import("./files.js");
|
|
1956
|
-
roadmapContext = (await load(roadmapFile)) ?? "";
|
|
1029
|
+
// Milestone registry summary
|
|
1030
|
+
if (state.registry.length > 0) {
|
|
1031
|
+
lines.push("");
|
|
1032
|
+
lines.push("Milestones:");
|
|
1033
|
+
for (const m of state.registry) {
|
|
1034
|
+
const statusIcon = m.status === "complete" ? "✓" : m.status === "active" ? "▶" : m.status === "parked" ? "⏸" : "○";
|
|
1035
|
+
lines.push(` ${statusIcon} ${m.id}: ${m.title} (${m.status})`);
|
|
1957
1036
|
}
|
|
1958
1037
|
}
|
|
1959
1038
|
|
|
1960
|
-
|
|
1961
|
-
const capturesList = pending.map(c =>
|
|
1962
|
-
`- **${c.id}**: "${c.text}" (captured: ${c.timestamp})`
|
|
1963
|
-
).join("\n");
|
|
1964
|
-
|
|
1965
|
-
// Dispatch triage prompt
|
|
1966
|
-
const { loadPrompt } = await import("./prompt-loader.js");
|
|
1967
|
-
const prompt = loadPrompt("triage-captures", {
|
|
1968
|
-
pendingCaptures: capturesList,
|
|
1969
|
-
currentPlan: currentPlan || "(no active slice plan)",
|
|
1970
|
-
roadmapContext: roadmapContext || "(no active roadmap)",
|
|
1971
|
-
});
|
|
1972
|
-
|
|
1973
|
-
const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".pi", "GSD-WORKFLOW.md");
|
|
1974
|
-
const workflow = readFileSync(workflowPath, "utf-8");
|
|
1975
|
-
|
|
1976
|
-
pi.sendMessage(
|
|
1977
|
-
{
|
|
1978
|
-
customType: "gsd-triage",
|
|
1979
|
-
content: `Read the following GSD workflow protocol and execute exactly.\n\n${workflow}\n\n## Your Task\n\n${prompt}`,
|
|
1980
|
-
display: false,
|
|
1981
|
-
},
|
|
1982
|
-
{ triggerTurn: true },
|
|
1983
|
-
);
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
async function handleSteer(change: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
1987
|
-
const basePath = process.cwd();
|
|
1988
|
-
const state = await deriveState(basePath);
|
|
1989
|
-
const mid = state.activeMilestone?.id ?? "none";
|
|
1990
|
-
const sid = state.activeSlice?.id ?? "none";
|
|
1991
|
-
const tid = state.activeTask?.id ?? "none";
|
|
1992
|
-
const appliedAt = `${mid}/${sid}/${tid}`;
|
|
1993
|
-
await appendOverride(basePath, change, appliedAt);
|
|
1994
|
-
|
|
1995
|
-
if (isAutoActive()) {
|
|
1996
|
-
pi.sendMessage({
|
|
1997
|
-
customType: "gsd-hard-steer",
|
|
1998
|
-
content: [
|
|
1999
|
-
"HARD STEER — User override registered.",
|
|
2000
|
-
"",
|
|
2001
|
-
`**Override:** ${change}`,
|
|
2002
|
-
"",
|
|
2003
|
-
"This override has been saved to `.gsd/OVERRIDES.md` and will be injected into all future task prompts.",
|
|
2004
|
-
"A document rewrite unit will run before the next task to propagate this change across all active plan documents.",
|
|
2005
|
-
"",
|
|
2006
|
-
"If you are mid-task, finish your current work respecting this override. The next dispatched unit will be a document rewrite.",
|
|
2007
|
-
].join("\n"),
|
|
2008
|
-
display: false,
|
|
2009
|
-
}, { triggerTurn: true });
|
|
2010
|
-
ctx.ui.notify(`Override registered: "${change}". Will be applied before next task dispatch.`, "info");
|
|
2011
|
-
} else {
|
|
2012
|
-
pi.sendMessage({
|
|
2013
|
-
customType: "gsd-hard-steer",
|
|
2014
|
-
content: [
|
|
2015
|
-
"HARD STEER — User override registered.",
|
|
2016
|
-
"",
|
|
2017
|
-
`**Override:** ${change}`,
|
|
2018
|
-
"",
|
|
2019
|
-
"This override has been saved to `.gsd/OVERRIDES.md`.",
|
|
2020
|
-
"Before continuing, read `.gsd/OVERRIDES.md` and update the current plan documents to reflect this change.",
|
|
2021
|
-
"Focus on: active slice plan, incomplete task plans, and DECISIONS.md.",
|
|
2022
|
-
].join("\n"),
|
|
2023
|
-
display: false,
|
|
2024
|
-
}, { triggerTurn: true });
|
|
2025
|
-
ctx.ui.notify(`Override registered: "${change}". Update plan documents to reflect this change.`, "info");
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
async function handleRunHook(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI): Promise<void> {
|
|
2030
|
-
const parts = args.trim().split(/\s+/);
|
|
2031
|
-
if (parts.length < 3) {
|
|
2032
|
-
ctx.ui.notify(`Usage: /gsd run-hook <hook-name> <unit-type> <unit-id>
|
|
2033
|
-
|
|
2034
|
-
Unit types:
|
|
2035
|
-
execute-task - Task execution (unit-id: M001/S01/T01)
|
|
2036
|
-
plan-slice - Slice planning (unit-id: M001/S01)
|
|
2037
|
-
research-milestone - Milestone research (unit-id: M001)
|
|
2038
|
-
complete-slice - Slice completion (unit-id: M001/S01)
|
|
2039
|
-
complete-milestone - Milestone completion (unit-id: M001)
|
|
2040
|
-
|
|
2041
|
-
Examples:
|
|
2042
|
-
/gsd run-hook code-review execute-task M001/S01/T01
|
|
2043
|
-
/gsd run-hook lint-check plan-slice M001/S01`, "warning");
|
|
2044
|
-
return;
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
const [hookName, unitType, unitId] = parts;
|
|
2048
|
-
const basePath = projectRoot();
|
|
2049
|
-
|
|
2050
|
-
// Import the hook trigger function
|
|
2051
|
-
const { triggerHookManually, formatHookStatus, getHookStatus } = await import("./post-unit-hooks.js");
|
|
2052
|
-
const { dispatchHookUnit } = await import("./auto.js");
|
|
2053
|
-
|
|
2054
|
-
// Check if the hook exists
|
|
2055
|
-
const hooks = getHookStatus();
|
|
2056
|
-
const hookExists = hooks.some(h => h.name === hookName);
|
|
2057
|
-
if (!hookExists) {
|
|
2058
|
-
ctx.ui.notify(`Hook "${hookName}" not found. Configured hooks:\n${formatHookStatus()}`, "error");
|
|
2059
|
-
return;
|
|
2060
|
-
}
|
|
2061
|
-
|
|
2062
|
-
// Validate unit ID format
|
|
2063
|
-
const unitIdPattern = /^M\d{3}\/S\d{2,3}\/T\d{2,3}$/;
|
|
2064
|
-
if (!unitIdPattern.test(unitId)) {
|
|
2065
|
-
ctx.ui.notify(`Invalid unit ID format: "${unitId}". Expected format: M004/S04/T03`, "warning");
|
|
2066
|
-
return;
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
// Trigger the hook manually
|
|
2070
|
-
const hookUnit = triggerHookManually(hookName, unitType, unitId, basePath);
|
|
2071
|
-
if (!hookUnit) {
|
|
2072
|
-
ctx.ui.notify(`Failed to trigger hook "${hookName}". The hook may be disabled or not configured for unit type "${unitType}".`, "error");
|
|
2073
|
-
return;
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2076
|
-
ctx.ui.notify(`Manually triggering hook: ${hookName} for ${unitType} ${unitId}`, "info");
|
|
2077
|
-
|
|
2078
|
-
// Dispatch the hook unit directly, bypassing normal pre-dispatch hooks
|
|
2079
|
-
const success = await dispatchHookUnit(
|
|
2080
|
-
ctx,
|
|
2081
|
-
pi,
|
|
2082
|
-
hookName,
|
|
2083
|
-
unitType,
|
|
2084
|
-
unitId,
|
|
2085
|
-
hookUnit.prompt,
|
|
2086
|
-
hookUnit.model,
|
|
2087
|
-
basePath,
|
|
2088
|
-
);
|
|
2089
|
-
|
|
2090
|
-
if (!success) {
|
|
2091
|
-
ctx.ui.notify("Failed to dispatch hook. Auto-mode may have been cancelled.", "error");
|
|
2092
|
-
}
|
|
1039
|
+
return lines.join("\n");
|
|
2093
1040
|
}
|