gsdd-cli 0.16.1 → 0.18.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/README.md +111 -61
- package/agents/README.md +1 -1
- package/bin/adapters/claude.mjs +8 -1
- package/bin/adapters/codex.mjs +5 -1
- package/bin/adapters/opencode.mjs +7 -1
- package/bin/gsdd.mjs +25 -20
- package/bin/lib/evidence-contract.mjs +112 -0
- package/bin/lib/health-truth.mjs +29 -31
- package/bin/lib/health.mjs +61 -106
- package/bin/lib/init-flow.mjs +91 -34
- package/bin/lib/init-runtime.mjs +46 -25
- package/bin/lib/init.mjs +3 -7
- package/bin/lib/lifecycle-preflight.mjs +333 -0
- package/bin/lib/lifecycle-state.mjs +476 -0
- package/bin/lib/manifest.mjs +24 -20
- package/bin/lib/phase.mjs +81 -26
- package/bin/lib/provenance.mjs +295 -54
- package/bin/lib/rendering.mjs +70 -12
- package/bin/lib/runtime-freshness.mjs +264 -0
- package/bin/lib/session-fingerprint.mjs +106 -0
- package/distilled/DESIGN.md +707 -13
- package/distilled/EVIDENCE-INDEX.md +166 -1
- package/distilled/README.md +44 -28
- package/distilled/SKILL.md +4 -4
- package/distilled/templates/agents.block.md +1 -1
- package/distilled/workflows/audit-milestone.md +50 -0
- package/distilled/workflows/complete-milestone.md +38 -2
- package/distilled/workflows/execute.md +16 -3
- package/distilled/workflows/map-codebase.md +15 -4
- package/distilled/workflows/new-milestone.md +53 -24
- package/distilled/workflows/new-project.md +44 -25
- package/distilled/workflows/pause.md +1 -1
- package/distilled/workflows/plan.md +187 -74
- package/distilled/workflows/progress.md +135 -31
- package/distilled/workflows/quick.md +20 -12
- package/distilled/workflows/resume.md +152 -65
- package/distilled/workflows/verify.md +55 -20
- package/docs/BROWNFIELD-PROOF.md +95 -0
- package/docs/RUNTIME-SUPPORT.md +77 -0
- package/docs/USER-GUIDE.md +443 -0
- package/docs/VERIFICATION-DISCIPLINE.md +59 -0
- package/docs/claude/context-monitor.md +98 -0
- package/docs/proof/consumer-node-cli/README.md +37 -0
- package/docs/proof/consumer-node-cli/ROADMAP.md +14 -0
- package/docs/proof/consumer-node-cli/SPEC.md +17 -0
- package/docs/proof/consumer-node-cli/brief.md +9 -0
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-PLAN.md +34 -0
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-SUMMARY.md +10 -0
- package/docs/proof/consumer-node-cli/phases/01-foundation/01-VERIFICATION.md +30 -0
- package/package.json +26 -20
package/bin/lib/provenance.mjs
CHANGED
|
@@ -9,7 +9,24 @@ function normalizeCount(value) {
|
|
|
9
9
|
return Number.isFinite(numeric) ? numeric : 'unknown';
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
function normalizeCheckpointWorkflow(workflow) {
|
|
13
|
+
const normalized = String(workflow || 'generic').trim().toLowerCase();
|
|
14
|
+
return ['phase', 'quick', 'generic'].includes(normalized) ? normalized : 'generic';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function classifyCheckpointRouting(workflow) {
|
|
18
|
+
const normalizedWorkflow = normalizeCheckpointWorkflow(workflow);
|
|
19
|
+
const progressBlocks = normalizedWorkflow === 'phase' || normalizedWorkflow === 'quick';
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
workflow: normalizedWorkflow,
|
|
23
|
+
routingClass: progressBlocks ? 'blocking' : 'informational',
|
|
24
|
+
progressBlocks,
|
|
25
|
+
resumeOwnsCleanup: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function parseGitStatusShort(statusText = '') {
|
|
13
30
|
const lines = statusText
|
|
14
31
|
.replace(/\r\n/g, '\n')
|
|
15
32
|
.split('\n')
|
|
@@ -34,26 +51,161 @@ export function parseGitStatusShort(statusText = '') {
|
|
|
34
51
|
});
|
|
35
52
|
}
|
|
36
53
|
|
|
37
|
-
return {
|
|
38
|
-
files,
|
|
39
|
-
stagedCount: files.filter((file) => file.staged).length,
|
|
40
|
-
unstagedCount: files.filter((file) => file.unstaged).length,
|
|
41
|
-
untrackedCount: files.filter((file) => file.untracked).length,
|
|
42
|
-
dirty: files.length > 0,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function
|
|
47
|
-
checkpoint = {},
|
|
48
|
-
planning = {},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
return {
|
|
55
|
+
files,
|
|
56
|
+
stagedCount: files.filter((file) => file.staged).length,
|
|
57
|
+
unstagedCount: files.filter((file) => file.unstaged).length,
|
|
58
|
+
untrackedCount: files.filter((file) => file.untracked).length,
|
|
59
|
+
dirty: files.length > 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function classifyBrownfieldCheckpointPrecedence({
|
|
64
|
+
checkpoint = {},
|
|
65
|
+
planning = {},
|
|
66
|
+
quick = {},
|
|
67
|
+
brownfieldChange = {},
|
|
68
|
+
git = {},
|
|
69
|
+
status = parseGitStatusShort(git.statusShort || ''),
|
|
70
|
+
} = {}) {
|
|
71
|
+
const checkpointRouting = classifyCheckpointRouting(checkpoint.workflow);
|
|
72
|
+
if (!brownfieldChange?.exists) {
|
|
73
|
+
return {
|
|
74
|
+
primary: checkpointRouting.progressBlocks ? 'checkpoint' : 'none',
|
|
75
|
+
checkpointRouting,
|
|
76
|
+
branchAligned: false,
|
|
77
|
+
scopeAligned: false,
|
|
78
|
+
executionActive: false,
|
|
79
|
+
checkpointCanOverrideBrownfield: false,
|
|
80
|
+
strictMatchRequired: false,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (checkpointRouting.workflow === 'generic') {
|
|
85
|
+
return {
|
|
86
|
+
primary: 'brownfield_change',
|
|
87
|
+
checkpointRouting,
|
|
88
|
+
branchAligned: false,
|
|
89
|
+
scopeAligned: false,
|
|
90
|
+
executionActive: false,
|
|
91
|
+
checkpointCanOverrideBrownfield: false,
|
|
92
|
+
strictMatchRequired: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const brownfieldMismatch = classifyBrownfieldArtifactMismatch({
|
|
97
|
+
brownfieldChange,
|
|
98
|
+
git,
|
|
99
|
+
status,
|
|
100
|
+
});
|
|
101
|
+
const currentBranch = normalizeBranchName(git.branch);
|
|
102
|
+
const checkpointBranch = normalizeBranchName(checkpoint.branch);
|
|
103
|
+
const brownfieldBranch = normalizeBranchName(brownfieldChange.currentIntegrationSurface);
|
|
104
|
+
const branchAligned = Boolean(
|
|
105
|
+
currentBranch
|
|
106
|
+
&& checkpointBranch
|
|
107
|
+
&& brownfieldBranch
|
|
108
|
+
&& checkpointBranch === currentBranch
|
|
109
|
+
&& brownfieldBranch === currentBranch
|
|
110
|
+
);
|
|
111
|
+
const scopeAligned = !brownfieldMismatch.warnings.some((warning) =>
|
|
112
|
+
warning.id === 'brownfield_scope_mismatch' || warning.id === 'brownfield_status_mismatch'
|
|
113
|
+
);
|
|
114
|
+
const executionActive = checkpointExecutionIsActive({
|
|
115
|
+
checkpoint,
|
|
116
|
+
checkpointRouting,
|
|
117
|
+
planning,
|
|
118
|
+
quick,
|
|
119
|
+
});
|
|
120
|
+
const checkpointCanOverrideBrownfield = branchAligned && scopeAligned && executionActive;
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
primary: checkpointCanOverrideBrownfield ? 'checkpoint' : 'brownfield_change',
|
|
124
|
+
checkpointRouting,
|
|
125
|
+
branchAligned,
|
|
126
|
+
scopeAligned,
|
|
127
|
+
executionActive,
|
|
128
|
+
checkpointCanOverrideBrownfield,
|
|
129
|
+
strictMatchRequired: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function classifyBrownfieldArtifactMismatch({
|
|
134
|
+
brownfieldChange = {},
|
|
135
|
+
git = {},
|
|
136
|
+
status = parseGitStatusShort(git.statusShort || ''),
|
|
137
|
+
} = {}) {
|
|
138
|
+
if (!brownfieldChange?.exists) {
|
|
139
|
+
return {
|
|
140
|
+
warnings: [],
|
|
141
|
+
requiresAcknowledgement: false,
|
|
142
|
+
outsideOwnedPaths: [],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const warnings = [];
|
|
147
|
+
const declaredBranch = normalizeDeclaredBranch(brownfieldChange.currentIntegrationSurface);
|
|
148
|
+
const branch = String(git.branch || '').trim().toLowerCase();
|
|
149
|
+
if (declaredBranch && branch && declaredBranch !== branch) {
|
|
150
|
+
warnings.push({
|
|
151
|
+
id: 'brownfield_branch_mismatch',
|
|
152
|
+
severity: 'acknowledgement_required',
|
|
153
|
+
summary: `CHANGE.md says the active integration surface is "${brownfieldChange.currentIntegrationSurface}", but git reports "${git.branch}".`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const ownedPaths = normalizeOwnedPaths(brownfieldChange.declaredOwnedPaths || []);
|
|
158
|
+
const outsideOwnedPaths = ownedPaths.length === 0
|
|
159
|
+
? []
|
|
160
|
+
: status.files
|
|
161
|
+
.map((file) => file.path)
|
|
162
|
+
.filter((filePath) => !ownedPaths.some((ownedPath) => matchesOwnedPath(filePath, ownedPath)));
|
|
163
|
+
if (outsideOwnedPaths.length > 0) {
|
|
164
|
+
warnings.push({
|
|
165
|
+
id: 'brownfield_scope_mismatch',
|
|
166
|
+
severity: 'acknowledgement_required',
|
|
167
|
+
summary: `Dirty files fall outside the CHANGE.md write scope: ${outsideOwnedPaths.join(', ')}`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if ((brownfieldChange.currentStatus === 'closed' || brownfieldChange.currentStatus === 'ready_for_verification') && status.dirty) {
|
|
172
|
+
warnings.push({
|
|
173
|
+
id: 'brownfield_status_mismatch',
|
|
174
|
+
severity: 'acknowledgement_required',
|
|
175
|
+
summary: `CHANGE.md marks the change as "${brownfieldChange.currentStatus}", but the live worktree is still dirty.`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
warnings,
|
|
181
|
+
requiresAcknowledgement: warnings.some((warning) => warning.severity === 'acknowledgement_required'),
|
|
182
|
+
outsideOwnedPaths,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function buildProvenanceSnapshot({
|
|
187
|
+
checkpoint = {},
|
|
188
|
+
planning = {},
|
|
189
|
+
quick = {},
|
|
190
|
+
brownfieldChange = {},
|
|
191
|
+
git = {},
|
|
192
|
+
} = {}) {
|
|
193
|
+
const checkpointRouting = classifyCheckpointRouting(checkpoint.workflow);
|
|
194
|
+
const status = parseGitStatusShort(git.statusShort || '');
|
|
195
|
+
const commitsAheadOfMain = normalizeCount(git.commitsAheadOfMain);
|
|
196
|
+
const commitsAheadOfRemote = normalizeCount(git.commitsAheadOfRemote);
|
|
197
|
+
const prState = normalizePrState(git.prState);
|
|
198
|
+
const brownfieldMismatch = classifyBrownfieldArtifactMismatch({ brownfieldChange, git, status });
|
|
199
|
+
const brownfieldRouting = classifyBrownfieldCheckpointPrecedence({
|
|
200
|
+
checkpoint,
|
|
201
|
+
planning,
|
|
202
|
+
quick,
|
|
203
|
+
brownfieldChange,
|
|
204
|
+
git,
|
|
205
|
+
status,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const warnings = [];
|
|
57
209
|
|
|
58
210
|
if (status.dirty) {
|
|
59
211
|
warnings.push({
|
|
@@ -103,30 +255,50 @@ export function buildProvenanceSnapshot({
|
|
|
103
255
|
});
|
|
104
256
|
}
|
|
105
257
|
|
|
106
|
-
if (git.materialCheckpointMismatch) {
|
|
107
|
-
warnings.push({
|
|
108
|
-
id: 'checkpoint_mismatch',
|
|
109
|
-
severity: 'acknowledgement_required',
|
|
110
|
-
summary: 'Checkpoint narrative truth materially understates or conflicts with the live branch/worktree truth.',
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
258
|
+
if (git.materialCheckpointMismatch) {
|
|
259
|
+
warnings.push({
|
|
260
|
+
id: 'checkpoint_mismatch',
|
|
261
|
+
severity: 'acknowledgement_required',
|
|
262
|
+
summary: 'Checkpoint narrative truth materially understates or conflicts with the live branch/worktree truth.',
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
warnings.push(...brownfieldMismatch.warnings);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
checkpoint: {
|
|
270
|
+
workflow: checkpointRouting.workflow,
|
|
271
|
+
phase: checkpoint.phase ?? null,
|
|
272
|
+
branch: checkpoint.branch || null,
|
|
273
|
+
runtime: checkpoint.runtime || 'unknown',
|
|
274
|
+
hasNarrative: Boolean(checkpoint.hasNarrative),
|
|
275
|
+
routing: checkpointRouting,
|
|
276
|
+
},
|
|
277
|
+
planning: {
|
|
278
|
+
currentPhase: planning.currentPhase || null,
|
|
279
|
+
nextPhase: planning.nextPhase || null,
|
|
280
|
+
completedPhaseCount: Number.isFinite(Number(planning.completedPhaseCount))
|
|
281
|
+
? Number(planning.completedPhaseCount)
|
|
282
|
+
: 0,
|
|
283
|
+
},
|
|
284
|
+
brownfieldChange: {
|
|
285
|
+
exists: Boolean(brownfieldChange?.exists),
|
|
286
|
+
title: brownfieldChange?.title || null,
|
|
287
|
+
currentStatus: brownfieldChange?.currentStatus || null,
|
|
288
|
+
currentIntegrationSurface: brownfieldChange?.currentIntegrationSurface || null,
|
|
289
|
+
nextAction: brownfieldChange?.nextAction || null,
|
|
290
|
+
declaredOwnedPaths: brownfieldChange?.declaredOwnedPaths || [],
|
|
291
|
+
},
|
|
292
|
+
routing: {
|
|
293
|
+
primary: brownfieldRouting.primary,
|
|
294
|
+
strictMatchRequired: brownfieldRouting.strictMatchRequired,
|
|
295
|
+
checkpointCanOverrideBrownfield: brownfieldRouting.checkpointCanOverrideBrownfield,
|
|
296
|
+
branchAligned: brownfieldRouting.branchAligned,
|
|
297
|
+
scopeAligned: brownfieldRouting.scopeAligned,
|
|
298
|
+
executionActive: brownfieldRouting.executionActive,
|
|
299
|
+
},
|
|
300
|
+
git: {
|
|
301
|
+
branch: git.branch || 'unknown',
|
|
130
302
|
prState,
|
|
131
303
|
commitsAheadOfMain,
|
|
132
304
|
commitsAheadOfRemote,
|
|
@@ -135,12 +307,81 @@ export function buildProvenanceSnapshot({
|
|
|
135
307
|
untrackedCount: status.untrackedCount,
|
|
136
308
|
dirty: status.dirty,
|
|
137
309
|
},
|
|
138
|
-
integrationSurface: {
|
|
139
|
-
staleBranch: Boolean(git.staleBranch),
|
|
140
|
-
mixedScope: Boolean(git.mixedScope),
|
|
141
|
-
materialCheckpointMismatch: Boolean(git.materialCheckpointMismatch),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
310
|
+
integrationSurface: {
|
|
311
|
+
staleBranch: Boolean(git.staleBranch),
|
|
312
|
+
mixedScope: Boolean(git.mixedScope),
|
|
313
|
+
materialCheckpointMismatch: Boolean(git.materialCheckpointMismatch),
|
|
314
|
+
materialBrownfieldMismatch: brownfieldMismatch.requiresAcknowledgement,
|
|
315
|
+
},
|
|
316
|
+
warnings,
|
|
317
|
+
requiresAcknowledgement: warnings.some((warning) => warning.severity === 'acknowledgement_required'),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function normalizeBranchName(value) {
|
|
322
|
+
return String(value || '')
|
|
323
|
+
.trim()
|
|
324
|
+
.toLowerCase()
|
|
325
|
+
.replace(/\\/g, '/');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function normalizeDeclaredBranch(value) {
|
|
329
|
+
return normalizeBranchName(value);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function normalizeOwnedPaths(values) {
|
|
333
|
+
return values
|
|
334
|
+
.map((value) => String(value || '').trim().replace(/\\/g, '/'))
|
|
335
|
+
.filter(Boolean);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function matchesOwnedPath(filePath, ownedPath) {
|
|
339
|
+
if (ownedPath.includes('*')) {
|
|
340
|
+
const prefix = ownedPath.split('*')[0];
|
|
341
|
+
return filePath.startsWith(prefix);
|
|
342
|
+
}
|
|
343
|
+
return filePath === ownedPath
|
|
344
|
+
|| filePath.startsWith(`${ownedPath}/`)
|
|
345
|
+
|| ownedPath.startsWith(`${filePath}/`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function checkpointExecutionIsActive({
|
|
349
|
+
checkpoint = {},
|
|
350
|
+
checkpointRouting = classifyCheckpointRouting(checkpoint.workflow),
|
|
351
|
+
planning = {},
|
|
352
|
+
quick = {},
|
|
353
|
+
} = {}) {
|
|
354
|
+
if (checkpointRouting.workflow === 'quick') {
|
|
355
|
+
return quick.hasIncompleteWork === true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (checkpointRouting.workflow !== 'phase') {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const checkpointPhase = normalizePhaseRef(checkpoint.phase);
|
|
363
|
+
if (!checkpointPhase) return false;
|
|
364
|
+
|
|
365
|
+
const phases = Array.isArray(planning.phases) ? planning.phases : [];
|
|
366
|
+
if (phases.length > 0) {
|
|
367
|
+
const matchingPhase = phases.find((phase) => normalizePhaseRef(phase.number) === checkpointPhase);
|
|
368
|
+
return Boolean(matchingPhase && matchingPhase.status !== 'done');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const currentPhase = normalizePhaseRef(planning.currentPhase);
|
|
372
|
+
const nextPhase = normalizePhaseRef(planning.nextPhase);
|
|
373
|
+
return checkpointPhase === currentPhase || checkpointPhase === nextPhase;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function normalizePhaseRef(value) {
|
|
377
|
+
const raw = String(value || '').trim().toLowerCase();
|
|
378
|
+
if (!raw) return '';
|
|
379
|
+
|
|
380
|
+
const match = raw.match(/^(\d+(?:\.\d+)*)([a-z]?)$/i);
|
|
381
|
+
if (!match) return raw;
|
|
382
|
+
|
|
383
|
+
const numericSegments = match[1]
|
|
384
|
+
.split('.')
|
|
385
|
+
.map((segment) => String(parseInt(segment, 10)));
|
|
386
|
+
return `${numericSegments.join('.')}${match[2] || ''}`;
|
|
387
|
+
}
|
package/bin/lib/rendering.mjs
CHANGED
|
@@ -18,16 +18,72 @@ function getDelegateContent(delegateFile) {
|
|
|
18
18
|
return `<!-- Delegate file not found: ${delegateFile} -->\n`;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function renderSkillContent(workflow) {
|
|
22
|
-
const workflowContent = getWorkflowContent(workflow.workflow);
|
|
23
|
-
return `---
|
|
24
|
-
name: ${workflow.name}
|
|
25
|
-
description: ${workflow.description}
|
|
21
|
+
function renderSkillContent(workflow) {
|
|
22
|
+
const workflowContent = getWorkflowContent(workflow.workflow);
|
|
23
|
+
return `---
|
|
24
|
+
name: ${workflow.name}
|
|
25
|
+
description: ${workflow.description}
|
|
26
26
|
context: fork
|
|
27
27
|
agent: ${workflow.agent}
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
${workflowContent}`;
|
|
30
|
+
${workflowContent}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function renderPlanningCliLauncher({ packageName = 'gsdd-cli', packageVersion }) {
|
|
34
|
+
if (!packageVersion) {
|
|
35
|
+
throw new Error('renderPlanningCliLauncher requires packageVersion');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const packageSpec = `${packageName}@${packageVersion}`;
|
|
39
|
+
|
|
40
|
+
return `#!/usr/bin/env node
|
|
41
|
+
|
|
42
|
+
import { spawnSync } from 'node:child_process';
|
|
43
|
+
|
|
44
|
+
const packageSpec = ${JSON.stringify(packageSpec)};
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
const env = { ...process.env };
|
|
47
|
+
|
|
48
|
+
function forwardResult(result, fallbackMessage) {
|
|
49
|
+
if (result.error) {
|
|
50
|
+
console.error(fallbackMessage ?? result.error.message);
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof result.status === 'number') {
|
|
56
|
+
process.exitCode = result.status;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (result.signal) {
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (env.GSDD_CLI_PATH) {
|
|
66
|
+
const localResult = spawnSync(process.execPath, [env.GSDD_CLI_PATH, ...args], {
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
env,
|
|
69
|
+
});
|
|
70
|
+
forwardResult(localResult, 'Failed to run the local GSDD CLI path from GSDD_CLI_PATH.');
|
|
71
|
+
} else {
|
|
72
|
+
const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
73
|
+
const npxResult = spawnSync(npxCommand, ['--yes', packageSpec, ...args], {
|
|
74
|
+
stdio: 'inherit',
|
|
75
|
+
env,
|
|
76
|
+
});
|
|
77
|
+
forwardResult(npxResult, \`Failed to run \${packageSpec} via npx.\`);
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function buildPortableSkillEntries(workflows) {
|
|
83
|
+
return workflows.map((workflow) => ({
|
|
84
|
+
relativePath: `.agents/skills/${workflow.name}/SKILL.md`,
|
|
85
|
+
content: renderSkillContent(workflow),
|
|
86
|
+
}));
|
|
31
87
|
}
|
|
32
88
|
|
|
33
89
|
function renderOpenCodeCommandContent(workflow) {
|
|
@@ -85,11 +141,13 @@ function upsertBoundedBlock(existing, blockContent) {
|
|
|
85
141
|
}
|
|
86
142
|
|
|
87
143
|
export {
|
|
144
|
+
buildPortableSkillEntries,
|
|
88
145
|
getDelegateContent,
|
|
89
146
|
getWorkflowContent,
|
|
90
|
-
renderAgentsBoundedBlock,
|
|
91
|
-
renderAgentsFileContent,
|
|
92
|
-
renderOpenCodeCommandContent,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
147
|
+
renderAgentsBoundedBlock,
|
|
148
|
+
renderAgentsFileContent,
|
|
149
|
+
renderOpenCodeCommandContent,
|
|
150
|
+
renderPlanningCliLauncher,
|
|
151
|
+
renderSkillContent,
|
|
152
|
+
upsertBoundedBlock,
|
|
153
|
+
};
|