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
|
@@ -5,17 +5,22 @@
|
|
|
5
5
|
* state, no globals — every dependency is passed as a parameter or imported as a
|
|
6
6
|
* utility.
|
|
7
7
|
*/
|
|
8
|
-
import { loadFile, parseContinue, parsePlan, parseRoadmap, parseSummary, extractUatType, loadActiveOverrides, formatOverridesSection } from "./files.js";
|
|
8
|
+
import { loadFile, parseContinue, parsePlan, parseRoadmap, parseSummary, extractUatType, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
|
|
9
9
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
10
|
-
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, } from "./paths.js";
|
|
11
|
-
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
12
|
-
import {
|
|
10
|
+
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
|
|
11
|
+
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
|
|
12
|
+
import { getLoadedSkills } from "@gsd/pi-coding-agent";
|
|
13
|
+
import { join, basename } from "node:path";
|
|
13
14
|
import { existsSync } from "node:fs";
|
|
14
|
-
import { computeBudgets, resolveExecutorContextWindow } from "./context-budget.js";
|
|
15
|
-
import { compressToTarget } from "./prompt-compressor.js";
|
|
16
|
-
import { distillSummaries } from "./summary-distiller.js";
|
|
15
|
+
import { computeBudgets, resolveExecutorContextWindow, truncateAtSectionBoundary } from "./context-budget.js";
|
|
17
16
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
18
|
-
|
|
17
|
+
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
18
|
+
const MAX_PREAMBLE_CHARS = 30_000;
|
|
19
|
+
function capPreamble(preamble) {
|
|
20
|
+
if (preamble.length <= MAX_PREAMBLE_CHARS)
|
|
21
|
+
return preamble;
|
|
22
|
+
return truncateAtSectionBoundary(preamble, MAX_PREAMBLE_CHARS).content;
|
|
23
|
+
}
|
|
19
24
|
// ─── Executor Constraints ─────────────────────────────────────────────────────
|
|
20
25
|
/**
|
|
21
26
|
* Format executor context constraints for injection into the plan-slice prompt.
|
|
@@ -126,14 +131,9 @@ export async function inlineFileSmart(absPath, relPath, label, query, threshold
|
|
|
126
131
|
if (content.length <= threshold || !query) {
|
|
127
132
|
return `### ${label}\nSource: \`${relPath}\`\n\n${content.trim()}`;
|
|
128
133
|
}
|
|
129
|
-
//
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
if (result.savingsPercent < 20) {
|
|
133
|
-
return `### ${label}\nSource: \`${relPath}\`\n\n${content.trim()}`;
|
|
134
|
-
}
|
|
135
|
-
const formatted = formatChunks(result, relPath);
|
|
136
|
-
return `### ${label} (${result.omittedChunks} sections omitted for relevance)\nSource: \`${relPath}\`\n\n${formatted}`;
|
|
134
|
+
// For large files, truncate at section boundary
|
|
135
|
+
const truncated = truncateAtSectionBoundary(content, threshold).content;
|
|
136
|
+
return `### ${label}\nSource: \`${relPath}\`\n\n${truncated}`;
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
139
139
|
* Load and inline dependency slice summaries (full content, not just paths).
|
|
@@ -165,21 +165,6 @@ export async function inlineDependencySummaries(mid, sid, base, budgetChars) {
|
|
|
165
165
|
}
|
|
166
166
|
const result = sections.join("\n\n");
|
|
167
167
|
if (budgetChars !== undefined && result.length > budgetChars) {
|
|
168
|
-
// For 3+ summaries, try distillation first (preserves more information)
|
|
169
|
-
if (sections.length >= 3) {
|
|
170
|
-
const rawSummaries = sections.map(s => {
|
|
171
|
-
// Extract content after the header line
|
|
172
|
-
const lines = s.split("\n");
|
|
173
|
-
const contentStart = lines.findIndex(l => l.startsWith("Source:"));
|
|
174
|
-
return contentStart >= 0 ? lines.slice(contentStart + 1).join("\n").trim() : s;
|
|
175
|
-
});
|
|
176
|
-
const distilled = distillSummaries(rawSummaries, budgetChars);
|
|
177
|
-
if (distilled.content.length <= budgetChars) {
|
|
178
|
-
return distilled.content;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// Fall back to section-boundary truncation
|
|
182
|
-
const { truncateAtSectionBoundary } = await import("./context-budget.js");
|
|
183
168
|
return truncateAtSectionBoundary(result, budgetChars).content;
|
|
184
169
|
}
|
|
185
170
|
return result;
|
|
@@ -266,7 +251,129 @@ export async function inlineProjectFromDb(base) {
|
|
|
266
251
|
}
|
|
267
252
|
return inlineGsdRootFile(base, "project.md", "Project");
|
|
268
253
|
}
|
|
269
|
-
// ─── Skill Discovery
|
|
254
|
+
// ─── Skill Activation & Discovery ─────────────────────────────────────────
|
|
255
|
+
function normalizeSkillReference(ref) {
|
|
256
|
+
const normalized = ref.replace(/\\/g, "/").trim();
|
|
257
|
+
const base = basename(normalized).replace(/\.md$/i, "");
|
|
258
|
+
const name = /^SKILL$/i.test(base)
|
|
259
|
+
? basename(normalized.replace(/\/SKILL(?:\.md)?$/i, ""))
|
|
260
|
+
: base;
|
|
261
|
+
return name.trim().toLowerCase();
|
|
262
|
+
}
|
|
263
|
+
function tokenizeSkillContext(...parts) {
|
|
264
|
+
const tokens = new Set();
|
|
265
|
+
const addVariants = (raw) => {
|
|
266
|
+
const value = raw.trim().toLowerCase();
|
|
267
|
+
if (!value || value.length < 2)
|
|
268
|
+
return;
|
|
269
|
+
tokens.add(value);
|
|
270
|
+
tokens.add(value.replace(/[-_]+/g, " "));
|
|
271
|
+
tokens.add(value.replace(/\s+/g, "-"));
|
|
272
|
+
tokens.add(value.replace(/\s+/g, ""));
|
|
273
|
+
};
|
|
274
|
+
for (const part of parts) {
|
|
275
|
+
if (!part)
|
|
276
|
+
continue;
|
|
277
|
+
const text = part.toLowerCase();
|
|
278
|
+
const phraseMatches = text.match(/[a-z0-9][a-z0-9+.#/_-]{1,}/g) ?? [];
|
|
279
|
+
for (const match of phraseMatches) {
|
|
280
|
+
addVariants(match);
|
|
281
|
+
for (const piece of match.split(/[^a-z0-9+.#]+/g)) {
|
|
282
|
+
if (piece.length >= 3)
|
|
283
|
+
addVariants(piece);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return tokens;
|
|
288
|
+
}
|
|
289
|
+
function skillMatchesContext(skill, contextTokens) {
|
|
290
|
+
const haystacks = [
|
|
291
|
+
skill.name.toLowerCase(),
|
|
292
|
+
skill.name.toLowerCase().replace(/[-_]+/g, " "),
|
|
293
|
+
skill.description.toLowerCase(),
|
|
294
|
+
];
|
|
295
|
+
return [...contextTokens].some(token => token.length >= 3 && haystacks.some(haystack => haystack.includes(token)));
|
|
296
|
+
}
|
|
297
|
+
function resolvePreferenceSkillNames(refs, base) {
|
|
298
|
+
if (refs.length === 0)
|
|
299
|
+
return [];
|
|
300
|
+
const prefs = { always_use_skills: refs };
|
|
301
|
+
const report = resolveAllSkillReferences(prefs, base);
|
|
302
|
+
return refs.map(ref => {
|
|
303
|
+
const resolution = report.resolutions.get(ref);
|
|
304
|
+
return normalizeSkillReference(resolution?.resolvedPath ?? ref);
|
|
305
|
+
}).filter(Boolean);
|
|
306
|
+
}
|
|
307
|
+
function ruleMatchesContext(when, contextTokens) {
|
|
308
|
+
const whenTokens = tokenizeSkillContext(when);
|
|
309
|
+
return [...whenTokens].some(token => contextTokens.has(token) || [...contextTokens].some(ctx => ctx.includes(token) || token.includes(ctx)));
|
|
310
|
+
}
|
|
311
|
+
function resolveSkillRuleMatches(prefs, contextTokens, base) {
|
|
312
|
+
if (!prefs?.skill_rules?.length)
|
|
313
|
+
return { include: [], avoid: [] };
|
|
314
|
+
const include = [];
|
|
315
|
+
const avoid = [];
|
|
316
|
+
for (const rule of prefs.skill_rules) {
|
|
317
|
+
if (!ruleMatchesContext(rule.when, contextTokens))
|
|
318
|
+
continue;
|
|
319
|
+
include.push(...resolvePreferenceSkillNames([...(rule.use ?? []), ...(rule.prefer ?? [])], base));
|
|
320
|
+
avoid.push(...resolvePreferenceSkillNames(rule.avoid ?? [], base));
|
|
321
|
+
}
|
|
322
|
+
return { include, avoid };
|
|
323
|
+
}
|
|
324
|
+
function resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, base) {
|
|
325
|
+
if (!prefs?.prefer_skills?.length)
|
|
326
|
+
return [];
|
|
327
|
+
const preferred = new Set(resolvePreferenceSkillNames(prefs.prefer_skills, base));
|
|
328
|
+
return visibleSkills
|
|
329
|
+
.filter(skill => preferred.has(normalizeSkillReference(skill.name)) && skillMatchesContext(skill, contextTokens))
|
|
330
|
+
.map(skill => normalizeSkillReference(skill.name));
|
|
331
|
+
}
|
|
332
|
+
function formatSkillActivationBlock(skillNames) {
|
|
333
|
+
if (skillNames.length === 0)
|
|
334
|
+
return "";
|
|
335
|
+
const calls = skillNames.map(name => `Call Skill('${name}')`).join('. ');
|
|
336
|
+
return `<skill_activation>${calls}.</skill_activation>`;
|
|
337
|
+
}
|
|
338
|
+
export function buildSkillActivationBlock(params) {
|
|
339
|
+
const prefs = params.preferences ?? loadEffectiveGSDPreferences()?.preferences;
|
|
340
|
+
const contextTokens = tokenizeSkillContext(params.milestoneId, params.milestoneTitle, params.sliceId, params.sliceTitle, params.taskId, params.taskTitle, ...(params.extraContext ?? []), params.taskPlanContent ?? undefined);
|
|
341
|
+
const visibleSkills = getLoadedSkills().filter(skill => !skill.disableModelInvocation);
|
|
342
|
+
const installedNames = new Set(visibleSkills.map(skill => normalizeSkillReference(skill.name)));
|
|
343
|
+
const avoided = new Set(resolvePreferenceSkillNames(prefs?.avoid_skills ?? [], params.base));
|
|
344
|
+
const matched = new Set();
|
|
345
|
+
for (const name of resolvePreferenceSkillNames(prefs?.always_use_skills ?? [], params.base)) {
|
|
346
|
+
matched.add(name);
|
|
347
|
+
}
|
|
348
|
+
const ruleMatches = resolveSkillRuleMatches(prefs, contextTokens, params.base);
|
|
349
|
+
for (const name of ruleMatches.include)
|
|
350
|
+
matched.add(name);
|
|
351
|
+
for (const name of ruleMatches.avoid)
|
|
352
|
+
avoided.add(name);
|
|
353
|
+
for (const name of resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, params.base)) {
|
|
354
|
+
matched.add(name);
|
|
355
|
+
}
|
|
356
|
+
if (params.taskPlanContent) {
|
|
357
|
+
try {
|
|
358
|
+
const taskPlan = parseTaskPlanFile(params.taskPlanContent);
|
|
359
|
+
for (const skillName of taskPlan.frontmatter.skills_used) {
|
|
360
|
+
matched.add(normalizeSkillReference(skillName));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
// Non-fatal — malformed task plan should not break prompt construction
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for (const skill of visibleSkills) {
|
|
368
|
+
if (skillMatchesContext(skill, contextTokens)) {
|
|
369
|
+
matched.add(normalizeSkillReference(skill.name));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const ordered = [...matched]
|
|
373
|
+
.filter(name => installedNames.has(name) && !avoided.has(name))
|
|
374
|
+
.sort();
|
|
375
|
+
return formatSkillActivationBlock(ordered);
|
|
376
|
+
}
|
|
270
377
|
/**
|
|
271
378
|
* Build the skill discovery template variables for research prompts.
|
|
272
379
|
* Returns { skillDiscoveryMode, skillDiscoveryInstructions } for template substitution.
|
|
@@ -546,7 +653,7 @@ export async function buildResearchMilestonePrompt(mid, midTitle, base) {
|
|
|
546
653
|
if (knowledgeInlineRM)
|
|
547
654
|
inlined.push(knowledgeInlineRM);
|
|
548
655
|
inlined.push(inlineTemplate("research", "Research"));
|
|
549
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
656
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
550
657
|
const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
|
|
551
658
|
return loadPrompt("research-milestone", {
|
|
552
659
|
workingDirectory: base,
|
|
@@ -555,6 +662,12 @@ export async function buildResearchMilestonePrompt(mid, midTitle, base) {
|
|
|
555
662
|
contextPath: contextRel,
|
|
556
663
|
outputPath: join(base, outputRelPath),
|
|
557
664
|
inlinedContext,
|
|
665
|
+
skillActivation: buildSkillActivationBlock({
|
|
666
|
+
base,
|
|
667
|
+
milestoneId: mid,
|
|
668
|
+
milestoneTitle: midTitle,
|
|
669
|
+
extraContext: [inlinedContext],
|
|
670
|
+
}),
|
|
558
671
|
...buildSkillDiscoveryVars(),
|
|
559
672
|
});
|
|
560
673
|
}
|
|
@@ -599,7 +712,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
599
712
|
inlined.push(inlineTemplate("plan", "Slice Plan"));
|
|
600
713
|
inlined.push(inlineTemplate("task-plan", "Task Plan"));
|
|
601
714
|
}
|
|
602
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
715
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
603
716
|
const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
|
|
604
717
|
const researchOutputPath = join(base, relMilestoneFile(base, mid, "RESEARCH"));
|
|
605
718
|
const secretsOutputPath = join(base, relMilestoneFile(base, mid, "SECRETS"));
|
|
@@ -614,6 +727,12 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
614
727
|
secretsOutputPath,
|
|
615
728
|
inlinedContext,
|
|
616
729
|
sourceFilePaths: buildSourceFilePaths(base, mid),
|
|
730
|
+
skillActivation: buildSkillActivationBlock({
|
|
731
|
+
base,
|
|
732
|
+
milestoneId: mid,
|
|
733
|
+
milestoneTitle: midTitle,
|
|
734
|
+
extraContext: [inlinedContext],
|
|
735
|
+
}),
|
|
617
736
|
...buildSkillDiscoveryVars(),
|
|
618
737
|
});
|
|
619
738
|
}
|
|
@@ -647,7 +766,7 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
647
766
|
const overridesInline = formatOverridesSection(activeOverrides);
|
|
648
767
|
if (overridesInline)
|
|
649
768
|
inlined.unshift(overridesInline);
|
|
650
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
769
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
651
770
|
const outputRelPath = relSliceFile(base, mid, sid, "RESEARCH");
|
|
652
771
|
return loadPrompt("research-slice", {
|
|
653
772
|
workingDirectory: base,
|
|
@@ -659,6 +778,13 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
659
778
|
outputPath: join(base, outputRelPath),
|
|
660
779
|
inlinedContext,
|
|
661
780
|
dependencySummaries: depContent,
|
|
781
|
+
skillActivation: buildSkillActivationBlock({
|
|
782
|
+
base,
|
|
783
|
+
milestoneId: mid,
|
|
784
|
+
sliceId: sid,
|
|
785
|
+
sliceTitle: sTitle,
|
|
786
|
+
extraContext: [inlinedContext, depContent],
|
|
787
|
+
}),
|
|
662
788
|
...buildSkillDiscoveryVars(),
|
|
663
789
|
});
|
|
664
790
|
}
|
|
@@ -693,7 +819,7 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
693
819
|
const planOverridesInline = formatOverridesSection(planActiveOverrides);
|
|
694
820
|
if (planOverridesInline)
|
|
695
821
|
inlined.unshift(planOverridesInline);
|
|
696
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
822
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
697
823
|
// Build executor context constraints from the budget engine
|
|
698
824
|
const executorContextConstraints = formatExecutorConstraints();
|
|
699
825
|
const outputRelPath = relSliceFile(base, mid, sid, "PLAN");
|
|
@@ -714,6 +840,13 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
714
840
|
sourceFilePaths: buildSourceFilePaths(base, mid, sid),
|
|
715
841
|
executorContextConstraints,
|
|
716
842
|
commitInstruction,
|
|
843
|
+
skillActivation: buildSkillActivationBlock({
|
|
844
|
+
base,
|
|
845
|
+
milestoneId: mid,
|
|
846
|
+
sliceId: sid,
|
|
847
|
+
sliceTitle: sTitle,
|
|
848
|
+
extraContext: [inlinedContext, depContent],
|
|
849
|
+
}),
|
|
717
850
|
});
|
|
718
851
|
}
|
|
719
852
|
export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base, level) {
|
|
@@ -777,18 +910,21 @@ export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base
|
|
|
777
910
|
const contextWindow = resolveExecutorContextWindow(undefined, prefs?.preferences);
|
|
778
911
|
const budgets = computeBudgets(contextWindow);
|
|
779
912
|
const verificationBudget = `~${Math.round(budgets.verificationBudgetChars / 1000)}K chars`;
|
|
780
|
-
//
|
|
781
|
-
// Only compress when compression_strategy is "compress" (budget/balanced profiles).
|
|
913
|
+
// Truncate carry-forward section when it exceeds 40% of inline context budget.
|
|
782
914
|
const carryForwardBudget = Math.floor(budgets.inlineContextBudgetChars * 0.4);
|
|
783
915
|
let finalCarryForward = carryForwardSection;
|
|
784
916
|
if (carryForwardSection.length > carryForwardBudget) {
|
|
785
|
-
|
|
786
|
-
if (resolveCompressionStrategy() === "compress") {
|
|
787
|
-
finalCarryForward = compressToTarget(carryForwardSection, carryForwardBudget).content;
|
|
788
|
-
}
|
|
917
|
+
finalCarryForward = truncateAtSectionBoundary(carryForwardSection, carryForwardBudget).content;
|
|
789
918
|
}
|
|
919
|
+
// Inline RUNTIME.md if present
|
|
920
|
+
const runtimePath = resolveRuntimeFile(base);
|
|
921
|
+
const runtimeContent = existsSync(runtimePath) ? await loadFile(runtimePath) : null;
|
|
922
|
+
const runtimeContext = runtimeContent
|
|
923
|
+
? `### Runtime Context\nSource: \`.gsd/RUNTIME.md\`\n\n${runtimeContent.trim()}`
|
|
924
|
+
: "";
|
|
790
925
|
return loadPrompt("execute-task", {
|
|
791
926
|
overridesSection,
|
|
927
|
+
runtimeContext,
|
|
792
928
|
workingDirectory: base,
|
|
793
929
|
milestoneId: mid, sliceId: sid, sliceTitle: sTitle, taskId: tid, taskTitle: tTitle,
|
|
794
930
|
planPath: join(base, relSliceFile(base, mid, sid, "PLAN")),
|
|
@@ -802,6 +938,16 @@ export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base
|
|
|
802
938
|
taskSummaryPath,
|
|
803
939
|
inlinedTemplates,
|
|
804
940
|
verificationBudget,
|
|
941
|
+
skillActivation: buildSkillActivationBlock({
|
|
942
|
+
base,
|
|
943
|
+
milestoneId: mid,
|
|
944
|
+
sliceId: sid,
|
|
945
|
+
sliceTitle: sTitle,
|
|
946
|
+
taskId: tid,
|
|
947
|
+
taskTitle: tTitle,
|
|
948
|
+
taskPlanContent,
|
|
949
|
+
extraContext: [taskPlanInline, slicePlanExcerpt, finalCarryForward, resumeSection],
|
|
950
|
+
}),
|
|
805
951
|
});
|
|
806
952
|
}
|
|
807
953
|
export async function buildCompleteSlicePrompt(mid, _midTitle, sid, sTitle, base, level) {
|
|
@@ -843,7 +989,7 @@ export async function buildCompleteSlicePrompt(mid, _midTitle, sid, sTitle, base
|
|
|
843
989
|
const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
|
|
844
990
|
if (completeOverridesInline)
|
|
845
991
|
inlined.unshift(completeOverridesInline);
|
|
846
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
992
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
847
993
|
const sliceRel = relSlicePath(base, mid, sid);
|
|
848
994
|
const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
|
|
849
995
|
const sliceUatPath = join(base, `${sliceRel}/${sid}-UAT.md`);
|
|
@@ -899,7 +1045,7 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
899
1045
|
if (contextInline)
|
|
900
1046
|
inlined.push(contextInline);
|
|
901
1047
|
inlined.push(inlineTemplate("milestone-summary", "Milestone Summary"));
|
|
902
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1048
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
903
1049
|
const milestoneSummaryPath = join(base, `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`);
|
|
904
1050
|
return loadPrompt("complete-milestone", {
|
|
905
1051
|
workingDirectory: base,
|
|
@@ -966,7 +1112,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|
|
966
1112
|
const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
|
|
967
1113
|
if (contextInline)
|
|
968
1114
|
inlined.push(contextInline);
|
|
969
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1115
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
970
1116
|
const validationOutputPath = join(base, `${relMilestonePath(base, mid)}/${mid}-VALIDATION.md`);
|
|
971
1117
|
const roadmapOutputPath = `${relMilestonePath(base, mid)}/${mid}-ROADMAP.md`;
|
|
972
1118
|
return loadPrompt("validate-milestone", {
|
|
@@ -1014,7 +1160,7 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
|
|
|
1014
1160
|
const replanOverridesInline = formatOverridesSection(replanActiveOverrides);
|
|
1015
1161
|
if (replanOverridesInline)
|
|
1016
1162
|
inlined.unshift(replanOverridesInline);
|
|
1017
|
-
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")}`);
|
|
1018
1164
|
const replanPath = join(base, `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`);
|
|
1019
1165
|
// Build capture context for replan prompt (captures that triggered this replan)
|
|
1020
1166
|
let captureContext = "(none)";
|
|
@@ -1039,6 +1185,14 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
|
|
|
1039
1185
|
inlinedContext,
|
|
1040
1186
|
replanPath,
|
|
1041
1187
|
captureContext,
|
|
1188
|
+
skillActivation: buildSkillActivationBlock({
|
|
1189
|
+
base,
|
|
1190
|
+
milestoneId: mid,
|
|
1191
|
+
milestoneTitle: midTitle,
|
|
1192
|
+
sliceId: sid,
|
|
1193
|
+
sliceTitle: sTitle,
|
|
1194
|
+
extraContext: [inlinedContext, captureContext],
|
|
1195
|
+
}),
|
|
1042
1196
|
});
|
|
1043
1197
|
}
|
|
1044
1198
|
export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base) {
|
|
@@ -1054,7 +1208,7 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
|
|
|
1054
1208
|
const projectInline = await inlineProjectFromDb(base);
|
|
1055
1209
|
if (projectInline)
|
|
1056
1210
|
inlined.push(projectInline);
|
|
1057
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1211
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1058
1212
|
const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
|
|
1059
1213
|
const uatType = extractUatType(uatContent) ?? "human-experience";
|
|
1060
1214
|
return loadPrompt("run-uat", {
|
|
@@ -1090,7 +1244,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
|
|
|
1090
1244
|
const knowledgeInlineRA = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
|
|
1091
1245
|
if (knowledgeInlineRA)
|
|
1092
1246
|
inlined.push(knowledgeInlineRA);
|
|
1093
|
-
const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}
|
|
1247
|
+
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
|
1094
1248
|
const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
|
|
1095
1249
|
// Build deferred captures context for reassess prompt
|
|
1096
1250
|
let deferredCaptures = "(none)";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { deriveState } from "./state.js";
|
|
12
12
|
import { loadFile, getManifestStatus } from "./files.js";
|
|
13
13
|
import { loadEffectiveGSDPreferences, resolveSkillDiscoveryMode, getIsolationMode, } from "./preferences.js";
|
|
14
|
-
import { ensureGsdSymlink } from "./repo-identity.js";
|
|
14
|
+
import { ensureGsdSymlink, validateProjectId } from "./repo-identity.js";
|
|
15
15
|
import { migrateToExternalState, recoverFailedMigration } from "./migrate-external.js";
|
|
16
16
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
17
17
|
import { gsdRoot, resolveMilestoneFile } from "./paths.js";
|
|
@@ -63,6 +63,12 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
65
65
|
try {
|
|
66
|
+
// Validate GSD_PROJECT_ID early so the user gets immediate feedback
|
|
67
|
+
const customProjectId = process.env.GSD_PROJECT_ID;
|
|
68
|
+
if (customProjectId && !validateProjectId(customProjectId)) {
|
|
69
|
+
ctx.ui.notify(`GSD_PROJECT_ID must contain only alphanumeric characters, hyphens, and underscores. Got: "${customProjectId}"`, "error");
|
|
70
|
+
return releaseLockAndReturn();
|
|
71
|
+
}
|
|
66
72
|
// Ensure git repo exists
|
|
67
73
|
if (!nativeIsRepo(base)) {
|
|
68
74
|
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
@@ -13,6 +13,7 @@ import { existsSync, readFileSync, unlinkSync, readdirSync, } from "node:fs";
|
|
|
13
13
|
import { join, sep as pathSep } from "node:path";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
16
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
16
17
|
// ─── Project Root → Worktree Sync ─────────────────────────────────────────
|
|
17
18
|
/**
|
|
18
19
|
* Sync milestone artifacts from project root INTO worktree before deriveState.
|
|
@@ -75,7 +76,7 @@ export function syncStateToProjectRoot(worktreePath, projectRoot, milestoneId) {
|
|
|
75
76
|
* doesn't falsely trigger staleness (#804).
|
|
76
77
|
*/
|
|
77
78
|
export function readResourceVersion() {
|
|
78
|
-
const agentDir = process.env.GSD_CODING_AGENT_DIR || join(
|
|
79
|
+
const agentDir = process.env.GSD_CODING_AGENT_DIR || join(gsdHome, "agent");
|
|
79
80
|
const manifestPath = join(agentDir, "managed-resources.json");
|
|
80
81
|
try {
|
|
81
82
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -15,10 +15,10 @@ import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
16
16
|
import { createWorktree, removeWorktree, worktreePath, } from "./worktree-manager.js";
|
|
17
17
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
18
|
-
import { MergeConflictError, readIntegrationBranch } from "./git-service.js";
|
|
18
|
+
import { MergeConflictError, readIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
19
19
|
import { parseRoadmap } from "./files.js";
|
|
20
20
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
21
|
-
import { nativeGetCurrentBranch, nativeWorkingTreeStatus,
|
|
21
|
+
import { nativeGetCurrentBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeCheckoutTheirs, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchExists, } from "./native-git-bridge.js";
|
|
22
22
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
23
23
|
/** Original project root before chdir into auto-worktree. */
|
|
24
24
|
let originalBase = null;
|
|
@@ -656,7 +656,7 @@ function autoCommitDirtyState(cwd) {
|
|
|
656
656
|
const status = nativeWorkingTreeStatus(cwd);
|
|
657
657
|
if (!status)
|
|
658
658
|
return false;
|
|
659
|
-
|
|
659
|
+
nativeAddAllWithExclusions(cwd, RUNTIME_EXCLUSION_PATHS);
|
|
660
660
|
const result = nativeCommit(cwd, "chore: auto-commit before milestone merge");
|
|
661
661
|
return result !== null;
|
|
662
662
|
}
|