gsd-pi 2.37.1 → 2.38.0-dev.4d4d14a
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 +1 -1
- package/dist/app-paths.js +1 -1
- package/dist/cli.js +9 -0
- package/dist/extension-discovery.d.ts +5 -3
- package/dist/extension-discovery.js +14 -9
- package/dist/extension-registry.js +2 -2
- package/dist/onboarding.js +1 -0
- package/dist/remote-questions-config.js +2 -2
- package/dist/resources/extensions/browser-tools/package.json +3 -1
- package/dist/resources/extensions/cmux/index.js +55 -1
- package/dist/resources/extensions/context7/package.json +1 -1
- 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/google-search/package.json +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +74 -9
- package/dist/resources/extensions/gsd/auto-loop.js +149 -170
- package/dist/resources/extensions/gsd/auto-post-unit.js +105 -68
- package/dist/resources/extensions/gsd/auto-prompts.js +98 -33
- package/dist/resources/extensions/gsd/auto-recovery.js +37 -1
- package/dist/resources/extensions/gsd/auto-start.js +13 -2
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/captures.js +9 -1
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +16 -3
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +22 -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-checks.js +82 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
- package/dist/resources/extensions/gsd/doctor-format.js +15 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +62 -12
- package/dist/resources/extensions/gsd/doctor.js +184 -11
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +43 -2
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +8 -1
- package/dist/resources/extensions/gsd/index.js +24 -20
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/observability-validator.js +24 -0
- package/dist/resources/extensions/gsd/package.json +1 -1
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +3 -2
- package/dist/resources/extensions/gsd/preferences-validation.js +101 -11
- package/dist/resources/extensions/gsd/preferences.js +8 -5
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -2
- 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-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +44 -0
- package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/reactive-graph.js +227 -0
- 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/state.js +1 -1
- package/dist/resources/extensions/gsd/templates/task-plan.md +11 -3
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/gsd/worktree.js +35 -16
- package/dist/resources/extensions/remote-questions/status.js +2 -1
- package/dist/resources/extensions/remote-questions/store.js +2 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/subagent/index.js +12 -3
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/dist/resources/extensions/universal-config/package.json +1 -1
- package/dist/welcome-screen.d.ts +12 -0
- package/dist/welcome-screen.js +53 -0
- package/package.json +2 -1
- package/packages/pi-ai/dist/env-api-keys.js +13 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +172 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +172 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +64 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.js +668 -0
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.d.ts +5 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.js +85 -0
- package/packages/pi-ai/dist/providers/anthropic-vertex.js.map +1 -0
- package/packages/pi-ai/dist/providers/anthropic.d.ts +4 -30
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +47 -764
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +6 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -2
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +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/package.json +1 -0
- package/packages/pi-ai/src/env-api-keys.ts +14 -0
- package/packages/pi-ai/src/models.generated.ts +172 -0
- package/packages/pi-ai/src/providers/anthropic-shared.ts +761 -0
- package/packages/pi-ai/src/providers/anthropic-vertex.ts +130 -0
- package/packages/pi-ai/src/providers/anthropic.ts +76 -868
- package/packages/pi-ai/src/providers/register-builtins.ts +7 -0
- package/packages/pi-ai/src/types.ts +2 -0
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cmux/index.ts +57 -1
- 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 +99 -8
- package/src/resources/extensions/gsd/auto-loop.ts +207 -252
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -39
- package/src/resources/extensions/gsd/auto-prompts.ts +132 -36
- package/src/resources/extensions/gsd/auto-recovery.ts +42 -0
- package/src/resources/extensions/gsd/auto-start.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/captures.ts +10 -1
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +17 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +24 -2
- 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-checks.ts +75 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
- package/src/resources/extensions/gsd/doctor-format.ts +20 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +64 -10
- package/src/resources/extensions/gsd/doctor-types.ts +16 -1
- package/src/resources/extensions/gsd/doctor.ts +177 -13
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +47 -2
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +13 -1
- package/src/resources/extensions/gsd/index.ts +24 -17
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/observability-validator.ts +27 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +9 -5
- package/src/resources/extensions/gsd/preferences-validation.ts +92 -11
- package/src/resources/extensions/gsd/preferences.ts +8 -5
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -2
- 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-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +44 -0
- package/src/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/reactive-graph.ts +289 -0
- 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/state.ts +1 -1
- package/src/resources/extensions/gsd/templates/task-plan.md +11 -3
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +16 -37
- package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +191 -3
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +111 -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/reactive-executor.test.ts +511 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +299 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +11 -3
- package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
- package/src/resources/extensions/gsd/types.ts +43 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/gsd/worktree.ts +35 -15
- package/src/resources/extensions/remote-questions/status.ts +3 -1
- package/src/resources/extensions/remote-questions/store.ts +3 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/subagent/index.ts +12 -3
- 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,7 +7,7 @@ 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,
|
|
@@ -15,11 +15,12 @@ import type {
|
|
|
15
15
|
Summary, SummaryFrontmatter, SummaryRequires, FileModified,
|
|
16
16
|
Continue, ContinueFrontmatter, ContinueStatus,
|
|
17
17
|
RequirementCounts,
|
|
18
|
+
TaskIO,
|
|
18
19
|
SecretsManifest, SecretsManifestEntry, SecretsManifestEntryStatus,
|
|
19
20
|
ManifestStatus,
|
|
20
21
|
} from './types.js';
|
|
21
22
|
|
|
22
|
-
import { checkExistingEnvKeys } from '../
|
|
23
|
+
import { checkExistingEnvKeys } from '../env-utils.js';
|
|
23
24
|
import { parseRoadmapSlices } from './roadmap-slices.js';
|
|
24
25
|
import { nativeParseRoadmap, nativeExtractSection, nativeParsePlanFile, nativeParseSummaryFile, NATIVE_UNAVAILABLE } from './native-parser-bridge.js';
|
|
25
26
|
import { debugTime, debugCount } from './debug-logger.js';
|
|
@@ -724,6 +725,50 @@ export function countMustHavesMentionedInSummary(
|
|
|
724
725
|
return count;
|
|
725
726
|
}
|
|
726
727
|
|
|
728
|
+
// ─── Task Plan IO Extractor ────────────────────────────────────────────────
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Extract input and output file paths from a task plan's `## Inputs` and
|
|
732
|
+
* `## Expected Output` sections. Looks for backtick-wrapped file paths on
|
|
733
|
+
* each line (e.g. `` `src/foo.ts` ``).
|
|
734
|
+
*
|
|
735
|
+
* Returns empty arrays for missing/empty sections — callers should treat
|
|
736
|
+
* tasks with no IO as ambiguous (sequential fallback trigger).
|
|
737
|
+
*/
|
|
738
|
+
export function parseTaskPlanIO(content: string): { inputFiles: string[]; outputFiles: string[] } {
|
|
739
|
+
const backtickPathRegex = /`([^`]+)`/g;
|
|
740
|
+
|
|
741
|
+
function extractPaths(sectionText: string | null): string[] {
|
|
742
|
+
if (!sectionText) return [];
|
|
743
|
+
const paths: string[] = [];
|
|
744
|
+
for (const line of sectionText.split("\n")) {
|
|
745
|
+
const trimmed = line.trim();
|
|
746
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
747
|
+
let match: RegExpExecArray | null;
|
|
748
|
+
backtickPathRegex.lastIndex = 0;
|
|
749
|
+
while ((match = backtickPathRegex.exec(trimmed)) !== null) {
|
|
750
|
+
const candidate = match[1];
|
|
751
|
+
// Filter out things that look like code tokens rather than file paths
|
|
752
|
+
// (e.g. `true`, `false`, `npm run test`). A file path has at least one
|
|
753
|
+
// dot or slash.
|
|
754
|
+
if (candidate.includes("/") || candidate.includes(".")) {
|
|
755
|
+
paths.push(candidate);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return paths;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const [, body] = splitFrontmatter(content);
|
|
763
|
+
const inputSection = extractSection(body, "Inputs");
|
|
764
|
+
const outputSection = extractSection(body, "Expected Output");
|
|
765
|
+
|
|
766
|
+
return {
|
|
767
|
+
inputFiles: extractPaths(inputSection),
|
|
768
|
+
outputFiles: extractPaths(outputSection),
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
727
772
|
// ─── UAT Type Extractor ────────────────────────────────────────────────────
|
|
728
773
|
|
|
729
774
|
/**
|
|
@@ -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 ────────────────────────────────────────────────────────────────────
|
|
@@ -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;
|
|
@@ -60,6 +60,8 @@ import { join } from "node:path";
|
|
|
60
60
|
import { existsSync, readFileSync } from "node:fs";
|
|
61
61
|
import { homedir } from "node:os";
|
|
62
62
|
import { shortcutDesc } from "../shared/mod.js";
|
|
63
|
+
|
|
64
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
63
65
|
import { Text } from "@gsd/pi-tui";
|
|
64
66
|
import { pauseAutoForProviderError, classifyProviderError } from "./provider-error-pause.js";
|
|
65
67
|
import { toPosixPath } from "../shared/mod.js";
|
|
@@ -73,7 +75,7 @@ import { markCmuxPromptShown, shouldPromptToEnableCmux } from "../cmux/index.js"
|
|
|
73
75
|
|
|
74
76
|
function warnDeprecatedAgentInstructions(): void {
|
|
75
77
|
const paths = [
|
|
76
|
-
join(
|
|
78
|
+
join(gsdHome, "agent-instructions.md"),
|
|
77
79
|
join(process.cwd(), ".gsd", "agent-instructions.md"),
|
|
78
80
|
];
|
|
79
81
|
for (const p of paths) {
|
|
@@ -90,6 +92,23 @@ function warnDeprecatedAgentInstructions(): void {
|
|
|
90
92
|
// ── Depth verification state ──────────────────────────────────────────────
|
|
91
93
|
let depthVerificationDone = false;
|
|
92
94
|
|
|
95
|
+
// ── DB lazy-open helper ───────────────────────────────────────────────────
|
|
96
|
+
// In manual sessions (no auto-mode), the DB is never opened by bootstrapAutoSession.
|
|
97
|
+
// This helper ensures the DB is lazily opened on first tool call that needs it.
|
|
98
|
+
async function ensureDbOpen(): Promise<boolean> {
|
|
99
|
+
try {
|
|
100
|
+
const db = await import("./gsd-db.js");
|
|
101
|
+
if (db.isDbAvailable()) return true;
|
|
102
|
+
const dbPath = join(process.cwd(), ".gsd", "gsd.db");
|
|
103
|
+
if (existsSync(dbPath)) {
|
|
104
|
+
return db.openDatabase(dbPath);
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
93
112
|
// ── Queue phase tracking ──────────────────────────────────────────────────
|
|
94
113
|
// When true, the LLM is in a queue flow writing CONTEXT.md files.
|
|
95
114
|
// The write-gate applies during queue flows just like discussion flows.
|
|
@@ -298,12 +317,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
298
317
|
when_context: Type.Optional(Type.String({ description: "When/context for the decision (e.g. milestone ID)" })),
|
|
299
318
|
}),
|
|
300
319
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
301
|
-
//
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
const db = await import("./gsd-db.js");
|
|
305
|
-
dbAvailable = db.isDbAvailable();
|
|
306
|
-
} catch { /* dynamic import failed */ }
|
|
320
|
+
// Ensure DB is open (lazy-open on first tool call in manual sessions)
|
|
321
|
+
const dbAvailable = await ensureDbOpen();
|
|
307
322
|
|
|
308
323
|
if (!dbAvailable) {
|
|
309
324
|
return {
|
|
@@ -365,11 +380,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
365
380
|
supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
|
|
366
381
|
}),
|
|
367
382
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
368
|
-
|
|
369
|
-
try {
|
|
370
|
-
const db = await import("./gsd-db.js");
|
|
371
|
-
dbAvailable = db.isDbAvailable();
|
|
372
|
-
} catch { /* dynamic import failed */ }
|
|
383
|
+
const dbAvailable = await ensureDbOpen();
|
|
373
384
|
|
|
374
385
|
if (!dbAvailable) {
|
|
375
386
|
return {
|
|
@@ -439,11 +450,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
439
450
|
content: Type.String({ description: "The full markdown content of the artifact" }),
|
|
440
451
|
}),
|
|
441
452
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
442
|
-
|
|
443
|
-
try {
|
|
444
|
-
const db = await import("./gsd-db.js");
|
|
445
|
-
dbAvailable = db.isDbAvailable();
|
|
446
|
-
} catch { /* dynamic import failed */ }
|
|
453
|
+
const dbAvailable = await ensureDbOpen();
|
|
447
454
|
|
|
448
455
|
if (!dbAvailable) {
|
|
449
456
|
return {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Zero Pi dependencies — uses only exported helpers from files.ts.
|
|
4
4
|
|
|
5
5
|
import { splitFrontmatter, parseFrontmatterMap, extractBoldField } from '../files.js';
|
|
6
|
-
import { normalizeStringArray } from '../../shared/
|
|
6
|
+
import { normalizeStringArray } from '../../shared/format-utils.js';
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
9
|
PlanningRoadmap,
|
|
@@ -235,6 +235,33 @@ export function validateTaskPlanContent(file: string, content: string): Validati
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
// Rule: Inputs and Expected Output should contain backtick-wrapped file paths
|
|
239
|
+
const inputsSection = getSection(content, "Inputs", 2);
|
|
240
|
+
const outputSection = getSection(content, "Expected Output", 2);
|
|
241
|
+
const backtickPathPattern = /`[^`]*[./][^`]*`/;
|
|
242
|
+
|
|
243
|
+
if (outputSection === null || !backtickPathPattern.test(outputSection)) {
|
|
244
|
+
issues.push({
|
|
245
|
+
severity: "warning",
|
|
246
|
+
scope: "task-plan",
|
|
247
|
+
file,
|
|
248
|
+
ruleId: "missing_output_file_paths",
|
|
249
|
+
message: "Task plan `## Expected Output` is missing or has no backtick-wrapped file paths.",
|
|
250
|
+
suggestion: "List concrete output file paths in backticks (e.g. `src/types.ts`). These are machine-parsed to derive task dependencies.",
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (inputsSection !== null && inputsSection.trim().length > 0 && !backtickPathPattern.test(inputsSection)) {
|
|
255
|
+
issues.push({
|
|
256
|
+
severity: "info",
|
|
257
|
+
scope: "task-plan",
|
|
258
|
+
file,
|
|
259
|
+
ruleId: "missing_input_file_paths",
|
|
260
|
+
message: "Task plan `## Inputs` has content but no backtick-wrapped file paths.",
|
|
261
|
+
suggestion: "List input file paths in backticks (e.g. `src/config.json`). These are machine-parsed to derive task dependencies.",
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
238
265
|
// ── Observability rules (gated by runtime relevance) ──
|
|
239
266
|
|
|
240
267
|
const relevant = textSuggestsObservabilityRelevant(content);
|
|
@@ -295,18 +295,6 @@ export function resolveInlineLevel(): InlineLevel {
|
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
/**
|
|
299
|
-
* Resolve the compression strategy from the active token profile.
|
|
300
|
-
* budget/balanced -> "compress", quality -> "truncate".
|
|
301
|
-
* Explicit preference always wins.
|
|
302
|
-
*/
|
|
303
|
-
export function resolveCompressionStrategy(): import("./types.js").CompressionStrategy {
|
|
304
|
-
const prefs = loadEffectiveGSDPreferences();
|
|
305
|
-
if (prefs?.preferences.compression_strategy) return prefs.preferences.compression_strategy;
|
|
306
|
-
const profile = resolveEffectiveProfile();
|
|
307
|
-
return profile === "quality" ? "truncate" : "compress";
|
|
308
|
-
}
|
|
309
|
-
|
|
310
298
|
/**
|
|
311
299
|
* Resolve the context selection mode from the active token profile.
|
|
312
300
|
* budget -> "smart", balanced/quality -> "full".
|
|
@@ -16,10 +16,11 @@ import type {
|
|
|
16
16
|
InlineLevel,
|
|
17
17
|
PhaseSkipPreferences,
|
|
18
18
|
ParallelConfig,
|
|
19
|
-
CompressionStrategy,
|
|
20
19
|
ContextSelectionMode,
|
|
20
|
+
ReactiveExecutionConfig,
|
|
21
21
|
} from "./types.js";
|
|
22
22
|
import type { DynamicRoutingConfig } from "./model-router.js";
|
|
23
|
+
import type { GitHubSyncConfig } from "../github-sync/types.js";
|
|
23
24
|
|
|
24
25
|
// ─── Workflow Modes ──────────────────────────────────────────────────────────
|
|
25
26
|
|
|
@@ -83,15 +84,16 @@ export const KNOWN_PREFERENCE_KEYS = new Set<string>([
|
|
|
83
84
|
"verification_auto_fix",
|
|
84
85
|
"verification_max_retries",
|
|
85
86
|
"search_provider",
|
|
86
|
-
"compression_strategy",
|
|
87
87
|
"context_selection",
|
|
88
88
|
"widget_mode",
|
|
89
|
+
"reactive_execution",
|
|
90
|
+
"github",
|
|
89
91
|
]);
|
|
90
92
|
|
|
91
93
|
/** Canonical list of all dispatch unit types. */
|
|
92
94
|
export const KNOWN_UNIT_TYPES = [
|
|
93
95
|
"research-milestone", "plan-milestone", "research-slice", "plan-slice",
|
|
94
|
-
"execute-task", "complete-slice", "replan-slice", "reassess-roadmap",
|
|
96
|
+
"execute-task", "reactive-execute", "complete-slice", "replan-slice", "reassess-roadmap",
|
|
95
97
|
"run-uat", "complete-milestone",
|
|
96
98
|
] as const;
|
|
97
99
|
export type UnitType = (typeof KNOWN_UNIT_TYPES)[number];
|
|
@@ -209,12 +211,14 @@ export interface GSDPreferences {
|
|
|
209
211
|
verification_max_retries?: number;
|
|
210
212
|
/** Search provider preference. "brave"/"tavily"/"ollama" force that backend and disable native Anthropic search. "native" forces native only. "auto" = current default behavior. */
|
|
211
213
|
search_provider?: "brave" | "tavily" | "ollama" | "native" | "auto";
|
|
212
|
-
/** Compression strategy for context that exceeds budget. "truncate" (default) drops sections, "compress" applies heuristic compression first. */
|
|
213
|
-
compression_strategy?: CompressionStrategy;
|
|
214
214
|
/** Context selection mode for file inlining. "full" inlines entire files, "smart" uses semantic chunking. Default derived from token profile. */
|
|
215
215
|
context_selection?: ContextSelectionMode;
|
|
216
216
|
/** Default widget display mode for auto-mode dashboard. "full" | "small" | "min" | "off". Default: "full". */
|
|
217
217
|
widget_mode?: "full" | "small" | "min" | "off";
|
|
218
|
+
/** Reactive (graph-derived parallel) task execution within slices. Disabled by default. */
|
|
219
|
+
reactive_execution?: ReactiveExecutionConfig;
|
|
220
|
+
/** GitHub sync configuration. Opt-in: syncs GSD events to GitHub Issues, Milestones, and PRs. */
|
|
221
|
+
github?: GitHubSyncConfig;
|
|
218
222
|
}
|
|
219
223
|
|
|
220
224
|
export interface LoadedGSDPreferences {
|
|
@@ -10,7 +10,7 @@ import type { GitPreferences } from "./git-service.js";
|
|
|
10
10
|
import type { PostUnitHookConfig, PreDispatchHookConfig, TokenProfile, PhaseSkipPreferences } from "./types.js";
|
|
11
11
|
import type { DynamicRoutingConfig } from "./model-router.js";
|
|
12
12
|
import { VALID_BRANCH_NAME } from "./git-service.js";
|
|
13
|
-
import { normalizeStringArray } from "../shared/
|
|
13
|
+
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
16
|
KNOWN_PREFERENCE_KEYS,
|
|
@@ -496,6 +496,47 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
// ─── Reactive Execution ─────────────────────────────────────────────────
|
|
500
|
+
if (preferences.reactive_execution !== undefined) {
|
|
501
|
+
if (typeof preferences.reactive_execution === "object" && preferences.reactive_execution !== null) {
|
|
502
|
+
const re = preferences.reactive_execution as unknown as Record<string, unknown>;
|
|
503
|
+
const validRe: Record<string, unknown> = {};
|
|
504
|
+
|
|
505
|
+
if (re.enabled !== undefined) {
|
|
506
|
+
if (typeof re.enabled === "boolean") validRe.enabled = re.enabled;
|
|
507
|
+
else errors.push("reactive_execution.enabled must be a boolean");
|
|
508
|
+
}
|
|
509
|
+
if (re.max_parallel !== undefined) {
|
|
510
|
+
const mp = typeof re.max_parallel === "number" ? re.max_parallel : Number(re.max_parallel);
|
|
511
|
+
if (Number.isFinite(mp) && mp >= 1 && mp <= 8) {
|
|
512
|
+
validRe.max_parallel = Math.floor(mp);
|
|
513
|
+
} else {
|
|
514
|
+
errors.push("reactive_execution.max_parallel must be a number between 1 and 8");
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (re.isolation_mode !== undefined) {
|
|
518
|
+
if (re.isolation_mode === "same-tree") {
|
|
519
|
+
validRe.isolation_mode = "same-tree";
|
|
520
|
+
} else {
|
|
521
|
+
errors.push('reactive_execution.isolation_mode must be "same-tree"');
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const knownReKeys = new Set(["enabled", "max_parallel", "isolation_mode"]);
|
|
526
|
+
for (const key of Object.keys(re)) {
|
|
527
|
+
if (!knownReKeys.has(key)) {
|
|
528
|
+
warnings.push(`unknown reactive_execution key "${key}" — ignored`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (Object.keys(validRe).length > 0) {
|
|
533
|
+
validated.reactive_execution = validRe as unknown as import("./types.js").ReactiveExecutionConfig;
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
errors.push("reactive_execution must be an object");
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
499
540
|
// ─── Verification Preferences ───────────────────────────────────────────
|
|
500
541
|
if (preferences.verification_commands !== undefined) {
|
|
501
542
|
if (Array.isArray(preferences.verification_commands)) {
|
|
@@ -645,16 +686,6 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
645
686
|
}
|
|
646
687
|
}
|
|
647
688
|
|
|
648
|
-
// ─── Compression Strategy ───────────────────────────────────────────
|
|
649
|
-
if (preferences.compression_strategy !== undefined) {
|
|
650
|
-
const validStrategies = new Set(["truncate", "compress"]);
|
|
651
|
-
if (typeof preferences.compression_strategy === "string" && validStrategies.has(preferences.compression_strategy)) {
|
|
652
|
-
validated.compression_strategy = preferences.compression_strategy as GSDPreferences["compression_strategy"];
|
|
653
|
-
} else {
|
|
654
|
-
errors.push(`compression_strategy must be one of: truncate, compress`);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
689
|
// ─── Context Selection ──────────────────────────────────────────────
|
|
659
690
|
if (preferences.context_selection !== undefined) {
|
|
660
691
|
const validModes = new Set(["full", "smart"]);
|
|
@@ -665,5 +696,55 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
665
696
|
}
|
|
666
697
|
}
|
|
667
698
|
|
|
699
|
+
// ─── GitHub Sync ────────────────────────────────────────────────────────
|
|
700
|
+
if (preferences.github !== undefined) {
|
|
701
|
+
if (typeof preferences.github === "object" && preferences.github !== null) {
|
|
702
|
+
const gh = preferences.github as unknown as Record<string, unknown>;
|
|
703
|
+
const validGh: Record<string, unknown> = {};
|
|
704
|
+
|
|
705
|
+
if (gh.enabled !== undefined) {
|
|
706
|
+
if (typeof gh.enabled === "boolean") validGh.enabled = gh.enabled;
|
|
707
|
+
else errors.push("github.enabled must be a boolean");
|
|
708
|
+
}
|
|
709
|
+
if (gh.repo !== undefined) {
|
|
710
|
+
if (typeof gh.repo === "string" && gh.repo.includes("/")) validGh.repo = gh.repo;
|
|
711
|
+
else errors.push('github.repo must be a string in "owner/repo" format');
|
|
712
|
+
}
|
|
713
|
+
if (gh.project !== undefined) {
|
|
714
|
+
const p = typeof gh.project === "number" ? gh.project : Number(gh.project);
|
|
715
|
+
if (Number.isFinite(p) && p > 0) validGh.project = Math.floor(p);
|
|
716
|
+
else errors.push("github.project must be a positive number");
|
|
717
|
+
}
|
|
718
|
+
if (gh.labels !== undefined) {
|
|
719
|
+
if (Array.isArray(gh.labels) && gh.labels.every((l: unknown) => typeof l === "string")) {
|
|
720
|
+
validGh.labels = gh.labels;
|
|
721
|
+
} else {
|
|
722
|
+
errors.push("github.labels must be an array of strings");
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (gh.auto_link_commits !== undefined) {
|
|
726
|
+
if (typeof gh.auto_link_commits === "boolean") validGh.auto_link_commits = gh.auto_link_commits;
|
|
727
|
+
else errors.push("github.auto_link_commits must be a boolean");
|
|
728
|
+
}
|
|
729
|
+
if (gh.slice_prs !== undefined) {
|
|
730
|
+
if (typeof gh.slice_prs === "boolean") validGh.slice_prs = gh.slice_prs;
|
|
731
|
+
else errors.push("github.slice_prs must be a boolean");
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const knownGhKeys = new Set(["enabled", "repo", "project", "labels", "auto_link_commits", "slice_prs"]);
|
|
735
|
+
for (const key of Object.keys(gh)) {
|
|
736
|
+
if (!knownGhKeys.has(key)) {
|
|
737
|
+
warnings.push(`unknown github key "${key}" — ignored`);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (Object.keys(validGh).length > 0) {
|
|
742
|
+
validated.github = validGh as unknown as import("../github-sync/types.js").GitHubSyncConfig;
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
errors.push("github must be an object");
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
668
749
|
return { preferences: validated, errors, warnings };
|
|
669
750
|
}
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
16
18
|
import { gsdRoot } from "./paths.js";
|
|
17
19
|
import { parse as parseYaml } from "yaml";
|
|
18
20
|
import type { PostUnitHookConfig, PreDispatchHookConfig, TokenProfile } from "./types.js";
|
|
19
21
|
import type { DynamicRoutingConfig } from "./model-router.js";
|
|
20
|
-
import { normalizeStringArray } from "../shared/
|
|
22
|
+
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
21
23
|
import { resolveProfileDefaults as _resolveProfileDefaults } from "./preferences-models.js";
|
|
22
24
|
|
|
23
25
|
import {
|
|
@@ -75,21 +77,20 @@ export {
|
|
|
75
77
|
resolveProfileDefaults,
|
|
76
78
|
resolveEffectiveProfile,
|
|
77
79
|
resolveInlineLevel,
|
|
78
|
-
resolveCompressionStrategy,
|
|
79
80
|
resolveContextSelection,
|
|
80
81
|
resolveSearchProviderFromPreferences,
|
|
81
82
|
} from "./preferences-models.js";
|
|
82
83
|
|
|
83
84
|
// ─── Path Constants & Getters ───────────────────────────────────────────────
|
|
84
85
|
|
|
85
|
-
const GLOBAL_PREFERENCES_PATH = join(
|
|
86
|
+
const GLOBAL_PREFERENCES_PATH = join(gsdHome, "preferences.md");
|
|
86
87
|
const LEGACY_GLOBAL_PREFERENCES_PATH = join(homedir(), ".pi", "agent", "gsd-preferences.md");
|
|
87
88
|
function projectPreferencesPath(): string {
|
|
88
89
|
return join(gsdRoot(process.cwd()), "preferences.md");
|
|
89
90
|
}
|
|
90
91
|
// Bootstrap in gitignore.ts historically created PREFERENCES.md (uppercase) by mistake.
|
|
91
92
|
// Check uppercase as a fallback so those files aren't silently ignored.
|
|
92
|
-
const GLOBAL_PREFERENCES_PATH_UPPERCASE = join(
|
|
93
|
+
const GLOBAL_PREFERENCES_PATH_UPPERCASE = join(gsdHome, "PREFERENCES.md");
|
|
93
94
|
function projectPreferencesPathUppercase(): string {
|
|
94
95
|
return join(gsdRoot(process.cwd()), "PREFERENCES.md");
|
|
95
96
|
}
|
|
@@ -267,10 +268,12 @@ function mergePreferences(base: GSDPreferences, override: GSDPreferences): GSDPr
|
|
|
267
268
|
verification_auto_fix: override.verification_auto_fix ?? base.verification_auto_fix,
|
|
268
269
|
verification_max_retries: override.verification_max_retries ?? base.verification_max_retries,
|
|
269
270
|
search_provider: override.search_provider ?? base.search_provider,
|
|
270
|
-
compression_strategy: override.compression_strategy ?? base.compression_strategy,
|
|
271
271
|
context_selection: override.context_selection ?? base.context_selection,
|
|
272
272
|
auto_visualize: override.auto_visualize ?? base.auto_visualize,
|
|
273
273
|
auto_report: override.auto_report ?? base.auto_report,
|
|
274
|
+
github: (base.github || override.github)
|
|
275
|
+
? { ...(base.github ?? {}), ...(override.github ?? {}) } as import("../github-sync/types.js").GitHubSyncConfig
|
|
276
|
+
: undefined,
|
|
274
277
|
};
|
|
275
278
|
}
|
|
276
279
|
|
|
@@ -11,7 +11,7 @@ After the user describes their idea, **do not ask questions yet**. First, prove
|
|
|
11
11
|
1. Summarize what you understood in your own words — concretely, not abstractly.
|
|
12
12
|
2. Give an honest size read: roughly how many milestones, roughly how many slices in the first one. Base this on the actual work involved, not a classification label. A config change might be 1 milestone with 1 slice. A social network might be 5 milestones with 8+ slices each. Use your judgment.
|
|
13
13
|
3. Include scope honesty — a bullet list of the major capabilities you're hearing: "Here's what I'm hearing: [bullet list of major capabilities]."
|
|
14
|
-
4.
|
|
14
|
+
4. Invite correction in one plain sentence: "Here's my read. Correct anything important I missed." — plain text, not `ask_user_questions`.
|
|
15
15
|
|
|
16
16
|
This prevents runaway questioning by forcing comprehension proof before anything else. Do not skip this step. Do not combine it with the first question round.
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ After reflection is confirmed, decide the approach based on the actual scope —
|
|
|
21
21
|
|
|
22
22
|
**If the work spans multiple milestones:** Before drilling into details, map the full landscape:
|
|
23
23
|
1. Propose a milestone sequence — names, one-line intents, rough dependencies
|
|
24
|
-
2. Present this
|
|
24
|
+
2. Present this as the working milestone sequence. Adjust it if the user objects, sharpens it, or adds constraints; otherwise keep moving.
|
|
25
25
|
3. Only then begin the deep Q&A — and scope the Q&A to the full vision, not just M001
|
|
26
26
|
|
|
27
27
|
**If the work fits in a single milestone:** Proceed directly to questioning.
|
|
@@ -48,7 +48,7 @@ You are a thinking partner, not an interviewer.
|
|
|
48
48
|
|
|
49
49
|
**Challenge vagueness, make abstract concrete.** When the user says something abstract ("it should be smart" / "it needs to handle edge cases" / "good UX"), push for specifics. What does "smart" mean in practice? Which edge cases? What does good UX look like for this specific interaction?
|
|
50
50
|
|
|
51
|
-
**
|
|
51
|
+
**Lead with experience, but ask implementation when it materially matters.** Default questions should target the experience and outcome. But when implementation choices materially change scope, proof, compliance, integration, deployment, or irreversible architecture, ask them directly instead of forcing a fake UX phrasing.
|
|
52
52
|
|
|
53
53
|
**Freeform rule:** When the user selects "Other" or clearly wants to explain something freely, stop using `ask_user_questions` and switch to plain text follow-ups. Let them talk. Resume structured questions when appropriate.
|
|
54
54
|
|
|
@@ -105,16 +105,13 @@ Example flow:
|
|
|
105
105
|
|
|
106
106
|
If they clarify, absorb the correction and re-verify.
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Only after the depth checklist is fully satisfied and you genuinely understand the work, offer to proceed.
|
|
108
|
+
The depth verification is the required write-gate. Do **not** add another meta "ready to proceed?" checkpoint immediately after it unless there is still material ambiguity.
|
|
111
109
|
|
|
112
|
-
|
|
113
|
-
"Here's what I'm planning to build: [list of capabilities with rough complexity]. Does this match your vision, or did I miss something?"
|
|
110
|
+
## Wrap-up Gate
|
|
114
111
|
|
|
115
|
-
|
|
112
|
+
Once the depth checklist is fully satisfied, move directly into requirements and roadmap preview. Do not insert a separate "are you ready to continue?" gate unless the user explicitly wants to keep brainstorming or you still see material ambiguity.
|
|
116
113
|
|
|
117
|
-
If
|
|
114
|
+
If you need a final scope reflection, fold it into the depth summary or roadmap preview rather than asking for permission twice.
|
|
118
115
|
|
|
119
116
|
## Focused Research
|
|
120
117
|
|
|
@@ -165,9 +162,9 @@ Rules:
|
|
|
165
162
|
|
|
166
163
|
For multi-milestone projects, requirements should span the full vision. Requirements owned by later milestones get provisional ownership. The full requirement set captures the user's complete vision — milestones are the sequencing strategy, not the scope boundary.
|
|
167
164
|
|
|
168
|
-
If the project is new or has no `REQUIREMENTS.md`,
|
|
165
|
+
If the project is new or has no `REQUIREMENTS.md`, surface candidate requirements in chat before writing the roadmap. Ask for correction only on material omissions, wrong ownership, or wrong scope. If the user has already been specific and raises no substantive objection, treat the requirement set as confirmed and continue.
|
|
169
166
|
|
|
170
|
-
**Print the requirements in chat before
|
|
167
|
+
**Print the requirements in chat before writing the roadmap.** Do not say "here are the requirements" and then only write them to a file. The user must see them in the terminal. Print a markdown table with columns: ID, Title, Status, Owner, Source. Group by status (Active, Deferred, Out of Scope). After the table, ask: "Confirm, adjust, or add?"
|
|
171
168
|
|
|
172
169
|
## Scope Assessment
|
|
173
170
|
|
|
@@ -179,7 +176,7 @@ Before moving to output, confirm the size estimate from your reflection still ho
|
|
|
179
176
|
|
|
180
177
|
Before writing any files, **print the planned roadmap in chat** so the user can see and approve it. Print a markdown table with columns: Slice, Title, Risk, Depends, Demo. One row per slice. Below the table, print the milestone definition of done as a bullet list.
|
|
181
178
|
|
|
182
|
-
|
|
179
|
+
If the user raises a substantive objection, adjust the roadmap. Otherwise, present the roadmap and ask: "Ready to write, or want to adjust?" — one gate, not two.
|
|
183
180
|
|
|
184
181
|
### Naming Convention
|
|
185
182
|
|
|
@@ -236,7 +233,7 @@ If a milestone has no dependencies, omit the frontmatter. The dependency chain f
|
|
|
236
233
|
|
|
237
234
|
#### Phase 3: Sequential readiness gate for remaining milestones
|
|
238
235
|
|
|
239
|
-
For each remaining milestone **one at a time, in sequence**, use `ask_user_questions` to
|
|
236
|
+
For each remaining milestone **one at a time, in sequence**, decide the most likely readiness mode from the evidence you already have, then use `ask_user_questions` to let the user correct that recommendation. Present three options:
|
|
240
237
|
|
|
241
238
|
- **"Discuss now"** — The user wants to conduct a focused discussion for this milestone in the current session, while the context from the broader discussion is still fresh. Proceed with a focused discussion for this milestone (reflection → investigation → questioning → depth verification). When the discussion concludes, write a full `CONTEXT.md`. Then move to the gate for the next milestone.
|
|
242
239
|
- **"Write draft for later"** — This milestone has seed material from the current conversation but needs its own dedicated discussion in a future session. Write a `CONTEXT-DRAFT.md` capturing the seed material (what was discussed, key ideas, provisional scope, open questions). Mark it clearly as a draft, not a finalized context. **What happens downstream:** When auto-mode reaches this milestone, it pauses and notifies the user: "M00x has draft context — needs discussion. Run /gsd." The `/gsd` wizard shows a "Discuss from draft" option that seeds the new discussion with this draft, so nothing from the current conversation is lost. After the dedicated discussion produces a full CONTEXT.md, the draft file is automatically deleted.
|
|
@@ -6,7 +6,7 @@ You are executing GSD auto-mode.
|
|
|
6
6
|
|
|
7
7
|
Your working directory is `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` to any other directory.
|
|
8
8
|
|
|
9
|
-
A researcher explored the codebase and a planner decomposed the work — you are the executor. The task plan below is your authoritative contract.
|
|
9
|
+
A researcher explored the codebase and a planner decomposed the work — you are the executor. The task plan below is your authoritative contract for the slice goal and verification bar, but it is not a substitute for local reality. Verify the referenced files and surrounding code before changing them. Do not do broad re-research or spontaneous re-planning. Small factual corrections, file-path fixes, and local implementation adaptations are part of execution. Escalate to `blocker_discovered: true` only when the slice contract or downstream task graph no longer holds.
|
|
10
10
|
|
|
11
11
|
{{overridesSection}}
|
|
12
12
|
|
|
@@ -27,7 +27,7 @@ A researcher explored the codebase and a planner decomposed the work — you are
|
|
|
27
27
|
Then:
|
|
28
28
|
0. Narrate step transitions, key implementation decisions, and verification outcomes as you work. Keep it terse — one line between tool-call clusters, not between every call — but write complete sentences in user-facing prose, not shorthand notes or scratchpad fragments.
|
|
29
29
|
1. **Load relevant skills before writing code.** Check the `GSD Skill Preferences` block in system context and the `<available_skills>` catalog in your system prompt. For each skill that matches this task's technology stack (e.g., React, Next.js, accessibility, component design), `read` its SKILL.md file now. Skills contain implementation rules and patterns that should guide your code. If no skills match this task, skip this step.
|
|
30
|
-
2. Execute the steps in the inlined task plan
|
|
30
|
+
2. Execute the steps in the inlined task plan, adapting minor local mismatches when the surrounding code differs from the planner's snapshot
|
|
31
31
|
3. Build the real thing. If the task plan says "create login endpoint", build an endpoint that actually authenticates against a real store, not one that returns a hardcoded success response. If the task plan says "create dashboard page", build a page that renders real data from the API, not a component with hardcoded props. Stubs and mocks are for tests, not for the shipped feature.
|
|
32
32
|
4. Write or update tests as part of execution — tests are verification, not an afterthought. If the slice plan defines test files in its Verification section and this is the first task, create them (they should initially fail).
|
|
33
33
|
5. When implementing non-trivial runtime behavior (async flows, API boundaries, background processes, error paths), add or preserve agent-usable observability. Skip this for simple changes where it doesn't apply.
|