gsd-lite 0.4.0 → 0.4.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.
@@ -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.4.0",
16
+ "version": "0.4.1",
17
17
  "keywords": [
18
18
  "orchestration",
19
19
  "mcp",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "AI orchestration tool for Claude Code — GSD management shell + Superpowers quality core",
5
5
  "author": {
6
6
  "name": "sdsrss",
package/install.js CHANGED
@@ -136,7 +136,7 @@ export function main() {
136
136
  copyDir(localNM, join(RUNTIME_DIR, 'node_modules'), 'runtime/node_modules (copied)');
137
137
  } else if (!DRY_RUN) {
138
138
  log(' ⧗ Installing runtime dependencies...');
139
- execSync('npm install --omit=dev', { cwd: RUNTIME_DIR, stdio: 'pipe' });
139
+ execSync('npm ci --omit=dev', { cwd: RUNTIME_DIR, stdio: 'pipe' });
140
140
  log(' ✓ runtime dependencies installed');
141
141
  } else {
142
142
  log(' [dry-run] Would install runtime dependencies');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-lite",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "AI orchestration tool for Claude Code — GSD management shell + Superpowers quality core",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,7 +39,8 @@
39
39
  "cli.js",
40
40
  "launcher.js",
41
41
  "install.js",
42
- "uninstall.js"
42
+ "uninstall.js",
43
+ "package-lock.json"
43
44
  ],
44
45
  "engines": {
45
46
  "node": ">=20.0.0"
package/src/schema.js CHANGED
@@ -387,6 +387,37 @@ export function validateState(state) {
387
387
  }
388
388
  }
389
389
  }
390
+ // P2-9: workflow_mode consistency — reviewing modes require matching current_review
391
+ if (state.workflow_mode === 'reviewing_phase' || state.workflow_mode === 'reviewing_task') {
392
+ const expectedScope = state.workflow_mode === 'reviewing_phase' ? 'phase' : 'task';
393
+ if (!state.current_review || state.current_review.scope !== expectedScope) {
394
+ errors.push(`workflow_mode "${state.workflow_mode}" requires current_review with scope="${expectedScope}"`);
395
+ }
396
+ }
397
+ // P2-9: current_review.scope_id must reference an existing phase or task
398
+ if (state.current_review && state.current_review.scope_id != null && Array.isArray(state.phases)) {
399
+ if (state.current_review.scope === 'phase') {
400
+ if (!state.phases.some(p => p.id === state.current_review.scope_id)) {
401
+ errors.push(`current_review.scope_id ${state.current_review.scope_id} references non-existent phase`);
402
+ }
403
+ } else if (state.current_review.scope === 'task') {
404
+ const curPhase = state.phases.find(p => p.id === state.current_phase);
405
+ if (curPhase && Array.isArray(curPhase.todo) && !curPhase.todo.some(t => t.id === state.current_review.scope_id)) {
406
+ errors.push(`current_review.scope_id "${state.current_review.scope_id}" references non-existent task in phase ${state.current_phase}`);
407
+ }
408
+ }
409
+ }
410
+ // P2-9: accepted phase must not contain non-accepted tasks
411
+ if (Array.isArray(state.phases)) {
412
+ for (const phase of state.phases) {
413
+ if (phase.lifecycle === 'accepted' && Array.isArray(phase.todo)) {
414
+ const nonAccepted = phase.todo.filter(t => t.lifecycle !== 'accepted');
415
+ if (nonAccepted.length > 0) {
416
+ errors.push(`Accepted phase ${phase.id} contains non-accepted tasks: ${nonAccepted.map(t => `${t.id}:${t.lifecycle}`).join(', ')}`);
417
+ }
418
+ }
419
+ }
420
+ }
390
421
  if (Array.isArray(state.phases)) {
391
422
  if (typeof state.total_phases === 'number' && state.total_phases !== state.phases.length) {
392
423
  errors.push(`total_phases (${state.total_phases}) does not match phases.length (${state.phases.length})`);