gsd-pi 2.38.0-dev.96dc7fb → 2.38.0-dev.98b44dc

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 (217) hide show
  1. package/README.md +15 -11
  2. package/dist/app-paths.js +1 -1
  3. package/dist/extension-registry.js +2 -2
  4. package/dist/remote-questions-config.js +2 -2
  5. package/dist/resource-loader.js +34 -1
  6. package/dist/resources/extensions/browser-tools/index.js +3 -1
  7. package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
  8. package/dist/resources/extensions/env-utils.js +29 -0
  9. package/dist/resources/extensions/get-secrets-from-user.js +5 -24
  10. package/dist/resources/extensions/github-sync/cli.js +284 -0
  11. package/dist/resources/extensions/github-sync/index.js +73 -0
  12. package/dist/resources/extensions/github-sync/mapping.js +67 -0
  13. package/dist/resources/extensions/github-sync/sync.js +424 -0
  14. package/dist/resources/extensions/github-sync/templates.js +118 -0
  15. package/dist/resources/extensions/github-sync/types.js +7 -0
  16. package/dist/resources/extensions/gsd/auto/session.js +6 -23
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
  18. package/dist/resources/extensions/gsd/auto-loop.js +636 -594
  19. package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
  20. package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
  21. package/dist/resources/extensions/gsd/auto-start.js +7 -1
  22. package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
  23. package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
  24. package/dist/resources/extensions/gsd/auto.js +143 -96
  25. package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
  26. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  27. package/dist/resources/extensions/gsd/commands.js +4 -2
  28. package/dist/resources/extensions/gsd/context-budget.js +2 -10
  29. package/dist/resources/extensions/gsd/detection.js +1 -2
  30. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  31. package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
  32. package/dist/resources/extensions/gsd/doctor.js +20 -1
  33. package/dist/resources/extensions/gsd/exit-command.js +2 -1
  34. package/dist/resources/extensions/gsd/export.js +1 -1
  35. package/dist/resources/extensions/gsd/files.js +48 -9
  36. package/dist/resources/extensions/gsd/forensics.js +1 -1
  37. package/dist/resources/extensions/gsd/git-service.js +30 -12
  38. package/dist/resources/extensions/gsd/gitignore.js +16 -3
  39. package/dist/resources/extensions/gsd/guided-flow.js +149 -38
  40. package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
  41. package/dist/resources/extensions/gsd/health-widget.js +3 -86
  42. package/dist/resources/extensions/gsd/index.js +24 -20
  43. package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
  44. package/dist/resources/extensions/gsd/migrate-external.js +18 -1
  45. package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
  46. package/dist/resources/extensions/gsd/paths.js +3 -0
  47. package/dist/resources/extensions/gsd/preferences-models.js +0 -12
  48. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  49. package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
  50. package/dist/resources/extensions/gsd/preferences.js +22 -11
  51. package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
  52. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  53. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
  55. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
  56. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  57. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  59. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  61. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
  67. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  68. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  69. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
  72. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  73. package/dist/resources/extensions/gsd/repo-identity.js +21 -4
  74. package/dist/resources/extensions/gsd/resource-version.js +2 -1
  75. package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
  76. package/dist/resources/extensions/gsd/state.js +42 -23
  77. package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
  78. package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
  79. package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
  80. package/dist/resources/extensions/mcp-client/index.js +14 -1
  81. package/dist/resources/extensions/remote-questions/status.js +4 -1
  82. package/dist/resources/extensions/remote-questions/store.js +4 -1
  83. package/dist/resources/extensions/search-the-web/provider.js +2 -1
  84. package/dist/resources/extensions/shared/frontmatter.js +1 -1
  85. package/dist/resources/extensions/subagent/isolation.js +2 -1
  86. package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
  87. package/package.json +1 -1
  88. package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
  89. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
  90. package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
  91. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
  93. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
  95. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/skills.js +6 -1
  97. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  99. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/index.js +1 -1
  101. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  102. package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
  103. package/packages/pi-coding-agent/src/core/skills.ts +9 -1
  104. package/packages/pi-coding-agent/src/index.ts +1 -0
  105. package/src/resources/extensions/browser-tools/index.ts +3 -0
  106. package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
  107. package/src/resources/extensions/env-utils.ts +31 -0
  108. package/src/resources/extensions/get-secrets-from-user.ts +5 -24
  109. package/src/resources/extensions/github-sync/cli.ts +364 -0
  110. package/src/resources/extensions/github-sync/index.ts +93 -0
  111. package/src/resources/extensions/github-sync/mapping.ts +81 -0
  112. package/src/resources/extensions/github-sync/sync.ts +556 -0
  113. package/src/resources/extensions/github-sync/templates.ts +183 -0
  114. package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
  115. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
  116. package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
  117. package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
  118. package/src/resources/extensions/github-sync/types.ts +47 -0
  119. package/src/resources/extensions/gsd/auto/session.ts +7 -25
  120. package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
  121. package/src/resources/extensions/gsd/auto-loop.ts +526 -545
  122. package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
  123. package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
  124. package/src/resources/extensions/gsd/auto-start.ts +11 -1
  125. package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
  126. package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
  127. package/src/resources/extensions/gsd/auto.ts +139 -101
  128. package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
  129. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  130. package/src/resources/extensions/gsd/commands.ts +5 -3
  131. package/src/resources/extensions/gsd/context-budget.ts +2 -12
  132. package/src/resources/extensions/gsd/detection.ts +2 -2
  133. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
  134. package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
  135. package/src/resources/extensions/gsd/doctor.ts +22 -1
  136. package/src/resources/extensions/gsd/exit-command.ts +2 -2
  137. package/src/resources/extensions/gsd/export.ts +1 -1
  138. package/src/resources/extensions/gsd/files.ts +51 -11
  139. package/src/resources/extensions/gsd/forensics.ts +1 -1
  140. package/src/resources/extensions/gsd/git-service.ts +44 -10
  141. package/src/resources/extensions/gsd/gitignore.ts +17 -3
  142. package/src/resources/extensions/gsd/guided-flow.ts +177 -44
  143. package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
  144. package/src/resources/extensions/gsd/health-widget.ts +3 -89
  145. package/src/resources/extensions/gsd/index.ts +24 -17
  146. package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
  147. package/src/resources/extensions/gsd/migrate-external.ts +18 -1
  148. package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
  149. package/src/resources/extensions/gsd/paths.ts +4 -0
  150. package/src/resources/extensions/gsd/preferences-models.ts +0 -12
  151. package/src/resources/extensions/gsd/preferences-types.ts +4 -4
  152. package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
  153. package/src/resources/extensions/gsd/preferences.ts +25 -11
  154. package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
  155. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  156. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  157. package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
  158. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
  159. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  160. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
  161. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
  162. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  163. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  164. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  165. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  166. package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  168. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  169. package/src/resources/extensions/gsd/prompts/queue.md +4 -8
  170. package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
  171. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  172. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  174. package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
  175. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
  176. package/src/resources/extensions/gsd/repo-identity.ts +23 -4
  177. package/src/resources/extensions/gsd/resource-version.ts +3 -1
  178. package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
  179. package/src/resources/extensions/gsd/state.ts +39 -21
  180. package/src/resources/extensions/gsd/templates/runtime.md +21 -0
  181. package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
  182. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
  183. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
  184. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
  185. package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
  186. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
  187. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
  188. package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
  189. package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
  190. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
  191. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
  192. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
  193. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
  194. package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
  195. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
  196. package/src/resources/extensions/gsd/types.ts +18 -1
  197. package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
  198. package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
  199. package/src/resources/extensions/mcp-client/index.ts +17 -1
  200. package/src/resources/extensions/remote-questions/status.ts +5 -1
  201. package/src/resources/extensions/remote-questions/store.ts +5 -1
  202. package/src/resources/extensions/search-the-web/provider.ts +2 -1
  203. package/src/resources/extensions/shared/frontmatter.ts +1 -1
  204. package/src/resources/extensions/subagent/isolation.ts +3 -1
  205. package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
  206. package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
  207. package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
  208. package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
  209. package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
  210. package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
  211. package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
  212. package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
  213. package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
  214. package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
  215. package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
  216. package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
  217. package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
@@ -7,11 +7,11 @@ import { promises as fs } from 'node:fs';
7
7
  import { resolve } from 'node:path';
8
8
  import { atomicWriteAsync } from './atomic-write.js';
9
9
  import { resolveMilestoneFile, relMilestoneFile, resolveGsdRootFile } from './paths.js';
10
- import { milestoneIdSort, findMilestoneIds } from './guided-flow.js';
10
+ import { milestoneIdSort, findMilestoneIds } from './milestone-ids.js';
11
11
 
12
12
  import type {
13
13
  Roadmap, BoundaryMapEntry,
14
- SlicePlan, TaskPlanEntry,
14
+ SlicePlan, TaskPlanEntry, TaskPlanFile, TaskPlanFrontmatter,
15
15
  Summary, SummaryFrontmatter, SummaryRequires, FileModified,
16
16
  Continue, ContinueFrontmatter, ContinueStatus,
17
17
  RequirementCounts,
@@ -20,7 +20,7 @@ import type {
20
20
  ManifestStatus,
21
21
  } from './types.js';
22
22
 
23
- import { checkExistingEnvKeys } from '../get-secrets-from-user.js';
23
+ import { checkExistingEnvKeys } from '../env-utils.js';
24
24
  import { parseRoadmapSlices } from './roadmap-slices.js';
25
25
  import { nativeParseRoadmap, nativeExtractSection, nativeParsePlanFile, nativeParseSummaryFile, NATIVE_UNAVAILABLE } from './native-parser-bridge.js';
26
26
  import { debugTime, debugCount } from './debug-logger.js';
@@ -277,14 +277,52 @@ export function formatSecretsManifest(manifest: SecretsManifest): string {
277
277
 
278
278
  // ─── Slice Plan Parser ─────────────────────────────────────────────────────
279
279
 
280
+ function normalizeTaskPlanFrontmatter(frontmatter: Record<string, unknown>): TaskPlanFrontmatter {
281
+ const estimatedStepsRaw = frontmatter.estimated_steps;
282
+ const estimatedFilesRaw = frontmatter.estimated_files;
283
+ const skillsUsedRaw = frontmatter.skills_used;
284
+
285
+ const parseOptionalNumber = (value: unknown): number | undefined => {
286
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
287
+ if (typeof value === 'string' && value.trim()) {
288
+ const parsed = parseInt(value, 10);
289
+ if (Number.isFinite(parsed)) return parsed;
290
+ }
291
+ return undefined;
292
+ };
293
+
294
+ const estimated_steps = parseOptionalNumber(estimatedStepsRaw);
295
+ const estimated_files = parseOptionalNumber(estimatedFilesRaw);
296
+ const skills_used = Array.isArray(skillsUsedRaw)
297
+ ? skillsUsedRaw.map(v => String(v).trim()).filter(Boolean)
298
+ : typeof skillsUsedRaw === 'string' && skillsUsedRaw.trim()
299
+ ? [skillsUsedRaw.trim()]
300
+ : [];
301
+
302
+ return {
303
+ ...(estimated_steps !== undefined ? { estimated_steps } : {}),
304
+ ...(estimated_files !== undefined ? { estimated_files } : {}),
305
+ skills_used,
306
+ };
307
+ }
308
+
309
+ export function parseTaskPlanFile(content: string): TaskPlanFile {
310
+ const [fmLines] = splitFrontmatter(content);
311
+ const fm = fmLines ? parseFrontmatterMap(fmLines) : {};
312
+ return {
313
+ frontmatter: normalizeTaskPlanFrontmatter(fm),
314
+ };
315
+ }
316
+
280
317
  export function parsePlan(content: string): SlicePlan {
281
318
  return cachedParse(content, 'plan', _parsePlanImpl);
282
319
  }
283
320
 
284
321
  function _parsePlanImpl(content: string): SlicePlan {
285
322
  const stopTimer = debugTime("parse-plan");
323
+ const [, body] = splitFrontmatter(content);
286
324
  // Try native parser first for better performance
287
- const nativeResult = nativeParsePlanFile(content);
325
+ const nativeResult = nativeParsePlanFile(body);
288
326
  if (nativeResult) {
289
327
  stopTimer({ native: true });
290
328
  return {
@@ -306,7 +344,7 @@ function _parsePlanImpl(content: string): SlicePlan {
306
344
  };
307
345
  }
308
346
 
309
- const lines = content.split('\n');
347
+ const lines = body.split('\n');
310
348
 
311
349
  const h1 = lines.find(l => l.startsWith('# '));
312
350
  let id = '';
@@ -321,13 +359,13 @@ function _parsePlanImpl(content: string): SlicePlan {
321
359
  }
322
360
  }
323
361
 
324
- const goal = extractBoldField(content, 'Goal') || '';
325
- const demo = extractBoldField(content, 'Demo') || '';
362
+ const goal = extractBoldField(body, 'Goal') || '';
363
+ const demo = extractBoldField(body, 'Demo') || '';
326
364
 
327
- const mhSection = extractSection(content, 'Must-Haves');
365
+ const mhSection = extractSection(body, 'Must-Haves');
328
366
  const mustHaves = mhSection ? parseBullets(mhSection) : [];
329
367
 
330
- const tasksSection = extractSection(content, 'Tasks');
368
+ const tasksSection = extractSection(body, 'Tasks');
331
369
  const tasks: TaskPlanEntry[] = [];
332
370
 
333
371
  if (tasksSection) {
@@ -375,7 +413,7 @@ function _parsePlanImpl(content: string): SlicePlan {
375
413
  if (currentTask) tasks.push(currentTask);
376
414
  }
377
415
 
378
- const filesSection = extractSection(content, 'Files Likely Touched');
416
+ const filesSection = extractSection(body, 'Files Likely Touched');
379
417
  const filesLikelyTouched = filesSection ? parseBullets(filesSection) : [];
380
418
 
381
419
  const result = { id, title, goal, demo, mustHaves, tasks, filesLikelyTouched };
@@ -775,7 +813,7 @@ export function parseTaskPlanIO(content: string): { inputFiles: string[]; output
775
813
  * The four UAT classification types recognised by GSD auto-mode.
776
814
  * `undefined` is returned (not this union) when no type can be determined.
777
815
  */
778
- export type UatType = 'artifact-driven' | 'live-runtime' | 'human-experience' | 'mixed';
816
+ export type UatType = 'artifact-driven' | 'live-runtime' | 'human-experience' | 'mixed' | 'browser-executable' | 'runtime-executable';
779
817
 
780
818
  /**
781
819
  * Extract the UAT type from a UAT file's raw content.
@@ -799,6 +837,8 @@ export function extractUatType(content: string): UatType | undefined {
799
837
  const rawValue = modeBullet.slice('UAT mode:'.length).trim().toLowerCase();
800
838
 
801
839
  if (rawValue.startsWith('artifact-driven')) return 'artifact-driven';
840
+ if (rawValue.startsWith('browser-executable')) return 'browser-executable';
841
+ if (rawValue.startsWith('runtime-executable')) return 'runtime-executable';
802
842
  if (rawValue.startsWith('live-runtime')) return 'live-runtime';
803
843
  if (rawValue.startsWith('human-experience')) return 'human-experience';
804
844
  if (rawValue.startsWith('mixed')) return 'mixed';
@@ -27,7 +27,7 @@ import { deriveState } from "./state.js";
27
27
  import { isAutoActive } from "./auto.js";
28
28
  import { loadPrompt } from "./prompt-loader.js";
29
29
  import { gsdRoot } from "./paths.js";
30
- import { formatDuration } from "../shared/mod.js";
30
+ import { formatDuration } from "../shared/format-utils.js";
31
31
  import { getAutoWorktreePath } from "./auto-worktree.js";
32
32
 
33
33
  // ─── Types ────────────────────────────────────────────────────────────────────
@@ -24,7 +24,7 @@ import {
24
24
  nativeDetectMainBranch,
25
25
  nativeBranchExists,
26
26
  nativeHasChanges,
27
- nativeAddAll,
27
+ nativeAddAllWithExclusions,
28
28
  nativeResetPaths,
29
29
  nativeHasStagedChanges,
30
30
  nativeCommit,
@@ -95,6 +95,8 @@ export interface TaskCommitContext {
95
95
  oneLiner?: string;
96
96
  /** Files modified by this task (from task summary frontmatter) */
97
97
  keyFiles?: string[];
98
+ /** GitHub issue number — appends "Resolves #N" trailer when set. */
99
+ issueNumber?: number;
98
100
  }
99
101
 
100
102
  /**
@@ -118,12 +120,22 @@ export function buildTaskCommitMessage(ctx: TaskCommitContext): string {
118
120
  const subject = `${type}(${scope}): ${truncated}`;
119
121
 
120
122
  // Build body with key files if available
123
+ const bodyParts: string[] = [];
124
+
121
125
  if (ctx.keyFiles && ctx.keyFiles.length > 0) {
122
126
  const fileLines = ctx.keyFiles
123
127
  .slice(0, 8) // cap at 8 files to keep commit concise
124
128
  .map(f => `- ${f}`)
125
129
  .join("\n");
126
- return `${subject}\n\n${fileLines}`;
130
+ bodyParts.push(fileLines);
131
+ }
132
+
133
+ if (ctx.issueNumber) {
134
+ bodyParts.push(`Resolves #${ctx.issueNumber}`);
135
+ }
136
+
137
+ if (bodyParts.length > 0) {
138
+ return `${subject}\n\n${bodyParts.join("\n\n")}`;
127
139
  }
128
140
 
129
141
  return subject;
@@ -373,7 +385,9 @@ export class GitServiceImpl {
373
385
  this._runtimeFilesCleanedUp = true;
374
386
  }
375
387
 
376
- // Stage everything, then unstage excluded paths.
388
+ // Stage everything using pathspec exclusions so excluded paths are never
389
+ // hashed by git. The old approach of `git add -A` followed by unstaging
390
+ // hangs indefinitely on repos with large untracked artifact trees (#1605).
377
391
  //
378
392
  // Exclude only RUNTIME paths from staging — not the entire .gsd/ directory.
379
393
  // When .gsd/milestones/ files are already tracked in the index (projects
@@ -383,13 +397,9 @@ export class GitServiceImpl {
383
397
  // the second half of a milestone's artifacts are never committed (#1326).
384
398
  //
385
399
  // If .gsd/ IS in .gitignore (the default for external state projects),
386
- // git add -A already skips it and the reset is a harmless no-op.
387
- nativeAddAll(this.basePath);
388
-
389
- const runtimeExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
390
- for (const exclusion of runtimeExclusions) {
391
- try { nativeResetPaths(this.basePath, [exclusion]); } catch { /* path not staged — ignore */ }
392
- }
400
+ // git add -A already skips it and the exclusions are harmless no-ops.
401
+ const allExclusions = [...RUNTIME_EXCLUSION_PATHS, ...extraExclusions];
402
+ nativeAddAllWithExclusions(this.basePath, allExclusions);
393
403
  }
394
404
 
395
405
  /** Tracks whether runtime file cleanup has run this session. */
@@ -574,6 +584,30 @@ export class GitServiceImpl {
574
584
 
575
585
  }
576
586
 
587
+ // ─── Draft PR Creation ─────────────────────────────────────────────────────
588
+
589
+ /**
590
+ * Create a draft pull request for a completed milestone using `gh pr create`.
591
+ * Returns the PR URL on success, or null on failure.
592
+ * Non-fatal: callers should treat failure as best-effort.
593
+ */
594
+ export function createDraftPR(
595
+ basePath: string,
596
+ milestoneId: string,
597
+ title: string,
598
+ body: string,
599
+ ): string | null {
600
+ try {
601
+ const result = execSync(
602
+ `gh pr create --draft --title ${JSON.stringify(title)} --body ${JSON.stringify(body)}`,
603
+ { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV },
604
+ );
605
+ return result.trim();
606
+ } catch {
607
+ return null;
608
+ }
609
+ }
610
+
577
611
  // ─── Factory ───────────────────────────────────────────────────────────────
578
612
 
579
613
  /** Create a GitServiceImpl with the current effective git preferences. */
@@ -7,9 +7,11 @@
7
7
  */
8
8
 
9
9
  import { join } from "node:path";
10
+ import { execFileSync } from "node:child_process";
10
11
  import { existsSync, lstatSync, readFileSync, writeFileSync } from "node:fs";
11
12
  import { nativeRmCached, nativeLsFiles } from "./native-git-bridge.js";
12
13
  import { gsdRoot } from "./paths.js";
14
+ import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
13
15
 
14
16
  /**
15
17
  * GSD runtime patterns for git index cleanup.
@@ -104,10 +106,22 @@ export function hasGitTrackedGsdFiles(basePath: string): boolean {
104
106
  // Check if git tracks any files under .gsd/
105
107
  try {
106
108
  const tracked = nativeLsFiles(basePath, ".gsd");
107
- return tracked.length > 0;
108
- } catch {
109
- // Not a git repo or git not available safe to proceed
109
+ if (tracked.length > 0) return true;
110
+
111
+ // nativeLsFiles swallows git failures and returns []. An empty result
112
+ // could mean "nothing tracked" OR "git failed silently". Verify git is
113
+ // reachable before trusting the empty result — if it isn't, fail safe
114
+ // by assuming files ARE tracked to prevent data loss.
115
+ execFileSync("git", ["rev-parse", "--git-dir"], {
116
+ cwd: basePath,
117
+ stdio: "pipe",
118
+ env: GIT_NO_PROMPT_ENV,
119
+ });
120
+
110
121
  return false;
122
+ } catch {
123
+ // git unavailable, index locked, or repo corrupt — fail safe
124
+ return true;
111
125
  }
112
126
  }
113
127
 
@@ -10,6 +10,7 @@ import type { ExtensionAPI, ExtensionContext, ExtensionCommandContext } from "@g
10
10
  import { showNextAction } from "../shared/mod.js";
11
11
  import { loadFile, parseRoadmap } from "./files.js";
12
12
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
13
+ import { buildSkillActivationBlock } from "./auto-prompts.js";
13
14
  import { deriveState } from "./state.js";
14
15
  import { invalidateAllCaches } from "./cache.js";
15
16
  import { startAuto } from "./auto.js";
@@ -34,6 +35,7 @@ import { showConfirm } from "../shared/mod.js";
34
35
  import { debugLog } from "./debug-logger.js";
35
36
  import { findMilestoneIds, nextMilestoneId } from "./milestone-ids.js";
36
37
  import { parkMilestone, discardMilestone } from "./milestone-actions.js";
38
+ import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
37
39
 
38
40
  // ─── Re-exports (preserve public API for existing importers) ────────────────
39
41
  export {
@@ -190,8 +192,40 @@ type UIContext = ExtensionContext;
190
192
  /**
191
193
  * Read GSD-WORKFLOW.md and dispatch it to the LLM with a contextual note.
192
194
  * This is the only way the wizard triggers work — everything else is the LLM's job.
195
+ *
196
+ * When a unitType is provided, resolves the user's model preference for that
197
+ * phase (e.g., models.planning → "plan-milestone") and applies it before
198
+ * dispatching. This ensures guided-flow dispatches respect the same
199
+ * per-phase model preferences that auto-mode uses.
193
200
  */
194
- function dispatchWorkflow(pi: ExtensionAPI, note: string, customType = "gsd-run"): void {
201
+ async function dispatchWorkflow(
202
+ pi: ExtensionAPI,
203
+ note: string,
204
+ customType = "gsd-run",
205
+ ctx?: ExtensionContext,
206
+ unitType?: string,
207
+ ): Promise<void> {
208
+ // Apply model preference for this unit type (if configured)
209
+ if (ctx && unitType) {
210
+ const modelConfig = resolveModelWithFallbacksForUnit(unitType);
211
+ if (modelConfig) {
212
+ const availableModels = ctx.modelRegistry.getAvailable();
213
+ const modelsToTry = [modelConfig.primary, ...modelConfig.fallbacks];
214
+
215
+ for (const modelId of modelsToTry) {
216
+ // Resolve model from available models (same logic as auto-model-selection)
217
+ const model = resolveAvailableModel(modelId, availableModels, ctx.model?.provider);
218
+ if (!model) continue;
219
+
220
+ const ok = await pi.setModel(model, { persist: false });
221
+ if (ok) {
222
+ debugLog("guided-flow-model-applied", { unitType, model: `${model.provider}/${model.id}` });
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+
195
229
  const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(process.env.HOME ?? "~", ".gsd", "agent", "GSD-WORKFLOW.md");
196
230
  const workflow = readFileSync(workflowPath, "utf-8");
197
231
 
@@ -205,6 +239,45 @@ function dispatchWorkflow(pi: ExtensionAPI, note: string, customType = "gsd-run"
205
239
  );
206
240
  }
207
241
 
242
+ /**
243
+ * Resolve a model ID string to a model object from available models.
244
+ * Handles "provider/model" and bare ID formats.
245
+ */
246
+ function resolveAvailableModel<T extends { id: string; provider: string }>(
247
+ modelId: string,
248
+ availableModels: T[],
249
+ currentProvider: string | undefined,
250
+ ): T | undefined {
251
+ const slashIdx = modelId.indexOf("/");
252
+
253
+ if (slashIdx !== -1) {
254
+ const maybeProvider = modelId.substring(0, slashIdx);
255
+ const id = modelId.substring(slashIdx + 1);
256
+
257
+ const knownProviders = new Set(availableModels.map(m => m.provider.toLowerCase()));
258
+ if (knownProviders.has(maybeProvider.toLowerCase())) {
259
+ const match = availableModels.find(
260
+ m => m.provider.toLowerCase() === maybeProvider.toLowerCase()
261
+ && m.id.toLowerCase() === id.toLowerCase(),
262
+ );
263
+ if (match) return match;
264
+ }
265
+
266
+ // Try matching the full string as a model ID (OpenRouter-style)
267
+ const lower = modelId.toLowerCase();
268
+ return availableModels.find(
269
+ m => m.id.toLowerCase() === lower
270
+ || `${m.provider}/${m.id}`.toLowerCase() === lower,
271
+ );
272
+ }
273
+
274
+ // Bare ID — prefer current provider, then first available
275
+ const exactProviderMatch = availableModels.find(
276
+ m => m.id === modelId && m.provider === currentProvider,
277
+ );
278
+ return exactProviderMatch ?? availableModels.find(m => m.id === modelId);
279
+ }
280
+
208
281
  /**
209
282
  * Build the discuss-and-plan prompt for a new milestone.
210
283
  * Used by all three "new milestone" paths (first ever, no active, all complete).
@@ -301,8 +374,8 @@ export async function showHeadlessMilestoneCreation(
301
374
  // Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
302
375
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId };
303
376
 
304
- // Dispatch
305
- dispatchWorkflow(pi, prompt);
377
+ // Dispatch — headless milestone creation is a planning activity
378
+ await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "plan-milestone");
306
379
  }
307
380
 
308
381
 
@@ -467,21 +540,21 @@ export async function showDiscuss(
467
540
  ? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
468
541
  : basePrompt;
469
542
  pendingAutoStart = { ctx, pi, basePath, milestoneId: mid, step: false };
470
- dispatchWorkflow(pi, seed, "gsd-discuss");
543
+ await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "plan-milestone");
471
544
  } else if (choice === "discuss_fresh") {
472
545
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
473
546
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
474
547
  pendingAutoStart = { ctx, pi, basePath, milestoneId: mid, step: false };
475
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
548
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
476
549
  milestoneId: mid, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
477
550
  commitInstruction: buildDocsCommitInstruction(`docs(${mid}): milestone context from discuss`),
478
- }), "gsd-discuss");
551
+ }), "gsd-discuss", ctx, "plan-milestone");
479
552
  } else if (choice === "skip_milestone") {
480
553
  const milestoneIds = findMilestoneIds(basePath);
481
554
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
482
555
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
483
556
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: false };
484
- dispatchWorkflow(pi, buildDiscussPrompt(nextId, `New milestone ${nextId}.`, basePath));
557
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "plan-milestone");
485
558
  }
486
559
  return;
487
560
  }
@@ -580,7 +653,7 @@ export async function showDiscuss(
580
653
  }
581
654
 
582
655
  const prompt = await buildDiscussSlicePrompt(mid, chosen.id, chosen.title, basePath, { rediscuss: isRediscuss });
583
- dispatchWorkflow(pi, prompt, "gsd-discuss");
656
+ await dispatchWorkflow(pi, prompt, "gsd-discuss", ctx, "plan-slice");
584
657
 
585
658
  // Wait for the discuss session to finish, then loop back to the picker
586
659
  await ctx.waitForIdle();
@@ -722,10 +795,10 @@ async function handleMilestoneActions(
722
795
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
723
796
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
724
797
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
725
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
798
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
726
799
  `New milestone ${nextId}.`,
727
800
  basePath
728
- ));
801
+ ), "gsd-run", ctx, "plan-milestone");
729
802
  return true;
730
803
  }
731
804
 
@@ -866,10 +939,10 @@ export async function showSmartEntry(
866
939
  if (isFirst) {
867
940
  // First ever — skip wizard, just ask directly
868
941
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
869
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
942
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
870
943
  `New project, milestone ${nextId}. Do NOT read or explore .gsd/ — it's empty scaffolding.`,
871
944
  basePath
872
- ));
945
+ ), "gsd-run", ctx, "plan-milestone");
873
946
  } else {
874
947
  const choice = await showNextAction(ctx, {
875
948
  title: "GSD — Get Shit Done",
@@ -887,10 +960,10 @@ export async function showSmartEntry(
887
960
 
888
961
  if (choice === "new_milestone") {
889
962
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
890
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
963
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
891
964
  `New milestone ${nextId}.`,
892
965
  basePath
893
- ));
966
+ ), "gsd-run", ctx, "plan-milestone");
894
967
  }
895
968
  }
896
969
  return;
@@ -926,10 +999,10 @@ export async function showSmartEntry(
926
999
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
927
1000
 
928
1001
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
929
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1002
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
930
1003
  `New milestone ${nextId}.`,
931
1004
  basePath
932
- ));
1005
+ ), "gsd-run", ctx, "plan-milestone");
933
1006
  } else if (choice === "status") {
934
1007
  const { fireStatusViaCommand } = await import("./commands.js");
935
1008
  await fireStatusViaCommand(ctx);
@@ -977,24 +1050,24 @@ export async function showSmartEntry(
977
1050
  ? `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\n${draftContent}`
978
1051
  : basePrompt;
979
1052
  pendingAutoStart = { ctx, pi, basePath, milestoneId, step: stepMode };
980
- dispatchWorkflow(pi, seed, "gsd-discuss");
1053
+ await dispatchWorkflow(pi, seed, "gsd-discuss", ctx, "plan-milestone");
981
1054
  } else if (choice === "discuss_fresh") {
982
1055
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
983
1056
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
984
1057
  pendingAutoStart = { ctx, pi, basePath, milestoneId, step: stepMode };
985
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1058
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
986
1059
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
987
1060
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
988
- }), "gsd-discuss");
1061
+ }), "gsd-discuss", ctx, "plan-milestone");
989
1062
  } else if (choice === "skip_milestone") {
990
1063
  const milestoneIds = findMilestoneIds(basePath);
991
1064
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
992
1065
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
993
1066
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
994
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1067
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
995
1068
  `New milestone ${nextId}.`,
996
1069
  basePath
997
- ));
1070
+ ), "gsd-run", ctx, "plan-milestone");
998
1071
  }
999
1072
  return;
1000
1073
  }
@@ -1051,25 +1124,34 @@ export async function showSmartEntry(
1051
1124
  inlineTemplate("secrets-manifest", "Secrets Manifest"),
1052
1125
  ].join("\n\n---\n\n");
1053
1126
  const secretsOutputPath = relMilestoneFile(basePath, milestoneId, "SECRETS");
1054
- dispatchWorkflow(pi, loadPrompt("guided-plan-milestone", {
1055
- milestoneId, milestoneTitle, secretsOutputPath, inlinedTemplates: planMilestoneTemplates,
1056
- }));
1127
+ await dispatchWorkflow(pi, loadPrompt("guided-plan-milestone", {
1128
+ milestoneId,
1129
+ milestoneTitle,
1130
+ secretsOutputPath,
1131
+ inlinedTemplates: planMilestoneTemplates,
1132
+ skillActivation: buildSkillActivationBlock({
1133
+ base: basePath,
1134
+ milestoneId,
1135
+ milestoneTitle,
1136
+ extraContext: [planMilestoneTemplates],
1137
+ }),
1138
+ }), "gsd-run", ctx, "plan-milestone");
1057
1139
  } else if (choice === "discuss") {
1058
1140
  const discussMilestoneTemplates = inlineTemplate("context", "Context");
1059
1141
  const structuredQuestionsAvailable = pi.getActiveTools().includes("ask_user_questions") ? "true" : "false";
1060
- dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1142
+ await dispatchWorkflow(pi, loadPrompt("guided-discuss-milestone", {
1061
1143
  milestoneId, milestoneTitle, inlinedTemplates: discussMilestoneTemplates, structuredQuestionsAvailable,
1062
1144
  commitInstruction: buildDocsCommitInstruction(`docs(${milestoneId}): milestone context from discuss`),
1063
- }));
1145
+ }), "gsd-run", ctx, "plan-milestone");
1064
1146
  } else if (choice === "skip_milestone") {
1065
1147
  const milestoneIds = findMilestoneIds(basePath);
1066
1148
  const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
1067
1149
  const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
1068
1150
  pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: stepMode };
1069
- dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1151
+ await dispatchWorkflow(pi, buildDiscussPrompt(nextId,
1070
1152
  `New milestone ${nextId}.`,
1071
1153
  basePath
1072
- ));
1154
+ ), "gsd-run", ctx, "plan-milestone");
1073
1155
  } else if (choice === "discard_milestone") {
1074
1156
  const confirmed = await showConfirm(ctx, {
1075
1157
  title: "Discard milestone?",
@@ -1181,16 +1263,36 @@ export async function showSmartEntry(
1181
1263
  inlineTemplate("plan", "Slice Plan"),
1182
1264
  inlineTemplate("task-plan", "Task Plan"),
1183
1265
  ].join("\n\n---\n\n");
1184
- dispatchWorkflow(pi, loadPrompt("guided-plan-slice", {
1185
- milestoneId, sliceId, sliceTitle, inlinedTemplates: planSliceTemplates,
1186
- }));
1266
+ await dispatchWorkflow(pi, loadPrompt("guided-plan-slice", {
1267
+ milestoneId,
1268
+ sliceId,
1269
+ sliceTitle,
1270
+ inlinedTemplates: planSliceTemplates,
1271
+ skillActivation: buildSkillActivationBlock({
1272
+ base: basePath,
1273
+ milestoneId,
1274
+ sliceId,
1275
+ sliceTitle,
1276
+ extraContext: [planSliceTemplates],
1277
+ }),
1278
+ }), "gsd-run", ctx, "plan-slice");
1187
1279
  } else if (choice === "discuss") {
1188
- dispatchWorkflow(pi, await buildDiscussSlicePrompt(milestoneId, sliceId, sliceTitle, basePath, { rediscuss: hasContext }));
1280
+ await dispatchWorkflow(pi, await buildDiscussSlicePrompt(milestoneId, sliceId, sliceTitle, basePath, { rediscuss: hasContext }), "gsd-run", ctx, "plan-slice");
1189
1281
  } else if (choice === "research") {
1190
1282
  const researchTemplates = inlineTemplate("research", "Research");
1191
- dispatchWorkflow(pi, loadPrompt("guided-research-slice", {
1192
- milestoneId, sliceId, sliceTitle, inlinedTemplates: researchTemplates,
1193
- }));
1283
+ await dispatchWorkflow(pi, loadPrompt("guided-research-slice", {
1284
+ milestoneId,
1285
+ sliceId,
1286
+ sliceTitle,
1287
+ inlinedTemplates: researchTemplates,
1288
+ skillActivation: buildSkillActivationBlock({
1289
+ base: basePath,
1290
+ milestoneId,
1291
+ sliceId,
1292
+ sliceTitle,
1293
+ extraContext: [researchTemplates],
1294
+ }),
1295
+ }), "gsd-run", ctx, "research-slice");
1194
1296
  } else if (choice === "status") {
1195
1297
  const { fireStatusViaCommand } = await import("./commands.js");
1196
1298
  await fireStatusViaCommand(ctx);
@@ -1232,9 +1334,20 @@ export async function showSmartEntry(
1232
1334
  inlineTemplate("slice-summary", "Slice Summary"),
1233
1335
  inlineTemplate("uat", "UAT"),
1234
1336
  ].join("\n\n---\n\n");
1235
- dispatchWorkflow(pi, loadPrompt("guided-complete-slice", {
1236
- workingDirectory: basePath, milestoneId, sliceId, sliceTitle, inlinedTemplates: completeSliceTemplates,
1237
- }));
1337
+ await dispatchWorkflow(pi, loadPrompt("guided-complete-slice", {
1338
+ workingDirectory: basePath,
1339
+ milestoneId,
1340
+ sliceId,
1341
+ sliceTitle,
1342
+ inlinedTemplates: completeSliceTemplates,
1343
+ skillActivation: buildSkillActivationBlock({
1344
+ base: basePath,
1345
+ milestoneId,
1346
+ sliceId,
1347
+ sliceTitle,
1348
+ extraContext: [completeSliceTemplates],
1349
+ }),
1350
+ }), "gsd-run", ctx, "complete-slice");
1238
1351
  } else if (choice === "status") {
1239
1352
  const { fireStatusViaCommand } = await import("./commands.js");
1240
1353
  await fireStatusViaCommand(ctx);
@@ -1297,14 +1410,34 @@ export async function showSmartEntry(
1297
1410
 
1298
1411
  if (choice === "execute") {
1299
1412
  if (hasInterrupted) {
1300
- dispatchWorkflow(pi, loadPrompt("guided-resume-task", {
1301
- milestoneId, sliceId,
1302
- }));
1413
+ await dispatchWorkflow(pi, loadPrompt("guided-resume-task", {
1414
+ milestoneId,
1415
+ sliceId,
1416
+ skillActivation: buildSkillActivationBlock({
1417
+ base: basePath,
1418
+ milestoneId,
1419
+ sliceId,
1420
+ taskId,
1421
+ taskTitle,
1422
+ }),
1423
+ }), "gsd-run", ctx, "execute-task");
1303
1424
  } else {
1304
1425
  const executeTaskTemplates = inlineTemplate("task-summary", "Task Summary");
1305
- dispatchWorkflow(pi, loadPrompt("guided-execute-task", {
1306
- milestoneId, sliceId, taskId, taskTitle, inlinedTemplates: executeTaskTemplates,
1307
- }));
1426
+ await dispatchWorkflow(pi, loadPrompt("guided-execute-task", {
1427
+ milestoneId,
1428
+ sliceId,
1429
+ taskId,
1430
+ taskTitle,
1431
+ inlinedTemplates: executeTaskTemplates,
1432
+ skillActivation: buildSkillActivationBlock({
1433
+ base: basePath,
1434
+ milestoneId,
1435
+ sliceId,
1436
+ taskId,
1437
+ taskTitle,
1438
+ extraContext: [executeTaskTemplates],
1439
+ }),
1440
+ }), "gsd-run", ctx, "execute-task");
1308
1441
  }
1309
1442
  } else if (choice === "status") {
1310
1443
  const { fireStatusViaCommand } = await import("./commands.js");