godpowers 2.3.0 → 2.4.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.
Files changed (169) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +28 -16
  3. package/RELEASE.md +35 -27
  4. package/SKILL.md +26 -3
  5. package/agents/god-debugger.md +44 -8
  6. package/agents/god-executor.md +28 -0
  7. package/agents/god-quality-reviewer.md +23 -1
  8. package/agents/god-spec-reviewer.md +6 -0
  9. package/bin/install.js +6 -0
  10. package/lib/README.md +5 -2
  11. package/lib/agent-cache.js +25 -3
  12. package/lib/code-intelligence.js +161 -0
  13. package/lib/command-families.js +375 -0
  14. package/lib/dashboard.js +54 -20
  15. package/lib/extensions.js +6 -13
  16. package/lib/feature-awareness.js +2 -2
  17. package/lib/host-capabilities.js +4 -0
  18. package/lib/install-profiles.js +1 -0
  19. package/lib/planning-systems.js +7 -4
  20. package/lib/quick-proof.js +5 -2
  21. package/lib/release-surface-sync.js +4 -1
  22. package/lib/route-quality-sync.js +42 -12
  23. package/lib/router.js +32 -0
  24. package/lib/workflow-helper-groups.js +50 -0
  25. package/lib/workflow-runner.js +6 -1
  26. package/package.json +2 -2
  27. package/routing/god-add-backlog.yaml +1 -0
  28. package/routing/god-add-tests.yaml +1 -0
  29. package/routing/god-add-todo.yaml +1 -0
  30. package/routing/god-agent-audit.yaml +6 -0
  31. package/routing/god-arch.yaml +1 -0
  32. package/routing/god-archaeology.yaml +1 -0
  33. package/routing/god-audit.yaml +1 -0
  34. package/routing/god-automation-setup.yaml +1 -0
  35. package/routing/god-automation-status.yaml +1 -0
  36. package/routing/god-budget.yaml +6 -0
  37. package/routing/god-build-agent.yaml +1 -0
  38. package/routing/god-build.yaml +1 -0
  39. package/routing/god-cache-clear.yaml +6 -0
  40. package/routing/god-check-todos.yaml +6 -0
  41. package/routing/god-context-scan.yaml +6 -0
  42. package/routing/god-context.yaml +1 -0
  43. package/routing/god-cost.yaml +6 -0
  44. package/routing/god-debug.yaml +1 -0
  45. package/routing/god-deploy.yaml +1 -0
  46. package/routing/god-design-impact.yaml +6 -0
  47. package/routing/god-design.yaml +1 -0
  48. package/routing/god-discuss.yaml +12 -0
  49. package/routing/god-docs.yaml +1 -0
  50. package/routing/god-doctor.yaml +6 -0
  51. package/routing/god-dogfood.yaml +1 -0
  52. package/routing/god-explore.yaml +1 -0
  53. package/routing/god-export-otel.yaml +1 -0
  54. package/routing/god-extension-add.yaml +6 -0
  55. package/routing/god-extension-info.yaml +6 -0
  56. package/routing/god-extension-list.yaml +6 -0
  57. package/routing/god-extension-remove.yaml +6 -0
  58. package/routing/god-extension-scaffold.yaml +26 -0
  59. package/routing/god-extract-learnings.yaml +1 -0
  60. package/routing/god-fast.yaml +1 -0
  61. package/routing/god-feature.yaml +1 -0
  62. package/routing/god-graph.yaml +6 -0
  63. package/routing/god-harden.yaml +1 -0
  64. package/routing/god-help.yaml +6 -0
  65. package/routing/god-hotfix.yaml +1 -0
  66. package/routing/god-hygiene.yaml +1 -0
  67. package/routing/god-init.yaml +1 -0
  68. package/routing/god-intel.yaml +1 -0
  69. package/routing/god-launch.yaml +6 -0
  70. package/routing/god-lifecycle.yaml +12 -0
  71. package/routing/god-link.yaml +1 -0
  72. package/routing/god-lint.yaml +1 -0
  73. package/routing/god-list-assumptions.yaml +6 -0
  74. package/routing/god-locate.yaml +6 -0
  75. package/routing/god-logs.yaml +12 -0
  76. package/routing/god-map-codebase.yaml +1 -0
  77. package/routing/god-metrics.yaml +6 -0
  78. package/routing/god-migrate.yaml +1 -0
  79. package/routing/god-mode.yaml +6 -0
  80. package/routing/god-next.yaml +12 -0
  81. package/routing/god-note.yaml +1 -0
  82. package/routing/god-observe.yaml +1 -0
  83. package/routing/god-org-context.yaml +1 -0
  84. package/routing/god-party.yaml +1 -0
  85. package/routing/god-pause-work.yaml +6 -0
  86. package/routing/god-plant-seed.yaml +1 -0
  87. package/routing/god-postmortem.yaml +1 -0
  88. package/routing/god-pr-branch.yaml +1 -0
  89. package/routing/god-prd.yaml +1 -0
  90. package/routing/god-preflight.yaml +1 -0
  91. package/routing/god-progress.yaml +7 -0
  92. package/routing/god-quick.yaml +1 -0
  93. package/routing/god-reconcile.yaml +6 -0
  94. package/routing/god-reconstruct.yaml +1 -0
  95. package/routing/god-redo.yaml +6 -0
  96. package/routing/god-refactor.yaml +1 -0
  97. package/routing/god-repair.yaml +1 -0
  98. package/routing/god-repo.yaml +1 -0
  99. package/routing/god-restore.yaml +1 -0
  100. package/routing/god-resume-work.yaml +6 -0
  101. package/routing/god-review-changes.yaml +1 -0
  102. package/routing/god-review.yaml +1 -0
  103. package/routing/god-roadmap-check.yaml +6 -0
  104. package/routing/god-roadmap-update.yaml +1 -0
  105. package/routing/god-roadmap.yaml +1 -0
  106. package/routing/god-rollback.yaml +1 -0
  107. package/routing/god-scan.yaml +1 -0
  108. package/routing/god-set-profile.yaml +1 -0
  109. package/routing/god-settings.yaml +1 -0
  110. package/routing/god-skip.yaml +1 -0
  111. package/routing/god-smite.yaml +1 -0
  112. package/routing/god-spike.yaml +1 -0
  113. package/routing/god-sprint.yaml +6 -0
  114. package/routing/god-stack.yaml +2 -1
  115. package/routing/god-standards.yaml +1 -0
  116. package/routing/god-status.yaml +1 -0
  117. package/routing/god-stories.yaml +1 -0
  118. package/routing/god-story-build.yaml +1 -0
  119. package/routing/god-story-close.yaml +1 -0
  120. package/routing/god-story-verify.yaml +1 -0
  121. package/routing/god-story.yaml +1 -0
  122. package/routing/god-suite-init.yaml +1 -0
  123. package/routing/god-suite-patch.yaml +1 -0
  124. package/routing/god-suite-release.yaml +1 -0
  125. package/routing/god-suite-status.yaml +6 -0
  126. package/routing/god-suite-sync.yaml +1 -0
  127. package/routing/god-sync.yaml +1 -0
  128. package/routing/god-tech-debt.yaml +1 -0
  129. package/routing/god-test-extension.yaml +6 -0
  130. package/routing/god-test-runtime.yaml +1 -0
  131. package/routing/god-thread.yaml +6 -0
  132. package/routing/god-trace.yaml +6 -0
  133. package/routing/god-undo.yaml +1 -0
  134. package/routing/god-update-deps.yaml +1 -0
  135. package/routing/god-upgrade.yaml +1 -0
  136. package/routing/god-version.yaml +1 -0
  137. package/routing/god-workstream.yaml +6 -0
  138. package/routing/god.yaml +6 -0
  139. package/routing/recipes/add-feature-mid-arc-pause.yaml +6 -0
  140. package/routing/recipes/brownfield-onboarding.yaml +5 -2
  141. package/routing/recipes/extension-authoring.yaml +32 -0
  142. package/routing/recipes/greenfield-fast.yaml +3 -0
  143. package/routing/recipes/production-broken.yaml +4 -0
  144. package/routing/recipes/release-maintenance.yaml +3 -0
  145. package/routing/recipes/returning-after-break.yaml +3 -0
  146. package/routing/recipes/weekly-health-check.yaml +2 -0
  147. package/schema/routing.v1.json +62 -4
  148. package/schema/workflow.v1.json +14 -0
  149. package/skills/god-discuss.md +10 -5
  150. package/skills/god-doctor.md +9 -3
  151. package/skills/god-extension-scaffold.md +66 -0
  152. package/skills/god-help.md +38 -3
  153. package/skills/god-next.md +19 -2
  154. package/skills/god-status.md +13 -0
  155. package/skills/god-sync.md +1 -1
  156. package/skills/god-version.md +2 -2
  157. package/skills/god.md +61 -12
  158. package/workflows/audit-only.yaml +2 -2
  159. package/workflows/bluefield-arc.yaml +3 -7
  160. package/workflows/brownfield-arc.yaml +4 -8
  161. package/workflows/deps-audit.yaml +2 -5
  162. package/workflows/docs-arc.yaml +2 -2
  163. package/workflows/feature-arc.yaml +3 -6
  164. package/workflows/full-arc.yaml +5 -11
  165. package/workflows/hotfix-arc.yaml +3 -6
  166. package/workflows/hygiene.yaml +2 -2
  167. package/workflows/migration-arc.yaml +3 -5
  168. package/workflows/postmortem.yaml +2 -5
  169. package/workflows/refactor-arc.yaml +3 -6
package/lib/extensions.js CHANGED
@@ -27,6 +27,7 @@ const fs = require('fs');
27
27
  const path = require('path');
28
28
 
29
29
  const intentLib = require('./intent'); // reuses parseSimpleYaml
30
+ const { copyRecursive } = require('./installer-files');
30
31
 
31
32
  function extensionsDir(runtimeConfigDir) {
32
33
  return path.join(runtimeConfigDir, 'godpowers-extensions');
@@ -159,11 +160,13 @@ function list(runtimeConfigDir) {
159
160
  const results = [];
160
161
  for (const scope of fs.readdirSync(dir)) {
161
162
  const scopePath = path.join(dir, scope);
162
- if (!fs.statSync(scopePath).isDirectory()) continue;
163
+ const scopeStat = fs.lstatSync(scopePath);
164
+ if (scopeStat.isSymbolicLink() || !scopeStat.isDirectory()) continue;
163
165
  if (!scope.startsWith('@')) continue;
164
166
  for (const name of fs.readdirSync(scopePath)) {
165
167
  const packDir = path.join(scopePath, name);
166
- if (!fs.statSync(packDir).isDirectory()) continue;
168
+ const packStat = fs.lstatSync(packDir);
169
+ if (packStat.isSymbolicLink() || !packStat.isDirectory()) continue;
167
170
  const manifestFile = path.join(packDir, 'manifest.yaml');
168
171
  if (!fs.existsSync(manifestFile)) continue;
169
172
  const { manifest } = parseManifest(fs.readFileSync(manifestFile, 'utf8'));
@@ -220,22 +223,12 @@ function install(runtimeConfigDir, sourceDir, godpowersVersion) {
220
223
  for (const sub of ['agents', 'skills', 'workflows', 'references']) {
221
224
  const src = path.join(sourceDir, sub);
222
225
  if (fs.existsSync(src)) {
223
- copyDirRecursive(src, path.join(destDir, sub));
226
+ copyRecursive(src, path.join(destDir, sub));
224
227
  }
225
228
  }
226
229
  return { installed: true, path: destDir, manifest };
227
230
  }
228
231
 
229
- function copyDirRecursive(src, dest) {
230
- fs.mkdirSync(dest, { recursive: true });
231
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
232
- const s = path.join(src, entry.name);
233
- const d = path.join(dest, entry.name);
234
- if (entry.isDirectory()) copyDirRecursive(s, d);
235
- else fs.copyFileSync(s, d);
236
- }
237
- }
238
-
239
232
  /**
240
233
  * Remove an installed extension by name.
241
234
  */
@@ -51,7 +51,7 @@ const FEATURES = [
51
51
  id: 'route-quality-sync',
52
52
  since: '1.6.19',
53
53
  commands: ['/god-sync', '/god-doctor', '/god-status', '/god-mode'],
54
- description: 'Detect symbolic route spawns, unresolved agent targets, and unapproved contextual route exits.'
54
+ description: 'Detect symbolic route spawns, unresolved agent targets, and untyped contextual route exits.'
55
55
  },
56
56
  {
57
57
  id: 'recipe-coverage-sync',
@@ -110,7 +110,7 @@ const FEATURES = [
110
110
  {
111
111
  id: 'extension-authoring',
112
112
  since: '1.6.22',
113
- commands: ['/god-extension-add', '/god-test-extension'],
113
+ commands: ['/god-extension-scaffold', '/god-test-extension', '/god-extension-add'],
114
114
  description: 'Scaffold and validate publishable Godpowers extension packs.'
115
115
  },
116
116
  {
@@ -10,6 +10,7 @@ const fs = require('fs');
10
10
  const path = require('path');
11
11
  const os = require('os');
12
12
  const cp = require('child_process');
13
+ const codeIntelligence = require('./code-intelligence');
13
14
 
14
15
  function exists(filePath) {
15
16
  return fs.existsSync(filePath);
@@ -55,6 +56,7 @@ function detect(projectRoot, opts = {}) {
55
56
  const git = commandVersion('git', ['--version'], { cwd: root });
56
57
  const npm = commandVersion('npm', ['--version'], { cwd: root });
57
58
  const gh = commandVersion('gh', ['--version'], { cwd: root });
59
+ const codeIntel = opts.codeIntelligence || codeIntelligence.detect(root, opts.codeIntelligenceOpts || {});
58
60
  const shell = Boolean(env.SHELL || env.ComSpec);
59
61
  const agentSpawn = Boolean(installedAgents.codex || installedAgents.claude || opts.agentSpawn);
60
62
  const extensionAuthoring = exists(path.join(root, 'lib', 'extension-authoring.js'))
@@ -84,6 +86,7 @@ function detect(projectRoot, opts = {}) {
84
86
  npm,
85
87
  gh,
86
88
  agentSpawn,
89
+ codeIntelligence: codeIntel,
87
90
  extensionAuthoring,
88
91
  suiteReleaseDryRun
89
92
  },
@@ -109,6 +112,7 @@ function render(report) {
109
112
  lines.push(` Git: ${report.guarantees.git || 'not detected'}`);
110
113
  lines.push(` npm: ${report.guarantees.npm || 'not detected'}`);
111
114
  lines.push(` GitHub CLI: ${report.guarantees.gh || 'not detected'}`);
115
+ lines.push(` Code intelligence: ${codeIntelligence.summary(report.guarantees.codeIntelligence)}`);
112
116
  lines.push(` Gaps: ${report.gaps.length > 0 ? report.gaps.join('; ') : 'none'}`);
113
117
  return lines.join('\n');
114
118
  }
@@ -70,6 +70,7 @@ const PROFILE_SKILLS = {
70
70
  'god-migrate',
71
71
  'god-automation-status',
72
72
  'god-automation-setup',
73
+ 'god-extension-scaffold',
73
74
  'god-extension-add',
74
75
  'god-extension-list',
75
76
  'god-extension-info',
@@ -112,7 +112,7 @@ function hashFiles(projectRoot, files) {
112
112
  for (const file of files.map((f) => f.path).sort()) {
113
113
  const full = path.join(projectRoot, file);
114
114
  h.update(file);
115
- if (fs.existsSync(full) && fs.statSync(full).isFile()) {
115
+ if (fs.existsSync(full) && fs.lstatSync(full).isFile()) {
116
116
  h.update(fs.readFileSync(full));
117
117
  }
118
118
  }
@@ -125,8 +125,10 @@ function isTextFile(filePath) {
125
125
 
126
126
  function readText(projectRoot, relPath) {
127
127
  const full = path.join(projectRoot, relPath);
128
- if (!fs.existsSync(full) || !fs.statSync(full).isFile()) return '';
129
- const size = fs.statSync(full).size;
128
+ if (!fs.existsSync(full)) return '';
129
+ const stat = fs.lstatSync(full);
130
+ if (!stat.isFile()) return '';
131
+ const size = stat.size;
130
132
  const buffer = fs.readFileSync(full);
131
133
  const raw = buffer.slice(0, Math.min(size, MAX_FILE_BYTES)).toString('utf8');
132
134
  return raw.replace(/\r\n/g, '\n');
@@ -134,7 +136,8 @@ function readText(projectRoot, relPath) {
134
136
 
135
137
  function walkFiles(rootDir, projectRoot, out = []) {
136
138
  if (!fs.existsSync(rootDir) || out.length >= MAX_SYSTEM_FILES) return out;
137
- const stat = fs.statSync(rootDir);
139
+ const stat = fs.lstatSync(rootDir);
140
+ if (stat.isSymbolicLink()) return out;
138
141
  if (stat.isFile()) {
139
142
  if (isTextFile(rootDir)) out.push(rel(projectRoot, rootDir));
140
143
  return out;
@@ -93,6 +93,9 @@ function render(proof, opts = {}) {
93
93
  const next = proof.dashboard.next || {};
94
94
  const progress = proof.dashboard.progress || {};
95
95
  const planning = proof.dashboard.planning || {};
96
+ const projectCommandRoot = path.resolve(proof.projectRoot) === path.resolve(proof.fixtureRoot)
97
+ ? '.'
98
+ : proof.projectRoot;
96
99
 
97
100
  if (opts.brief) {
98
101
  return [
@@ -140,8 +143,8 @@ function render(proof, opts = {}) {
140
143
  ` npx godpowers next --project=${proof.fixtureRoot} --brief`,
141
144
  '',
142
145
  'Try it on your project:',
143
- ` npx godpowers status --project=${proof.projectRoot} --brief`,
144
- ` npx godpowers next --project=${proof.projectRoot} --brief`
146
+ ` npx godpowers status --project=${projectCommandRoot} --brief`,
147
+ ` npx godpowers next --project=${projectCommandRoot} --brief`
145
148
  ].join('\n');
146
149
  }
147
150
 
@@ -12,15 +12,18 @@ const path = require('path');
12
12
  const LOG_PATH = '.godpowers/surface/RELEASE-SURFACE-SYNC.md';
13
13
 
14
14
  const REQUIRED_PACKAGE_GUARDS = [
15
+ 'lib/command-families.js',
15
16
  'lib/dogfood-runner.js',
16
17
  'lib/extension-authoring.js',
17
18
  'lib/host-capabilities.js',
18
19
  'lib/route-quality-sync.js',
19
20
  'lib/recipe-coverage-sync.js',
20
- 'lib/release-surface-sync.js'
21
+ 'lib/release-surface-sync.js',
22
+ 'lib/workflow-helper-groups.js'
21
23
  ];
22
24
 
23
25
  const REQUIRED_RELEASE_TESTS = [
26
+ 'scripts/test-command-families.js',
24
27
  'scripts/test-dogfood-runner.js',
25
28
  'scripts/test-extension-authoring.js',
26
29
  'scripts/test-host-capabilities.js',
@@ -2,8 +2,8 @@
2
2
  * Route quality sync.
3
3
  *
4
4
  * Detects disconnected route automation surfaces: symbolic spawn tokens,
5
- * unresolved agent targets, contextual exits without an approved reason,
6
- * missing standards coverage, and agent-spawn routes without trace events.
5
+ * unresolved agent targets, contextual exits without typed outcomes, missing
6
+ * standards coverage, and agent-spawn routes without trace events.
7
7
  */
8
8
 
9
9
  const fs = require('fs');
@@ -12,6 +12,21 @@ const path = require('path');
12
12
  const { parseSimpleYaml } = require('./intent');
13
13
 
14
14
  const LOG_PATH = '.godpowers/surface/ROUTE-QUALITY-SYNC.md';
15
+ const CONTEXTUAL_NEXT_VALUES = new Set([
16
+ 'varies',
17
+ 'varies-by-verdict',
18
+ 'steady-state',
19
+ 'session-end'
20
+ ]);
21
+ const OUTCOME_TYPES = new Set([
22
+ 'contextual',
23
+ 'verdict-based',
24
+ 'steady-state',
25
+ 'session-end',
26
+ 'requires-selection',
27
+ 'no-next-command',
28
+ 'explicit-command'
29
+ ]);
15
30
 
16
31
  const CONTEXTUAL_NEXT_ALLOWED = new Set([
17
32
  '/god',
@@ -21,6 +36,7 @@ const CONTEXTUAL_NEXT_ALLOWED = new Set([
21
36
  '/god-check-todos',
22
37
  '/god-context-scan',
23
38
  '/god-cost',
39
+ '/god-design-impact',
24
40
  '/god-discuss',
25
41
  '/god-doctor',
26
42
  '/god-extension-add',
@@ -33,10 +49,17 @@ const CONTEXTUAL_NEXT_ALLOWED = new Set([
33
49
  '/god-list-assumptions',
34
50
  '/god-locate',
35
51
  '/god-logs',
52
+ '/god-launch',
36
53
  '/god-metrics',
54
+ '/god-mode',
37
55
  '/god-next',
56
+ '/god-pause-work',
38
57
  '/god-redo',
58
+ '/god-reconcile',
39
59
  '/god-resume-work',
60
+ '/god-roadmap-check',
61
+ '/god-sprint',
62
+ '/god-suite-status',
40
63
  '/god-test-extension',
41
64
  '/god-thread',
42
65
  '/god-trace',
@@ -61,6 +84,7 @@ const STANDARDS_EXEMPT_COMMANDS = new Set([
61
84
  '/god-progress',
62
85
  '/god-reconstruct',
63
86
  '/god-roadmap-check',
87
+ '/god-extension-scaffold',
64
88
  '/god-smite',
65
89
  '/god-tech-debt'
66
90
  ]);
@@ -139,7 +163,7 @@ function detect(projectRoot) {
139
163
  .map((file) => path.basename(file, '.md')));
140
164
  let symbolicCount = 0;
141
165
  let unresolvedCount = 0;
142
- let contextualExitCount = 0;
166
+ let typedOutcomeCount = 0;
143
167
  let standardsExemptCount = 0;
144
168
  let traceEventMissingCount = 0;
145
169
 
@@ -192,18 +216,22 @@ function detect(projectRoot) {
192
216
  );
193
217
  }
194
218
 
195
- const next = route['success-path'] && route['success-path']['next-recommended'];
219
+ const successPath = route['success-path'] || {};
220
+ const next = successPath['next-recommended'];
196
221
  const conditionalNext = route['success-path'] && arr(route['success-path']['conditional-next']);
197
- if (next === 'varies' && conditionalNext.length === 0) {
198
- if (CONTEXTUAL_NEXT_ALLOWED.has(command)) {
199
- contextualExitCount++;
222
+ const outcome = successPath.outcome || {};
223
+ const needsTypedOutcome = next
224
+ && (CONTEXTUAL_NEXT_VALUES.has(String(next)) || /\s+or\s+/.test(String(next)));
225
+ if (needsTypedOutcome) {
226
+ if (outcome.type && OUTCOME_TYPES.has(String(outcome.type))) {
227
+ typedOutcomeCount++;
200
228
  } else {
201
229
  addCheck(
202
230
  checks,
203
- `unapproved-varies-${command.replace(/[^a-z0-9]+/gi, '-')}`,
231
+ `missing-route-outcome-${command.replace(/[^a-z0-9]+/gi, '-')}`,
204
232
  'stale',
205
233
  routePath,
206
- `${command} uses next-recommended: varies without an approved contextual-exit classification.`,
234
+ `${command} uses contextual next route ${next} without a typed success-path.outcome.`,
207
235
  { spawn: 'god-roadmap-reconciler' }
208
236
  );
209
237
  }
@@ -236,10 +264,10 @@ function detect(projectRoot) {
236
264
  addCheck(
237
265
  checks,
238
266
  'contextual-exit-policy',
239
- checks.some((check) => check.id.startsWith('unapproved-varies-')) ? 'stale' : 'fresh',
267
+ checks.some((check) => check.id.startsWith('missing-route-outcome-')) ? 'stale' : 'fresh',
240
268
  'routing/',
241
- `${contextualExitCount} contextual route exits are approved and all other next routes are explicit.`,
242
- { spawn: checks.some((check) => check.id.startsWith('unapproved-varies-')) ? 'god-roadmap-reconciler' : null }
269
+ `${typedOutcomeCount} contextual route exits have typed outcomes and all other next routes are explicit.`,
270
+ { spawn: checks.some((check) => check.id.startsWith('missing-route-outcome-')) ? 'god-roadmap-reconciler' : null }
243
271
  );
244
272
  addCheck(
245
273
  checks,
@@ -307,6 +335,8 @@ function summary(report) {
307
335
  module.exports = {
308
336
  LOG_PATH,
309
337
  CONTEXTUAL_NEXT_ALLOWED,
338
+ CONTEXTUAL_NEXT_VALUES,
339
+ OUTCOME_TYPES,
310
340
  STANDARDS_EXEMPT_COMMANDS,
311
341
  detect,
312
342
  run,
package/lib/router.js CHANGED
@@ -12,6 +12,7 @@ const fs = require('fs');
12
12
  const path = require('path');
13
13
  const { parseSimpleYaml } = require('./intent');
14
14
  const state = require('./state');
15
+ const commandFamilies = require('./command-families');
15
16
 
16
17
  const ROUTING_DIR = path.join(__dirname, '..', 'routing');
17
18
  const SAFE_SYNC_PLAN = '.godpowers/sync/SAFE-SYNC-PLAN.md';
@@ -186,6 +187,33 @@ function getNextCommand(command, opts = {}) {
186
187
  return sp['next-recommended'] || null;
187
188
  }
188
189
 
190
+ function inferOutcomeType(next) {
191
+ if (!next) return 'no-next-command';
192
+ if (next === 'varies') return 'contextual';
193
+ if (next === 'varies-by-verdict') return 'verdict-based';
194
+ if (next === 'steady-state') return 'steady-state';
195
+ if (next === 'session-end') return 'session-end';
196
+ if (/\s+or\s+/.test(next)) return 'requires-selection';
197
+ if (/^\/god(?:-[a-z-]+)?(?:\s.*)?$/.test(next)) return 'explicit-command';
198
+ return 'contextual';
199
+ }
200
+
201
+ function getRouteOutcome(command) {
202
+ const routing = getRouting(command);
203
+ if (!routing) return null;
204
+ const sp = routing['success-path'] || {};
205
+ const outcome = sp.outcome || {};
206
+ const next = sp['next-recommended'] || null;
207
+ const type = outcome.type || inferOutcomeType(next);
208
+ return {
209
+ type,
210
+ label: outcome.label || type,
211
+ reason: outcome.reason || 'Route outcome is inferred from success-path.next-recommended.',
212
+ next,
213
+ allowedNext: outcome['allowed-next'] || []
214
+ };
215
+ }
216
+
189
217
  /**
190
218
  * Evaluate a routing condition against the project state.
191
219
  */
@@ -368,9 +396,13 @@ module.exports = {
368
396
  getRouting,
369
397
  checkPrerequisites,
370
398
  getNextCommand,
399
+ getRouteOutcome,
371
400
  getAlternatives,
372
401
  getStandards,
373
402
  getSpawnedAgents,
403
+ getCommandFamily: commandFamilies.familyForCommand,
404
+ resolveTrigger: commandFamilies.resolveTrigger,
405
+ commandFamilies,
374
406
  suggestNext,
375
407
  evaluateCheck,
376
408
  resolveProjectRelative,
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Workflow helper groups.
3
+ *
4
+ * Workflow YAML can use these groups to avoid repeating long closeout helper
5
+ * lists. Plans still expand them into exact helper names for visibility.
6
+ */
7
+
8
+ const HELPER_GROUPS = {
9
+ 'standard-closeout': [
10
+ 'repo-doc-sync',
11
+ 'repo-surface-sync',
12
+ 'checkpoint-sync',
13
+ 'pillars-sync-plan'
14
+ ],
15
+ 'repo-maintenance-closeout': [
16
+ 'repo-doc-sync',
17
+ 'repo-surface-sync'
18
+ ],
19
+ 'runtime-awareness-closeout': [
20
+ 'feature-awareness',
21
+ 'host-capabilities'
22
+ ],
23
+ 'release-readiness-closeout': [
24
+ 'route-quality-sync',
25
+ 'recipe-coverage-sync',
26
+ 'release-surface-sync'
27
+ ],
28
+ 'source-sync-closeout': [
29
+ 'source-sync-back'
30
+ ]
31
+ };
32
+
33
+ function expand(groups = [], helpers = []) {
34
+ const expanded = [];
35
+ const names = Array.isArray(groups) ? groups : [groups].filter(Boolean);
36
+ for (const group of names) {
37
+ for (const helper of HELPER_GROUPS[group] || []) {
38
+ if (!expanded.includes(helper)) expanded.push(helper);
39
+ }
40
+ }
41
+ for (const helper of helpers || []) {
42
+ if (!expanded.includes(helper)) expanded.push(helper);
43
+ }
44
+ return expanded;
45
+ }
46
+
47
+ module.exports = {
48
+ HELPER_GROUPS,
49
+ expand
50
+ };
@@ -31,6 +31,7 @@ const path = require('path');
31
31
  const parser = require('./workflow-parser');
32
32
  const asyncFs = require('./fs-async');
33
33
  const agentRefs = require('./agent-refs');
34
+ const helperGroups = require('./workflow-helper-groups');
34
35
 
35
36
  /**
36
37
  * @typedef {Object} WorkflowPlanStep
@@ -134,7 +135,8 @@ function plan(workflow, ctx = {}) {
134
135
  review: job.review || null,
135
136
  'on-pass': job['on-pass'] || null,
136
137
  'on-fail': job['on-fail'] || null,
137
- localHelpers: job['local-helpers'] || [],
138
+ localHelperGroups: job['local-helper-groups'] || [],
139
+ localHelpers: helperGroups.expand(job['local-helper-groups'] || [], job['local-helpers'] || []),
138
140
  with: job.with || null
139
141
  });
140
142
  }
@@ -221,6 +223,9 @@ function serializePlan(p) {
221
223
  if (step.tier) lines.push(` tier: ${step.tier}`);
222
224
  if (step.agent) lines.push(` agent: ${step.agent}`);
223
225
  if (step.uses) lines.push(` uses: ${step.uses}`);
226
+ if (step.localHelperGroups && step.localHelperGroups.length) {
227
+ lines.push(` local-helper-groups: [${step.localHelperGroups.join(', ')}]`);
228
+ }
224
229
  if (step.localHelpers && step.localHelpers.length) {
225
230
  lines.push(` local-helpers: [${step.localHelpers.join(', ')}]`);
226
231
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "godpowers",
3
- "version": "2.3.0",
4
- "description": "AI-powered development system: 111 slash commands and 40 specialist agents that take a project from raw idea to hardened production. Runs inside Claude Code, Codex, Cursor, Windsurf, Gemini, and 10+ other AI coding tools.",
3
+ "version": "2.4.0",
4
+ "description": "AI-powered development system: 112 slash commands and 40 specialist agents that take a project from raw idea to hardened production. Runs inside Claude Code, Codex, Cursor, Windsurf, Gemini, and 10+ other AI coding tools.",
5
5
  "bin": {
6
6
  "godpowers": "./bin/install.js"
7
7
  },
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-add-backlog
5
5
  description: Add idea to backlog (less urgent than todo)
6
6
  tier: 0
7
+ family: capture
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-add-tests
5
5
  description: Add tests to legacy code
6
6
  tier: 0
7
+ family: build
7
8
 
8
9
  prerequisites:
9
10
  required:
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-add-todo
5
5
  description: Capture a todo from current context
6
6
  tier: 0
7
+ family: capture
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-agent-audit
5
5
  description: Validate agents/*.md against agent contract
6
6
  tier: 0
7
+ family: verify
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -15,6 +16,11 @@ execution:
15
16
 
16
17
  success-path:
17
18
  next-recommended: varies
19
+ outcome:
20
+ type: contextual
21
+ label: Context-specific next route
22
+ reason: The next route depends on current disk state, command arguments, or user choice.
23
+ allowed-next: [/god-status, /god-next, /god-help]
18
24
 
19
25
  failure-path:
20
26
  on-error: /god-doctor
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-arch
5
5
  description: Design system architecture
6
6
  tier: 1
7
+ family: start
7
8
 
8
9
  prerequisites:
9
10
  required:
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-archaeology
5
5
  description: Deep brownfield code archaeology
6
6
  tier: 0
7
+ family: start
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-audit
5
5
  description: Score artifacts against have-nots
6
6
  tier: 0
7
+ family: verify
7
8
 
8
9
  prerequisites:
9
10
  required:
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-automation-setup
5
5
  description: Prepare opt-in host automation setup
6
6
  tier: 0
7
+ family: configure
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-automation-status
5
5
  description: Show host automation provider support
6
6
  tier: 0
7
+ family: configure
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-budget
5
5
  description:
6
6
  tier: 0
7
+ family: configure
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -15,6 +16,11 @@ execution:
15
16
 
16
17
  success-path:
17
18
  next-recommended: varies
19
+ outcome:
20
+ type: contextual
21
+ label: Context-specific next route
22
+ reason: The next route depends on current disk state, command arguments, or user choice.
23
+ allowed-next: [/god-status, /god-next, /god-help]
18
24
 
19
25
  failure-path:
20
26
  on-error: /god-doctor
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-build-agent
5
5
  description: Generate custom specialist agent
6
6
  tier: 0
7
+ family: extend
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-build
5
5
  description: Build slices with TDD enforcement and two-stage review
6
6
  tier: 2
7
+ family: build
7
8
 
8
9
  prerequisites:
9
10
  required:
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-cache-clear
5
5
  description:
6
6
  tier: 0
7
+ family: configure
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -15,6 +16,11 @@ execution:
15
16
 
16
17
  success-path:
17
18
  next-recommended: varies
19
+ outcome:
20
+ type: contextual
21
+ label: Context-specific next route
22
+ reason: The next route depends on current disk state, command arguments, or user choice.
23
+ allowed-next: [/god-status, /god-next, /god-help]
18
24
 
19
25
  failure-path:
20
26
  on-error: /god-doctor
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-check-todos
5
5
  description: List pending todos; optionally route to one
6
6
  tier: 0
7
+ family: capture
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -15,6 +16,11 @@ execution:
15
16
 
16
17
  success-path:
17
18
  next-recommended: varies
19
+ outcome:
20
+ type: contextual
21
+ label: Context-specific next route
22
+ reason: The next route depends on current disk state, command arguments, or user choice.
23
+ allowed-next: [/god-status, /god-next, /god-help]
18
24
 
19
25
  failure-path:
20
26
  on-error: /god-doctor
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-context-scan
5
5
  description:
6
6
  tier: 0
7
+ family: maintain
7
8
 
8
9
  prerequisites:
9
10
  required: []
@@ -15,6 +16,11 @@ execution:
15
16
 
16
17
  success-path:
17
18
  next-recommended: varies
19
+ outcome:
20
+ type: contextual
21
+ label: Context-specific next route
22
+ reason: The next route depends on current disk state, command arguments, or user choice.
23
+ allowed-next: [/god-status, /god-next, /god-help]
18
24
 
19
25
  failure-path:
20
26
  on-error: /god-doctor
@@ -4,6 +4,7 @@ metadata:
4
4
  command: /god-context
5
5
  description: Manage Godpowers fence in AGENTS.md / CLAUDE.md / GEMINI.md / others
6
6
  tier: 0
7
+ family: maintain
7
8
 
8
9
  prerequisites:
9
10
  required: