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.
- package/README.md +15 -11
- package/dist/app-paths.js +1 -1
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resource-loader.js +34 -1
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/env-utils.js +29 -0
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
- package/dist/resources/extensions/gsd/auto-loop.js +636 -594
- package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
- package/dist/resources/extensions/gsd/auto-start.js +7 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +4 -2
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
- package/dist/resources/extensions/gsd/doctor.js +20 -1
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +48 -9
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +3 -86
- package/dist/resources/extensions/gsd/index.js +24 -20
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +22 -11
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +42 -23
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -1
- package/dist/resources/extensions/remote-questions/store.js +4 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +6 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/skills.ts +9 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/env-utils.ts +31 -0
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
- package/src/resources/extensions/gsd/auto-loop.ts +526 -545
- package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
- package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
- package/src/resources/extensions/gsd/auto-start.ts +11 -1
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +5 -3
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
- package/src/resources/extensions/gsd/doctor.ts +22 -1
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +51 -11
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +3 -89
- package/src/resources/extensions/gsd/index.ts +24 -17
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +25 -11
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +39 -21
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/types.ts +18 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +5 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -6,25 +6,32 @@
|
|
|
6
6
|
* utility.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { loadFile, parseContinue, parsePlan, parseRoadmap, parseSummary, extractUatType, loadActiveOverrides, formatOverridesSection } from "./files.js";
|
|
9
|
+
import { loadFile, parseContinue, parsePlan, parseRoadmap, parseSummary, extractUatType, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
|
|
10
10
|
import type { Override, UatType } from "./files.js";
|
|
11
11
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
12
12
|
import {
|
|
13
13
|
resolveMilestoneFile, resolveSliceFile, resolveSlicePath,
|
|
14
14
|
resolveTasksDir, resolveTaskFiles, resolveTaskFile,
|
|
15
15
|
relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath,
|
|
16
|
-
resolveGsdRootFile, relGsdRootFile,
|
|
16
|
+
resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile,
|
|
17
17
|
} from "./paths.js";
|
|
18
|
-
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
18
|
+
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
|
|
19
19
|
import type { GSDState, InlineLevel } from "./types.js";
|
|
20
20
|
import type { GSDPreferences } from "./preferences.js";
|
|
21
|
-
import {
|
|
21
|
+
import { getLoadedSkills, type Skill } from "@gsd/pi-coding-agent";
|
|
22
|
+
import { join, basename } from "node:path";
|
|
22
23
|
import { existsSync } from "node:fs";
|
|
23
|
-
import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
|
|
24
|
-
import { compressToTarget } from "./prompt-compressor.js";
|
|
25
|
-
import { distillSummaries } from "./summary-distiller.js";
|
|
24
|
+
import { computeBudgets, resolveExecutorContextWindow, truncateAtSectionBoundary } from "./context-budget.js";
|
|
26
25
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
const MAX_PREAMBLE_CHARS = 30_000;
|
|
30
|
+
|
|
31
|
+
function capPreamble(preamble: string): string {
|
|
32
|
+
if (preamble.length <= MAX_PREAMBLE_CHARS) return preamble;
|
|
33
|
+
return truncateAtSectionBoundary(preamble, MAX_PREAMBLE_CHARS).content;
|
|
34
|
+
}
|
|
28
35
|
|
|
29
36
|
// ─── Executor Constraints ─────────────────────────────────────────────────────
|
|
30
37
|
|
|
@@ -159,16 +166,9 @@ export async function inlineFileSmart(
|
|
|
159
166
|
return `### ${label}\nSource: \`${relPath}\`\n\n${content.trim()}`;
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
//
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
// If chunking didn't save much (< 20%), just include full content
|
|
166
|
-
if (result.savingsPercent < 20) {
|
|
167
|
-
return `### ${label}\nSource: \`${relPath}\`\n\n${content.trim()}`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const formatted = formatChunks(result, relPath);
|
|
171
|
-
return `### ${label} (${result.omittedChunks} sections omitted for relevance)\nSource: \`${relPath}\`\n\n${formatted}`;
|
|
169
|
+
// For large files, truncate at section boundary
|
|
170
|
+
const truncated = truncateAtSectionBoundary(content, threshold).content;
|
|
171
|
+
return `### ${label}\nSource: \`${relPath}\`\n\n${truncated}`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/**
|
|
@@ -202,21 +202,6 @@ export async function inlineDependencySummaries(
|
|
|
202
202
|
|
|
203
203
|
const result = sections.join("\n\n");
|
|
204
204
|
if (budgetChars !== undefined && result.length > budgetChars) {
|
|
205
|
-
// For 3+ summaries, try distillation first (preserves more information)
|
|
206
|
-
if (sections.length >= 3) {
|
|
207
|
-
const rawSummaries = sections.map(s => {
|
|
208
|
-
// Extract content after the header line
|
|
209
|
-
const lines = s.split("\n");
|
|
210
|
-
const contentStart = lines.findIndex(l => l.startsWith("Source:"));
|
|
211
|
-
return contentStart >= 0 ? lines.slice(contentStart + 1).join("\n").trim() : s;
|
|
212
|
-
});
|
|
213
|
-
const distilled = distillSummaries(rawSummaries, budgetChars);
|
|
214
|
-
if (distilled.content.length <= budgetChars) {
|
|
215
|
-
return distilled.content;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
// Fall back to section-boundary truncation
|
|
219
|
-
const { truncateAtSectionBoundary } = await import("./context-budget.js");
|
|
220
205
|
return truncateAtSectionBoundary(result, budgetChars).content;
|
|
221
206
|
}
|
|
222
207
|
return result;
|
|
@@ -313,7 +298,171 @@ export async function inlineProjectFromDb(
|
|
|
313
298
|
return inlineGsdRootFile(base, "project.md", "Project");
|
|
314
299
|
}
|
|
315
300
|
|
|
316
|
-
// ─── Skill Discovery
|
|
301
|
+
// ─── Skill Activation & Discovery ─────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
function normalizeSkillReference(ref: string): string {
|
|
304
|
+
const normalized = ref.replace(/\\/g, "/").trim();
|
|
305
|
+
const base = basename(normalized).replace(/\.md$/i, "");
|
|
306
|
+
const name = /^SKILL$/i.test(base)
|
|
307
|
+
? basename(normalized.replace(/\/SKILL(?:\.md)?$/i, ""))
|
|
308
|
+
: base;
|
|
309
|
+
return name.trim().toLowerCase();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function tokenizeSkillContext(...parts: Array<string | null | undefined>): Set<string> {
|
|
313
|
+
const tokens = new Set<string>();
|
|
314
|
+
const addVariants = (raw: string) => {
|
|
315
|
+
const value = raw.trim().toLowerCase();
|
|
316
|
+
if (!value || value.length < 2) return;
|
|
317
|
+
tokens.add(value);
|
|
318
|
+
tokens.add(value.replace(/[-_]+/g, " "));
|
|
319
|
+
tokens.add(value.replace(/\s+/g, "-"));
|
|
320
|
+
tokens.add(value.replace(/\s+/g, ""));
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
for (const part of parts) {
|
|
324
|
+
if (!part) continue;
|
|
325
|
+
const text = part.toLowerCase();
|
|
326
|
+
const phraseMatches = text.match(/[a-z0-9][a-z0-9+.#/_-]{1,}/g) ?? [];
|
|
327
|
+
for (const match of phraseMatches) {
|
|
328
|
+
addVariants(match);
|
|
329
|
+
for (const piece of match.split(/[^a-z0-9+.#]+/g)) {
|
|
330
|
+
if (piece.length >= 3) addVariants(piece);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return tokens;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function skillMatchesContext(skill: Skill, contextTokens: Set<string>): boolean {
|
|
339
|
+
const haystacks = [
|
|
340
|
+
skill.name.toLowerCase(),
|
|
341
|
+
skill.name.toLowerCase().replace(/[-_]+/g, " "),
|
|
342
|
+
skill.description.toLowerCase(),
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
return [...contextTokens].some(token =>
|
|
346
|
+
token.length >= 3 && haystacks.some(haystack => haystack.includes(token)),
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function resolvePreferenceSkillNames(refs: string[], base: string): string[] {
|
|
351
|
+
if (refs.length === 0) return [];
|
|
352
|
+
const prefs: GSDPreferences = { always_use_skills: refs };
|
|
353
|
+
const report = resolveAllSkillReferences(prefs, base);
|
|
354
|
+
return refs.map(ref => {
|
|
355
|
+
const resolution = report.resolutions.get(ref);
|
|
356
|
+
return normalizeSkillReference(resolution?.resolvedPath ?? ref);
|
|
357
|
+
}).filter(Boolean);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function ruleMatchesContext(when: string, contextTokens: Set<string>): boolean {
|
|
361
|
+
const whenTokens = tokenizeSkillContext(when);
|
|
362
|
+
return [...whenTokens].some(token =>
|
|
363
|
+
contextTokens.has(token) || [...contextTokens].some(ctx => ctx.includes(token) || token.includes(ctx)),
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function resolveSkillRuleMatches(
|
|
368
|
+
prefs: GSDPreferences | undefined,
|
|
369
|
+
contextTokens: Set<string>,
|
|
370
|
+
base: string,
|
|
371
|
+
): { include: string[]; avoid: string[] } {
|
|
372
|
+
if (!prefs?.skill_rules?.length) return { include: [], avoid: [] };
|
|
373
|
+
|
|
374
|
+
const include: string[] = [];
|
|
375
|
+
const avoid: string[] = [];
|
|
376
|
+
for (const rule of prefs.skill_rules) {
|
|
377
|
+
if (!ruleMatchesContext(rule.when, contextTokens)) continue;
|
|
378
|
+
include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
|
|
379
|
+
avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
|
|
380
|
+
}
|
|
381
|
+
return { include, avoid };
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function resolvePreferredSkillNames(
|
|
385
|
+
prefs: GSDPreferences | undefined,
|
|
386
|
+
visibleSkills: Skill[],
|
|
387
|
+
contextTokens: Set<string>,
|
|
388
|
+
base: string,
|
|
389
|
+
): string[] {
|
|
390
|
+
if (!prefs?.prefer_skills?.length) return [];
|
|
391
|
+
const preferred = new Set(resolvePreferenceSkillNames(prefs.prefer_skills, base));
|
|
392
|
+
return visibleSkills
|
|
393
|
+
.filter(skill => preferred.has(normalizeSkillReference(skill.name)) && skillMatchesContext(skill, contextTokens))
|
|
394
|
+
.map(skill => normalizeSkillReference(skill.name));
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function formatSkillActivationBlock(skillNames: string[]): string {
|
|
398
|
+
if (skillNames.length === 0) return "";
|
|
399
|
+
const calls = skillNames.map(name => `Call Skill('${name}')`).join('. ');
|
|
400
|
+
return `<skill_activation>${calls}.</skill_activation>`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export function buildSkillActivationBlock(params: {
|
|
404
|
+
base: string;
|
|
405
|
+
milestoneId: string;
|
|
406
|
+
milestoneTitle?: string;
|
|
407
|
+
sliceId?: string;
|
|
408
|
+
sliceTitle?: string;
|
|
409
|
+
taskId?: string;
|
|
410
|
+
taskTitle?: string;
|
|
411
|
+
extraContext?: string[];
|
|
412
|
+
taskPlanContent?: string | null;
|
|
413
|
+
preferences?: GSDPreferences;
|
|
414
|
+
}): string {
|
|
415
|
+
const prefs = params.preferences ?? loadEffectiveGSDPreferences()?.preferences;
|
|
416
|
+
const contextTokens = tokenizeSkillContext(
|
|
417
|
+
params.milestoneId,
|
|
418
|
+
params.milestoneTitle,
|
|
419
|
+
params.sliceId,
|
|
420
|
+
params.sliceTitle,
|
|
421
|
+
params.taskId,
|
|
422
|
+
params.taskTitle,
|
|
423
|
+
...(params.extraContext ?? []),
|
|
424
|
+
params.taskPlanContent ?? undefined,
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const visibleSkills = getLoadedSkills().filter(skill => !skill.disableModelInvocation);
|
|
428
|
+
const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
|
|
429
|
+
const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
|
|
430
|
+
const matched = new Set<string>();
|
|
431
|
+
|
|
432
|
+
for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
|
|
433
|
+
matched.add(name);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
|
|
437
|
+
for (const name of ruleMatches.include) matched.add(name);
|
|
438
|
+
for (const name of ruleMatches.avoid) avoided.add(name);
|
|
439
|
+
|
|
440
|
+
for (const name of resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, params.base)) {
|
|
441
|
+
matched.add(name);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (params.taskPlanContent) {
|
|
445
|
+
try {
|
|
446
|
+
const taskPlan = parseTaskPlanFile(params.taskPlanContent);
|
|
447
|
+
for (const skillName of taskPlan.frontmatter.skills_used) {
|
|
448
|
+
matched.add(normalizeSkillReference(skillName));
|
|
449
|
+
}
|
|
450
|
+
} catch {
|
|
451
|
+
// Non-fatal — malformed task plan should not break prompt construction
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
for (const skill of visibleSkills) {
|
|
456
|
+
if (skillMatchesContext(skill, contextTokens)) {
|
|
457
|
+
matched.add(normalizeSkillReference(skill.name));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const ordered = [...matched]
|
|
462
|
+
.filter(name => installedNames.has(name) && !avoided.has(name))
|
|
463
|
+
.sort();
|
|
464
|
+
return formatSkillActivationBlock(ordered);
|
|
465
|
+
}
|
|
317
466
|
|
|
318
467
|
/**
|
|
319
468
|
* Build the skill discovery template variables for research prompts.
|
|
@@ -634,7 +783,7 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
|
|
|
634
783
|
if (knowledgeInlineRM) inlined.push(knowledgeInlineRM);
|
|
635
784
|
inlined.push(inlineTemplate("research", "Research"));
|
|
636
785
|
|
|
637
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
786
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
638
787
|
|
|
639
788
|
const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
|
|
640
789
|
return loadPrompt("research-milestone", {
|
|
@@ -644,6 +793,12 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
|
|
|
644
793
|
contextPath: contextRel,
|
|
645
794
|
outputPath: join(base, outputRelPath),
|
|
646
795
|
inlinedContext,
|
|
796
|
+
skillActivation: buildSkillActivationBlock({
|
|
797
|
+
base,
|
|
798
|
+
milestoneId: mid,
|
|
799
|
+
milestoneTitle: midTitle,
|
|
800
|
+
extraContext: [inlinedContext],
|
|
801
|
+
}),
|
|
647
802
|
...buildSkillDiscoveryVars(),
|
|
648
803
|
});
|
|
649
804
|
}
|
|
@@ -684,7 +839,7 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
684
839
|
inlined.push(inlineTemplate("task-plan", "Task Plan"));
|
|
685
840
|
}
|
|
686
841
|
|
|
687
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
842
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
688
843
|
|
|
689
844
|
const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
|
|
690
845
|
const researchOutputPath = join(base, relMilestoneFile(base, mid, "RESEARCH"));
|
|
@@ -700,6 +855,12 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
|
|
|
700
855
|
secretsOutputPath,
|
|
701
856
|
inlinedContext,
|
|
702
857
|
sourceFilePaths: buildSourceFilePaths(base, mid),
|
|
858
|
+
skillActivation: buildSkillActivationBlock({
|
|
859
|
+
base,
|
|
860
|
+
milestoneId: mid,
|
|
861
|
+
milestoneTitle: midTitle,
|
|
862
|
+
extraContext: [inlinedContext],
|
|
863
|
+
}),
|
|
703
864
|
...buildSkillDiscoveryVars(),
|
|
704
865
|
});
|
|
705
866
|
}
|
|
@@ -733,7 +894,7 @@ export async function buildResearchSlicePrompt(
|
|
|
733
894
|
const overridesInline = formatOverridesSection(activeOverrides);
|
|
734
895
|
if (overridesInline) inlined.unshift(overridesInline);
|
|
735
896
|
|
|
736
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
897
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
737
898
|
|
|
738
899
|
const outputRelPath = relSliceFile(base, mid, sid, "RESEARCH");
|
|
739
900
|
return loadPrompt("research-slice", {
|
|
@@ -746,6 +907,13 @@ export async function buildResearchSlicePrompt(
|
|
|
746
907
|
outputPath: join(base, outputRelPath),
|
|
747
908
|
inlinedContext,
|
|
748
909
|
dependencySummaries: depContent,
|
|
910
|
+
skillActivation: buildSkillActivationBlock({
|
|
911
|
+
base,
|
|
912
|
+
milestoneId: mid,
|
|
913
|
+
sliceId: sid,
|
|
914
|
+
sliceTitle: sTitle,
|
|
915
|
+
extraContext: [inlinedContext, depContent],
|
|
916
|
+
}),
|
|
749
917
|
...buildSkillDiscoveryVars(),
|
|
750
918
|
});
|
|
751
919
|
}
|
|
@@ -781,7 +949,7 @@ export async function buildPlanSlicePrompt(
|
|
|
781
949
|
const planOverridesInline = formatOverridesSection(planActiveOverrides);
|
|
782
950
|
if (planOverridesInline) inlined.unshift(planOverridesInline);
|
|
783
951
|
|
|
784
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
952
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
785
953
|
|
|
786
954
|
// Build executor context constraints from the budget engine
|
|
787
955
|
const executorContextConstraints = formatExecutorConstraints();
|
|
@@ -804,6 +972,13 @@ export async function buildPlanSlicePrompt(
|
|
|
804
972
|
sourceFilePaths: buildSourceFilePaths(base, mid, sid),
|
|
805
973
|
executorContextConstraints,
|
|
806
974
|
commitInstruction,
|
|
975
|
+
skillActivation: buildSkillActivationBlock({
|
|
976
|
+
base,
|
|
977
|
+
milestoneId: mid,
|
|
978
|
+
sliceId: sid,
|
|
979
|
+
sliceTitle: sTitle,
|
|
980
|
+
extraContext: [inlinedContext, depContent],
|
|
981
|
+
}),
|
|
807
982
|
});
|
|
808
983
|
}
|
|
809
984
|
|
|
@@ -900,19 +1075,23 @@ export async function buildExecuteTaskPrompt(
|
|
|
900
1075
|
const budgets = computeBudgets(contextWindow);
|
|
901
1076
|
const verificationBudget = `~${Math.round(budgets.verificationBudgetChars / 1000)}K chars`;
|
|
902
1077
|
|
|
903
|
-
//
|
|
904
|
-
// Only compress when compression_strategy is "compress" (budget/balanced profiles).
|
|
1078
|
+
// Truncate carry-forward section when it exceeds 40% of inline context budget.
|
|
905
1079
|
const carryForwardBudget = Math.floor(budgets.inlineContextBudgetChars * 0.4);
|
|
906
1080
|
let finalCarryForward = carryForwardSection;
|
|
907
1081
|
if (carryForwardSection.length > carryForwardBudget) {
|
|
908
|
-
|
|
909
|
-
if (resolveCompressionStrategy() === "compress") {
|
|
910
|
-
finalCarryForward = compressToTarget(carryForwardSection, carryForwardBudget).content;
|
|
911
|
-
}
|
|
1082
|
+
finalCarryForward = truncateAtSectionBoundary(carryForwardSection, carryForwardBudget).content;
|
|
912
1083
|
}
|
|
913
1084
|
|
|
1085
|
+
// Inline RUNTIME.md if present
|
|
1086
|
+
const runtimePath = resolveRuntimeFile(base);
|
|
1087
|
+
const runtimeContent = existsSync(runtimePath) ? await loadFile(runtimePath) : null;
|
|
1088
|
+
const runtimeContext = runtimeContent
|
|
1089
|
+
? `### Runtime Context\nSource: \`.gsd/RUNTIME.md\`\n\n${runtimeContent.trim()}`
|
|
1090
|
+
: "";
|
|
1091
|
+
|
|
914
1092
|
return loadPrompt("execute-task", {
|
|
915
1093
|
overridesSection,
|
|
1094
|
+
runtimeContext,
|
|
916
1095
|
workingDirectory: base,
|
|
917
1096
|
milestoneId: mid, sliceId: sid, sliceTitle: sTitle, taskId: tid, taskTitle: tTitle,
|
|
918
1097
|
planPath: join(base, relSliceFile(base, mid, sid, "PLAN")),
|
|
@@ -926,6 +1105,16 @@ export async function buildExecuteTaskPrompt(
|
|
|
926
1105
|
taskSummaryPath,
|
|
927
1106
|
inlinedTemplates,
|
|
928
1107
|
verificationBudget,
|
|
1108
|
+
skillActivation: buildSkillActivationBlock({
|
|
1109
|
+
base,
|
|
1110
|
+
milestoneId: mid,
|
|
1111
|
+
sliceId: sid,
|
|
1112
|
+
sliceTitle: sTitle,
|
|
1113
|
+
taskId: tid,
|
|
1114
|
+
taskTitle: tTitle,
|
|
1115
|
+
taskPlanContent,
|
|
1116
|
+
extraContext: [taskPlanInline, slicePlanExcerpt, finalCarryForward, resumeSection],
|
|
1117
|
+
}),
|
|
929
1118
|
});
|
|
930
1119
|
}
|
|
931
1120
|
|
|
@@ -971,7 +1160,7 @@ export async function buildCompleteSlicePrompt(
|
|
|
971
1160
|
const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
|
|
972
1161
|
if (completeOverridesInline) inlined.unshift(completeOverridesInline);
|
|
973
1162
|
|
|
974
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1163
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
975
1164
|
|
|
976
1165
|
const sliceRel = relSlicePath(base, mid, sid);
|
|
977
1166
|
const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
|
|
@@ -1030,7 +1219,7 @@ export async function buildCompleteMilestonePrompt(
|
|
|
1030
1219
|
if (contextInline) inlined.push(contextInline);
|
|
1031
1220
|
inlined.push(inlineTemplate("milestone-summary", "Milestone Summary"));
|
|
1032
1221
|
|
|
1033
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1222
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1034
1223
|
|
|
1035
1224
|
const milestoneSummaryPath = join(base, `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`);
|
|
1036
1225
|
|
|
@@ -1101,7 +1290,7 @@ export async function buildValidateMilestonePrompt(
|
|
|
1101
1290
|
const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
|
|
1102
1291
|
if (contextInline) inlined.push(contextInline);
|
|
1103
1292
|
|
|
1104
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1293
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1105
1294
|
|
|
1106
1295
|
const validationOutputPath = join(base, `${relMilestonePath(base, mid)}/${mid}-VALIDATION.md`);
|
|
1107
1296
|
const roadmapOutputPath = `${relMilestonePath(base, mid)}/${mid}-ROADMAP.md`;
|
|
@@ -1155,7 +1344,7 @@ export async function buildReplanSlicePrompt(
|
|
|
1155
1344
|
const replanOverridesInline = formatOverridesSection(replanActiveOverrides);
|
|
1156
1345
|
if (replanOverridesInline) inlined.unshift(replanOverridesInline);
|
|
1157
1346
|
|
|
1158
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1347
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1159
1348
|
|
|
1160
1349
|
const replanPath = join(base, `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`);
|
|
1161
1350
|
|
|
@@ -1184,6 +1373,14 @@ export async function buildReplanSlicePrompt(
|
|
|
1184
1373
|
inlinedContext,
|
|
1185
1374
|
replanPath,
|
|
1186
1375
|
captureContext,
|
|
1376
|
+
skillActivation: buildSkillActivationBlock({
|
|
1377
|
+
base,
|
|
1378
|
+
milestoneId: mid,
|
|
1379
|
+
milestoneTitle: midTitle,
|
|
1380
|
+
sliceId: sid,
|
|
1381
|
+
sliceTitle: sTitle,
|
|
1382
|
+
extraContext: [inlinedContext, captureContext],
|
|
1383
|
+
}),
|
|
1187
1384
|
});
|
|
1188
1385
|
}
|
|
1189
1386
|
|
|
@@ -1203,7 +1400,7 @@ export async function buildRunUatPrompt(
|
|
|
1203
1400
|
const projectInline = await inlineProjectFromDb(base);
|
|
1204
1401
|
if (projectInline) inlined.push(projectInline);
|
|
1205
1402
|
|
|
1206
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1403
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1207
1404
|
|
|
1208
1405
|
const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
|
|
1209
1406
|
const uatType = extractUatType(uatContent) ?? "human-experience";
|
|
@@ -1242,7 +1439,7 @@ export async function buildReassessRoadmapPrompt(
|
|
|
1242
1439
|
const knowledgeInlineRA = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
1243
1440
|
if (knowledgeInlineRA) inlined.push(knowledgeInlineRA);
|
|
1244
1441
|
|
|
1245
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1442
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1246
1443
|
|
|
1247
1444
|
const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
|
|
1248
1445
|
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveSkillDiscoveryMode,
|
|
21
21
|
getIsolationMode,
|
|
22
22
|
} from "./preferences.js";
|
|
23
|
-
import { ensureGsdSymlink } from "./repo-identity.js";
|
|
23
|
+
import { ensureGsdSymlink, validateProjectId } from "./repo-identity.js";
|
|
24
24
|
import { migrateToExternalState, recoverFailedMigration } from "./migrate-external.js";
|
|
25
25
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
26
26
|
import { gsdRoot, resolveMilestoneFile, milestonesDir } from "./paths.js";
|
|
@@ -130,6 +130,16 @@ export async function bootstrapAutoSession(
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
try {
|
|
133
|
+
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
134
|
+
const customProjectId = process.env.GSD_PROJECT_ID;
|
|
135
|
+
if (customProjectId && !validateProjectId(customProjectId)) {
|
|
136
|
+
ctx.ui.notify(
|
|
137
|
+
`GSD_PROJECT_ID must contain only alphanumeric characters, hyphens, and underscores. Got: "${customProjectId}"`,
|
|
138
|
+
"error",
|
|
139
|
+
);
|
|
140
|
+
return releaseLockAndReturn();
|
|
141
|
+
}
|
|
142
|
+
|
|
133
143
|
// Ensure git repo exists
|
|
134
144
|
if (!nativeIsRepo(base)) {
|
|
135
145
|
const mainBranch =
|
|
@@ -22,6 +22,8 @@ import { join, sep as pathSep } from "node:path";
|
|
|
22
22
|
import { homedir } from "node:os";
|
|
23
23
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
24
24
|
|
|
25
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
26
|
+
|
|
25
27
|
// ─── Project Root → Worktree Sync ─────────────────────────────────────────
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -111,7 +113,7 @@ export function syncStateToProjectRoot(
|
|
|
111
113
|
*/
|
|
112
114
|
export function readResourceVersion(): string | null {
|
|
113
115
|
const agentDir =
|
|
114
|
-
process.env.GSD_CODING_AGENT_DIR || join(
|
|
116
|
+
process.env.GSD_CODING_AGENT_DIR || join(gsdHome, "agent");
|
|
115
117
|
const manifestPath = join(agentDir, "managed-resources.json");
|
|
116
118
|
try {
|
|
117
119
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -37,13 +37,13 @@ import {
|
|
|
37
37
|
resolveGitHeadPath,
|
|
38
38
|
nudgeGitBranchCache,
|
|
39
39
|
} from "./worktree.js";
|
|
40
|
-
import { MergeConflictError, readIntegrationBranch } from "./git-service.js";
|
|
40
|
+
import { MergeConflictError, readIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
41
41
|
import { parseRoadmap } from "./files.js";
|
|
42
42
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
43
43
|
import {
|
|
44
44
|
nativeGetCurrentBranch,
|
|
45
45
|
nativeWorkingTreeStatus,
|
|
46
|
-
|
|
46
|
+
nativeAddAllWithExclusions,
|
|
47
47
|
nativeCommit,
|
|
48
48
|
nativeCheckoutBranch,
|
|
49
49
|
nativeMergeSquash,
|
|
@@ -768,7 +768,7 @@ function autoCommitDirtyState(cwd: string): boolean {
|
|
|
768
768
|
try {
|
|
769
769
|
const status = nativeWorkingTreeStatus(cwd);
|
|
770
770
|
if (!status) return false;
|
|
771
|
-
|
|
771
|
+
nativeAddAllWithExclusions(cwd, RUNTIME_EXCLUSION_PATHS);
|
|
772
772
|
const result = nativeCommit(
|
|
773
773
|
cwd,
|
|
774
774
|
"chore: auto-commit before milestone merge",
|