godpowers 2.3.1 → 2.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +56 -12
  3. package/RELEASE.md +24 -39
  4. package/SKILL.md +26 -3
  5. package/bin/install.js +6 -0
  6. package/lib/README.md +3 -1
  7. package/lib/adoption-metrics.js +87 -0
  8. package/lib/command-families.js +375 -0
  9. package/lib/feature-awareness.js +1 -1
  10. package/lib/quick-proof.js +10 -1
  11. package/lib/release-surface-sync.js +4 -1
  12. package/lib/route-quality-sync.js +41 -13
  13. package/lib/router.js +32 -0
  14. package/lib/workflow-helper-groups.js +50 -0
  15. package/lib/workflow-runner.js +6 -1
  16. package/package.json +1 -1
  17. package/routing/god-add-backlog.yaml +1 -0
  18. package/routing/god-add-tests.yaml +1 -0
  19. package/routing/god-add-todo.yaml +1 -0
  20. package/routing/god-agent-audit.yaml +6 -0
  21. package/routing/god-arch.yaml +1 -0
  22. package/routing/god-archaeology.yaml +1 -0
  23. package/routing/god-audit.yaml +1 -0
  24. package/routing/god-automation-setup.yaml +1 -0
  25. package/routing/god-automation-status.yaml +1 -0
  26. package/routing/god-budget.yaml +6 -0
  27. package/routing/god-build-agent.yaml +1 -0
  28. package/routing/god-build.yaml +1 -0
  29. package/routing/god-cache-clear.yaml +6 -0
  30. package/routing/god-check-todos.yaml +6 -0
  31. package/routing/god-context-scan.yaml +6 -0
  32. package/routing/god-context.yaml +1 -0
  33. package/routing/god-cost.yaml +6 -0
  34. package/routing/god-debug.yaml +1 -0
  35. package/routing/god-deploy.yaml +1 -0
  36. package/routing/god-design-impact.yaml +6 -0
  37. package/routing/god-design.yaml +1 -0
  38. package/routing/god-discuss.yaml +12 -0
  39. package/routing/god-docs.yaml +1 -0
  40. package/routing/god-doctor.yaml +6 -0
  41. package/routing/god-dogfood.yaml +1 -0
  42. package/routing/god-explore.yaml +1 -0
  43. package/routing/god-export-otel.yaml +1 -0
  44. package/routing/god-extension-add.yaml +6 -0
  45. package/routing/god-extension-info.yaml +6 -0
  46. package/routing/god-extension-list.yaml +6 -0
  47. package/routing/god-extension-remove.yaml +6 -0
  48. package/routing/god-extension-scaffold.yaml +1 -0
  49. package/routing/god-extract-learnings.yaml +1 -0
  50. package/routing/god-fast.yaml +1 -0
  51. package/routing/god-feature.yaml +1 -0
  52. package/routing/god-graph.yaml +6 -0
  53. package/routing/god-harden.yaml +1 -0
  54. package/routing/god-help.yaml +6 -0
  55. package/routing/god-hotfix.yaml +1 -0
  56. package/routing/god-hygiene.yaml +1 -0
  57. package/routing/god-init.yaml +1 -0
  58. package/routing/god-intel.yaml +1 -0
  59. package/routing/god-launch.yaml +6 -0
  60. package/routing/god-lifecycle.yaml +12 -0
  61. package/routing/god-link.yaml +1 -0
  62. package/routing/god-lint.yaml +1 -0
  63. package/routing/god-list-assumptions.yaml +6 -0
  64. package/routing/god-locate.yaml +6 -0
  65. package/routing/god-logs.yaml +12 -0
  66. package/routing/god-map-codebase.yaml +1 -0
  67. package/routing/god-metrics.yaml +6 -0
  68. package/routing/god-migrate.yaml +1 -0
  69. package/routing/god-mode.yaml +6 -0
  70. package/routing/god-next.yaml +12 -0
  71. package/routing/god-note.yaml +1 -0
  72. package/routing/god-observe.yaml +1 -0
  73. package/routing/god-org-context.yaml +1 -0
  74. package/routing/god-party.yaml +1 -0
  75. package/routing/god-pause-work.yaml +6 -0
  76. package/routing/god-plant-seed.yaml +1 -0
  77. package/routing/god-postmortem.yaml +1 -0
  78. package/routing/god-pr-branch.yaml +1 -0
  79. package/routing/god-prd.yaml +1 -0
  80. package/routing/god-preflight.yaml +1 -0
  81. package/routing/god-progress.yaml +7 -0
  82. package/routing/god-quick.yaml +1 -0
  83. package/routing/god-reconcile.yaml +6 -0
  84. package/routing/god-reconstruct.yaml +1 -0
  85. package/routing/god-redo.yaml +6 -0
  86. package/routing/god-refactor.yaml +1 -0
  87. package/routing/god-repair.yaml +1 -0
  88. package/routing/god-repo.yaml +1 -0
  89. package/routing/god-restore.yaml +1 -0
  90. package/routing/god-resume-work.yaml +6 -0
  91. package/routing/god-review-changes.yaml +1 -0
  92. package/routing/god-review.yaml +1 -0
  93. package/routing/god-roadmap-check.yaml +6 -0
  94. package/routing/god-roadmap-update.yaml +1 -0
  95. package/routing/god-roadmap.yaml +1 -0
  96. package/routing/god-rollback.yaml +1 -0
  97. package/routing/god-scan.yaml +1 -0
  98. package/routing/god-set-profile.yaml +1 -0
  99. package/routing/god-settings.yaml +1 -0
  100. package/routing/god-skip.yaml +1 -0
  101. package/routing/god-smite.yaml +1 -0
  102. package/routing/god-spike.yaml +1 -0
  103. package/routing/god-sprint.yaml +6 -0
  104. package/routing/god-stack.yaml +1 -0
  105. package/routing/god-standards.yaml +1 -0
  106. package/routing/god-status.yaml +1 -0
  107. package/routing/god-stories.yaml +1 -0
  108. package/routing/god-story-build.yaml +1 -0
  109. package/routing/god-story-close.yaml +1 -0
  110. package/routing/god-story-verify.yaml +1 -0
  111. package/routing/god-story.yaml +1 -0
  112. package/routing/god-suite-init.yaml +1 -0
  113. package/routing/god-suite-patch.yaml +1 -0
  114. package/routing/god-suite-release.yaml +1 -0
  115. package/routing/god-suite-status.yaml +6 -0
  116. package/routing/god-suite-sync.yaml +1 -0
  117. package/routing/god-sync.yaml +1 -0
  118. package/routing/god-tech-debt.yaml +1 -0
  119. package/routing/god-test-extension.yaml +6 -0
  120. package/routing/god-test-runtime.yaml +1 -0
  121. package/routing/god-thread.yaml +6 -0
  122. package/routing/god-trace.yaml +6 -0
  123. package/routing/god-undo.yaml +1 -0
  124. package/routing/god-update-deps.yaml +1 -0
  125. package/routing/god-upgrade.yaml +1 -0
  126. package/routing/god-version.yaml +1 -0
  127. package/routing/god-workstream.yaml +6 -0
  128. package/routing/god.yaml +6 -0
  129. package/schema/routing.v1.json +62 -4
  130. package/schema/workflow.v1.json +14 -0
  131. package/skills/god-doctor.md +1 -1
  132. package/skills/god-help.md +38 -3
  133. package/skills/god-next.md +19 -2
  134. package/skills/god-status.md +13 -0
  135. package/skills/god-sync.md +1 -1
  136. package/skills/god.md +53 -1
  137. package/workflows/audit-only.yaml +2 -2
  138. package/workflows/bluefield-arc.yaml +3 -7
  139. package/workflows/brownfield-arc.yaml +4 -8
  140. package/workflows/deps-audit.yaml +2 -5
  141. package/workflows/docs-arc.yaml +2 -2
  142. package/workflows/feature-arc.yaml +3 -6
  143. package/workflows/full-arc.yaml +5 -11
  144. package/workflows/hotfix-arc.yaml +3 -6
  145. package/workflows/hygiene.yaml +2 -2
  146. package/workflows/migration-arc.yaml +3 -5
  147. package/workflows/postmortem.yaml +2 -5
  148. package/workflows/refactor-arc.yaml +3 -6
@@ -0,0 +1,375 @@
1
+ /**
2
+ * Command family metadata.
3
+ *
4
+ * Keeps the user-facing command catalog small without removing leaf commands.
5
+ * These groupings are used by help, routing, docs, and UX audits.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const COMMAND_FAMILIES = [
12
+ {
13
+ id: 'start',
14
+ label: 'Start',
15
+ purpose: 'Start or import a project.',
16
+ commands: [
17
+ '/god',
18
+ '/god-init',
19
+ '/god-mode',
20
+ '/god-explore',
21
+ '/god-discuss',
22
+ '/god-list-assumptions',
23
+ '/god-prd',
24
+ '/god-design',
25
+ '/god-design-impact',
26
+ '/god-arch',
27
+ '/god-roadmap',
28
+ '/god-stack',
29
+ '/god-repo',
30
+ '/god-preflight',
31
+ '/god-map-codebase',
32
+ '/god-archaeology',
33
+ '/god-org-context',
34
+ '/god-migrate'
35
+ ]
36
+ },
37
+ {
38
+ id: 'continue',
39
+ label: 'Continue',
40
+ purpose: 'Understand state and choose the next move.',
41
+ commands: [
42
+ '/god-status',
43
+ '/god-next',
44
+ '/god-progress',
45
+ '/god-lifecycle',
46
+ '/god-locate',
47
+ '/god-resume-work',
48
+ '/god-pause-work'
49
+ ]
50
+ },
51
+ {
52
+ id: 'build',
53
+ label: 'Build',
54
+ purpose: 'Plan, implement, test, and ship product work.',
55
+ commands: [
56
+ '/god-build',
57
+ '/god-feature',
58
+ '/god-story',
59
+ '/god-stories',
60
+ '/god-story-build',
61
+ '/god-story-verify',
62
+ '/god-story-close',
63
+ '/god-fast',
64
+ '/god-quick',
65
+ '/god-debug',
66
+ '/god-add-tests',
67
+ '/god-refactor',
68
+ '/god-spike'
69
+ ]
70
+ },
71
+ {
72
+ id: 'verify',
73
+ label: 'Verify',
74
+ purpose: 'Check artifacts, code, runtime behavior, and release readiness.',
75
+ commands: [
76
+ '/god-lint',
77
+ '/god-standards',
78
+ '/god-review',
79
+ '/god-review-changes',
80
+ '/god-test-runtime',
81
+ '/god-audit',
82
+ '/god-agent-audit',
83
+ '/god-hygiene',
84
+ '/god-dogfood',
85
+ '/god-preflight'
86
+ ]
87
+ },
88
+ {
89
+ id: 'operate',
90
+ label: 'Operate',
91
+ purpose: 'Deploy, observe, harden, launch, and respond in production.',
92
+ commands: [
93
+ '/god-deploy',
94
+ '/god-observe',
95
+ '/god-harden',
96
+ '/god-launch',
97
+ '/god-hotfix',
98
+ '/god-postmortem',
99
+ '/god-logs',
100
+ '/god-metrics',
101
+ '/god-trace',
102
+ '/god-export-otel'
103
+ ]
104
+ },
105
+ {
106
+ id: 'maintain',
107
+ label: 'Maintain',
108
+ purpose: 'Keep artifacts, docs, dependencies, context, and repo surfaces current.',
109
+ commands: [
110
+ '/god-docs',
111
+ '/god-sync',
112
+ '/god-scan',
113
+ '/god-link',
114
+ '/god-reconcile',
115
+ '/god-reconstruct',
116
+ '/god-intel',
117
+ '/god-tech-debt',
118
+ '/god-update-deps',
119
+ '/god-upgrade',
120
+ '/god-context',
121
+ '/god-context-scan',
122
+ '/god-roadmap-check',
123
+ '/god-roadmap-update'
124
+ ]
125
+ },
126
+ {
127
+ id: 'capture',
128
+ label: 'Capture',
129
+ purpose: 'Save thoughts, tasks, backlog items, seeds, and learnings.',
130
+ commands: [
131
+ '/god-note',
132
+ '/god-add-todo',
133
+ '/god-check-todos',
134
+ '/god-add-backlog',
135
+ '/god-plant-seed',
136
+ '/god-extract-learnings',
137
+ '/god-thread',
138
+ '/god-graph'
139
+ ]
140
+ },
141
+ {
142
+ id: 'recover',
143
+ label: 'Recover',
144
+ purpose: 'Undo, repair, restore, skip, or diagnose broken state.',
145
+ commands: [
146
+ '/god-undo',
147
+ '/god-redo',
148
+ '/god-rollback',
149
+ '/god-restore',
150
+ '/god-repair',
151
+ '/god-skip',
152
+ '/god-smite',
153
+ '/god-doctor'
154
+ ]
155
+ },
156
+ {
157
+ id: 'extend',
158
+ label: 'Extend',
159
+ purpose: 'Install, inspect, test, remove, or author extension packs.',
160
+ commands: [
161
+ '/god-extension-scaffold',
162
+ '/god-extension-add',
163
+ '/god-extension-list',
164
+ '/god-extension-info',
165
+ '/god-extension-remove',
166
+ '/god-test-extension',
167
+ '/god-build-agent'
168
+ ]
169
+ },
170
+ {
171
+ id: 'collaborate',
172
+ label: 'Collaborate',
173
+ purpose: 'Coordinate people, workstreams, suites, sprints, and pull requests.',
174
+ commands: [
175
+ '/god-workstream',
176
+ '/god-suite-init',
177
+ '/god-suite-status',
178
+ '/god-suite-sync',
179
+ '/god-suite-patch',
180
+ '/god-suite-release',
181
+ '/god-party',
182
+ '/god-sprint',
183
+ '/god-pr-branch'
184
+ ]
185
+ },
186
+ {
187
+ id: 'configure',
188
+ label: 'Configure',
189
+ purpose: 'Tune settings, budgets, cache, profiles, help, and version info.',
190
+ commands: [
191
+ '/god-settings',
192
+ '/god-set-profile',
193
+ '/god-budget',
194
+ '/god-cost',
195
+ '/god-cache-clear',
196
+ '/god-automation-status',
197
+ '/god-automation-setup',
198
+ '/god-help',
199
+ '/god-version'
200
+ ]
201
+ }
202
+ ];
203
+
204
+ const STATUS_VIEWS = [
205
+ { id: 'overview', command: '/god-status', label: 'Overview', purpose: 'Operational state, proactive checks, and blockers.' },
206
+ { id: 'progress', command: '/god-progress', label: 'Progress', purpose: 'Requirement and roadmap increment completion.' },
207
+ { id: 'lifecycle', command: '/god-lifecycle', label: 'Lifecycle', purpose: 'Project phase and fitting workflows.' },
208
+ { id: 'locate', command: '/god-locate', label: 'Locate', purpose: 'Resume orientation from checkpoint and disk state.' },
209
+ { id: 'next', command: '/god-next', label: 'Next', purpose: 'Single recommended command with reason.' }
210
+ ];
211
+
212
+ const CAPTURE_LADDER = [
213
+ { id: 'note', command: '/god-note', signal: 'save only', purpose: 'Save a thought without priority or workflow impact.' },
214
+ { id: 'todo', command: '/god-add-todo', signal: 'actionable soon', purpose: 'Create a prioritized action item.' },
215
+ { id: 'backlog', command: '/god-add-backlog', signal: 'optional later', purpose: 'Park an idea for future roadmap review.' },
216
+ { id: 'seed', command: '/god-plant-seed', signal: 'conditional future trigger', purpose: 'Store an idea until a metric, date, or event happens.' }
217
+ ];
218
+
219
+ const WORK_SIZE_LADDER = [
220
+ { id: 'fast', command: '/god-fast', signal: 'trivial direct edit', purpose: 'One tiny edit with existing verification.' },
221
+ { id: 'quick', command: '/god-quick', signal: 'small TDD task', purpose: 'Small task with TDD and review but no full planning tier.' },
222
+ { id: 'story', command: '/god-story', signal: 'fine-grained planned slice', purpose: 'Create a STORY.md before implementation.' },
223
+ { id: 'feature', command: '/god-feature', signal: 'existing-product feature', purpose: 'Feature workflow with mini-PRD, build, harden, and sync.' },
224
+ { id: 'build', command: '/god-build', signal: 'current milestone work', purpose: 'Build the planned roadmap increment.' },
225
+ { id: 'debug', command: '/god-debug', signal: 'non-urgent bug', purpose: 'Run the systematic debug loop.' },
226
+ { id: 'hotfix', command: '/god-hotfix', signal: 'production outage', purpose: 'Expedited production fix and postmortem trigger.' }
227
+ ];
228
+
229
+ const VERIFY_LADDER = [
230
+ { id: 'lint', command: '/god-lint', signal: 'mechanical artifact check', purpose: 'Fast file-level artifact validation.' },
231
+ { id: 'standards', command: '/god-standards', signal: 'artifact quality gate', purpose: 'Substitution, labels, and have-nots for one artifact.' },
232
+ { id: 'review', command: '/god-review', signal: 'code diff review', purpose: 'Two-stage spec and quality review.' },
233
+ { id: 'runtime', command: '/god-test-runtime', signal: 'live behavior check', purpose: 'Browser-backed design and acceptance verification.' },
234
+ { id: 'audit', command: '/god-audit', signal: 'artifact set score', purpose: 'Score existing Godpowers artifacts.' },
235
+ { id: 'hygiene', command: '/god-hygiene', signal: 'ongoing project health', purpose: 'Composite audit, dependency, and docs check.' },
236
+ { id: 'preflight', command: '/god-preflight', signal: 'existing repo intake', purpose: 'Read-only readiness check before stronger workflows.' },
237
+ { id: 'dogfood', command: '/god-dogfood', signal: 'release fixture readiness', purpose: 'Messy-repo scenarios for release confidence.' }
238
+ ];
239
+
240
+ const TRIGGER_PRECEDENCE = {
241
+ continue: {
242
+ default: '/god-next',
243
+ conditional: [
244
+ { command: '/god-resume-work', when: 'handoff-exists', reason: 'A handoff exists on disk.' }
245
+ ],
246
+ reason: 'Continue means resume a handoff when present, otherwise compute the next route.'
247
+ },
248
+ 'think through': {
249
+ default: '/god-discuss',
250
+ conditional: [
251
+ { command: '/god-explore', when: 'broad-idea', reason: 'The request is broad ideation rather than a concrete decision.' }
252
+ ],
253
+ reason: 'Discussion handles concrete decisions while exploration handles broad ideation.'
254
+ },
255
+ 'what happened': {
256
+ default: '/god-logs',
257
+ conditional: [
258
+ { command: '/god-postmortem', when: 'post-incident-pending', reason: 'The project is waiting on incident follow-up.' }
259
+ ],
260
+ reason: 'Logs answer run history unless an incident loop is open.'
261
+ },
262
+ "what's done": {
263
+ default: '/god-progress',
264
+ conditional: [
265
+ { command: '/god-status', when: 'operational-status-request', reason: 'The wording asks for operational state, not deliverables.' }
266
+ ],
267
+ reason: 'Progress answers deliverables while status answers operational state.'
268
+ },
269
+ 'where am i': {
270
+ default: '/god-lifecycle',
271
+ conditional: [
272
+ { command: '/god-locate', when: 'checkpoint-or-handoff-exists', reason: 'Resume artifacts exist on disk.' }
273
+ ],
274
+ reason: 'Lifecycle explains the phase while locate orients a resumed session.'
275
+ }
276
+ };
277
+
278
+ function familyForCommand(command) {
279
+ return COMMAND_FAMILIES.find((family) => family.commands.includes(command)) || null;
280
+ }
281
+
282
+ function renderFamilyCards(families = COMMAND_FAMILIES) {
283
+ return families.map((family) => (
284
+ `${family.label}: ${family.purpose} (${family.commands.join(', ')})`
285
+ ));
286
+ }
287
+
288
+ function renderLadder(ladder) {
289
+ return ladder.map((step) => `${step.command}: ${step.signal} - ${step.purpose}`);
290
+ }
291
+
292
+ function detectCondition(condition, projectRoot, text = '') {
293
+ if (!condition) return false;
294
+ const root = projectRoot || process.cwd();
295
+ if (condition === 'handoff-exists') {
296
+ return fs.existsSync(path.join(root, '.godpowers', 'HANDOFF.md'));
297
+ }
298
+ if (condition === 'checkpoint-or-handoff-exists') {
299
+ return fs.existsSync(path.join(root, '.godpowers', 'CHECKPOINT.md'))
300
+ || fs.existsSync(path.join(root, '.godpowers', 'HANDOFF.md'));
301
+ }
302
+ if (condition === 'post-incident-pending') {
303
+ try {
304
+ const statePath = path.join(root, '.godpowers', 'state.json');
305
+ if (!fs.existsSync(statePath)) return false;
306
+ const parsed = JSON.parse(fs.readFileSync(statePath, 'utf8'));
307
+ return parsed['lifecycle-phase'] === 'post-incident-pending';
308
+ } catch (e) {
309
+ return false;
310
+ }
311
+ }
312
+ if (condition === 'broad-idea') {
313
+ return /\b(idea|brainstorm|explore|what if|possibilities|options)\b/i.test(text || '');
314
+ }
315
+ if (condition === 'operational-status-request') {
316
+ return /\b(status|state|blocked|sync|health|where)\b/i.test(text || '');
317
+ }
318
+ return false;
319
+ }
320
+
321
+ function resolveTrigger(trigger, opts = {}) {
322
+ const key = String(trigger || '').trim().toLowerCase();
323
+ const rule = TRIGGER_PRECEDENCE[key];
324
+ if (!rule) return null;
325
+ for (const branch of rule.conditional || []) {
326
+ if (detectCondition(branch.when, opts.projectRoot, opts.text)) {
327
+ return { trigger: key, command: branch.command, reason: branch.reason, rule };
328
+ }
329
+ }
330
+ return { trigger: key, command: rule.default, reason: rule.reason, rule };
331
+ }
332
+
333
+ function classifyCapture(text = '') {
334
+ if (/\b(when|if|after|in \d+|once)\b/i.test(text)) return CAPTURE_LADDER.find((item) => item.id === 'seed');
335
+ if (/\b(todo|task|remind|priority|p[0-3])\b/i.test(text)) return CAPTURE_LADDER.find((item) => item.id === 'todo');
336
+ if (/\b(backlog|later|someday|future)\b/i.test(text)) return CAPTURE_LADDER.find((item) => item.id === 'backlog');
337
+ return CAPTURE_LADDER.find((item) => item.id === 'note');
338
+ }
339
+
340
+ function classifyWorkSize(text = '') {
341
+ if (/\b(production|outage|down|urgent|hotfix)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'hotfix');
342
+ if (/\b(bug|debug|failing|error|regression)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'debug');
343
+ if (/\b(story|acceptance criteria)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'story');
344
+ if (/\b(feature|new capability|enhancement)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'feature');
345
+ if (/\b(milestone|roadmap|increment)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'build');
346
+ if (/\b(tiny|typo|one-line|config tweak|trivial)\b/i.test(text)) return WORK_SIZE_LADDER.find((item) => item.id === 'fast');
347
+ return WORK_SIZE_LADDER.find((item) => item.id === 'quick');
348
+ }
349
+
350
+ function classifyVerification(text = '') {
351
+ if (/\b(dogfood|release readiness|fixture)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'dogfood');
352
+ if (/\b(preflight|intake|existing repo)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'preflight');
353
+ if (/\b(hygiene|health|weekly|monthly)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'hygiene');
354
+ if (/\b(audit|score artifacts)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'audit');
355
+ if (/\b(runtime|browser|e2e|flow|render|design audit)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'runtime');
356
+ if (/\b(review|diff|code review)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'review');
357
+ if (/\b(standard|substitution|have-nots)\b/i.test(text)) return VERIFY_LADDER.find((item) => item.id === 'standards');
358
+ return VERIFY_LADDER.find((item) => item.id === 'lint');
359
+ }
360
+
361
+ module.exports = {
362
+ COMMAND_FAMILIES,
363
+ STATUS_VIEWS,
364
+ CAPTURE_LADDER,
365
+ WORK_SIZE_LADDER,
366
+ VERIFY_LADDER,
367
+ TRIGGER_PRECEDENCE,
368
+ familyForCommand,
369
+ renderFamilyCards,
370
+ renderLadder,
371
+ resolveTrigger,
372
+ classifyCapture,
373
+ classifyWorkSize,
374
+ classifyVerification
375
+ };
@@ -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',
@@ -10,6 +10,7 @@ const path = require('path');
10
10
 
11
11
  const dashboard = require('./dashboard');
12
12
  const hostCapabilities = require('./host-capabilities');
13
+ const adoptionMetrics = require('./adoption-metrics');
13
14
 
14
15
  const FIXTURE_ROOT = path.join(__dirname, '..', 'fixtures', 'quick-proof', 'project');
15
16
  const MANIFEST_PATH = path.join(__dirname, '..', 'fixtures', 'quick-proof', 'manifest.json');
@@ -85,6 +86,8 @@ function compute(projectRoot = process.cwd(), opts = {}) {
85
86
  ]
86
87
  };
87
88
 
89
+ proof.metrics = adoptionMetrics.fromQuickProof(proof);
90
+
88
91
  return proof;
89
92
  }
90
93
 
@@ -111,7 +114,10 @@ function render(proof, opts = {}) {
111
114
  ` State on disk: ${proof.statePath}`,
112
115
  ` Fixture: ${proof.fixturePath}`,
113
116
  ` PRD: ${planning.prd ? planning.prd.status : 'unknown'}`,
114
- ` Roadmap: ${planning.roadmap ? planning.roadmap.status : 'unknown'}`
117
+ ` Roadmap: ${planning.roadmap ? planning.roadmap.status : 'unknown'}`,
118
+ '',
119
+ 'Outcome metrics:',
120
+ adoptionMetrics.render(proof.metrics)
115
121
  ].join('\n');
116
122
  }
117
123
 
@@ -138,6 +144,9 @@ function render(proof, opts = {}) {
138
144
  'Evidence:',
139
145
  ...proof.evidence.map((item, index) => ` ${index + 1}. ${item.label}: ${item.value}`),
140
146
  '',
147
+ 'Outcome metrics:',
148
+ adoptionMetrics.render(proof.metrics),
149
+ '',
141
150
  'Try it on the fixture:',
142
151
  ` npx godpowers status --project=${proof.fixtureRoot} --brief`,
143
152
  ` npx godpowers next --project=${proof.fixtureRoot} --brief`,
@@ -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,23 +36,30 @@ 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',
27
43
  '/god-extension-info',
28
44
  '/god-extension-list',
29
45
  '/god-extension-remove',
30
- '/god-extension-scaffold',
31
46
  '/god-graph',
32
47
  '/god-help',
33
48
  '/god-lifecycle',
34
49
  '/god-list-assumptions',
35
50
  '/god-locate',
36
51
  '/god-logs',
52
+ '/god-launch',
37
53
  '/god-metrics',
54
+ '/god-mode',
38
55
  '/god-next',
56
+ '/god-pause-work',
39
57
  '/god-redo',
58
+ '/god-reconcile',
40
59
  '/god-resume-work',
60
+ '/god-roadmap-check',
61
+ '/god-sprint',
62
+ '/god-suite-status',
41
63
  '/god-test-extension',
42
64
  '/god-thread',
43
65
  '/god-trace',
@@ -141,7 +163,7 @@ function detect(projectRoot) {
141
163
  .map((file) => path.basename(file, '.md')));
142
164
  let symbolicCount = 0;
143
165
  let unresolvedCount = 0;
144
- let contextualExitCount = 0;
166
+ let typedOutcomeCount = 0;
145
167
  let standardsExemptCount = 0;
146
168
  let traceEventMissingCount = 0;
147
169
 
@@ -194,18 +216,22 @@ function detect(projectRoot) {
194
216
  );
195
217
  }
196
218
 
197
- const next = route['success-path'] && route['success-path']['next-recommended'];
219
+ const successPath = route['success-path'] || {};
220
+ const next = successPath['next-recommended'];
198
221
  const conditionalNext = route['success-path'] && arr(route['success-path']['conditional-next']);
199
- if (next === 'varies' && conditionalNext.length === 0) {
200
- if (CONTEXTUAL_NEXT_ALLOWED.has(command)) {
201
- 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++;
202
228
  } else {
203
229
  addCheck(
204
230
  checks,
205
- `unapproved-varies-${command.replace(/[^a-z0-9]+/gi, '-')}`,
231
+ `missing-route-outcome-${command.replace(/[^a-z0-9]+/gi, '-')}`,
206
232
  'stale',
207
233
  routePath,
208
- `${command} uses next-recommended: varies without an approved contextual-exit classification.`,
234
+ `${command} uses contextual next route ${next} without a typed success-path.outcome.`,
209
235
  { spawn: 'god-roadmap-reconciler' }
210
236
  );
211
237
  }
@@ -238,10 +264,10 @@ function detect(projectRoot) {
238
264
  addCheck(
239
265
  checks,
240
266
  'contextual-exit-policy',
241
- checks.some((check) => check.id.startsWith('unapproved-varies-')) ? 'stale' : 'fresh',
267
+ checks.some((check) => check.id.startsWith('missing-route-outcome-')) ? 'stale' : 'fresh',
242
268
  'routing/',
243
- `${contextualExitCount} contextual route exits are approved and all other next routes are explicit.`,
244
- { 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 }
245
271
  );
246
272
  addCheck(
247
273
  checks,
@@ -309,6 +335,8 @@ function summary(report) {
309
335
  module.exports = {
310
336
  LOG_PATH,
311
337
  CONTEXTUAL_NEXT_ALLOWED,
338
+ CONTEXTUAL_NEXT_VALUES,
339
+ OUTCOME_TYPES,
312
340
  STANDARDS_EXEMPT_COMMANDS,
313
341
  detect,
314
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
+ };