gsd-lite 0.5.3 → 0.5.4
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +0 -0
- package/README.md +0 -0
- package/agents/debugger.md +0 -0
- package/agents/executor.md +0 -0
- package/agents/researcher.md +0 -0
- package/agents/reviewer.md +0 -0
- package/commands/doctor.md +0 -0
- package/commands/prd.md +0 -0
- package/commands/resume.md +0 -0
- package/commands/start.md +0 -0
- package/commands/status.md +0 -0
- package/commands/stop.md +0 -0
- package/hooks/context-monitor.js +0 -0
- package/hooks/gsd-auto-update.cjs +0 -0
- package/hooks/gsd-context-monitor.cjs +0 -0
- package/hooks/gsd-session-init.cjs +0 -0
- package/hooks/gsd-statusline.cjs +1 -1
- package/hooks/hooks.json +0 -0
- package/install.js +0 -0
- package/launcher.js +0 -0
- package/package.json +1 -1
- package/references/anti-rationalization-full.md +0 -0
- package/references/evidence-spec.md +0 -0
- package/references/execution-loop.md +0 -0
- package/references/git-worktrees.md +0 -0
- package/references/questioning.md +0 -0
- package/references/review-classification.md +0 -0
- package/references/state-diagram.md +0 -0
- package/references/testing-patterns.md +0 -0
- package/src/schema.js +40 -2
- package/src/server.js +9 -3
- package/src/tools/orchestrator.js +0 -0
- package/src/tools/state.js +7 -4
- package/src/tools/verify.js +0 -0
- package/src/utils.js +0 -0
- package/uninstall.js +0 -0
- package/workflows/debugging.md +0 -0
- package/workflows/deviation-rules.md +0 -0
- package/workflows/execution-flow.md +0 -0
- package/workflows/research.md +0 -0
- package/workflows/review-cycle.md +0 -0
- package/workflows/tdd-cycle.md +0 -0
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "gsd",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "AI orchestration tool — GSD management shell + Superpowers quality core. 5 commands, 4 agents, 5 workflows, MCP server, context monitoring.",
|
|
16
|
-
"version": "0.5.
|
|
16
|
+
"version": "0.5.4",
|
|
17
17
|
"keywords": [
|
|
18
18
|
"orchestration",
|
|
19
19
|
"mcp",
|
package/.mcp.json
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/agents/debugger.md
CHANGED
|
File without changes
|
package/agents/executor.md
CHANGED
|
File without changes
|
package/agents/researcher.md
CHANGED
|
File without changes
|
package/agents/reviewer.md
CHANGED
|
File without changes
|
package/commands/doctor.md
CHANGED
|
File without changes
|
package/commands/prd.md
CHANGED
|
File without changes
|
package/commands/resume.md
CHANGED
|
File without changes
|
package/commands/start.md
CHANGED
|
File without changes
|
package/commands/status.md
CHANGED
|
File without changes
|
package/commands/stop.md
CHANGED
|
File without changes
|
package/hooks/context-monitor.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/hooks/gsd-statusline.cjs
CHANGED
|
@@ -74,7 +74,7 @@ process.stdin.on('end', () => {
|
|
|
74
74
|
let needsWrite = true;
|
|
75
75
|
try {
|
|
76
76
|
const existing = JSON.parse(fs.readFileSync(bridgePath, 'utf8'));
|
|
77
|
-
if (existing.remaining_percentage === remaining) needsWrite = false;
|
|
77
|
+
if (existing.remaining_percentage === remaining && existing.has_gsd === hasGsd) needsWrite = false;
|
|
78
78
|
} catch { /* no existing file */ }
|
|
79
79
|
if (needsWrite) {
|
|
80
80
|
const tmpBridge = bridgePath + '.tmp';
|
package/hooks/hooks.json
CHANGED
|
File without changes
|
package/install.js
CHANGED
|
File without changes
|
package/launcher.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/schema.js
CHANGED
|
@@ -17,6 +17,23 @@ export const WORKFLOW_MODES = [
|
|
|
17
17
|
'failed',
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
+
// Valid workflow_mode transitions — unlisted transitions are rejected by validateStateUpdate.
|
|
21
|
+
// Terminal states (completed, failed) are guarded separately by the FROM-terminal check in state-update.
|
|
22
|
+
export const WORKFLOW_TRANSITIONS = {
|
|
23
|
+
planning: ['executing_task', 'paused_by_user'],
|
|
24
|
+
executing_task: ['planning', 'reviewing_task', 'reviewing_phase', 'awaiting_user', 'awaiting_clear', 'paused_by_user', 'reconcile_workspace', 'replan_required', 'research_refresh_needed', 'failed'],
|
|
25
|
+
reviewing_task: ['executing_task', 'reviewing_phase', 'awaiting_user', 'awaiting_clear', 'paused_by_user', 'failed'],
|
|
26
|
+
reviewing_phase: ['executing_task', 'awaiting_user', 'awaiting_clear', 'paused_by_user', 'completed', 'failed'],
|
|
27
|
+
awaiting_user: ['executing_task', 'reviewing_task', 'reviewing_phase', 'paused_by_user', 'awaiting_clear'],
|
|
28
|
+
awaiting_clear: ['executing_task', 'paused_by_user'],
|
|
29
|
+
paused_by_user: ['executing_task', 'awaiting_user', 'awaiting_clear', 'reconcile_workspace', 'replan_required', 'research_refresh_needed', 'reviewing_task', 'reviewing_phase'],
|
|
30
|
+
reconcile_workspace: ['executing_task', 'paused_by_user'],
|
|
31
|
+
replan_required: ['executing_task', 'paused_by_user'],
|
|
32
|
+
research_refresh_needed: ['executing_task', 'reviewing_task', 'reviewing_phase', 'paused_by_user'],
|
|
33
|
+
completed: [], // terminal — guarded by FROM-terminal check
|
|
34
|
+
failed: [], // terminal — guarded by FROM-terminal check
|
|
35
|
+
};
|
|
36
|
+
|
|
20
37
|
export const TASK_LIFECYCLE = {
|
|
21
38
|
pending: ['running', 'blocked'],
|
|
22
39
|
running: ['checkpointed', 'blocked', 'failed', 'accepted'], // accepted: auto-accept for L0/review_required=false (atomic, skips checkpointed)
|
|
@@ -154,11 +171,28 @@ export function validateStateUpdate(state, updates) {
|
|
|
154
171
|
|
|
155
172
|
for (const key of Object.keys(updates)) {
|
|
156
173
|
switch (key) {
|
|
157
|
-
case 'workflow_mode':
|
|
174
|
+
case 'workflow_mode': {
|
|
158
175
|
if (!WORKFLOW_MODES.includes(updates.workflow_mode)) {
|
|
159
176
|
errors.push(`Invalid workflow_mode: ${updates.workflow_mode}`);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
// Transition whitelist — reject unlisted transitions
|
|
180
|
+
const currentMode = state.workflow_mode;
|
|
181
|
+
if (currentMode && updates.workflow_mode !== currentMode) {
|
|
182
|
+
const allowed = WORKFLOW_TRANSITIONS[currentMode];
|
|
183
|
+
if (allowed && !allowed.includes(updates.workflow_mode)) {
|
|
184
|
+
errors.push(`Invalid workflow_mode transition: '${currentMode}' → '${updates.workflow_mode}' (allowed: ${allowed.join(', ') || 'none (terminal state)'})`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Guard: 'completed' requires all phases accepted
|
|
188
|
+
if (updates.workflow_mode === 'completed' && Array.isArray(state.phases)) {
|
|
189
|
+
const unfinished = state.phases.filter(p => p.lifecycle !== 'accepted');
|
|
190
|
+
if (unfinished.length > 0) {
|
|
191
|
+
errors.push(`Cannot set workflow_mode to 'completed': ${unfinished.length} phase(s) not accepted (${unfinished.map(p => `${p.id}:${p.lifecycle}`).join(', ')})`);
|
|
192
|
+
}
|
|
160
193
|
}
|
|
161
194
|
break;
|
|
195
|
+
}
|
|
162
196
|
case 'current_phase':
|
|
163
197
|
if (!Number.isFinite(updates.current_phase)) {
|
|
164
198
|
errors.push('current_phase must be a finite number');
|
|
@@ -383,8 +417,12 @@ export function validateState(state) {
|
|
|
383
417
|
}
|
|
384
418
|
}
|
|
385
419
|
}
|
|
386
|
-
// P2-9: workflow_mode consistency — completed project
|
|
420
|
+
// P2-9: workflow_mode consistency — completed project requires all phases accepted
|
|
387
421
|
if (state.workflow_mode === 'completed' && Array.isArray(state.phases)) {
|
|
422
|
+
const unfinishedPhases = state.phases.filter(p => p.lifecycle !== 'accepted');
|
|
423
|
+
if (unfinishedPhases.length > 0) {
|
|
424
|
+
errors.push(`Completed project has ${unfinishedPhases.length} unfinished phase(s): ${unfinishedPhases.map(p => `${p.id}:${p.lifecycle}`).join(', ')}`);
|
|
425
|
+
}
|
|
388
426
|
for (const phase of state.phases) {
|
|
389
427
|
for (const task of (phase.todo || [])) {
|
|
390
428
|
if (task.lifecycle === 'running') {
|
package/src/server.js
CHANGED
|
@@ -90,7 +90,7 @@ const TOOLS = [
|
|
|
90
90
|
properties: {
|
|
91
91
|
updates: {
|
|
92
92
|
type: 'object',
|
|
93
|
-
description: 'Key-value pairs of canonical fields
|
|
93
|
+
description: 'Key-value pairs of canonical fields: workflow_mode, current_phase, current_task, current_review, git_head, plan_version, schema_version, total_phases, project, decisions, context, evidence, research',
|
|
94
94
|
},
|
|
95
95
|
},
|
|
96
96
|
required: ['updates'],
|
|
@@ -105,7 +105,13 @@ const TOOLS = [
|
|
|
105
105
|
phase_id: { type: 'number', description: 'Phase number to complete' },
|
|
106
106
|
verification: {
|
|
107
107
|
type: 'object',
|
|
108
|
-
description: 'Optional precomputed verification
|
|
108
|
+
description: 'Optional precomputed verification — all three keys required, exit_code 0 = passed',
|
|
109
|
+
properties: {
|
|
110
|
+
lint: { type: 'object', properties: { exit_code: { type: 'number' } }, required: ['exit_code'] },
|
|
111
|
+
typecheck: { type: 'object', properties: { exit_code: { type: 'number' } }, required: ['exit_code'] },
|
|
112
|
+
test: { type: 'object', properties: { exit_code: { type: 'number' } }, required: ['exit_code'] },
|
|
113
|
+
},
|
|
114
|
+
required: ['lint', 'typecheck', 'test'],
|
|
109
115
|
},
|
|
110
116
|
run_verify: {
|
|
111
117
|
type: 'boolean',
|
|
@@ -135,7 +141,7 @@ const TOOLS = [
|
|
|
135
141
|
properties: {
|
|
136
142
|
result: {
|
|
137
143
|
type: 'object',
|
|
138
|
-
description: 'Executor result: {task_id: string, outcome: "checkpointed"|"blocked"|"failed", summary: string, checkpoint_commit: string|null, files_changed: string[], decisions:
|
|
144
|
+
description: 'Executor result: {task_id: string, outcome: "checkpointed"|"blocked"|"failed", summary: string, checkpoint_commit: string|null, files_changed: string[], decisions: [{id, summary, rationale}], blockers: [{description}], contract_changed: boolean, evidence: string[]}',
|
|
139
145
|
},
|
|
140
146
|
},
|
|
141
147
|
required: ['result'],
|
|
File without changes
|
package/src/tools/state.js
CHANGED
|
@@ -341,10 +341,13 @@ function verificationPassed(verification) {
|
|
|
341
341
|
|
|
342
342
|
function verificationSummary(verification) {
|
|
343
343
|
if (!verification || typeof verification !== 'object') return 'no verification details';
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
344
|
+
const parts = ['lint', 'typecheck', 'test'].map((key) => {
|
|
345
|
+
const v = verification[key];
|
|
346
|
+
if (!v) return `${key}:missing`;
|
|
347
|
+
if (typeof v !== 'object' || !('exit_code' in v)) return `${key}:invalid-format (expected {exit_code: number})`;
|
|
348
|
+
return `${key}:${v.exit_code === 0 ? 'pass' : `fail(${v.exit_code})`}`;
|
|
349
|
+
});
|
|
350
|
+
return parts.join(', ');
|
|
348
351
|
}
|
|
349
352
|
|
|
350
353
|
export async function phaseComplete({
|
package/src/tools/verify.js
CHANGED
|
File without changes
|
package/src/utils.js
CHANGED
|
File without changes
|
package/uninstall.js
CHANGED
|
File without changes
|
package/workflows/debugging.md
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/workflows/research.md
CHANGED
|
File without changes
|
|
File without changes
|
package/workflows/tdd-cycle.md
CHANGED
|
File without changes
|