pi-gsd 1.11.5 → 1.12.0
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/.gsd/extensions/pi-gsd-hooks.ts +106 -56
- package/README.md +2 -4
- package/package.json +1 -1
- package/prompts/gsd-add-phase.md +1 -1
- package/prompts/gsd-add-tests.md +1 -1
- package/prompts/gsd-add-todo.md +1 -1
- package/prompts/gsd-audit-milestone.md +1 -1
- package/prompts/gsd-audit-uat.md +1 -1
- package/prompts/gsd-autonomous.md +2 -2
- package/prompts/gsd-check-todos.md +1 -1
- package/prompts/gsd-cleanup.md +1 -1
- package/prompts/gsd-discuss-phase.md +3 -3
- package/prompts/gsd-do.md +2 -2
- package/prompts/gsd-execute-milestone.md +5 -5
- package/prompts/gsd-execute-phase.md +2 -2
- package/prompts/gsd-fast.md +1 -1
- package/prompts/gsd-forensics.md +1 -1
- package/prompts/gsd-insert-phase.md +1 -1
- package/prompts/gsd-list-phase-assumptions.md +1 -1
- package/prompts/gsd-list-workspaces.md +1 -1
- package/prompts/gsd-manager.md +1 -1
- package/prompts/gsd-map-codebase.md +1 -1
- package/prompts/gsd-milestone-summary.md +1 -1
- package/prompts/gsd-new-milestone.md +5 -5
- package/prompts/gsd-new-project.md +5 -5
- package/prompts/gsd-new-workspace.md +1 -1
- package/prompts/gsd-note.md +1 -1
- package/prompts/gsd-pause-work.md +1 -1
- package/prompts/gsd-plan-milestone-gaps.md +1 -1
- package/prompts/gsd-plan-milestone.md +4 -4
- package/prompts/gsd-plan-phase.md +2 -2
- package/prompts/gsd-plant-seed.md +1 -1
- package/prompts/gsd-pr-branch.md +1 -1
- package/prompts/gsd-profile-user.md +1 -1
- package/prompts/gsd-quick.md +1 -1
- package/prompts/gsd-remove-phase.md +1 -1
- package/prompts/gsd-remove-workspace.md +1 -1
- package/prompts/gsd-resume-work.md +1 -1
- package/prompts/gsd-review.md +1 -1
- package/prompts/gsd-session-report.md +1 -1
- package/prompts/gsd-settings.md +1 -1
- package/prompts/gsd-ship.md +1 -1
- package/prompts/gsd-ui-phase.md +2 -2
- package/prompts/gsd-ui-review.md +2 -2
- package/prompts/gsd-validate-phase.md +1 -1
- package/prompts/gsd-verify-work.md +2 -2
|
@@ -76,92 +76,145 @@ const ensureHarnessSymlink = (cwd: string): void => {
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
const syncReferenceToCore = (cwd: string, ref: string[]): void => {
|
|
80
|
-
try {
|
|
81
|
-
const refsDir = join(cwd, ".pi", "gsd", "references");
|
|
82
|
-
const refName = ref.join("-") + ".md";
|
|
83
|
-
const coreName = [...ref, "core"].join("-") + ".md";
|
|
84
|
-
const src = join(refsDir, refName);
|
|
85
|
-
const dst = join(refsDir, coreName);
|
|
86
|
-
if (!existsSync(src)) return;
|
|
87
|
-
const srcMtime = statSync(src).mtimeMs;
|
|
88
|
-
const dstMtime = existsSync(dst) ? statSync(dst).mtimeMs : 0;
|
|
89
|
-
if (srcMtime <= dstMtime) return; // already in sync
|
|
90
|
-
const content = readFileSync(src, "utf8");
|
|
91
|
-
const match = content.match(/<core>([\s\S]*?)<\/core>/i);
|
|
92
|
-
writeFileSync(dst, match ? match[1].trim() : content, "utf8");
|
|
93
|
-
} catch {
|
|
94
|
-
/* silent — never block session startup or tool execution */
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
79
|
|
|
98
80
|
export default function (pi: ExtensionAPI) {
|
|
99
|
-
// ── input:
|
|
100
|
-
// Replaces
|
|
101
|
-
//
|
|
102
|
-
//
|
|
81
|
+
// ── input: <gsd-include> injection ───────────────────────────────────
|
|
82
|
+
// Replaces <gsd-include path="..." /> tags with actual file contents.
|
|
83
|
+
// Supports selectors: tag:NAME, heading:TEXT, lines:N-M
|
|
84
|
+
// Valid chains: tag|heading, tag|lines, heading|lines, heading|tag
|
|
85
|
+
// On ANY failure: red error + abort (action:"handled"). No partial injection.
|
|
103
86
|
pi.on("input", async (event, ctx) => {
|
|
104
87
|
if (event.source === "extension") return { action: "continue" };
|
|
105
88
|
|
|
106
89
|
const text = event.text;
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
if (
|
|
90
|
+
const includePattern = /<gsd-include\s+path="([^"]+)"(?:\s+select="([^"]*)")?\s*\/>/g;
|
|
91
|
+
const includes = [...text.matchAll(includePattern)];
|
|
92
|
+
if (includes.length === 0) return { action: "continue" };
|
|
110
93
|
|
|
111
|
-
//
|
|
112
|
-
// <pkg>/.gsd/extensions/pi-gsd-hooks.ts → <pkg>/.gsd/harnesses/pi/get-shit-done
|
|
94
|
+
// Package harness fallback path
|
|
113
95
|
const extFile = typeof __filename !== "undefined" ? __filename : "";
|
|
114
|
-
const pkgHarness = extFile
|
|
96
|
+
const pkgHarness = extFile
|
|
97
|
+
? join(dirname(extFile), "..", "harnesses", "pi", "get-shit-done")
|
|
98
|
+
: "";
|
|
115
99
|
|
|
116
|
-
const
|
|
100
|
+
const errors: string[] = [];
|
|
117
101
|
let transformed = text;
|
|
118
102
|
|
|
119
|
-
for (const match of
|
|
120
|
-
const
|
|
121
|
-
const
|
|
103
|
+
for (const match of includes) {
|
|
104
|
+
const fullMatch = match[0];
|
|
105
|
+
const filePath = match[1];
|
|
106
|
+
const selectExpr = match[2] ?? "";
|
|
122
107
|
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
// 2. Package harness: <pkg>/.gsd/harnesses/pi/get-shit-done/<subPath>
|
|
108
|
+
// ── Resolve file path ───────────────────────────────────────
|
|
109
|
+
const subPath = filePath.replace(/^\.pi\/gsd\//, "");
|
|
126
110
|
const candidates = [
|
|
127
|
-
join(ctx.cwd,
|
|
128
|
-
...(
|
|
111
|
+
join(ctx.cwd, filePath),
|
|
112
|
+
...(filePath.startsWith(".pi/gsd/") && pkgHarness
|
|
113
|
+
? [join(pkgHarness, subPath)]
|
|
114
|
+
: []),
|
|
129
115
|
];
|
|
130
116
|
|
|
131
|
-
let
|
|
132
|
-
for (const
|
|
117
|
+
let raw: string | null = null;
|
|
118
|
+
for (const c of candidates) {
|
|
133
119
|
try {
|
|
134
|
-
if (existsSync(
|
|
135
|
-
fileContent = readFileSync(candidate, "utf8");
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
120
|
+
if (existsSync(c)) { raw = readFileSync(c, "utf8"); break; }
|
|
138
121
|
} catch { /* try next */ }
|
|
139
122
|
}
|
|
123
|
+
if (raw === null) {
|
|
124
|
+
errors.push(`File not found: ${filePath}`);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
140
127
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
128
|
+
// ── Apply selector ─────────────────────────────────────────
|
|
129
|
+
let result = raw;
|
|
130
|
+
if (selectExpr) {
|
|
131
|
+
const parts = selectExpr.split("|");
|
|
132
|
+
if (parts.length > 2) {
|
|
133
|
+
errors.push(`Invalid selector (max 2 segments): ${selectExpr}`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// lines: must be standalone — reject any chain involving lines
|
|
137
|
+
if (parts.length > 1 && parts.some((p) => p.trim().startsWith("lines:"))) {
|
|
138
|
+
errors.push(`lines: cannot be chained — use it alone: ${selectExpr}`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (let i = 0; i < parts.length; i++) {
|
|
143
|
+
const part = parts[i].trim();
|
|
144
|
+
const prev = i > 0 ? parts[i - 1].trim().split(":")[0] : null;
|
|
145
|
+
|
|
146
|
+
if (part.startsWith("tag:")) {
|
|
147
|
+
const tagName = part.slice(4);
|
|
148
|
+
const tagRe = new RegExp(
|
|
149
|
+
`<${tagName}>([\\s\\S]*?)</${tagName}>`,
|
|
150
|
+
"i",
|
|
151
|
+
);
|
|
152
|
+
const tagMatch = result.match(tagRe);
|
|
153
|
+
if (!tagMatch) {
|
|
154
|
+
errors.push(`Tag <${tagName}> not found in ${filePath}`);
|
|
155
|
+
result = "";
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
result = tagMatch[1].trim();
|
|
159
|
+
|
|
160
|
+
} else if (part.startsWith("heading:")) {
|
|
161
|
+
const headingText = part.slice(8);
|
|
162
|
+
const headingRe = new RegExp(
|
|
163
|
+
`(^|\\n)(#{1,6})\\s+${headingText.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}\\s*\\n`,
|
|
164
|
+
);
|
|
165
|
+
const hMatch = result.match(headingRe);
|
|
166
|
+
if (!hMatch) {
|
|
167
|
+
errors.push(`Heading \"${headingText}\" not found in ${filePath}`);
|
|
168
|
+
result = "";
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
const level = hMatch[2].length;
|
|
172
|
+
const startIdx = (hMatch.index ?? 0) + hMatch[0].length;
|
|
173
|
+
const nextHeading = result.slice(startIdx).search(
|
|
174
|
+
new RegExp(`\\n#{1,${level}}\\s`),
|
|
175
|
+
);
|
|
176
|
+
result = nextHeading === -1
|
|
177
|
+
? result.slice(startIdx).trim()
|
|
178
|
+
: result.slice(startIdx, startIdx + nextHeading).trim();
|
|
179
|
+
|
|
180
|
+
} else if (part.startsWith("lines:")) {
|
|
181
|
+
const rangeMatch = part.match(/^lines:(\d+)-(\d+)$/);
|
|
182
|
+
if (!rangeMatch) {
|
|
183
|
+
errors.push(`Invalid lines selector: ${part}`);
|
|
184
|
+
result = "";
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
const start = parseInt(rangeMatch[1], 10) - 1;
|
|
188
|
+
const end = parseInt(rangeMatch[2], 10);
|
|
189
|
+
result = result.split("\n").slice(start, end).join("\n");
|
|
190
|
+
|
|
191
|
+
} else {
|
|
192
|
+
errors.push(`Unknown selector: ${part}`);
|
|
193
|
+
result = "";
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (result === "") continue; // error already logged
|
|
145
198
|
}
|
|
199
|
+
|
|
200
|
+
transformed = transformed.replace(fullMatch, result);
|
|
146
201
|
}
|
|
147
202
|
|
|
148
|
-
if (
|
|
149
|
-
ctx.ui.notify(
|
|
150
|
-
`❌ GSD context injection failed — missing files:\n${failed.map((f) => ` • ${f}`).join("\n")}\n\nRun /gsd-setup-pi to reinstall the harness.`,
|
|
203
|
+
if (errors.length > 0) {
|
|
204
|
+
ctx.ui.notify("\u274c GSD include failed:\n" + errors.map((e) => " \u2022 " + e).join("\n"),
|
|
151
205
|
"error",
|
|
152
206
|
);
|
|
153
|
-
return { action: "handled" };
|
|
207
|
+
return { action: "handled" };
|
|
154
208
|
}
|
|
155
209
|
|
|
156
210
|
return { action: "transform", text: transformed };
|
|
157
211
|
});
|
|
212
|
+
|
|
158
213
|
// ── session_start: GSD update check ──────────────────────────────────────
|
|
159
214
|
pi.on("session_start", async (_event, ctx) => {
|
|
160
215
|
// Ensure harness files are reachable via .pi/gsd/ symlink
|
|
161
216
|
ensureHarnessSymlink(ctx.cwd);
|
|
162
217
|
|
|
163
|
-
// Sync derived core files from tagged reference sources
|
|
164
|
-
syncReferenceToCore(ctx.cwd, ["ui", "brand"]);
|
|
165
218
|
|
|
166
219
|
try {
|
|
167
220
|
const cacheDir = join(homedir(), ".pi", "cache");
|
|
@@ -667,9 +720,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
667
720
|
let lastLevel: "warning" | "critical" | null = null;
|
|
668
721
|
|
|
669
722
|
pi.on("tool_result", async (_event, ctx) => {
|
|
670
|
-
// Keep derived core files in sync after any tool write (e.g. gsd-new-project
|
|
671
|
-
// creating ui-brand.md mid-session — no reboot needed)
|
|
672
|
-
syncReferenceToCore(ctx.cwd, ["ui", "brand"]);
|
|
673
723
|
|
|
674
724
|
try {
|
|
675
725
|
const usage: ContextUsage | undefined = ctx.getContextUsage();
|
package/README.md
CHANGED
|
@@ -139,10 +139,8 @@ Switch profile: `/gsd-set-profile <profile>`
|
|
|
139
139
|
| Instant commands (no LLM cost) | ❌ | ✔️ | `/gsd-progress`, `/gsd-stats`, `/gsd-health`, `/gsd-help`, `/gsd-next` - zero LLM, editor pivot |
|
|
140
140
|
| `/gsd-next` auto-advance | ❌ | ✔️ | Deterministic phase routing, pre-fills editor with the correct next command |
|
|
141
141
|
| Prompt-dispatch for all skills | ❌ | ✔️ | 54 pi prompt templates - clean autocomplete, arg hints, direct workflow dispatch |
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
| Programmatic `@file` injection | ❌ | ✔️ | Extension intercepts `@.pi/gsd/...` refs, injects file contents before LLM sees them — zero tool calls |
|
|
145
|
-
| Auto harness symlink + self-repair | ❌ | ✔️ | `.pi/gsd/` → package harness; detects stale dirs, replaces with symlink; fallback to package root |
|
|
142
|
+
| `<gsd-include>` context injection | ❌ | ✔️ | `<gsd-include path select>` replaces file refs before LLM sees them — selectors: tag, heading, lines |
|
|
143
|
+
| Auto harness symlink + self-repair | ❌ | ✔️ | `.pi/gsd/` → package harness; detects stale dirs, replaces with symlink; fallback to package root |
|
|
146
144
|
| `/gsd-plan-milestone` command | ❌ | ✔️ | Plan all unplanned phases - one mode question, scope pre-check per phase, context-safe checkpoint |
|
|
147
145
|
| `/gsd-execute-milestone` command | ❌ | ✔️ | Execute all phases + scope guardian + auto gap/debt retry loop (insert-phase) + audit→complete→cleanup |
|
|
148
146
|
|
package/package.json
CHANGED
package/prompts/gsd-add-phase.md
CHANGED
package/prompts/gsd-add-tests.md
CHANGED
package/prompts/gsd-add-todo.md
CHANGED
package/prompts/gsd-audit-uat.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run all remaining phases autonomously - discuss→plan→execute per phase
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/autonomous.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|
package/prompts/gsd-cleanup.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Gather phase context through adaptive questioning before planning. Use --auto to skip interactive questions (the agent picks recommended defaults).
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/discuss-phase.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/workflows/discuss-phase-assumptions.md" />
|
|
6
|
+
<gsd-include path=".pi/gsd/templates/context.md" />
|
|
7
7
|
|
|
8
8
|
$ARGUMENTS
|
package/prompts/gsd-do.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Route freeform text to the right GSD command automatically
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/do.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Execute all planned phases + full lifecycle (audit→complete→cleanup), scope guardian, UAT gates, worktree isolation
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/execute-milestone.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" />
|
|
6
|
+
<gsd-include path=".planning/REQUIREMENTS.md" />
|
|
7
|
+
<gsd-include path=".planning/ROADMAP.md" />
|
|
8
|
+
<gsd-include path=".planning/STATE.md" />
|
|
9
9
|
|
|
10
10
|
$ARGUMENTS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Execute all plans in a phase with wave-based parallelization
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/execute-phase.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|
package/prompts/gsd-fast.md
CHANGED
package/prompts/gsd-forensics.md
CHANGED
package/prompts/gsd-manager.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Start a new milestone cycle - update PROJECT.md and route to requirements
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/new-milestone.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/questioning.md" />
|
|
6
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
7
|
+
<gsd-include path=".pi/gsd/templates/project.md" />
|
|
8
|
+
<gsd-include path=".pi/gsd/templates/requirements.md" />
|
|
9
9
|
|
|
10
10
|
$ARGUMENTS
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Initialize a new project with deep context gathering and PROJECT.md
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/new-project.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/questioning.md" />
|
|
6
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
7
|
+
<gsd-include path=".pi/gsd/templates/project.md" />
|
|
8
|
+
<gsd-include path=".pi/gsd/templates/requirements.md" />
|
|
9
9
|
|
|
10
10
|
$ARGUMENTS
|
package/prompts/gsd-note.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Plan all unplanned phases in the current milestone — one mode question, scope pre-check per phase, context-safe checkpointing
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/plan-milestone.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
6
|
+
<gsd-include path=".planning/REQUIREMENTS.md" />
|
|
7
|
+
<gsd-include path=".planning/ROADMAP.md" />
|
|
8
8
|
|
|
9
9
|
$ARGUMENTS
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Create detailed phase plan (PLAN.md) with verification loop
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/plan-phase.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" select="tag:core" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|
package/prompts/gsd-pr-branch.md
CHANGED
package/prompts/gsd-quick.md
CHANGED
package/prompts/gsd-review.md
CHANGED
package/prompts/gsd-settings.md
CHANGED
package/prompts/gsd-ship.md
CHANGED
package/prompts/gsd-ui-phase.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Generate UI design contract (UI-SPEC.md) for frontend phases
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/ui-phase.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|
package/prompts/gsd-ui-review.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Retroactive 6-pillar visual audit of implemented frontend code
|
|
3
3
|
---
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<gsd-include path=".pi/gsd/workflows/ui-review.md" />
|
|
5
|
+
<gsd-include path=".pi/gsd/references/ui-brand.md" />
|
|
6
6
|
|
|
7
7
|
$ARGUMENTS
|