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