@warpgogol/forge 2.9.2 → 2.9.5

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 (181) hide show
  1. package/README.md +14 -8
  2. package/README.uk.md +14 -0
  3. package/dist/bin/cli.js +0 -0
  4. package/dist/os/adr/handlers/implement-stamp.d.ts.map +1 -1
  5. package/dist/os/adr/handlers/implement-stamp.js +7 -1
  6. package/dist/os/adr/handlers/implement-stamp.js.map +1 -1
  7. package/dist/os/adr/handlers/list-create.d.ts.map +1 -1
  8. package/dist/os/adr/handlers/list-create.js +40 -4
  9. package/dist/os/adr/handlers/list-create.js.map +1 -1
  10. package/dist/os/adr/handlers/validate.d.ts.map +1 -1
  11. package/dist/os/adr/handlers/validate.js +17 -3
  12. package/dist/os/adr/handlers/validate.js.map +1 -1
  13. package/dist/os/adr/types.d.ts +1 -0
  14. package/dist/os/adr/types.d.ts.map +1 -1
  15. package/dist/os/adr/types.js +1 -0
  16. package/dist/os/adr/types.js.map +1 -1
  17. package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +1 -1
  18. package/dist/os/compass/handlers/compass-audit-handler.js +22 -0
  19. package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
  20. package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
  21. package/dist/os/compass/handlers/compass-change-summary-handler.js +6 -0
  22. package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
  23. package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
  24. package/dist/os/compass/handlers/compass-inventory-handler.js +19 -0
  25. package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
  26. package/dist/os/core/handlers/package-health.d.ts.map +1 -1
  27. package/dist/os/core/handlers/package-health.js +8 -4
  28. package/dist/os/core/handlers/package-health.js.map +1 -1
  29. package/dist/os/core/handlers/pinned-validate.d.ts.map +1 -1
  30. package/dist/os/core/handlers/pinned-validate.js +2 -2
  31. package/dist/os/core/handlers/pinned-validate.js.map +1 -1
  32. package/dist/os/exploration/handlers/archive.d.ts.map +1 -1
  33. package/dist/os/exploration/handlers/archive.js +6 -0
  34. package/dist/os/exploration/handlers/archive.js.map +1 -1
  35. package/dist/os/exploration/handlers/list.d.ts.map +1 -1
  36. package/dist/os/exploration/handlers/list.js +8 -0
  37. package/dist/os/exploration/handlers/list.js.map +1 -1
  38. package/dist/os/exploration/handlers/show.d.ts.map +1 -1
  39. package/dist/os/exploration/handlers/show.js +6 -0
  40. package/dist/os/exploration/handlers/show.js.map +1 -1
  41. package/dist/os/program/handlers/complete.d.ts.map +1 -1
  42. package/dist/os/program/handlers/complete.js +19 -1
  43. package/dist/os/program/handlers/complete.js.map +1 -1
  44. package/dist/os/program/handlers/lease.js +7 -1
  45. package/dist/os/program/handlers/lease.js.map +1 -1
  46. package/dist/os/program/handlers/seal.d.ts.map +1 -1
  47. package/dist/os/program/handlers/seal.js +13 -1
  48. package/dist/os/program/handlers/seal.js.map +1 -1
  49. package/dist/os/program/handlers/validate.js +8 -2
  50. package/dist/os/program/handlers/validate.js.map +1 -1
  51. package/dist/os/rfc/acceptance.d.ts.map +1 -1
  52. package/dist/os/rfc/acceptance.js +8 -0
  53. package/dist/os/rfc/acceptance.js.map +1 -1
  54. package/dist/os/rfc/dna-trace.js +1 -1
  55. package/dist/os/rfc/dna-trace.js.map +1 -1
  56. package/dist/os/rfc/handlers/check.d.ts.map +1 -1
  57. package/dist/os/rfc/handlers/check.js +10 -2
  58. package/dist/os/rfc/handlers/check.js.map +1 -1
  59. package/dist/os/rfc/handlers/implement-stamp.d.ts.map +1 -1
  60. package/dist/os/rfc/handlers/implement-stamp.js +7 -1
  61. package/dist/os/rfc/handlers/implement-stamp.js.map +1 -1
  62. package/dist/os/rfc/handlers/index-graph.js +4 -4
  63. package/dist/os/rfc/handlers/index-graph.js.map +1 -1
  64. package/dist/os/rfc/handlers/lifecycle.js +1 -1
  65. package/dist/os/rfc/handlers/lifecycle.js.map +1 -1
  66. package/dist/os/rfc/handlers/list-create.d.ts.map +1 -1
  67. package/dist/os/rfc/handlers/list-create.js +20 -0
  68. package/dist/os/rfc/handlers/list-create.js.map +1 -1
  69. package/dist/os/rfc/handlers/validate.d.ts.map +1 -1
  70. package/dist/os/rfc/handlers/validate.js +17 -3
  71. package/dist/os/rfc/handlers/validate.js.map +1 -1
  72. package/dist/os/session/handlers/validate.d.ts.map +1 -1
  73. package/dist/os/session/handlers/validate.js +17 -3
  74. package/dist/os/session/handlers/validate.js.map +1 -1
  75. package/dist/os/spec/live-spec-list.d.ts.map +1 -1
  76. package/dist/os/spec/live-spec-list.js +8 -0
  77. package/dist/os/spec/live-spec-list.js.map +1 -1
  78. package/dist/os/spec/live-spec-merge.js +2 -2
  79. package/dist/os/spec/live-spec-merge.js.map +1 -1
  80. package/dist/os/spec/live-spec-show.d.ts.map +1 -1
  81. package/dist/os/spec/live-spec-show.js +6 -0
  82. package/dist/os/spec/live-spec-show.js.map +1 -1
  83. package/dist/os/spec/live-spec-validate.js +2 -2
  84. package/dist/os/spec/live-spec-validate.js.map +1 -1
  85. package/dist/os/spec/spec-materialize.d.ts.map +1 -1
  86. package/dist/os/spec/spec-materialize.js +6 -0
  87. package/dist/os/spec/spec-materialize.js.map +1 -1
  88. package/dist/os/spec/spec-status.d.ts.map +1 -1
  89. package/dist/os/spec/spec-status.js +6 -0
  90. package/dist/os/spec/spec-status.js.map +1 -1
  91. package/dist/os/spec/spec-validate.js +1 -1
  92. package/dist/os/spec/spec-validate.js.map +1 -1
  93. package/dist/os/werkstatt/handlers/werkstatt-lock-recover.d.ts.map +1 -1
  94. package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +8 -0
  95. package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +1 -1
  96. package/dist/os/werkstatt/handlers/werkstatt-lock-status.d.ts.map +1 -1
  97. package/dist/os/werkstatt/handlers/werkstatt-lock-status.js +8 -0
  98. package/dist/os/werkstatt/handlers/werkstatt-lock-status.js.map +1 -1
  99. package/dist/os/workflow/handlers.d.ts.map +1 -1
  100. package/dist/os/workflow/handlers.js +9 -1
  101. package/dist/os/workflow/handlers.js.map +1 -1
  102. package/dist/src/onboarding/create.js +1 -1
  103. package/dist/src/onboarding/create.js.map +1 -1
  104. package/dist/src/onboarding/doctor.js +1 -1
  105. package/dist/src/onboarding/doctor.js.map +1 -1
  106. package/dist/src/onboarding/init.d.ts.map +1 -1
  107. package/dist/src/onboarding/init.js +31 -1
  108. package/dist/src/onboarding/init.js.map +1 -1
  109. package/dist/src/onboarding/profile-validate.js +1 -1
  110. package/dist/src/onboarding/profile-validate.js.map +1 -1
  111. package/dist/src/utils/fs-trash.d.ts.map +1 -1
  112. package/dist/src/utils/fs-trash.js +1 -1
  113. package/dist/src/utils/fs-trash.js.map +1 -1
  114. package/dist/src/validators/note-frontmatter-validate.js +1 -1
  115. package/dist/src/validators/note-frontmatter-validate.js.map +1 -1
  116. package/dist/src/validators/note-link-validate.js +1 -1
  117. package/dist/src/validators/note-link-validate.js.map +1 -1
  118. package/os/adr/adr-0000-template.md +46 -0
  119. package/os/adr/handlers/implement-stamp.ts +7 -1
  120. package/os/adr/handlers/list-create.ts +48 -4
  121. package/os/adr/handlers/validate.ts +15 -3
  122. package/os/adr/types.ts +1 -0
  123. package/os/compass/handlers/compass-audit-handler.ts +24 -0
  124. package/os/compass/handlers/compass-change-summary-handler.ts +6 -0
  125. package/os/compass/handlers/compass-inventory-handler.ts +19 -0
  126. package/os/core/handlers/package-health.ts +9 -5
  127. package/os/core/handlers/pinned-validate.ts +4 -2
  128. package/os/exploration/handlers/archive.ts +6 -0
  129. package/os/exploration/handlers/list.ts +9 -0
  130. package/os/exploration/handlers/show.ts +6 -0
  131. package/os/program/handlers/complete.ts +19 -1
  132. package/os/program/handlers/lease.ts +7 -1
  133. package/os/program/handlers/seal.ts +13 -1
  134. package/os/program/handlers/validate.ts +8 -2
  135. package/os/rfc/acceptance.ts +9 -0
  136. package/os/rfc/dna-trace.ts +1 -1
  137. package/os/rfc/handlers/check.ts +10 -2
  138. package/os/rfc/handlers/implement-stamp.ts +7 -1
  139. package/os/rfc/handlers/index-graph.ts +4 -4
  140. package/os/rfc/handlers/lifecycle.ts +1 -1
  141. package/os/rfc/handlers/list-create.ts +21 -0
  142. package/os/rfc/handlers/validate.ts +15 -3
  143. package/os/rfc/rfc-0000-template.md +16 -20
  144. package/os/session/handlers/validate.ts +15 -3
  145. package/os/spec/live-spec-list.ts +8 -0
  146. package/os/spec/live-spec-merge.ts +2 -2
  147. package/os/spec/live-spec-show.ts +6 -0
  148. package/os/spec/live-spec-validate.ts +2 -2
  149. package/os/spec/spec-materialize.ts +6 -0
  150. package/os/spec/spec-status.ts +6 -0
  151. package/os/spec/spec-validate.ts +1 -1
  152. package/os/werkstatt/handlers/werkstatt-lock-recover.ts +9 -0
  153. package/os/werkstatt/handlers/werkstatt-lock-status.ts +9 -0
  154. package/os/workflow/handlers.ts +10 -1
  155. package/package.json +73 -195
  156. package/skills/_shared/fo-pipeline-conventions.md +44 -5
  157. package/skills/_shared/fo-prerequisites.md +81 -0
  158. package/skills/fo/fo-extract-dna/SKILL.md +1 -1
  159. package/skills/fo/fo-idea-audit/AUDIT-AXES.md +66 -0
  160. package/skills/fo/fo-idea-audit/SKILL.md +2 -2
  161. package/skills/fo/fo-idea-create-adr/SKILL.md +1 -1
  162. package/skills/fo/fo-idea-create-rfc/SKILL.md +3 -3
  163. package/skills/fo/fo-idea-enhance/SKILL.md +2 -2
  164. package/skills/fo/fo-idea-implement/ADR-FLOW.md +179 -0
  165. package/skills/fo/fo-idea-implement/SKILL.md +1 -1
  166. package/skills/fo/fo-idea-plan/SKILL.md +4 -2
  167. package/skills/fo/fo-review/AXES.md +70 -0
  168. package/skills/fo/fo-session-retro/learned-principles.md +15 -0
  169. package/skills/fo/fo-step-commit/SKILL.md +2 -2
  170. package/skills/shared/windows-ai-tooling/.gitattributes.template +49 -0
  171. package/skills/shared/windows-ai-tooling/AGENTS_WINDOWS.md.template +42 -0
  172. package/skills/shared/writing-great-skills/GLOSSARY.md +201 -0
  173. package/src/onboarding/create.ts +1 -1
  174. package/src/onboarding/doctor.ts +1 -1
  175. package/src/onboarding/init.ts +30 -1
  176. package/src/onboarding/profile-validate.ts +1 -1
  177. package/src/tests/package-files.test.ts +5 -2
  178. package/src/tests/stack-profile.test.ts +4 -0
  179. package/src/utils/fs-trash.ts +1 -1
  180. package/src/validators/note-frontmatter-validate.ts +1 -1
  181. package/src/validators/note-link-validate.ts +1 -1
@@ -142,10 +142,14 @@ export async function runRfcValidate(
142
142
  }
143
143
  const errorCount = violations.filter((v) => v.severity === "error").length;
144
144
  const warnCount = violations.filter((v) => v.severity === "warning").length;
145
+ const parts: string[] = [];
146
+ if (errorCount > 0) parts.push(`${errorCount} error${errorCount === 1 ? "" : "s"}`);
147
+ if (warnCount > 0) parts.push(`${warnCount} warning${warnCount === 1 ? "" : "s"}`);
148
+ const counts = parts.join(", ");
145
149
  if (errorCount > 0) {
146
- logger.error(`${errorCount} error(s), ${warnCount} warning(s)`);
150
+ logger.error(counts);
147
151
  } else {
148
- logger.warn(`${warnCount} warning(s), 0 errors — passed`);
152
+ logger.warn(`${counts} — passed`);
149
153
  }
150
154
  }
151
155
  }
@@ -160,7 +164,15 @@ export async function runRfcValidate(
160
164
  },
161
165
  exitCode: hasErrors ? 1 : 0,
162
166
  summary: hasErrors
163
- ? `${violations.filter((v) => v.severity === "error").length} error(s) found`
167
+ ? `${violations.filter((v) => v.severity === "error").length} error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} found`
164
168
  : `All ${filesToValidate.length} RFC(s) passed validation`,
169
+ nextSteps: hasErrors
170
+ ? [
171
+ {
172
+ action: `Fix the ${violations.filter((v) => v.severity === "error").length} error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run rfc.validate`,
173
+ kind: "required",
174
+ },
175
+ ]
176
+ : undefined,
165
177
  };
166
178
  }
@@ -8,10 +8,9 @@ kind: architecture
8
8
  scope: workspace
9
9
  owners:
10
10
  - architecture
11
- # Set by the deciding human together with the status change (RFC-0335).
11
+ # Set by the deciding human together with the status change.
12
12
  # Draft scaffolds must keep this empty; do not prefill a default identity.
13
- # Format: human:<handle> (agent:<id> reserved — see RFC-0335).
14
- # Default reviewer when none is specified by the operator: human:andrii-syrokomskyi
13
+ # Format: human:<handle>
15
14
  reviewers: []
16
15
  createdAt: YYYY-MM-DD
17
16
  updatedAt: YYYY-MM-DD
@@ -26,8 +25,6 @@ related:
26
25
  # - DNA-1
27
26
  # - AP-3
28
27
  # - RFC-0005
29
- # - PAGE-MANDATORY-ARTIFACTS
30
- # - COMPONENT-THREE-WAY-MIRROR
31
28
  # RFC-0331: DNA invariants this RFC implements, protects, or extends.
32
29
  # Required for architecture/contract RFCs created on or after 2026-07-07.
33
30
  # Entries must match ^DNA-\d+$ and exist in docs/architecture-dna.md.
@@ -55,17 +52,16 @@ appsImpacted: []
55
52
  packagesImpacted: []
56
53
  successSignals: []
57
54
  nonGoals: []
58
- # RFC-0268: OPTIONAL machine-checkable acceptance probes, executed on-demand
59
- # via `pnpm exec werkstatt run rfc.acceptance.run --id <this-rfc-id>` (never
60
- # automatically inside build pipelines). Closed probe vocabulary — see
61
- # docs/rfcs/rfc-0268-make-rfc-acceptance-criteria-machine-checkable.md.
55
+ # OPTIONAL machine-checkable acceptance probes, executed on-demand
56
+ # via `pnpm exec forge rfc.acceptance.run --id <this-rfc-id>` (never
57
+ # automatically inside build pipelines).
62
58
  # acceptance:
63
59
  # - probe: run
64
- # command: "site-kernel run some.command.validate --app warpgogol-com"
60
+ # command: "pnpm exec forge some.command.validate"
65
61
  # expect:
66
62
  # exitCode: 0
67
63
  # - probe: file-exists
68
- # path: "packages/share/src/some-new-module.ts"
64
+ # path: "packages/my-package/src/some-new-module.ts"
69
65
  # - probe: command-registered
70
66
  # name: "some.new.command"
71
67
  # - probe: file-contains
@@ -119,8 +115,8 @@ nonGoals: []
119
115
  <!-- Show the exact command(s) as a user would type them:
120
116
 
121
117
  ```sh
122
- pnpm exec werkstatt run domain.command --app main
123
- pnpm exec werkstatt run domain.command --all --json
118
+ pnpm exec forge domain.command
119
+ pnpm exec forge domain.command --json
124
120
  ```
125
121
 
126
122
  Describe flags, arguments, and scope (app | workspace).
@@ -150,7 +146,7 @@ interface ExampleResult {
150
146
 
151
147
  | Path | Role |
152
148
  |---|---|
153
- | `src/pages/[lang]/**/*.astro` | Scanned for violations |
149
+ | `src/**/*.ts` | Scanned for violations |
154
150
  | `docs/rfcs/index.json` | Updated by rfc.index.generate |
155
151
  -->
156
152
 
@@ -163,7 +159,7 @@ interface ExampleResult {
163
159
  "command": "domain.command",
164
160
  "status": "fail",
165
161
  "violations": [
166
- { "file": "src/pages/de/legal.astro", "rule": "missing-schema", "message": "..." }
162
+ { "file": "src/some-file.ts", "rule": "missing-schema", "message": "..." }
167
163
  ]
168
164
  }
169
165
  ```
@@ -216,12 +212,12 @@ interface ExampleResult {
216
212
 
217
213
  - Agents MAY implement code changes ONLY when this RFC has status: accepted (or implemented).
218
214
  - Agents MAY transition this RFC from `accepted` to `implemented` per RFC-0224 preconditions; reference this RFC ID in commits.
219
- - For RFCs created on or after 2026-07-07 with acceptance probes: before stamping `implemented`, run
220
- `site-kernel run rfc.verification.emit --id <this-rfc-id>` and commit the evidence file
221
- in the same commit (RFC-0330 amended transition precondition).
215
+ - For RFCs with acceptance probes: before stamping `implemented`, run
216
+ `pnpm exec forge rfc.verification.emit --id <this-rfc-id>` and commit the evidence file
217
+ in the same commit.
222
218
  - Agents MUST NOT weaken or remove enforcement rules established by this RFC
223
219
  without a new RFC that supersedes it.
224
220
  - If implementation reveals an invariant conflict, run
225
- `site-kernel run rfc.supersede.propose --id <this-rfc-id> --reason "..." --invariant "DNA-N"`
226
- instead of working around it (RFC-0334).
221
+ `pnpm exec forge rfc.supersede.propose --id <this-rfc-id> --reason "..." --invariant "DNA-N"`
222
+ instead of working around it.
227
223
  -->
@@ -227,10 +227,14 @@ export async function runSessionValidate(
227
227
  }
228
228
  const errorCount = violations.filter((v) => v.severity === "error").length;
229
229
  const warnCount = violations.filter((v) => v.severity === "warning").length;
230
+ const parts: string[] = [];
231
+ if (errorCount > 0) parts.push(`${errorCount} error${errorCount === 1 ? "" : "s"}`);
232
+ if (warnCount > 0) parts.push(`${warnCount} warning${warnCount === 1 ? "" : "s"}`);
233
+ const counts = parts.join(", ");
230
234
  if (errorCount > 0) {
231
- logger.error(`${errorCount} error(s), ${warnCount} warning(s)`);
235
+ logger.error(counts);
232
236
  } else {
233
- logger.warn(`${warnCount} warning(s), 0 errors — passed`);
237
+ logger.warn(`${counts} — passed`);
234
238
  }
235
239
  }
236
240
  }
@@ -244,7 +248,15 @@ export async function runSessionValidate(
244
248
  },
245
249
  exitCode: hasErrors ? 1 : 0,
246
250
  summary: hasErrors
247
- ? `${violations.filter((v) => v.severity === "error").length} error(s) found`
251
+ ? `${violations.filter((v) => v.severity === "error").length} error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} found`
248
252
  : `All ${filesToValidate.length} session file(s) passed validation`,
253
+ nextSteps: hasErrors
254
+ ? [
255
+ {
256
+ action: `Fix the ${violations.filter((v) => v.severity === "error").length} error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run session.validate`,
257
+ kind: "required",
258
+ },
259
+ ]
260
+ : undefined,
249
261
  };
250
262
  }
@@ -74,5 +74,13 @@ export async function runSpecLiveList(
74
74
  data: result,
75
75
  exitCode: 0,
76
76
  summary: `spec.live.list: ${entries.length} living spec(s)`,
77
+ nextSteps: entries.length > 0
78
+ ? [
79
+ {
80
+ action: `Validate living specs: pnpm exec forge run spec.live.validate`,
81
+ kind: "optional",
82
+ },
83
+ ]
84
+ : undefined,
77
85
  };
78
86
  }
@@ -323,7 +323,7 @@ export async function runSpecLiveMerge(
323
323
  );
324
324
  }
325
325
 
326
- return { data: result, exitCode: 0, summary: `spec.live.merge: created ${domain} from ${rfcId}` };
326
+ return { data: result, exitCode: 0, summary: `spec.live.merge: created ${domain} from ${rfcId}`, nextSteps: [{ action: `Validate the living spec: pnpm exec forge run spec.live.validate`, kind: "optional" }] };
327
327
  }
328
328
 
329
329
  for (const heading of rfcHeadings) {
@@ -409,5 +409,5 @@ export async function runSpecLiveMerge(
409
409
  );
410
410
  }
411
411
 
412
- return { data: result, exitCode: 0, summary: `spec.live.merge: modified ${domain} from ${rfcId}` };
412
+ return { data: result, exitCode: 0, summary: `spec.live.merge: modified ${domain} from ${rfcId}`, nextSteps: [{ action: `Validate the living spec: pnpm exec forge run spec.live.validate`, kind: "optional" }] };
413
413
  }
@@ -113,5 +113,11 @@ export async function runSpecLiveShow(
113
113
  data: result,
114
114
  exitCode: 0,
115
115
  summary: `spec.live.show: ${domain}`,
116
+ nextSteps: [
117
+ {
118
+ action: `Validate the living spec: pnpm exec forge run spec.live.validate`,
119
+ kind: "optional",
120
+ },
121
+ ],
116
122
  };
117
123
  }
@@ -151,7 +151,7 @@ export async function runSpecLiveValidate(
151
151
 
152
152
  if (outputFormat === "pretty") {
153
153
  if (hasFailures) {
154
- logger.error(`spec.live.validate: ${violations.length} violation(s) across ${specsChecked} spec(s)`);
154
+ logger.error(`spec.live.validate: ${violations.length} violation${violations.length === 1 ? "" : "s"} across ${specsChecked} spec(s)`);
155
155
  for (const v of violations) {
156
156
  logger.error(` ${v.rule}: ${v.message}`);
157
157
  }
@@ -164,7 +164,7 @@ export async function runSpecLiveValidate(
164
164
  data: result,
165
165
  exitCode: hasFailures ? 1 : 0,
166
166
  summary: hasFailures
167
- ? `spec.live.validate: ${violations.length} violation(s)`
167
+ ? `spec.live.validate: ${violations.length} violation${violations.length === 1 ? "" : "s"}`
168
168
  : `spec.live.validate: ${specsChecked} spec(s) — pass`,
169
169
  };
170
170
  }
@@ -386,5 +386,11 @@ export async function runSpecMaterialize(
386
386
  },
387
387
  exitCode: 0,
388
388
  summary: `spec.materialize: created ${created.length} RFC(s) from spec '${specId}'`,
389
+ nextSteps: [
390
+ {
391
+ action: `Validate the created RFCs: pnpm exec forge run rfc.validate`,
392
+ kind: "optional",
393
+ },
394
+ ],
389
395
  };
390
396
  }
@@ -280,5 +280,11 @@ export async function runSpecStatus(
280
280
  },
281
281
  exitCode: 0,
282
282
  summary: `spec.status: ${results.length} spec(s)`,
283
+ nextSteps: [
284
+ {
285
+ action: `Validate specs: pnpm exec forge run spec.validate`,
286
+ kind: "optional",
287
+ },
288
+ ],
283
289
  };
284
290
  }
@@ -490,7 +490,7 @@ export async function runSpecValidate(
490
490
  if (result.violations.length === 0) {
491
491
  logger.success(`spec.validate: ${result.id} — pass`);
492
492
  } else {
493
- logger.error(`spec.validate: ${result.id} — ${result.violations.length} violation(s)`);
493
+ logger.error(`spec.validate: ${result.id} — ${result.violations.length} violation${result.violations.length === 1 ? "" : "s"}`);
494
494
  for (const v of result.violations) {
495
495
  logger.error(` ${v.rule}: ${v.message}`);
496
496
  }
@@ -168,6 +168,15 @@ export async function runWerkstattLockRecover(
168
168
  return {
169
169
  data: { recovered, failed },
170
170
  summary: `[werkstatt.lock.recover] ${recovered.length} artifact${recovered.length === 1 ? "" : "s"} recovered, ${failed.length} failure${failed.length === 1 ? "" : "s"}`,
171
+ nextSteps:
172
+ failed.length > 0
173
+ ? [
174
+ {
175
+ action: `Investigate the ${failed.length} failed recovery item(s) above and retry manually`,
176
+ kind: "required",
177
+ },
178
+ ]
179
+ : undefined,
171
180
  };
172
181
  } finally {
173
182
  await releaseLock(workspaceRoot, "werkstatt-recovery");
@@ -69,5 +69,14 @@ export async function runWerkstattLockStatus(
69
69
  staleCount,
70
70
  },
71
71
  summary: `[werkstatt.lock.status] ${locks.length} lock${locks.length === 1 ? "" : "s"}, ${staleCount} stale`,
72
+ nextSteps:
73
+ staleCount > 0
74
+ ? [
75
+ {
76
+ action: `Recover stale locks: pnpm exec forge run werkstatt.lock.recover`,
77
+ kind: "optional",
78
+ },
79
+ ]
80
+ : undefined,
72
81
  };
73
82
  }
@@ -203,6 +203,15 @@ export async function runWorkflowList(
203
203
  data: { command: "workflow.list", workflows: entries },
204
204
  exitCode: 0,
205
205
  summary: `workflow.list: ${entries.length} workflow file(s) found`,
206
+ nextSteps:
207
+ entries.length === 0
208
+ ? [
209
+ {
210
+ action: `Create a workflow file in .devin/workflows/ or .windsurf/workflows/`,
211
+ kind: "optional",
212
+ },
213
+ ]
214
+ : undefined,
206
215
  };
207
216
  }
208
217
 
@@ -298,7 +307,7 @@ export async function runWorkflowLint(
298
307
  exitCode: violations.length > 0 ? 1 : 0,
299
308
  summary:
300
309
  violations.length > 0
301
- ? `workflow.lint: ${violations.length} violation(s)`
310
+ ? `workflow.lint: ${violations.length} violation${violations.length === 1 ? "" : "s"}`
302
311
  : `workflow.lint: ${workflows.length} workflow file(s) valid`,
303
312
  };
304
313
  }