gsd-pi 2.75.0-dev.b6ad8c5f7 → 2.75.0-dev.e41b70b10

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.
Files changed (181) hide show
  1. package/dist/resources/extensions/gsd/auto/phases.js +2 -0
  2. package/dist/resources/extensions/gsd/auto-dashboard.js +22 -1
  3. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -2
  4. package/dist/resources/extensions/gsd/auto-dispatch.js +11 -11
  5. package/dist/resources/extensions/gsd/auto-model-selection.js +3 -1
  6. package/dist/resources/extensions/gsd/auto-prompts.js +19 -9
  7. package/dist/resources/extensions/gsd/auto-worktree.js +16 -1
  8. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +128 -0
  9. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  10. package/dist/resources/extensions/gsd/bootstrap/system-context.js +17 -4
  11. package/dist/resources/extensions/gsd/commands/handlers/onboarding.js +52 -92
  12. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  13. package/dist/resources/extensions/gsd/commands-memory.js +462 -0
  14. package/dist/resources/extensions/gsd/doctor-git-checks.js +22 -2
  15. package/dist/resources/extensions/gsd/gsd-db.js +237 -4
  16. package/dist/resources/extensions/gsd/memory-embeddings.js +219 -0
  17. package/dist/resources/extensions/gsd/memory-extractor.js +78 -27
  18. package/dist/resources/extensions/gsd/memory-ingest.js +218 -0
  19. package/dist/resources/extensions/gsd/memory-relations.js +189 -0
  20. package/dist/resources/extensions/gsd/memory-source-store.js +113 -0
  21. package/dist/resources/extensions/gsd/memory-store.js +299 -6
  22. package/dist/resources/extensions/gsd/pre-execution-checks.js +12 -8
  23. package/dist/resources/extensions/gsd/prompts/add-tests.md +1 -0
  24. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  25. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  26. package/dist/resources/extensions/gsd/tools/memory-tools.js +306 -0
  27. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +14 -0
  28. package/dist/resources/extensions/search-the-web/command-search-provider.js +4 -1
  29. package/dist/resources/extensions/search-the-web/native-search.js +13 -2
  30. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  31. package/dist/web/standalone/.next/BUILD_ID +1 -1
  32. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  33. package/dist/web/standalone/.next/build-manifest.json +2 -2
  34. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  35. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/index.html +1 -1
  52. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  59. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  61. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  62. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  63. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  64. package/package.json +1 -1
  65. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  66. package/packages/mcp-server/dist/server.js +12 -10
  67. package/packages/mcp-server/dist/server.js.map +1 -1
  68. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  69. package/packages/mcp-server/dist/session-manager.js +8 -1
  70. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  71. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -0
  72. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  73. package/packages/mcp-server/dist/workflow-tools.js +207 -71
  74. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  75. package/packages/mcp-server/src/mcp-server.test.ts +40 -4
  76. package/packages/mcp-server/src/server.ts +12 -10
  77. package/packages/mcp-server/src/session-manager.ts +10 -3
  78. package/packages/mcp-server/src/workflow-tools.test.ts +346 -1
  79. package/packages/mcp-server/src/workflow-tools.ts +228 -75
  80. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  81. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  82. package/packages/pi-ai/dist/index.d.ts +1 -0
  83. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  84. package/packages/pi-ai/dist/index.js +1 -0
  85. package/packages/pi-ai/dist/index.js.map +1 -1
  86. package/packages/pi-ai/dist/providers/api-family.d.ts +27 -0
  87. package/packages/pi-ai/dist/providers/api-family.d.ts.map +1 -0
  88. package/packages/pi-ai/dist/providers/api-family.js +47 -0
  89. package/packages/pi-ai/dist/providers/api-family.js.map +1 -0
  90. package/packages/pi-ai/dist/providers/api-family.test.d.ts +2 -0
  91. package/packages/pi-ai/dist/providers/api-family.test.d.ts.map +1 -0
  92. package/packages/pi-ai/dist/providers/api-family.test.js +101 -0
  93. package/packages/pi-ai/dist/providers/api-family.test.js.map +1 -0
  94. package/packages/pi-ai/src/index.ts +1 -0
  95. package/packages/pi-ai/src/providers/api-family.test.ts +129 -0
  96. package/packages/pi-ai/src/providers/api-family.ts +57 -0
  97. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  98. package/packages/pi-coding-agent/dist/cli/args.d.ts +6 -0
  99. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/cli/args.js +14 -4
  101. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  102. package/packages/pi-coding-agent/dist/cli/args.test.d.ts +2 -0
  103. package/packages/pi-coding-agent/dist/cli/args.test.d.ts.map +1 -0
  104. package/packages/pi-coding-agent/dist/cli/args.test.js +38 -0
  105. package/packages/pi-coding-agent/dist/cli/args.test.js.map +1 -0
  106. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
  107. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  108. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  110. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/retry-handler.js +4 -1
  114. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -0
  116. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/sdk.js +7 -1
  118. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/main.js +3 -0
  121. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  122. package/packages/pi-coding-agent/src/cli/args.test.ts +44 -0
  123. package/packages/pi-coding-agent/src/cli/args.ts +21 -6
  124. package/packages/pi-coding-agent/src/core/extensions/runner.ts +4 -1
  125. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -2
  126. package/packages/pi-coding-agent/src/core/retry-handler.ts +4 -1
  127. package/packages/pi-coding-agent/src/core/sdk.ts +17 -1
  128. package/packages/pi-coding-agent/src/main.ts +4 -0
  129. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  130. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -10
  131. package/src/resources/extensions/gsd/auto/phases.ts +3 -0
  132. package/src/resources/extensions/gsd/auto-dashboard.ts +25 -1
  133. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +15 -2
  134. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -7
  135. package/src/resources/extensions/gsd/auto-model-selection.ts +3 -1
  136. package/src/resources/extensions/gsd/auto-prompts.ts +33 -9
  137. package/src/resources/extensions/gsd/auto-worktree.ts +16 -1
  138. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +158 -0
  139. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  140. package/src/resources/extensions/gsd/bootstrap/system-context.ts +20 -4
  141. package/src/resources/extensions/gsd/commands/handlers/onboarding.ts +65 -131
  142. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  143. package/src/resources/extensions/gsd/commands-memory.ts +551 -0
  144. package/src/resources/extensions/gsd/doctor-git-checks.ts +23 -2
  145. package/src/resources/extensions/gsd/gsd-db.ts +273 -4
  146. package/src/resources/extensions/gsd/memory-embeddings.ts +235 -0
  147. package/src/resources/extensions/gsd/memory-extractor.ts +100 -34
  148. package/src/resources/extensions/gsd/memory-ingest.ts +286 -0
  149. package/src/resources/extensions/gsd/memory-relations.ts +240 -0
  150. package/src/resources/extensions/gsd/memory-source-store.ts +138 -0
  151. package/src/resources/extensions/gsd/memory-store.ts +351 -7
  152. package/src/resources/extensions/gsd/pre-execution-checks.ts +12 -8
  153. package/src/resources/extensions/gsd/prompts/add-tests.md +1 -0
  154. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  155. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  156. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +49 -0
  157. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  158. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  159. package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -2
  160. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  161. package/src/resources/extensions/gsd/tests/integration/doctor-git-symlink-cwd.test.ts +79 -0
  162. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  163. package/src/resources/extensions/gsd/tests/memory-embeddings.test.ts +213 -0
  164. package/src/resources/extensions/gsd/tests/memory-ingest.test.ts +153 -0
  165. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +107 -0
  166. package/src/resources/extensions/gsd/tests/memory-relations.test.ts +175 -0
  167. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  168. package/src/resources/extensions/gsd/tests/memory-tools.test.ts +295 -0
  169. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +66 -0
  170. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +132 -8
  171. package/src/resources/extensions/gsd/tests/prompts-no-gitignored-test-refs.test.ts +56 -0
  172. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +54 -0
  173. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +97 -0
  174. package/src/resources/extensions/gsd/tools/memory-tools.ts +380 -0
  175. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +14 -0
  176. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  177. package/src/resources/extensions/search-the-web/command-search-provider.ts +4 -1
  178. package/src/resources/extensions/search-the-web/native-search.ts +13 -3
  179. package/src/resources/extensions/gsd/tests/onboarding-handler-loader.test.ts +0 -41
  180. /package/dist/web/standalone/.next/static/{J2z3GMC9QtSLr7gyoM38c → By_yegSJ-AA1OP0QjYbSl}/_buildManifest.js +0 -0
  181. /package/dist/web/standalone/.next/static/{J2z3GMC9QtSLr7gyoM38c → By_yegSJ-AA1OP0QjYbSl}/_ssgManifest.js +0 -0
@@ -1,18 +1,19 @@
1
- // GSD — /gsd onboarding command handler (re-entry, --resume, --reset, --step)
1
+ // GSD — /gsd onboarding command handler (re-entry hub)
2
2
  //
3
- // Provides the discoverable re-entry point for the onboarding wizard. The
4
- // first-run wizard in src/onboarding.ts is hidden behind shouldRunOnboarding;
5
- // this handler lets users re-launch it on demand.
3
+ // The first-run wizard in src/onboarding.ts uses @clack/prompts and takes over
4
+ // raw stdin. Running it from inside the pi-coding-agent TUI wedges the TUI
5
+ // (clack leaves stdin paused + cooked, pi-tui's data handler then receives no
6
+ // keypresses). So re-entry cannot replay the clack wizard — instead it routes
7
+ // to a setup hub built from ctx.ui.select, which the TUI owns.
8
+ //
9
+ // Clack-only steps (llm/search/remote/tool-keys via the first-run wizard) are
10
+ // surfaced as notifications pointing the user at the canonical per-step
11
+ // commands (/login, /gsd keys, /gsd remote) that are already ctx.ui-safe.
6
12
 
7
13
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent"
8
- import { AuthStorage } from "@gsd/pi-coding-agent"
9
- import { homedir } from "node:os"
10
- import { dirname, join, resolve } from "node:path"
11
- import { pathToFileURL } from "node:url"
12
14
  import {
13
15
  ONBOARDING_STEPS,
14
16
  isValidStepId,
15
- nearestResumeStep,
16
17
  type OnboardingStepId,
17
18
  } from "../../setup-catalog.js"
18
19
  import {
@@ -21,69 +22,7 @@ import {
21
22
  resetOnboarding,
22
23
  } from "../../onboarding-state.js"
23
24
 
24
- // Inline auth path (mirrors src/app-paths.ts) — keep this module rootDir-clean
25
- // for the resources tsconfig. Importing from src/ pulls files outside
26
- // src/resources and breaks the build.
27
- const AUTH_FILE_PATH = join(
28
- process.env.GSD_CODING_AGENT_DIR ||
29
- join(process.env.GSD_HOME || join(homedir(), ".gsd"), "agent"),
30
- "auth.json",
31
- )
32
-
33
- /**
34
- * Dynamic import shim for the first-run wizard.
35
- *
36
- * src/onboarding.ts lives outside the resources rootDir, so a static import
37
- * pulls it into this tsconfig project and triggers TS6059. We resolve the
38
- * specifier through a variable + opaque type so TS can't pull the file at
39
- * compile time; the path resolves correctly at runtime via dist/onboarding.js.
40
- */
41
- type FirstRunWizardModule = {
42
- runOnboarding: (
43
- storage: AuthStorage,
44
- opts?: { showIntro?: boolean },
45
- ) => Promise<void>
46
- runLlmStep: (...args: unknown[]) => Promise<unknown>
47
- runWebSearchStep: (...args: unknown[]) => Promise<unknown>
48
- runRemoteQuestionsStep: (...args: unknown[]) => Promise<unknown>
49
- runToolKeysStep: (...args: unknown[]) => Promise<unknown>
50
- }
51
- async function loadFirstRunWizard(): Promise<FirstRunWizardModule> {
52
- const candidates: string[] = []
53
-
54
- // Primary deployed path: loader sets GSD_PKG_ROOT (gsd package root).
55
- if (process.env.GSD_PKG_ROOT) {
56
- candidates.push(pathToFileURL(join(process.env.GSD_PKG_ROOT, "dist", "onboarding.js")).href)
57
- }
58
-
59
- // Fallback: derive package root from process entry (typically dist/loader.js).
60
- // This keeps /gsd onboarding resilient if GSD_PKG_ROOT is absent.
61
- const argvEntry = process.argv[1]
62
- if (argvEntry) {
63
- const pkgRootFromArgv = resolve(dirname(argvEntry), "..")
64
- candidates.push(pathToFileURL(join(pkgRootFromArgv, "dist", "onboarding.js")).href)
65
- }
66
-
67
- // Source-tree/dev fallback (works in dist/resources/... and ts test loaders).
68
- candidates.push("../../../../../onboarding.js")
69
-
70
- let lastError: unknown = null
71
- for (const specifier of candidates) {
72
- try {
73
- return (await import(/* @vite-ignore */ specifier)) as FirstRunWizardModule
74
- } catch (err) {
75
- lastError = err
76
- }
77
- }
78
-
79
- const reason = lastError instanceof Error ? lastError.message : String(lastError)
80
- throw new Error(
81
- `[gsd] Failed to load onboarding wizard module. Tried: ${candidates.join(", ")}. Last error: ${reason}`,
82
- )
83
- }
84
-
85
25
  interface ParsedArgs {
86
- resume: boolean
87
26
  reset: boolean
88
27
  step: string | null
89
28
  stepValid: boolean | null
@@ -91,11 +30,13 @@ interface ParsedArgs {
91
30
 
92
31
  function parseArgs(raw: string): ParsedArgs {
93
32
  const tokens = raw.split(/\s+/).filter(Boolean)
94
- const out: ParsedArgs = { resume: false, reset: false, step: null, stepValid: null }
33
+ const out: ParsedArgs = { reset: false, step: null, stepValid: null }
95
34
  for (let i = 0; i < tokens.length; i++) {
96
35
  const t = tokens[i]
97
- if (t === "--resume" || t === "resume") out.resume = true
98
- else if (t === "--reset" || t === "reset") out.reset = true
36
+ if (t === "--reset" || t === "reset") out.reset = true
37
+ else if (t === "--resume" || t === "resume") {
38
+ // Re-entry no longer replays the wizard; --resume collapses into the hub.
39
+ }
99
40
  else if (t === "--step" || t === "step") {
100
41
  const next = tokens[i + 1]
101
42
  if (next) {
@@ -112,52 +53,39 @@ function parseArgs(raw: string): ParsedArgs {
112
53
  return out
113
54
  }
114
55
 
115
- async function getAuthStorage(): Promise<AuthStorage> {
116
- return AuthStorage.create(AUTH_FILE_PATH)
117
- }
118
-
119
- async function runWholeWizard(ctx: ExtensionCommandContext, fromStep?: OnboardingStepId): Promise<void> {
120
- const authStorage = await getAuthStorage()
121
- // The first-run wizard ignores the resume hint today — it always walks the
122
- // full sequence with skip prompts. We still mark completion at the end and
123
- // record the resume hint for next time. This keeps the wizard linear and
124
- // simple; per-step jump support comes via --step.
125
- if (fromStep) {
126
- ctx.ui.notify(
127
- `Resuming from step: ${fromStep}. The wizard runs all remaining steps; press skip on any you've already configured.`,
128
- "info",
129
- )
130
- }
131
- const { runOnboarding } = await loadFirstRunWizard()
132
- await runOnboarding(authStorage, { showIntro: false })
133
- }
134
-
135
- async function runSingleStep(ctx: ExtensionCommandContext, stepId: OnboardingStepId): Promise<void> {
136
- const authStorage = await getAuthStorage()
137
- const ob = await loadFirstRunWizard()
138
- // Lazy-load clack + chalk via the same path the wizard uses
139
- const p = await import("@clack/prompts")
140
- const { default: chalk } = await import("chalk")
141
- const pc = {
142
- cyan: chalk.cyan, green: chalk.green, yellow: chalk.yellow,
143
- dim: chalk.dim, bold: chalk.bold, red: chalk.red, reset: chalk.reset,
144
- }
56
+ // ─── Per-step routing ────────────────────────────────────────────────────────
57
+ //
58
+ // Clack-based steps are surfaced as notifications — running them inline from
59
+ // the TUI would wedge stdin (see header comment). Everything else routes to an
60
+ // existing ctx.ui-safe handler.
145
61
 
62
+ async function runStep(ctx: ExtensionCommandContext, stepId: OnboardingStepId): Promise<void> {
146
63
  switch (stepId) {
147
64
  case "llm":
148
- await ob.runLlmStep(p as any, pc as any, authStorage)
65
+ ctx.ui.notify(
66
+ "LLM provider setup: run /login to sign in via OAuth, or /gsd keys add to paste an API key.",
67
+ "info",
68
+ )
149
69
  return
150
70
  case "search":
151
- await ob.runWebSearchStep(p as any, pc as any, authStorage, false)
71
+ ctx.ui.notify(
72
+ "Web search setup: run /gsd keys add and pick a search provider (brave, tavily, etc.).",
73
+ "info",
74
+ )
152
75
  return
153
76
  case "remote":
154
- await ob.runRemoteQuestionsStep(p as any, pc as any, authStorage)
77
+ ctx.ui.notify(
78
+ "Remote questions setup: run /gsd remote to configure Discord / Slack / Telegram notifications.",
79
+ "info",
80
+ )
155
81
  return
156
82
  case "tool-keys":
157
- await ob.runToolKeysStep(p as any, pc as any, authStorage)
83
+ ctx.ui.notify(
84
+ "Tool keys setup: run /gsd keys add to save API keys for Context7, Jina, Groq voice, etc.",
85
+ "info",
86
+ )
158
87
  return
159
88
  case "model": {
160
- // Delegate to /gsd model picker
161
89
  const { handleCoreCommand } = await import("./core.js")
162
90
  await handleCoreCommand("model", ctx)
163
91
  return
@@ -170,7 +98,6 @@ async function runSingleStep(ctx: ExtensionCommandContext, stepId: OnboardingSte
170
98
  return
171
99
  }
172
100
  case "doctor": {
173
- // Best-effort: surface provider doctor results inline
174
101
  try {
175
102
  const { runProviderDoctor } = await import("../../doctor-providers.js") as any
176
103
  if (typeof runProviderDoctor === "function") {
@@ -181,10 +108,9 @@ async function runSingleStep(ctx: ExtensionCommandContext, stepId: OnboardingSte
181
108
  ctx.ui.notify("Run /gsd doctor to validate your setup.", "info")
182
109
  return
183
110
  }
184
- case "skills": {
185
- ctx.ui.notify("Skill install runs automatically during /gsd init. Use /gsd init or /skill manage.", "info")
111
+ case "skills":
112
+ ctx.ui.notify("Skill install runs during /gsd init. Use /gsd init or /skill manage.", "info")
186
113
  return
187
- }
188
114
  case "project": {
189
115
  const { handleCoreCommand } = await import("./core.js")
190
116
  await handleCoreCommand("init", ctx)
@@ -193,6 +119,27 @@ async function runSingleStep(ctx: ExtensionCommandContext, stepId: OnboardingSte
193
119
  }
194
120
  }
195
121
 
122
+ // ─── Setup hub ───────────────────────────────────────────────────────────────
123
+
124
+ async function renderSetupHub(ctx: ExtensionCommandContext): Promise<void> {
125
+ const record = readOnboardingRecord()
126
+ const completed = new Set(record.completedSteps)
127
+ const skipped = new Set(record.skippedSteps)
128
+
129
+ const labels = ONBOARDING_STEPS.map(step => {
130
+ const mark = completed.has(step.id) ? "✓" : skipped.has(step.id) ? "↷" : "○"
131
+ const req = step.required ? " (required)" : ""
132
+ return `${mark} ${step.label}${req} — ${step.hint}`
133
+ })
134
+ const labelToStep = new Map(labels.map((label, i) => [label, ONBOARDING_STEPS[i].id]))
135
+
136
+ const choice = await ctx.ui.select("GSD Setup — pick a step to configure", labels)
137
+ if (typeof choice !== "string") return
138
+ const stepId = labelToStep.get(choice)
139
+ if (!stepId) return
140
+ await runStep(ctx, stepId)
141
+ }
142
+
196
143
  function renderStatus(): string {
197
144
  const r = readOnboardingRecord()
198
145
  const lines: string[] = ["GSD Onboarding\n"]
@@ -225,38 +172,25 @@ export async function handleOnboarding(rawArgs: string, ctx: ExtensionCommandCon
225
172
  ctx.ui.notify(`Unknown step "${args.step}". Valid: ${validIds}`, "warning")
226
173
  return
227
174
  }
228
- await runSingleStep(ctx, args.step as OnboardingStepId)
175
+ await runStep(ctx, args.step as OnboardingStepId)
229
176
  return
230
177
  }
231
178
 
232
179
  if (args.reset) {
233
180
  resetOnboarding()
234
181
  ctx.ui.notify(
235
- "Onboarding reset. Existing API keys/credentials are unchanged — manage them with /gsd keys.",
182
+ "Onboarding state cleared. API keys/credentials are unchanged — manage them with /gsd keys. Restart GSD to re-run the first-run wizard, or pick a step below.",
236
183
  "info",
237
184
  )
238
- await runWholeWizard(ctx)
185
+ await renderSetupHub(ctx)
239
186
  return
240
187
  }
241
188
 
242
- if (args.resume) {
243
- const r = readOnboardingRecord()
244
- const next = nearestResumeStep(r.lastResumePoint, r.completedSteps)
245
- await runWholeWizard(ctx, next)
246
- return
247
- }
248
-
249
- // No flags. If already complete, show status + offer choice.
189
+ // No flags (or --resume). Show status if complete, then open the hub.
250
190
  if (isOnboardingComplete()) {
251
191
  ctx.ui.notify(renderStatus(), "info")
252
- ctx.ui.notify(
253
- "Onboarding already complete. Use /gsd onboarding --reset to start over, or --step <name> to redo one section.",
254
- "info",
255
- )
256
- return
257
192
  }
258
-
259
- await runWholeWizard(ctx)
193
+ await renderSetupHub(ctx)
260
194
  }
261
195
 
262
196
  export { renderStatus as renderOnboardingStatus }
@@ -251,6 +251,11 @@ Examples:
251
251
  await handleExtractLearnings(trimmed.replace(/^extract-learnings\s*/, "").trim(), ctx, pi);
252
252
  return true;
253
253
  }
254
+ if (trimmed === "memory" || trimmed.startsWith("memory ") || trimmed === "memory help") {
255
+ const { handleMemory } = await import("../../commands-memory.js");
256
+ await handleMemory(trimmed.replace(/^memory\s*/, "").trim(), ctx, pi);
257
+ return true;
258
+ }
254
259
  if (trimmed === "scan" || trimmed.startsWith("scan ")) {
255
260
  const { handleScan } = await import("../../commands-scan.js");
256
261
  // \s* (not \s+) is intentional: handles both /gsd scan (no args) and /gsd scan --focus X