gsd-pi 2.76.0-dev.4100bd590 → 2.76.0-dev.76f9a2dc5

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 (112) hide show
  1. package/dist/resource-loader.d.ts +1 -1
  2. package/dist/resource-loader.js +2 -8
  3. package/dist/resources/extensions/gsd/auto/phases.js +4 -1
  4. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  5. package/dist/resources/extensions/gsd/auto-model-selection.js +13 -2
  6. package/dist/resources/extensions/gsd/auto-start.js +12 -7
  7. package/dist/resources/extensions/gsd/auto.js +4 -1
  8. package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
  9. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  10. package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
  11. package/dist/resources/extensions/gsd/safety/file-change-validator.js +1 -1
  12. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  13. package/dist/web/standalone/.next/BUILD_ID +1 -1
  14. package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
  15. package/dist/web/standalone/.next/build-manifest.json +2 -2
  16. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  17. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/index.html +1 -1
  34. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app-paths-manifest.json +20 -20
  41. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  43. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  44. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  45. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  46. package/package.json +1 -1
  47. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  48. package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
  49. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  50. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
  51. package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
  52. package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
  53. package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
  54. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
  55. package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
  56. package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
  57. package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
  58. package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
  59. package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
  60. package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
  61. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  62. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
  63. package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
  64. package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
  65. package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
  67. package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
  68. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
  69. package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
  71. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  72. package/packages/pi-coding-agent/dist/core/model-registry.js +76 -10
  73. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  75. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  76. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  77. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  78. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  79. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
  80. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  82. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  83. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  84. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  85. package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
  86. package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
  87. package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
  88. package/packages/pi-coding-agent/src/core/model-registry.ts +86 -10
  89. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  90. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
  91. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  92. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  93. package/scripts/link-workspace-packages.cjs +1 -0
  94. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  95. package/src/resources/extensions/gsd/auto/phases.ts +4 -0
  96. package/src/resources/extensions/gsd/auto/session.ts +7 -1
  97. package/src/resources/extensions/gsd/auto-model-selection.ts +16 -1
  98. package/src/resources/extensions/gsd/auto-start.ts +12 -7
  99. package/src/resources/extensions/gsd/auto.ts +4 -1
  100. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
  101. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  102. package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
  103. package/src/resources/extensions/gsd/safety/file-change-validator.ts +1 -1
  104. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
  105. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
  106. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
  107. package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
  108. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +20 -0
  109. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  110. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
  111. /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → UMCfv_sVnLXawpUAjvArc}/_buildManifest.js +0 -0
  112. /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → UMCfv_sVnLXawpUAjvArc}/_ssgManifest.js +0 -0
@@ -21,6 +21,6 @@ export declare function getNewerManagedResourceVersion(agentDir: string, current
21
21
  *
22
22
  * Inspectable: `ls ~/.gsd/agent/extensions/`
23
23
  */
24
- export declare function initResources(agentDir: string): void;
24
+ export declare function initResources(agentDir: string, skillsDir?: string): void;
25
25
  export declare function hasStaleCompiledExtensionSiblings(extensionsDir: string, sourceDir?: string): boolean;
26
26
  export declare function buildResourceLoader(agentDir: string): DefaultResourceLoader;
@@ -506,7 +506,7 @@ function pruneRemovedBundledExtensions(manifest, agentDir) {
506
506
  *
507
507
  * Inspectable: `ls ~/.gsd/agent/extensions/`
508
508
  */
509
- export function initResources(agentDir) {
509
+ export function initResources(agentDir, skillsDir = join(homedir(), '.agents', 'skills')) {
510
510
  mkdirSync(agentDir, { recursive: true });
511
511
  const currentVersion = getBundledGsdVersion();
512
512
  const manifest = readManagedResourceManifest(agentDir);
@@ -538,13 +538,7 @@ export function initResources(agentDir) {
538
538
  // Sync bundled resources — overwrite so updates land on next launch.
539
539
  syncResourceDir(bundledExtensionsDir, join(agentDir, 'extensions'));
540
540
  syncResourceDir(join(resourcesDir, 'agents'), join(agentDir, 'agents'));
541
- // Skills are no longer force-synced here. Users install skills via the
542
- // skills.sh CLI (`npx skills add <repo>`) into ~/.agents/skills/ which
543
- // is the industry-standard Agent Skills ecosystem directory.
544
- //
545
- // Migration from the legacy ~/.gsd/agent/skills/ directory is handled
546
- // above the manifest check so it runs on every launch (including retries
547
- // after partial copy failures).
541
+ syncResourceDir(join(resourcesDir, 'skills'), skillsDir);
548
542
  // Sync GSD-WORKFLOW.md to agentDir as a fallback for when GSD_WORKFLOW_PATH
549
543
  // env var is not set (e.g. fork/dev builds, alternative entry points).
550
544
  const workflowSrc = join(resourcesDir, 'GSD-WORKFLOW.md');
@@ -1094,7 +1094,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1094
1094
  logWarning("engine", "Prompt reorder failed", { error: msg });
1095
1095
  }
1096
1096
  // Select and apply model (with tier escalation on retry — normal units only)
1097
- const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride);
1097
+ const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, sidecarItem ? undefined : { isRetry, previousTier }, undefined, s.manualSessionModelOverride, s.autoModeStartThinkingLevel);
1098
1098
  s.currentUnitRouting =
1099
1099
  modelResult.routing;
1100
1100
  s.currentUnitModel =
@@ -1107,6 +1107,9 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
1107
1107
  if (match) {
1108
1108
  const ok = await pi.setModel(match, { persist: false });
1109
1109
  if (ok) {
1110
+ if (s.autoModeStartThinkingLevel) {
1111
+ pi.setThinkingLevel(s.autoModeStartThinkingLevel);
1112
+ }
1110
1113
  s.currentUnitModel = match;
1111
1114
  ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
1112
1115
  }
@@ -65,6 +65,8 @@ export class AutoSession {
65
65
  currentDispatchedModelId = null;
66
66
  originalModelId = null;
67
67
  originalModelProvider = null;
68
+ autoModeStartThinkingLevel = null;
69
+ originalThinkingLevel = null;
68
70
  lastBudgetAlertLevel = 0;
69
71
  // ── Recovery ─────────────────────────────────────────────────────────────
70
72
  pendingCrashRecovery = null;
@@ -177,6 +179,8 @@ export class AutoSession {
177
179
  this.currentDispatchedModelId = null;
178
180
  this.originalModelId = null;
179
181
  this.originalModelProvider = null;
182
+ this.autoModeStartThinkingLevel = null;
183
+ this.originalThinkingLevel = null;
180
184
  this.lastBudgetAlertLevel = 0;
181
185
  // Recovery
182
186
  this.pendingCrashRecovery = null;
@@ -13,6 +13,11 @@ import { logWarning } from "./workflow-logger.js";
13
13
  import { resolveUokFlags } from "./uok/flags.js";
14
14
  import { applyModelPolicyFilter } from "./uok/model-policy.js";
15
15
  import { isModelBlocked } from "./blocked-models.js";
16
+ function reapplyThinkingLevel(pi, level) {
17
+ if (!level)
18
+ return;
19
+ pi.setThinkingLevel(level);
20
+ }
16
21
  export function resolvePreferredModelConfig(unitType, autoModeStartModel, isAutoMode = true) {
17
22
  const explicitConfig = resolveModelWithFallbacksForUnit(unitType);
18
23
  if (explicitConfig) {
@@ -58,7 +63,9 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
58
63
  * Dynamic routing only applies in auto-mode where cost optimization is expected. (#3962) */
59
64
  isAutoMode = true,
60
65
  /** Explicit /gsd model pin captured at bootstrap for long-running auto loops. */
61
- sessionModelOverride) {
66
+ sessionModelOverride,
67
+ /** Thinking level captured at auto-mode start and re-applied after model swaps. */
68
+ autoModeStartThinkingLevel) {
62
69
  const uokFlags = resolveUokFlags(prefs);
63
70
  const effectiveSessionModelOverride = sessionModelOverride === undefined
64
71
  ? getSessionModelOverride(ctx.sessionManager.getSessionId())
@@ -280,6 +287,7 @@ sessionModelOverride) {
280
287
  const ok = await pi.setModel(model, { persist: false });
281
288
  if (ok) {
282
289
  appliedModel = model;
290
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
283
291
  // ADR-005: Adjust active tool set for the selected model's provider capabilities.
284
292
  // Hard-filter incompatible tools, then let extensions override via adjust_tool_set hook.
285
293
  const activeToolNames = pi.getActiveTools();
@@ -346,12 +354,15 @@ sessionModelOverride) {
346
354
  const byId = availableModels.find(m => m.id === autoModeStartModel.id && !isModelBlocked(basePath, m.provider, m.id));
347
355
  if (byId) {
348
356
  const fallbackOk = await pi.setModel(byId, { persist: false });
349
- if (fallbackOk)
357
+ if (fallbackOk) {
350
358
  appliedModel = byId;
359
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
360
+ }
351
361
  }
352
362
  }
353
363
  else {
354
364
  appliedModel = startModel;
365
+ reapplyThinkingLevel(pi, autoModeStartThinkingLevel);
355
366
  }
356
367
  }
357
368
  }
@@ -190,8 +190,8 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
190
190
  //
191
191
  // Precedence:
192
192
  // 1) Explicit session override via /gsd model (this session)
193
- // 2) GSD model preferences from PREFERENCES.md (validated against live auth)
194
- // 3) Current session model from settings/session restore (if provider ready)
193
+ // 2) Current session model from settings/session restore (if provider ready)
194
+ // 3) GSD model preferences from PREFERENCES.md (validated against live auth)
195
195
  //
196
196
  // This preserves #3517 defaults while honoring explicit runtime model
197
197
  // selection for subsequent /gsd runs in the same session.
@@ -224,11 +224,14 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
224
224
  }
225
225
  }
226
226
  const sessionModelReady = ctx.model && ctx.modelRegistry.isProviderRequestReady(ctx.model.provider);
227
+ const currentSessionModel = (sessionModelReady && ctx.model)
228
+ ? { provider: ctx.model.provider, id: ctx.model.id }
229
+ : null;
230
+ const startThinkingSnapshot = pi.getThinkingLevel();
227
231
  const startModelSnapshot = manualSessionOverride
232
+ ?? currentSessionModel
228
233
  ?? validatedPreferredModel
229
- ?? (sessionModelReady && ctx.model
230
- ? { provider: ctx.model.provider, id: ctx.model.id }
231
- : null);
234
+ ?? null;
232
235
  try {
233
236
  // Validate GSD_PROJECT_ID early so the user gets immediate feedback
234
237
  const customProjectId = process.env.GSD_PROJECT_ID;
@@ -506,8 +509,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
506
509
  s.pendingQuickTasks = [];
507
510
  s.currentUnit = null;
508
511
  s.currentMilestoneId = state.activeMilestone?.id ?? null;
509
- s.originalModelId = ctx.model?.id ?? null;
510
- s.originalModelProvider = ctx.model?.provider ?? null;
512
+ s.originalModelId = startModelSnapshot?.id ?? ctx.model?.id ?? null;
513
+ s.originalModelProvider = startModelSnapshot?.provider ?? ctx.model?.provider ?? null;
514
+ s.originalThinkingLevel = startThinkingSnapshot ?? null;
511
515
  // Register SIGTERM handler
512
516
  registerSigtermHandler(base);
513
517
  // Capture integration branch
@@ -608,6 +612,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
608
612
  id: startModelSnapshot.id,
609
613
  };
610
614
  }
615
+ s.autoModeStartThinkingLevel = startThinkingSnapshot ?? null;
611
616
  s.manualSessionModelOverride = manualSessionOverride ?? null;
612
617
  // Apply worker model override from parallel orchestrator (#worker-model).
613
618
  // GSD_WORKER_MODEL is injected by the coordinator when parallel.worker_model
@@ -695,13 +695,16 @@ export async function stopAuto(ctx, pi, reason) {
695
695
  catch (err) { /* non-fatal */
696
696
  logWarning("engine", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
697
697
  }
698
- // ── Step 13: Restore original model (before reset clears IDs) ──
698
+ // ── Step 13: Restore original model + thinking (before reset clears IDs) ──
699
699
  try {
700
700
  if (pi && ctx && s.originalModelId && s.originalModelProvider) {
701
701
  const original = ctx.modelRegistry.find(s.originalModelProvider, s.originalModelId);
702
702
  if (original)
703
703
  await pi.setModel(original);
704
704
  }
705
+ if (pi && s.originalThinkingLevel) {
706
+ pi.setThinkingLevel(s.originalThinkingLevel);
707
+ }
705
708
  }
706
709
  catch (e) {
707
710
  debugLog("stop-cleanup-model", { error: e instanceof Error ? e.message : String(e) });
@@ -8,10 +8,12 @@ import { getAdaptiveTierAdjustment } from "./routing-history.js";
8
8
  import { parseUnitId } from "./unit-id.js";
9
9
  // ─── Unit Type → Default Tier Mapping ────────────────────────────────────────
10
10
  const UNIT_TYPE_TIERS = {
11
- // Tier 1 — Light: structured summaries, completion, UAT
12
- "complete-slice": "light",
11
+ // Tier 1 — Light: compact verification turns
13
12
  "run-uat": "light",
14
- // Tier 2 — Standard: research, routine discussion
13
+ // Tier 2 — Standard: research, routine discussion, slice completion
14
+ // complete-slice can carry large inlined context; avoid routing it to the
15
+ // cheapest "light" model by default (#4520).
16
+ "complete-slice": "standard",
15
17
  "discuss-milestone": "standard",
16
18
  "discuss-slice": "standard",
17
19
  "research-milestone": "standard",
@@ -8,7 +8,7 @@
8
8
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { showNextAction } from "../shared/tui.js";
11
- import { nativeInit } from "./native-git-bridge.js";
11
+ import { nativeInit, nativeAddAll, nativeCommit } from "./native-git-bridge.js";
12
12
  import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
13
13
  import { gsdRoot } from "./paths.js";
14
14
  import { assertSafeDirectory } from "./validate-directory.js";
@@ -40,6 +40,7 @@ export async function showProjectInit(ctx, pi, basePath, detection) {
40
40
  ctx.ui.notify(`Project detected:\n${detectionSummary.join("\n")}`, "info");
41
41
  }
42
42
  // ── Step 2: Git setup ──────────────────────────────────────────────────────
43
+ let didInitGit = false;
43
44
  if (!signals.isGitRepo) {
44
45
  const gitChoice = await showNextAction(ctx, {
45
46
  title: "GSD — Project Setup",
@@ -54,6 +55,7 @@ export async function showProjectInit(ctx, pi, basePath, detection) {
54
55
  return { completed: false, bootstrapped: false };
55
56
  if (gitChoice === "init_git") {
56
57
  nativeInit(basePath, prefs.mainBranch);
58
+ didInitGit = true;
57
59
  }
58
60
  }
59
61
  else {
@@ -244,6 +246,18 @@ export async function showProjectInit(ctx, pi, basePath, detection) {
244
246
  // Ensure .gitignore
245
247
  ensureGitignore(basePath);
246
248
  untrackRuntimeFiles(basePath);
249
+ // Create initial commit so git log and git worktree work immediately (#4530).
250
+ // Without this, the branch is "unborn" (zero commits) and downstream operations
251
+ // like `git log` and `git worktree add` fail.
252
+ if (didInitGit) {
253
+ try {
254
+ nativeAddAll(basePath);
255
+ nativeCommit(basePath, "chore: init project");
256
+ }
257
+ catch {
258
+ // Non-fatal — user can commit manually; don't block project init
259
+ }
260
+ }
247
261
  // Auto-generate codebase map for instant agent orientation
248
262
  try {
249
263
  const result = generateCodebaseMap(basePath);
@@ -22,6 +22,27 @@ import { join, dirname } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { homedir } from "node:os";
24
24
  import { logWarning } from "./workflow-logger.js";
25
+ function hasRequiredExtensionAssets(rootDir, exists = existsSync) {
26
+ return (exists(join(rootDir, "prompts")) &&
27
+ exists(join(rootDir, "templates", "task-summary.md")));
28
+ }
29
+ export function resolveExtensionDirFromCandidates(moduleDir, agentGsdDir, exists = existsSync) {
30
+ const moduleUsable = hasRequiredExtensionAssets(moduleDir, exists);
31
+ const agentUsable = hasRequiredExtensionAssets(agentGsdDir, exists);
32
+ // Prefer the user-local extension tree when both are valid. This avoids
33
+ // leaking npm/global-install paths into prompts on Windows.
34
+ if (agentUsable)
35
+ return agentGsdDir;
36
+ if (moduleUsable)
37
+ return moduleDir;
38
+ // Degraded fallback: if required template is missing in both locations,
39
+ // keep previous behavior and prefer whichever still has prompts/.
40
+ if (exists(join(moduleDir, "prompts")))
41
+ return moduleDir;
42
+ if (exists(join(agentGsdDir, "prompts")))
43
+ return agentGsdDir;
44
+ return moduleDir;
45
+ }
25
46
  /**
26
47
  * Resolve the GSD extension directory.
27
48
  *
@@ -34,15 +55,9 @@ import { logWarning } from "./workflow-logger.js";
34
55
  */
35
56
  function resolveExtensionDir() {
36
57
  const moduleDir = dirname(fileURLToPath(import.meta.url));
37
- if (existsSync(join(moduleDir, "prompts")))
38
- return moduleDir;
39
- // Fallback: user-local agent directory
40
58
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
41
59
  const agentGsdDir = join(gsdHome, "agent", "extensions", "gsd");
42
- if (existsSync(join(agentGsdDir, "prompts")))
43
- return agentGsdDir;
44
- // Last resort: return the module dir (warmCache will silently handle the miss)
45
- return moduleDir;
60
+ return resolveExtensionDirFromCandidates(moduleDir, agentGsdDir);
46
61
  }
47
62
  const __extensionDir = resolveExtensionDir();
48
63
  const promptsDir = join(__extensionDir, "prompts");
@@ -62,7 +62,7 @@ export function validateFileChanges(basePath, expectedOutput, plannedFiles) {
62
62
  // ─── Internals ──────────────────────────────────────────────────────────────
63
63
  function getChangedFilesFromLastCommit(basePath) {
64
64
  try {
65
- const result = execFileSync("git", ["diff", "--name-only", "HEAD~1", "HEAD"], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
65
+ const result = execFileSync("git", ["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", "HEAD"], { cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
66
66
  return result ? result.split("\n").filter(Boolean) : [];
67
67
  }
68
68
  catch (e) {