pi-gsd 1.12.4 → 2.0.1
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 +202 -40
- package/.gsd/harnesses/pi/get-shit-done/workflows/add-phase.md +66 -11
- package/.gsd/harnesses/pi/get-shit-done/workflows/add-tests.md +69 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/add-todo.md +30 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/audit-milestone.md +75 -17
- package/.gsd/harnesses/pi/get-shit-done/workflows/audit-uat.md +38 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/autonomous.md +95 -286
- package/.gsd/harnesses/pi/get-shit-done/workflows/check-todos.md +67 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/cleanup.md +25 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/complete-milestone.md +51 -529
- package/.gsd/harnesses/pi/get-shit-done/workflows/diagnose-issues.md +39 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/discovery-phase.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/discuss-phase-assumptions.md +80 -5
- package/.gsd/harnesses/pi/get-shit-done/workflows/discuss-phase.md +43 -5
- package/.gsd/harnesses/pi/get-shit-done/workflows/discuss-phase.md.bak +1049 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/do.md +30 -3
- package/.gsd/harnesses/pi/get-shit-done/workflows/execute-milestone.md +64 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/execute-phase.md +78 -20
- package/.gsd/harnesses/pi/get-shit-done/workflows/execute-phase.md.bak +846 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/execute-plan.md +56 -19
- package/.gsd/harnesses/pi/get-shit-done/workflows/fast.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/forensics.md +40 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/health.md +25 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/help.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/insert-phase.md +69 -11
- package/.gsd/harnesses/pi/get-shit-done/workflows/list-phase-assumptions.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/list-workspaces.md +51 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/manager.md +81 -8
- package/.gsd/harnesses/pi/get-shit-done/workflows/map-codebase.md +40 -5
- package/.gsd/harnesses/pi/get-shit-done/workflows/milestone-summary.md +66 -48
- package/.gsd/harnesses/pi/get-shit-done/workflows/new-milestone.md +41 -13
- package/.gsd/harnesses/pi/get-shit-done/workflows/new-milestone.md.bak +486 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/new-project.md +43 -7
- package/.gsd/harnesses/pi/get-shit-done/workflows/new-project.md.bak +1250 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/new-workspace.md +55 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/next.md +39 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/node-repair.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/note.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/pause-work.md +46 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/plan-milestone-gaps.md +39 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/plan-milestone.md +40 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/plan-phase.md +57 -7
- package/.gsd/harnesses/pi/get-shit-done/workflows/plan-phase.md.bak +859 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/plant-seed.md +28 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/pr-branch.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/profile-user.md +51 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/progress.md +52 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/quick.md +99 -32
- package/.gsd/harnesses/pi/get-shit-done/workflows/remove-phase.md +66 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/remove-workspace.md +55 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/research-phase.md +79 -22
- package/.gsd/harnesses/pi/get-shit-done/workflows/resume-project.md +66 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/review.md +66 -36
- package/.gsd/harnesses/pi/get-shit-done/workflows/session-report.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/settings.md +27 -5
- package/.gsd/harnesses/pi/get-shit-done/workflows/ship.md +41 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/stats.md +24 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/transition.md +54 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/ui-phase.md +91 -6
- package/.gsd/harnesses/pi/get-shit-done/workflows/ui-review.md +80 -5
- package/.gsd/harnesses/pi/get-shit-done/workflows/update.md +2 -0
- package/.gsd/harnesses/pi/get-shit-done/workflows/validate-phase.md +90 -17
- package/.gsd/harnesses/pi/get-shit-done/workflows/verify-phase.md +79 -4
- package/.gsd/harnesses/pi/get-shit-done/workflows/verify-work.md +87 -31
- package/README.md +146 -112
- package/dist/pi-gsd-tools.js +166 -163
- package/package.json +14 -5
- package/prompts/gsd-add-backlog.md +2 -3
- package/prompts/gsd-add-phase.md +3 -2
- package/prompts/gsd-add-tests.md +3 -2
- package/prompts/gsd-add-todo.md +3 -2
- package/prompts/gsd-audit-milestone.md +3 -2
- package/prompts/gsd-audit-uat.md +3 -2
- package/prompts/gsd-autonomous.md +3 -2
- package/prompts/gsd-check-todos.md +3 -2
- package/prompts/gsd-cleanup.md +3 -2
- package/prompts/gsd-complete-milestone.md +2 -3
- package/prompts/gsd-debug.md +2 -3
- package/prompts/gsd-discuss-phase.md +4 -3
- package/prompts/gsd-do.md +3 -2
- package/prompts/gsd-execute-milestone.md +3 -2
- package/prompts/gsd-execute-phase.md +3 -2
- package/prompts/gsd-fast.md +2 -1
- package/prompts/gsd-forensics.md +3 -2
- package/prompts/gsd-insert-phase.md +3 -2
- package/prompts/gsd-join-discord.md +2 -3
- package/prompts/gsd-list-phase-assumptions.md +2 -1
- package/prompts/gsd-list-workspaces.md +3 -2
- package/prompts/gsd-manager.md +3 -2
- package/prompts/gsd-map-codebase.md +3 -2
- package/prompts/gsd-milestone-summary.md +3 -2
- package/prompts/gsd-new-milestone.md +3 -2
- package/prompts/gsd-new-project.md +3 -2
- package/prompts/gsd-new-workspace.md +3 -2
- package/prompts/gsd-note.md +2 -1
- package/prompts/gsd-pause-work.md +3 -2
- package/prompts/gsd-plan-milestone-gaps.md +3 -2
- package/prompts/gsd-plan-milestone.md +3 -2
- package/prompts/gsd-plan-phase.md +3 -2
- package/prompts/gsd-plant-seed.md +3 -2
- package/prompts/gsd-pr-branch.md +2 -1
- package/prompts/gsd-profile-user.md +3 -2
- package/prompts/gsd-quick.md +3 -2
- package/prompts/gsd-reapply-patches.md +2 -3
- package/prompts/gsd-remove-phase.md +3 -2
- package/prompts/gsd-remove-workspace.md +3 -2
- package/prompts/gsd-research-phase.md +2 -3
- package/prompts/gsd-resume-work.md +3 -2
- package/prompts/gsd-review-backlog.md +2 -3
- package/prompts/gsd-review.md +3 -2
- package/prompts/gsd-session-report.md +2 -1
- package/prompts/gsd-set-profile.md +2 -3
- package/prompts/gsd-settings.md +3 -2
- package/prompts/gsd-ship.md +3 -2
- package/prompts/gsd-thread.md +2 -3
- package/prompts/gsd-ui-phase.md +3 -2
- package/prompts/gsd-ui-review.md +3 -2
- package/prompts/gsd-validate-phase.md +3 -2
- package/prompts/gsd-verify-work.md +3 -2
- package/prompts/gsd-workstreams.md +2 -3
- package/src/cli.ts +644 -0
- package/src/commands/base.ts +67 -0
- package/src/commands/commit.ts +22 -0
- package/src/commands/config.ts +71 -0
- package/src/commands/frontmatter.ts +51 -0
- package/src/commands/index.ts +76 -0
- package/src/commands/init.ts +43 -0
- package/src/commands/milestone.ts +37 -0
- package/src/commands/phase.ts +92 -0
- package/src/commands/progress.ts +71 -0
- package/src/commands/roadmap.ts +40 -0
- package/src/commands/scaffold.ts +19 -0
- package/src/commands/state.ts +102 -0
- package/src/commands/template.ts +52 -0
- package/src/commands/verify.ts +70 -0
- package/src/commands/workstream.ts +98 -0
- package/src/commands/wxp.ts +65 -0
- package/src/lib/commands.ts +1040 -0
- package/src/lib/config.ts +385 -0
- package/src/lib/core.ts +1167 -0
- package/src/lib/frontmatter.ts +462 -0
- package/src/lib/init.ts +517 -0
- package/src/lib/milestone.ts +290 -0
- package/src/lib/model-profiles.ts +272 -0
- package/src/lib/phase.ts +1012 -0
- package/src/lib/profile-output.ts +237 -0
- package/src/lib/profile-pipeline.ts +556 -0
- package/src/lib/roadmap.ts +378 -0
- package/src/lib/schemas.ts +290 -0
- package/src/lib/security.ts +176 -0
- package/src/lib/state.ts +1175 -0
- package/src/lib/template.ts +246 -0
- package/src/lib/uat.ts +289 -0
- package/src/lib/verify.ts +879 -0
- package/src/lib/workstream.ts +524 -0
- package/src/output.ts +45 -0
- package/src/schemas/pi-gsd-settings.schema.json +80 -0
- package/src/schemas/wxp.xsd +619 -0
- package/src/schemas/wxp.zod.ts +318 -0
- package/src/wxp/__tests__/arguments.test.ts +86 -0
- package/src/wxp/__tests__/conditions.test.ts +106 -0
- package/src/wxp/__tests__/executor.test.ts +95 -0
- package/src/wxp/__tests__/helpers.ts +26 -0
- package/src/wxp/__tests__/integration.test.ts +166 -0
- package/src/wxp/__tests__/new-features.test.ts +222 -0
- package/src/wxp/__tests__/parser.test.ts +159 -0
- package/src/wxp/__tests__/paste.test.ts +66 -0
- package/src/wxp/__tests__/schema.test.ts +120 -0
- package/src/wxp/__tests__/security.test.ts +87 -0
- package/src/wxp/__tests__/shell.test.ts +85 -0
- package/src/wxp/__tests__/string-ops.test.ts +25 -0
- package/src/wxp/__tests__/variables.test.ts +65 -0
- package/src/wxp/arguments.ts +89 -0
- package/src/wxp/conditions.ts +78 -0
- package/src/wxp/executor.ts +191 -0
- package/src/wxp/index.ts +191 -0
- package/src/wxp/parser.ts +198 -0
- package/src/wxp/paste.ts +51 -0
- package/src/wxp/security.ts +102 -0
- package/src/wxp/shell.ts +81 -0
- package/src/wxp/string-ops.ts +44 -0
- package/src/wxp/variables.ts +109 -0
|
@@ -18,18 +18,20 @@
|
|
|
18
18
|
|
|
19
19
|
import { execSync } from "node:child_process";
|
|
20
20
|
import {
|
|
21
|
+
copyFileSync,
|
|
21
22
|
existsSync,
|
|
22
23
|
lstatSync,
|
|
23
24
|
mkdirSync,
|
|
24
25
|
readFileSync,
|
|
25
|
-
|
|
26
|
-
statSync,
|
|
27
|
-
symlinkSync,
|
|
26
|
+
readdirSync,
|
|
28
27
|
writeFileSync,
|
|
29
28
|
} from "node:fs";
|
|
30
29
|
import { homedir } from "node:os";
|
|
31
|
-
import { dirname, join } from "node:path";
|
|
30
|
+
import { dirname, join, relative } from "node:path";
|
|
32
31
|
import type { ContextUsage, ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
32
|
+
import { processWxpTrustedContent, WxpProcessingError, readWorkflowVersionTag } from "../../src/wxp/index.js";
|
|
33
|
+
import { DEFAULT_SHELL_ALLOWLIST } from "../../src/wxp/security.js";
|
|
34
|
+
import type { WxpSecurityConfig } from "../../src/schemas/wxp.zod.js";
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Ensures .pi/gsd/ in the project is a symlink to the harness files
|
|
@@ -37,45 +39,92 @@ import type { ContextUsage, ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
|
37
39
|
* if already present. Never overwrites a real directory (user may have
|
|
38
40
|
* customised it).
|
|
39
41
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Copy-on-first-run harness distribution (HRN-01, HRN-03).
|
|
45
|
+
* - Detects symlinks and replaces with real file copies.
|
|
46
|
+
* - Copies missing files; never overwrites existing real files.
|
|
47
|
+
* - Silent on any failure (non-blocking).
|
|
48
|
+
*/
|
|
49
|
+
function copyHarness(
|
|
50
|
+
src: string,
|
|
51
|
+
dest: string,
|
|
52
|
+
): { symlinksReplaced: number; filesCopied: number } {
|
|
53
|
+
let symlinksReplaced = 0;
|
|
54
|
+
let filesCopied = 0;
|
|
55
|
+
|
|
56
|
+
const walk = (srcDir: string, destDir: string): void => {
|
|
57
|
+
mkdirSync(destDir, { recursive: true });
|
|
58
|
+
const entries = readdirSync(srcDir, { withFileTypes: true });
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
const srcPath = join(srcDir, entry.name);
|
|
61
|
+
const destPath = join(destDir, entry.name);
|
|
62
|
+
if (entry.isDirectory()) {
|
|
63
|
+
walk(srcPath, destPath);
|
|
64
|
+
continue;
|
|
55
65
|
}
|
|
66
|
+
if (existsSync(destPath)) {
|
|
67
|
+
try {
|
|
68
|
+
const st = lstatSync(destPath);
|
|
69
|
+
if (st.isSymbolicLink()) {
|
|
70
|
+
// Replace symlink with real copy (HRN-03)
|
|
71
|
+
try {
|
|
72
|
+
// unlinkSync removes the symlink without following it
|
|
73
|
+
const { unlinkSync } = require("node:fs") as typeof import("node:fs");
|
|
74
|
+
unlinkSync(destPath);
|
|
75
|
+
} catch { /* ignore */ }
|
|
76
|
+
copyFileSync(srcPath, destPath);
|
|
77
|
+
symlinksReplaced++;
|
|
78
|
+
}
|
|
79
|
+
// Real file exists → skip (HRN-01: never overwrite)
|
|
80
|
+
} catch { /* ignore */ }
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
copyFileSync(srcPath, destPath);
|
|
85
|
+
filesCopied++;
|
|
86
|
+
} catch { /* ignore */ }
|
|
56
87
|
}
|
|
88
|
+
};
|
|
57
89
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const pkgRoot = join(dirname(extFile), "..", "..");
|
|
62
|
-
const harnessSrc = join(
|
|
63
|
-
pkgRoot,
|
|
64
|
-
".gsd",
|
|
65
|
-
"harnesses",
|
|
66
|
-
"pi",
|
|
67
|
-
"get-shit-done",
|
|
68
|
-
);
|
|
90
|
+
walk(src, dest);
|
|
91
|
+
return { symlinksReplaced, filesCopied };
|
|
92
|
+
}
|
|
69
93
|
|
|
70
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Extract the raw arguments string from a message that was produced by pi template expansion.
|
|
96
|
+
* Pi replaces $ARGUMENTS in prompt templates with the user's typed text.
|
|
97
|
+
* After <gsd-include> resolution, $ARGUMENTS text appears as trailing plain text
|
|
98
|
+
* at the end of the message — everything after the last WXP/include tag block.
|
|
99
|
+
*
|
|
100
|
+
* Example message after pi expansion + include resolution:
|
|
101
|
+
* [workflow content with <gsd-execute> blocks...]
|
|
102
|
+
* 16 --auto
|
|
103
|
+
*
|
|
104
|
+
* Returns: "16 --auto"
|
|
105
|
+
*/
|
|
106
|
+
function extractRawArguments(content: string): string {
|
|
107
|
+
// Find the last <...> block (WXP tag or include) position
|
|
108
|
+
const lastTagEnd = (() => {
|
|
109
|
+
const tagPattern = /<\/(?:gsd-[a-zA-Z0-9_-]+|shell|if|then|else|condition|args|outs|string-op|settings)>/g;
|
|
110
|
+
let lastEnd = 0;
|
|
111
|
+
let m: RegExpExecArray | null;
|
|
112
|
+
while ((m = tagPattern.exec(content)) !== null) {
|
|
113
|
+
lastEnd = m.index + m[0].length;
|
|
114
|
+
}
|
|
115
|
+
return lastEnd;
|
|
116
|
+
})();
|
|
71
117
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
} catch {
|
|
75
|
-
/* silent — never block session startup */
|
|
76
|
-
}
|
|
77
|
-
};
|
|
118
|
+
// Everything after the last closing tag is the trailing plain text ($ARGUMENTS expansion)
|
|
119
|
+
const trailing = content.slice(lastTagEnd).trim();
|
|
78
120
|
|
|
121
|
+
// Only return if it looks like user arguments (not a full document block)
|
|
122
|
+
// Reject if it contains markdown headings or is very long (probably included file content)
|
|
123
|
+
if (trailing.length === 0 || trailing.length > 500 || trailing.includes("\n\n\n")) {
|
|
124
|
+
return "";
|
|
125
|
+
}
|
|
126
|
+
return trailing;
|
|
127
|
+
}
|
|
79
128
|
|
|
80
129
|
export default function (pi: ExtensionAPI) {
|
|
81
130
|
/** Resolve a single <gsd-include> match: file lookup + selector extraction. */
|
|
@@ -227,15 +276,128 @@ function resolveGsdInclude(
|
|
|
227
276
|
return { messages: [] }; // block LLM call
|
|
228
277
|
}
|
|
229
278
|
|
|
279
|
+
// ── WXP post-processing: run after <gsd-include> resolution (WXP-14) ──
|
|
280
|
+
// Load global + project settings (HRN-06, HRN-07)
|
|
281
|
+
const extFile2 = typeof __filename !== "undefined" ? __filename : "";
|
|
282
|
+
const pkgRoot2 = join(dirname(extFile2), "..", "..");
|
|
283
|
+
|
|
284
|
+
type SettingsFile = {
|
|
285
|
+
shellAllowlist?: string[];
|
|
286
|
+
shellBanlist?: string[];
|
|
287
|
+
trustedPaths?: Array<{ position: "project" | "pkg" | "absolute"; path: string }>;
|
|
288
|
+
untrustedPaths?: Array<{ position: "project" | "pkg" | "absolute"; path: string }>;
|
|
289
|
+
shellTimeoutMs?: number;
|
|
290
|
+
};
|
|
291
|
+
const loadSettings = (settingsPath: string): SettingsFile => {
|
|
292
|
+
try {
|
|
293
|
+
if (existsSync(settingsPath)) {
|
|
294
|
+
return JSON.parse(readFileSync(settingsPath, "utf8")) as SettingsFile;
|
|
295
|
+
}
|
|
296
|
+
} catch { /* ignore */ }
|
|
297
|
+
return {};
|
|
298
|
+
};
|
|
299
|
+
const globalSettings = loadSettings(join(homedir(), ".gsd", "pi-gsd-settings.json"));
|
|
300
|
+
const projectSettings = loadSettings(join(ctx.cwd, ".pi", "gsd", "pi-gsd-settings.json"));
|
|
301
|
+
const mergedAllowlist = [
|
|
302
|
+
...DEFAULT_SHELL_ALLOWLIST,
|
|
303
|
+
...(globalSettings.shellAllowlist ?? []),
|
|
304
|
+
...(projectSettings.shellAllowlist ?? []),
|
|
305
|
+
];
|
|
306
|
+
const wxpSecurity: WxpSecurityConfig = {
|
|
307
|
+
trustedPaths: [
|
|
308
|
+
...(globalSettings.trustedPaths ?? []),
|
|
309
|
+
...(projectSettings.trustedPaths ?? []),
|
|
310
|
+
{ position: "pkg", path: ".gsd/harnesses/pi/get-shit-done" },
|
|
311
|
+
{ position: "project", path: ".pi/gsd" },
|
|
312
|
+
],
|
|
313
|
+
untrustedPaths: [
|
|
314
|
+
...(globalSettings.untrustedPaths ?? []),
|
|
315
|
+
...(projectSettings.untrustedPaths ?? []),
|
|
316
|
+
],
|
|
317
|
+
shellAllowlist: [...new Set(mergedAllowlist)],
|
|
318
|
+
shellBanlist: [
|
|
319
|
+
...(globalSettings.shellBanlist ?? []),
|
|
320
|
+
...(projectSettings.shellBanlist ?? []),
|
|
321
|
+
],
|
|
322
|
+
shellTimeoutMs: projectSettings.shellTimeoutMs ?? globalSettings.shellTimeoutMs ?? 30_000,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
for (const msg of messages) {
|
|
327
|
+
if (msg.role !== "user") continue;
|
|
328
|
+
if (typeof msg.content === "string") {
|
|
329
|
+
if (!msg.content.includes("<gsd-")) continue;
|
|
330
|
+
const virtualPath = join(ctx.cwd, ".pi", "gsd", "workflows", "_message.md");
|
|
331
|
+
const rawArgs = extractRawArguments(msg.content);
|
|
332
|
+
msg.content = processWxpTrustedContent(msg.content, virtualPath, wxpSecurity, ctx.cwd, pkgRoot2, rawArgs, (m, lv) => ctx.ui.notify(m, lv === "error" ? "error" : "info"));
|
|
333
|
+
} else if (Array.isArray(msg.content)) {
|
|
334
|
+
for (const block of msg.content) {
|
|
335
|
+
if (block.type !== "text" || !block.text) continue;
|
|
336
|
+
if (!block.text.includes("<gsd-")) continue;
|
|
337
|
+
const virtualPath = join(ctx.cwd, ".pi", "gsd", "workflows", "_message.md");
|
|
338
|
+
const rawArgs = extractRawArguments(block.text);
|
|
339
|
+
block.text = processWxpTrustedContent(block.text, virtualPath, wxpSecurity, ctx.cwd, pkgRoot2, rawArgs, (m, lv) => ctx.ui.notify(m, lv === "error" ? "error" : "info"));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} catch (wxpErr) {
|
|
344
|
+
if (wxpErr instanceof WxpProcessingError) {
|
|
345
|
+
ctx.ui.notify(wxpErr.message, "error");
|
|
346
|
+
return { messages: [] }; // WXP-09: no partial content reaches LLM
|
|
347
|
+
}
|
|
348
|
+
// Non-WXP error: log but don't block
|
|
349
|
+
const errMsg = wxpErr instanceof Error ? wxpErr.message : String(wxpErr);
|
|
350
|
+
ctx.ui.notify(`GSD WXP: unexpected context error: ${errMsg}`, "info");
|
|
351
|
+
}
|
|
352
|
+
|
|
230
353
|
return { messages };
|
|
231
354
|
});
|
|
232
355
|
|
|
233
356
|
// ── session_start: GSD update check ──────────────────────────────────────
|
|
234
357
|
pi.on("session_start", async (_event, ctx) => {
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
358
|
+
// Copy-on-first-run harness distribution (HRN-01, HRN-03)
|
|
359
|
+
try {
|
|
360
|
+
const extFile = typeof __filename !== "undefined" ? __filename : "";
|
|
361
|
+
const pkgRoot = join(dirname(extFile), "..", "..");
|
|
362
|
+
const pkgHarness = join(pkgRoot, ".gsd", "harnesses", "pi", "get-shit-done");
|
|
363
|
+
const projectHarness = join(ctx.cwd, ".pi", "gsd");
|
|
364
|
+
if (existsSync(pkgHarness)) {
|
|
365
|
+
const { symlinksReplaced } = copyHarness(pkgHarness, projectHarness);
|
|
366
|
+
if (symlinksReplaced > 0) {
|
|
367
|
+
ctx.ui.notify(
|
|
368
|
+
`ℹ️ GSD: Replaced ${symlinksReplaced} symlink(s) in .pi/gsd/ with real file copies.`,
|
|
369
|
+
"info",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
238
372
|
|
|
373
|
+
// Version-aware update detection (HRN-02)
|
|
374
|
+
try {
|
|
375
|
+
const pkgJsonPath = join(pkgRoot, "package.json");
|
|
376
|
+
if (existsSync(pkgJsonPath)) {
|
|
377
|
+
const pkgVersion = (JSON.parse(readFileSync(pkgJsonPath, "utf8")) as { version?: string }).version ?? "0.0.0";
|
|
378
|
+
const outdated: string[] = [];
|
|
379
|
+
// Check a sample of key workflow files for version drift
|
|
380
|
+
const sampleFiles = ["workflows/execute-phase.md", "workflows/plan-phase.md"];
|
|
381
|
+
for (const rel of sampleFiles) {
|
|
382
|
+
const projFile = join(projectHarness, rel);
|
|
383
|
+
if (!existsSync(projFile)) continue;
|
|
384
|
+
const content = readFileSync(projFile, "utf8");
|
|
385
|
+
const vtag = readWorkflowVersionTag(content);
|
|
386
|
+
if (!vtag || vtag.doNotUpdate) continue;
|
|
387
|
+
if (vtag.version !== pkgVersion) outdated.push(rel);
|
|
388
|
+
}
|
|
389
|
+
if (outdated.length > 0) {
|
|
390
|
+
ctx.ui.notify(
|
|
391
|
+
`ℹ️ GSD harness update available (package v${pkgVersion}).\n` +
|
|
392
|
+
`Outdated files: ${outdated.join(", ")}\n` +
|
|
393
|
+
`Run: pi-gsd-tools harness update [y|n|pick|diff]`,
|
|
394
|
+
"info",
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
} catch { /* silent */ }
|
|
399
|
+
}
|
|
400
|
+
} catch { /* silent */ }
|
|
239
401
|
try {
|
|
240
402
|
const cacheDir = join(homedir(), ".pi", "cache");
|
|
241
403
|
const cacheFile = join(cacheDir, "gsd-update-check.json");
|
|
@@ -1,10 +1,68 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<gsd-version v="1.12.4" />
|
|
2
|
+
|
|
3
|
+
<gsd-arguments>
|
|
4
|
+
<settings>
|
|
5
|
+
<keep-extra-args />
|
|
6
|
+
</settings>
|
|
7
|
+
<arg name="description" type="string" optional />
|
|
8
|
+
</gsd-arguments>
|
|
9
|
+
|
|
10
|
+
<gsd-execute>
|
|
11
|
+
<shell command="pi-gsd-tools">
|
|
12
|
+
<args>
|
|
13
|
+
<arg string="init" />
|
|
14
|
+
<arg string="phase-op" />
|
|
15
|
+
<arg string="0" />
|
|
16
|
+
</args>
|
|
17
|
+
<outs>
|
|
18
|
+
<out type="string" name="init" />
|
|
19
|
+
</outs>
|
|
20
|
+
</shell>
|
|
21
|
+
<if>
|
|
22
|
+
<condition>
|
|
23
|
+
<starts-with>
|
|
24
|
+
<left name="init" />
|
|
25
|
+
<right type="string" value="@file:" />
|
|
26
|
+
</starts-with>
|
|
27
|
+
</condition>
|
|
28
|
+
<then>
|
|
29
|
+
<string-op op="split">
|
|
30
|
+
<args>
|
|
31
|
+
<arg name="init" />
|
|
32
|
+
<arg type="string" value="@file:" />
|
|
33
|
+
</args>
|
|
34
|
+
<outs>
|
|
35
|
+
<out type="string" name="init-file" />
|
|
36
|
+
</outs>
|
|
37
|
+
</string-op>
|
|
38
|
+
<shell command="cat">
|
|
39
|
+
<args>
|
|
40
|
+
<arg name="init-file" wrap='"' />
|
|
41
|
+
</args>
|
|
42
|
+
<outs>
|
|
43
|
+
<out type="string" name="init" />
|
|
44
|
+
</outs>
|
|
45
|
+
</shell>
|
|
46
|
+
</then>
|
|
47
|
+
</if>
|
|
48
|
+
<shell command="pi-gsd-tools">
|
|
49
|
+
<args>
|
|
50
|
+
<arg string="state" />
|
|
51
|
+
<arg string="json" />
|
|
52
|
+
<arg string="--raw" />
|
|
53
|
+
</args>
|
|
54
|
+
<outs>
|
|
55
|
+
<out type="string" name="state" />
|
|
56
|
+
</outs>
|
|
57
|
+
</shell>
|
|
58
|
+
</gsd-execute>
|
|
59
|
+
|
|
60
|
+
## Context (pre-injected by WXP)
|
|
61
|
+
|
|
62
|
+
**Description:** <gsd-paste name="description" />
|
|
63
|
+
|
|
64
|
+
**Project State:**
|
|
65
|
+
<gsd-paste name="state" />
|
|
8
66
|
|
|
9
67
|
<process>
|
|
10
68
|
|
|
@@ -28,10 +86,7 @@ Exit.
|
|
|
28
86
|
<step name="init_context">
|
|
29
87
|
Load phase operation context:
|
|
30
88
|
|
|
31
|
-
|
|
32
|
-
INIT=$(pi-gsd-tools init phase-op "0")
|
|
33
|
-
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
34
|
-
```
|
|
89
|
+
<!-- Context pre-injected above via WXP — variables available via <gsd-paste name="..."> -->
|
|
35
90
|
|
|
36
91
|
Check `roadmap_exists` from init JSON. If false:
|
|
37
92
|
```
|
|
@@ -1,3 +1,71 @@
|
|
|
1
|
+
<gsd-version v="1.12.4" />
|
|
2
|
+
|
|
3
|
+
<gsd-arguments>
|
|
4
|
+
<settings><keep-extra-args /></settings>
|
|
5
|
+
<arg name="phase" type="number" />
|
|
6
|
+
</gsd-arguments>
|
|
7
|
+
|
|
8
|
+
<gsd-execute>
|
|
9
|
+
<shell command="pi-gsd-tools">
|
|
10
|
+
<args>
|
|
11
|
+
<arg string="pi-gsd-tools" />
|
|
12
|
+
<arg string="init" />
|
|
13
|
+
<arg string="phase-op" />
|
|
14
|
+
</args>
|
|
15
|
+
<outs>
|
|
16
|
+
<out type="string" name="init" />
|
|
17
|
+
</outs>
|
|
18
|
+
</shell>
|
|
19
|
+
<if>
|
|
20
|
+
<condition>
|
|
21
|
+
<starts-with>
|
|
22
|
+
<left name="init" />
|
|
23
|
+
<right type="string" value="@file:" />
|
|
24
|
+
</starts-with>
|
|
25
|
+
</condition>
|
|
26
|
+
<then>
|
|
27
|
+
<string-op op="split">
|
|
28
|
+
<args>
|
|
29
|
+
<arg name="init" />
|
|
30
|
+
<arg type="string" value="@file:" />
|
|
31
|
+
</args>
|
|
32
|
+
<outs>
|
|
33
|
+
<out type="string" name="init-file" />
|
|
34
|
+
</outs>
|
|
35
|
+
</string-op>
|
|
36
|
+
<shell command="cat">
|
|
37
|
+
<args>
|
|
38
|
+
<arg name="init-file" wrap='"' />
|
|
39
|
+
</args>
|
|
40
|
+
<outs>
|
|
41
|
+
<out type="string" name="init" />
|
|
42
|
+
</outs>
|
|
43
|
+
</shell>
|
|
44
|
+
</then>
|
|
45
|
+
</if>
|
|
46
|
+
<shell command="pi-gsd-tools">
|
|
47
|
+
<args>
|
|
48
|
+
<arg string="pi-gsd-tools" />
|
|
49
|
+
<arg string="state" />
|
|
50
|
+
<arg string="json" />
|
|
51
|
+
<arg string="--raw" />
|
|
52
|
+
</args>
|
|
53
|
+
<outs>
|
|
54
|
+
<out type="string" name="state" />
|
|
55
|
+
</outs>
|
|
56
|
+
</shell>
|
|
57
|
+
</gsd-execute>
|
|
58
|
+
|
|
59
|
+
## Context (pre-injected)
|
|
60
|
+
|
|
61
|
+
**Phase:** <gsd-paste name="phase" />
|
|
62
|
+
|
|
63
|
+
**Phase Data:**
|
|
64
|
+
<gsd-paste name="init" />
|
|
65
|
+
|
|
66
|
+
**State:**
|
|
67
|
+
<gsd-paste name="state" />
|
|
68
|
+
|
|
1
69
|
<purpose>
|
|
2
70
|
Generate unit and E2E tests for a completed phase based on its SUMMARY.md, CONTEXT.md, and implementation. Classifies each changed file into TDD (unit), E2E (browser), or Skip categories, presents a test plan for user approval, then generates tests following RED-GREEN conventions.
|
|
3
71
|
|
|
@@ -32,10 +100,7 @@ Exit.
|
|
|
32
100
|
<step name="init_context">
|
|
33
101
|
Load phase operation context:
|
|
34
102
|
|
|
35
|
-
|
|
36
|
-
INIT=$(pi-gsd-tools init phase-op "${PHASE_ARG}")
|
|
37
|
-
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
38
|
-
```
|
|
103
|
+
<!-- Context pre-injected above via WXP — variables available via <gsd-paste name="..."> -->
|
|
39
104
|
|
|
40
105
|
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`.
|
|
41
106
|
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
<gsd-version v="1.12.4" />
|
|
2
|
+
|
|
3
|
+
<gsd-arguments>
|
|
4
|
+
<settings><keep-extra-args /></settings>
|
|
5
|
+
<arg name="text" type="string" optional />
|
|
6
|
+
</gsd-arguments>
|
|
7
|
+
|
|
8
|
+
<gsd-execute>
|
|
9
|
+
<shell command="pi-gsd-tools">
|
|
10
|
+
<args>
|
|
11
|
+
<arg string="pi-gsd-tools" />
|
|
12
|
+
<arg string="state" />
|
|
13
|
+
<arg string="json" />
|
|
14
|
+
<arg string="--raw" />
|
|
15
|
+
</args>
|
|
16
|
+
<outs>
|
|
17
|
+
<suppress-errors />
|
|
18
|
+
<out type="string" name="state" />
|
|
19
|
+
</outs>
|
|
20
|
+
</shell>
|
|
21
|
+
</gsd-execute>
|
|
22
|
+
|
|
23
|
+
## Context (pre-injected)
|
|
24
|
+
|
|
25
|
+
**Todo text:** <gsd-paste name="text" />
|
|
26
|
+
|
|
27
|
+
**State:**
|
|
28
|
+
<gsd-paste name="state" />
|
|
29
|
+
|
|
1
30
|
<purpose>
|
|
2
31
|
Capture an idea, task, or issue that surfaces during a GSD session as a structured todo for later work. Enables "thought → capture → continue" flow without losing context.
|
|
3
32
|
</purpose>
|
|
@@ -11,10 +40,7 @@ Read all files referenced by the invoking prompt's execution_context before star
|
|
|
11
40
|
<step name="init_context">
|
|
12
41
|
Load todo context:
|
|
13
42
|
|
|
14
|
-
|
|
15
|
-
INIT=$(pi-gsd-tools init todos)
|
|
16
|
-
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
17
|
-
```
|
|
43
|
+
<!-- Context pre-injected above via WXP — variables available via <gsd-paste name="..."> -->
|
|
18
44
|
|
|
19
45
|
Extract from init JSON: `commit_docs`, `date`, `timestamp`, `todo_count`, `todos`, `pending_dir`, `todos_dir_exists`.
|
|
20
46
|
|
|
@@ -1,25 +1,83 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
</
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
<gsd-version v="1.12.4" />
|
|
2
|
+
|
|
3
|
+
<gsd-arguments>
|
|
4
|
+
<settings>
|
|
5
|
+
<keep-extra-args />
|
|
6
|
+
</settings>
|
|
7
|
+
</gsd-arguments>
|
|
8
|
+
|
|
9
|
+
<gsd-execute>
|
|
10
|
+
<shell command="pi-gsd-tools">
|
|
11
|
+
<args>
|
|
12
|
+
<arg string="init" />
|
|
13
|
+
<arg string="milestone-op" />
|
|
14
|
+
</args>
|
|
15
|
+
<outs>
|
|
16
|
+
<out type="string" name="init" />
|
|
17
|
+
</outs>
|
|
18
|
+
</shell>
|
|
19
|
+
<if>
|
|
20
|
+
<condition>
|
|
21
|
+
<starts-with>
|
|
22
|
+
<left name="init" />
|
|
23
|
+
<right type="string" value="@file:" />
|
|
24
|
+
</starts-with>
|
|
25
|
+
</condition>
|
|
26
|
+
<then>
|
|
27
|
+
<string-op op="split">
|
|
28
|
+
<args>
|
|
29
|
+
<arg name="init" />
|
|
30
|
+
<arg type="string" value="@file:" />
|
|
31
|
+
</args>
|
|
32
|
+
<outs>
|
|
33
|
+
<out type="string" name="init-file" />
|
|
34
|
+
</outs>
|
|
35
|
+
</string-op>
|
|
36
|
+
<shell command="cat">
|
|
37
|
+
<args>
|
|
38
|
+
<arg name="init-file" wrap='"' />
|
|
39
|
+
</args>
|
|
40
|
+
<outs>
|
|
41
|
+
<out type="string" name="init" />
|
|
42
|
+
</outs>
|
|
43
|
+
</shell>
|
|
44
|
+
</then>
|
|
45
|
+
</if>
|
|
46
|
+
<shell command="pi-gsd-tools">
|
|
47
|
+
<args>
|
|
48
|
+
<arg string="agent-skills" />
|
|
49
|
+
<arg string="gsd-integration-checker" />
|
|
50
|
+
</args>
|
|
51
|
+
<outs>
|
|
52
|
+
<suppress-errors />
|
|
53
|
+
<out type="string" name="agent-skills-checker" />
|
|
54
|
+
</outs>
|
|
55
|
+
</shell>
|
|
56
|
+
<shell command="pi-gsd-tools">
|
|
57
|
+
<args>
|
|
58
|
+
<arg string="resolve-model" />
|
|
59
|
+
<arg string="gsd-integration-checker" />
|
|
60
|
+
<arg string="--raw" />
|
|
61
|
+
</args>
|
|
62
|
+
<outs>
|
|
63
|
+
<suppress-errors />
|
|
64
|
+
<out type="string" name="integration-checker-model" />
|
|
65
|
+
</outs>
|
|
66
|
+
</shell>
|
|
67
|
+
</gsd-execute>
|
|
68
|
+
|
|
69
|
+
## Milestone Audit Context (pre-injected by WXP)
|
|
70
|
+
|
|
71
|
+
**Milestone Init Data:**
|
|
72
|
+
<gsd-paste name="init" />
|
|
73
|
+
|
|
74
|
+
**Integration Checker Model:** <gsd-paste name="integration-checker-model" />
|
|
13
75
|
|
|
14
76
|
<process>
|
|
15
77
|
|
|
16
78
|
## 0. Initialize Milestone Context
|
|
17
79
|
|
|
18
|
-
|
|
19
|
-
INIT=$(pi-gsd-tools init milestone-op)
|
|
20
|
-
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
21
|
-
AGENT_SKILLS_CHECKER=$(pi-gsd-tools agent-skills gsd-integration-checker 2>/dev/null)
|
|
22
|
-
```
|
|
80
|
+
<!-- Context pre-injected above via WXP — variables available via <gsd-paste name="..."> -->
|
|
23
81
|
|
|
24
82
|
Extract from init JSON: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `commit_docs`.
|
|
25
83
|
|
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
<gsd-version v="1.12.4" />
|
|
2
|
+
|
|
3
|
+
<gsd-arguments>
|
|
4
|
+
<settings><keep-extra-args /></settings>
|
|
5
|
+
</gsd-arguments>
|
|
6
|
+
|
|
7
|
+
<gsd-execute>
|
|
8
|
+
<shell command="pi-gsd-tools">
|
|
9
|
+
<args>
|
|
10
|
+
<arg string="pi-gsd-tools" />
|
|
11
|
+
<arg string="audit-uat" />
|
|
12
|
+
<arg string="--raw" />
|
|
13
|
+
</args>
|
|
14
|
+
<outs>
|
|
15
|
+
<out type="string" name="audit-data" />
|
|
16
|
+
</outs>
|
|
17
|
+
</shell>
|
|
18
|
+
<shell command="pi-gsd-tools">
|
|
19
|
+
<args>
|
|
20
|
+
<arg string="pi-gsd-tools" />
|
|
21
|
+
<arg string="state" />
|
|
22
|
+
<arg string="json" />
|
|
23
|
+
<arg string="--raw" />
|
|
24
|
+
</args>
|
|
25
|
+
<outs>
|
|
26
|
+
<out type="string" name="state" />
|
|
27
|
+
</outs>
|
|
28
|
+
</shell>
|
|
29
|
+
</gsd-execute>
|
|
30
|
+
|
|
31
|
+
## Audit Data (pre-injected)
|
|
32
|
+
|
|
33
|
+
**UAT Audit:**
|
|
34
|
+
<gsd-paste name="audit-data" />
|
|
35
|
+
|
|
36
|
+
**State:**
|
|
37
|
+
<gsd-paste name="state" />
|
|
38
|
+
|
|
1
39
|
<purpose>
|
|
2
40
|
Cross-phase audit of all UAT and verification files. Finds every outstanding item (pending, skipped, blocked, human_needed), optionally verifies against the codebase to detect stale docs, and produces a prioritized human test plan.
|
|
3
41
|
</purpose>
|