@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.
- package/README.md +14 -8
- package/README.uk.md +14 -0
- package/dist/bin/cli.js +0 -0
- package/dist/os/adr/handlers/implement-stamp.d.ts.map +1 -1
- package/dist/os/adr/handlers/implement-stamp.js +7 -1
- package/dist/os/adr/handlers/implement-stamp.js.map +1 -1
- package/dist/os/adr/handlers/list-create.d.ts.map +1 -1
- package/dist/os/adr/handlers/list-create.js +40 -4
- package/dist/os/adr/handlers/list-create.js.map +1 -1
- package/dist/os/adr/handlers/validate.d.ts.map +1 -1
- package/dist/os/adr/handlers/validate.js +17 -3
- package/dist/os/adr/handlers/validate.js.map +1 -1
- package/dist/os/adr/types.d.ts +1 -0
- package/dist/os/adr/types.d.ts.map +1 -1
- package/dist/os/adr/types.js +1 -0
- package/dist/os/adr/types.js.map +1 -1
- package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-audit-handler.js +22 -0
- package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-change-summary-handler.js +6 -0
- package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
- package/dist/os/compass/handlers/compass-inventory-handler.js +19 -0
- package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
- package/dist/os/core/handlers/package-health.d.ts.map +1 -1
- package/dist/os/core/handlers/package-health.js +8 -4
- package/dist/os/core/handlers/package-health.js.map +1 -1
- package/dist/os/core/handlers/pinned-validate.d.ts.map +1 -1
- package/dist/os/core/handlers/pinned-validate.js +2 -2
- package/dist/os/core/handlers/pinned-validate.js.map +1 -1
- package/dist/os/exploration/handlers/archive.d.ts.map +1 -1
- package/dist/os/exploration/handlers/archive.js +6 -0
- package/dist/os/exploration/handlers/archive.js.map +1 -1
- package/dist/os/exploration/handlers/list.d.ts.map +1 -1
- package/dist/os/exploration/handlers/list.js +8 -0
- package/dist/os/exploration/handlers/list.js.map +1 -1
- package/dist/os/exploration/handlers/show.d.ts.map +1 -1
- package/dist/os/exploration/handlers/show.js +6 -0
- package/dist/os/exploration/handlers/show.js.map +1 -1
- package/dist/os/program/handlers/complete.d.ts.map +1 -1
- package/dist/os/program/handlers/complete.js +19 -1
- package/dist/os/program/handlers/complete.js.map +1 -1
- package/dist/os/program/handlers/lease.js +7 -1
- package/dist/os/program/handlers/lease.js.map +1 -1
- package/dist/os/program/handlers/seal.d.ts.map +1 -1
- package/dist/os/program/handlers/seal.js +13 -1
- package/dist/os/program/handlers/seal.js.map +1 -1
- package/dist/os/program/handlers/validate.js +8 -2
- package/dist/os/program/handlers/validate.js.map +1 -1
- package/dist/os/rfc/acceptance.d.ts.map +1 -1
- package/dist/os/rfc/acceptance.js +8 -0
- package/dist/os/rfc/acceptance.js.map +1 -1
- package/dist/os/rfc/dna-trace.js +1 -1
- package/dist/os/rfc/dna-trace.js.map +1 -1
- package/dist/os/rfc/handlers/check.d.ts.map +1 -1
- package/dist/os/rfc/handlers/check.js +10 -2
- package/dist/os/rfc/handlers/check.js.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.d.ts.map +1 -1
- package/dist/os/rfc/handlers/implement-stamp.js +7 -1
- package/dist/os/rfc/handlers/implement-stamp.js.map +1 -1
- package/dist/os/rfc/handlers/index-graph.js +4 -4
- package/dist/os/rfc/handlers/index-graph.js.map +1 -1
- package/dist/os/rfc/handlers/lifecycle.js +1 -1
- package/dist/os/rfc/handlers/lifecycle.js.map +1 -1
- package/dist/os/rfc/handlers/list-create.d.ts.map +1 -1
- package/dist/os/rfc/handlers/list-create.js +20 -0
- package/dist/os/rfc/handlers/list-create.js.map +1 -1
- package/dist/os/rfc/handlers/validate.d.ts.map +1 -1
- package/dist/os/rfc/handlers/validate.js +17 -3
- package/dist/os/rfc/handlers/validate.js.map +1 -1
- package/dist/os/session/handlers/validate.d.ts.map +1 -1
- package/dist/os/session/handlers/validate.js +17 -3
- package/dist/os/session/handlers/validate.js.map +1 -1
- package/dist/os/spec/live-spec-list.d.ts.map +1 -1
- package/dist/os/spec/live-spec-list.js +8 -0
- package/dist/os/spec/live-spec-list.js.map +1 -1
- package/dist/os/spec/live-spec-merge.js +2 -2
- package/dist/os/spec/live-spec-merge.js.map +1 -1
- package/dist/os/spec/live-spec-show.d.ts.map +1 -1
- package/dist/os/spec/live-spec-show.js +6 -0
- package/dist/os/spec/live-spec-show.js.map +1 -1
- package/dist/os/spec/live-spec-validate.js +2 -2
- package/dist/os/spec/live-spec-validate.js.map +1 -1
- package/dist/os/spec/spec-materialize.d.ts.map +1 -1
- package/dist/os/spec/spec-materialize.js +6 -0
- package/dist/os/spec/spec-materialize.js.map +1 -1
- package/dist/os/spec/spec-status.d.ts.map +1 -1
- package/dist/os/spec/spec-status.js +6 -0
- package/dist/os/spec/spec-status.js.map +1 -1
- package/dist/os/spec/spec-validate.js +1 -1
- package/dist/os/spec/spec-validate.js.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.d.ts.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +8 -0
- package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.d.ts.map +1 -1
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.js +8 -0
- package/dist/os/werkstatt/handlers/werkstatt-lock-status.js.map +1 -1
- package/dist/os/workflow/handlers.d.ts.map +1 -1
- package/dist/os/workflow/handlers.js +9 -1
- package/dist/os/workflow/handlers.js.map +1 -1
- package/dist/src/onboarding/create.js +1 -1
- package/dist/src/onboarding/create.js.map +1 -1
- package/dist/src/onboarding/doctor.js +1 -1
- package/dist/src/onboarding/doctor.js.map +1 -1
- package/dist/src/onboarding/init.d.ts.map +1 -1
- package/dist/src/onboarding/init.js +31 -1
- package/dist/src/onboarding/init.js.map +1 -1
- package/dist/src/onboarding/profile-validate.js +1 -1
- package/dist/src/onboarding/profile-validate.js.map +1 -1
- package/dist/src/utils/fs-trash.d.ts.map +1 -1
- package/dist/src/utils/fs-trash.js +1 -1
- package/dist/src/utils/fs-trash.js.map +1 -1
- package/dist/src/validators/note-frontmatter-validate.js +1 -1
- package/dist/src/validators/note-frontmatter-validate.js.map +1 -1
- package/dist/src/validators/note-link-validate.js +1 -1
- package/dist/src/validators/note-link-validate.js.map +1 -1
- package/os/adr/adr-0000-template.md +46 -0
- package/os/adr/handlers/implement-stamp.ts +7 -1
- package/os/adr/handlers/list-create.ts +48 -4
- package/os/adr/handlers/validate.ts +15 -3
- package/os/adr/types.ts +1 -0
- package/os/compass/handlers/compass-audit-handler.ts +24 -0
- package/os/compass/handlers/compass-change-summary-handler.ts +6 -0
- package/os/compass/handlers/compass-inventory-handler.ts +19 -0
- package/os/core/handlers/package-health.ts +9 -5
- package/os/core/handlers/pinned-validate.ts +4 -2
- package/os/exploration/handlers/archive.ts +6 -0
- package/os/exploration/handlers/list.ts +9 -0
- package/os/exploration/handlers/show.ts +6 -0
- package/os/program/handlers/complete.ts +19 -1
- package/os/program/handlers/lease.ts +7 -1
- package/os/program/handlers/seal.ts +13 -1
- package/os/program/handlers/validate.ts +8 -2
- package/os/rfc/acceptance.ts +9 -0
- package/os/rfc/dna-trace.ts +1 -1
- package/os/rfc/handlers/check.ts +10 -2
- package/os/rfc/handlers/implement-stamp.ts +7 -1
- package/os/rfc/handlers/index-graph.ts +4 -4
- package/os/rfc/handlers/lifecycle.ts +1 -1
- package/os/rfc/handlers/list-create.ts +21 -0
- package/os/rfc/handlers/validate.ts +15 -3
- package/os/rfc/rfc-0000-template.md +16 -20
- package/os/session/handlers/validate.ts +15 -3
- package/os/spec/live-spec-list.ts +8 -0
- package/os/spec/live-spec-merge.ts +2 -2
- package/os/spec/live-spec-show.ts +6 -0
- package/os/spec/live-spec-validate.ts +2 -2
- package/os/spec/spec-materialize.ts +6 -0
- package/os/spec/spec-status.ts +6 -0
- package/os/spec/spec-validate.ts +1 -1
- package/os/werkstatt/handlers/werkstatt-lock-recover.ts +9 -0
- package/os/werkstatt/handlers/werkstatt-lock-status.ts +9 -0
- package/os/workflow/handlers.ts +10 -1
- package/package.json +73 -195
- package/skills/_shared/fo-pipeline-conventions.md +44 -5
- package/skills/_shared/fo-prerequisites.md +81 -0
- package/skills/fo/fo-extract-dna/SKILL.md +1 -1
- package/skills/fo/fo-idea-audit/AUDIT-AXES.md +66 -0
- package/skills/fo/fo-idea-audit/SKILL.md +2 -2
- package/skills/fo/fo-idea-create-adr/SKILL.md +1 -1
- package/skills/fo/fo-idea-create-rfc/SKILL.md +3 -3
- package/skills/fo/fo-idea-enhance/SKILL.md +2 -2
- package/skills/fo/fo-idea-implement/ADR-FLOW.md +179 -0
- package/skills/fo/fo-idea-implement/SKILL.md +1 -1
- package/skills/fo/fo-idea-plan/SKILL.md +4 -2
- package/skills/fo/fo-review/AXES.md +70 -0
- package/skills/fo/fo-session-retro/learned-principles.md +15 -0
- package/skills/fo/fo-step-commit/SKILL.md +2 -2
- package/skills/shared/windows-ai-tooling/.gitattributes.template +49 -0
- package/skills/shared/windows-ai-tooling/AGENTS_WINDOWS.md.template +42 -0
- package/skills/shared/writing-great-skills/GLOSSARY.md +201 -0
- package/src/onboarding/create.ts +1 -1
- package/src/onboarding/doctor.ts +1 -1
- package/src/onboarding/init.ts +30 -1
- package/src/onboarding/profile-validate.ts +1 -1
- package/src/tests/package-files.test.ts +5 -2
- package/src/tests/stack-profile.test.ts +4 -0
- package/src/utils/fs-trash.ts +1 -1
- package/src/validators/note-frontmatter-validate.ts +1 -1
- package/src/validators/note-link-validate.ts +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: ADR-0000
|
|
3
|
+
title: "Short imperative title"
|
|
4
|
+
# Lifecycle:
|
|
5
|
+
# proposed → reviewing → accepted → implemented
|
|
6
|
+
# any → superseded (requires supersededBy)
|
|
7
|
+
# any → rejected
|
|
8
|
+
status: proposed
|
|
9
|
+
scope: package
|
|
10
|
+
decider: architecture
|
|
11
|
+
createdAt: YYYY-MM-DD
|
|
12
|
+
updatedAt: YYYY-MM-DD
|
|
13
|
+
implementedAt:
|
|
14
|
+
closedAt:
|
|
15
|
+
supersedes: []
|
|
16
|
+
supersededBy:
|
|
17
|
+
related: []
|
|
18
|
+
# Set by the deciding human together with the status change.
|
|
19
|
+
# Draft scaffolds must keep this empty; do not prefill a default identity.
|
|
20
|
+
# Format: human:<handle>
|
|
21
|
+
reviewers: []
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# ADR-0000: Short imperative title
|
|
25
|
+
|
|
26
|
+
## Context
|
|
27
|
+
|
|
28
|
+
Brief description of the local situation, constraints, and RFC or DNA context that bounds the decision. Name actual packages, files, or components.
|
|
29
|
+
|
|
30
|
+
## Decision
|
|
31
|
+
|
|
32
|
+
A single sentence in the present tense stating the decision as a fact. Add 1-3 bullets clarifying scope or boundaries if needed.
|
|
33
|
+
|
|
34
|
+
## Justification
|
|
35
|
+
|
|
36
|
+
Forces and trade-offs that led to the decision: alternatives considered, constraints, alignment with existing architecture.
|
|
37
|
+
|
|
38
|
+
## Consequences
|
|
39
|
+
|
|
40
|
+
- Positive: what becomes simpler, safer, cheaper, or more predictable.
|
|
41
|
+
- Negative: trade-offs, limitations, operational overhead.
|
|
42
|
+
- Technical debt: what is knowingly postponed.
|
|
43
|
+
|
|
44
|
+
## Evolution
|
|
45
|
+
|
|
46
|
+
How the decision may change: thresholds that trigger revisiting it, metrics to watch, and — for post-hoc ADRs — references to commits or PRs that implemented it.
|
|
@@ -301,6 +301,12 @@ export async function runAdrImplementStamp(
|
|
|
301
301
|
},
|
|
302
302
|
exitCode: 0,
|
|
303
303
|
summary: `adr.implement.stamp: ${targetId} stamped as implemented`,
|
|
304
|
+
nextSteps: [
|
|
305
|
+
{
|
|
306
|
+
action: `Commit the stamp: pnpm exec forge run ecosystem.commit`,
|
|
307
|
+
kind: "optional",
|
|
308
|
+
},
|
|
309
|
+
],
|
|
304
310
|
};
|
|
305
311
|
} finally {
|
|
306
312
|
await releaseAdrLock(lockPath);
|
|
@@ -326,6 +332,6 @@ function stampFailResult(
|
|
|
326
332
|
violations,
|
|
327
333
|
},
|
|
328
334
|
exitCode: 1,
|
|
329
|
-
summary: `${prefix}adr.implement.stamp: ${violations.length} violation
|
|
335
|
+
summary: `${prefix}adr.implement.stamp: ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
330
336
|
};
|
|
331
337
|
}
|
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import fs from "node:fs/promises";
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
15
16
|
import path from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
16
18
|
import { toKebabCase } from "../../../src/utils/string-utils.ts";
|
|
19
|
+
import { resolveForgeRoot } from "../../../src/config/forge-config.ts";
|
|
17
20
|
import { listAdrFiles, readAndParseAdr } from "../frontmatter-io.ts";
|
|
18
21
|
import type {
|
|
19
22
|
ForgeCommandInput,
|
|
@@ -27,7 +30,13 @@ import type {
|
|
|
27
30
|
AdrStatus,
|
|
28
31
|
AdrScope,
|
|
29
32
|
} from "../types.ts";
|
|
30
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
ADR_DIR,
|
|
35
|
+
ADR_TEMPLATE_FILE,
|
|
36
|
+
ADR_TEMPLATE_FALLBACK_FILE,
|
|
37
|
+
ADR_SCOPES,
|
|
38
|
+
ADR_STATUSES,
|
|
39
|
+
} from "../types.ts";
|
|
31
40
|
|
|
32
41
|
function toIsoDate(d: Date): string {
|
|
33
42
|
return d.toISOString().slice(0, 10);
|
|
@@ -137,14 +146,13 @@ export async function runAdrCreate(
|
|
|
137
146
|
const nextSlug = `adr-${paddedNum}`;
|
|
138
147
|
const nextId = `ADR-${paddedNum}`;
|
|
139
148
|
|
|
140
|
-
const
|
|
141
|
-
const templatePath = path.join(workspaceRoot, templateRelPath);
|
|
149
|
+
const templatePath = resolveAdrTemplate(workspaceRoot);
|
|
142
150
|
let templateContent: string;
|
|
143
151
|
try {
|
|
144
152
|
templateContent = await fs.readFile(templatePath, "utf-8");
|
|
145
153
|
} catch {
|
|
146
154
|
throw new Error(
|
|
147
|
-
`ADR template not found at ${
|
|
155
|
+
`ADR template not found at ${templatePath}. Ensure docs/adrs/ contains the template.`,
|
|
148
156
|
);
|
|
149
157
|
}
|
|
150
158
|
|
|
@@ -205,3 +213,39 @@ export async function runAdrCreate(
|
|
|
205
213
|
summary: `Created ${nextId}: ${title}`,
|
|
206
214
|
};
|
|
207
215
|
}
|
|
216
|
+
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// ADR template resolver — finds adr-0000-template.md from project docs/adrs/
|
|
219
|
+
// first (canonical location), then falls back to the forge package copy
|
|
220
|
+
// (npm consumers without a project-level template).
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
function resolveAdrTemplate(workspaceRoot: string): string {
|
|
224
|
+
// 1. Try project-level docs/adrs/adr-0000-template.md (canonical)
|
|
225
|
+
const projectPath = path.join(workspaceRoot, ADR_TEMPLATE_FILE);
|
|
226
|
+
if (existsSync(projectPath)) return projectPath;
|
|
227
|
+
|
|
228
|
+
// 2. Try forge root (monorepo or npm-installed) — fallback copy
|
|
229
|
+
try {
|
|
230
|
+
const forgeRoot = resolveForgeRoot(workspaceRoot);
|
|
231
|
+
const p = path.join(forgeRoot, ADR_TEMPLATE_FALLBACK_FILE);
|
|
232
|
+
if (existsSync(p)) return p;
|
|
233
|
+
} catch {
|
|
234
|
+
// forge root not resolvable — fall through to module-relative search
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 3. Fallback: walk up from this module's location to find os/adr/adr-0000-template.md
|
|
238
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
239
|
+
let dir = here;
|
|
240
|
+
for (let i = 0; i < 10; i++) {
|
|
241
|
+
const candidate = path.join(dir, "os", "adr", "adr-0000-template.md");
|
|
242
|
+
if (existsSync(candidate)) return candidate;
|
|
243
|
+
const parent = path.dirname(dir);
|
|
244
|
+
if (parent === dir) break;
|
|
245
|
+
dir = parent;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
throw new Error(
|
|
249
|
+
`ADR template not found. Tried ${ADR_TEMPLATE_FILE} relative to ${workspaceRoot}, forge root, and module-relative search from ${here}.`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
@@ -135,10 +135,14 @@ export async function runAdrValidate(
|
|
|
135
135
|
}
|
|
136
136
|
const errorCount = violations.filter((v) => v.severity === "error").length;
|
|
137
137
|
const warnCount = violations.filter((v) => v.severity === "warning").length;
|
|
138
|
+
const parts: string[] = [];
|
|
139
|
+
if (errorCount > 0) parts.push(`${errorCount} error${errorCount === 1 ? "" : "s"}`);
|
|
140
|
+
if (warnCount > 0) parts.push(`${warnCount} warning${warnCount === 1 ? "" : "s"}`);
|
|
141
|
+
const counts = parts.join(", ");
|
|
138
142
|
if (errorCount > 0) {
|
|
139
|
-
logger.error(
|
|
143
|
+
logger.error(counts);
|
|
140
144
|
} else {
|
|
141
|
-
logger.warn(`${
|
|
145
|
+
logger.warn(`${counts} — passed`);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
}
|
|
@@ -152,8 +156,16 @@ export async function runAdrValidate(
|
|
|
152
156
|
},
|
|
153
157
|
exitCode: hasErrors ? 1 : 0,
|
|
154
158
|
summary: hasErrors
|
|
155
|
-
? `${violations.filter((v) => v.severity === "error").length} error(
|
|
159
|
+
? `${violations.filter((v) => v.severity === "error").length} error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} found`
|
|
156
160
|
: `All ${filesToValidate.length} ADR(s) passed validation`,
|
|
161
|
+
nextSteps: hasErrors
|
|
162
|
+
? [
|
|
163
|
+
{
|
|
164
|
+
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 adr.validate`,
|
|
165
|
+
kind: "required",
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
: undefined,
|
|
157
169
|
};
|
|
158
170
|
}
|
|
159
171
|
|
package/os/adr/types.ts
CHANGED
|
@@ -92,6 +92,7 @@ export interface AdrCreateResult {
|
|
|
92
92
|
|
|
93
93
|
export const ADR_DIR = "docs/adrs";
|
|
94
94
|
export const ADR_TEMPLATE_FILE = "docs/adrs/adr-0000-template.md";
|
|
95
|
+
export const ADR_TEMPLATE_FALLBACK_FILE = "os/adr/adr-0000-template.md";
|
|
95
96
|
export const ADR_ID_PATTERN = /^ADR-\d{4}$/;
|
|
96
97
|
|
|
97
98
|
export const ADR_REQUIRED_SECTIONS = [
|
|
@@ -186,6 +186,15 @@ export async function runCompassAuditPlan(
|
|
|
186
186
|
data: { threshold, dueCount: items.length, items },
|
|
187
187
|
exitCode: 0,
|
|
188
188
|
summary: `[compass.audit.plan] ${items.length} files due for audit (threshold=${threshold})`,
|
|
189
|
+
nextSteps:
|
|
190
|
+
items.length > 0
|
|
191
|
+
? [
|
|
192
|
+
{
|
|
193
|
+
action: `Record an audit: pnpm exec forge run compass.audit.record --file <path> --verdict <verdict> --revision <rev>`,
|
|
194
|
+
kind: "optional",
|
|
195
|
+
},
|
|
196
|
+
]
|
|
197
|
+
: undefined,
|
|
189
198
|
};
|
|
190
199
|
}
|
|
191
200
|
|
|
@@ -251,6 +260,12 @@ export async function runCompassAuditRecord(
|
|
|
251
260
|
data: { path: filePath, action: "recorded" },
|
|
252
261
|
exitCode: 0,
|
|
253
262
|
summary: `[compass.audit.record] ${filePath}: ${verdict} at revision ${revision}`,
|
|
263
|
+
nextSteps: [
|
|
264
|
+
{
|
|
265
|
+
action: `Validate audits: pnpm exec forge run compass.audit.validate`,
|
|
266
|
+
kind: "optional",
|
|
267
|
+
},
|
|
268
|
+
],
|
|
254
269
|
};
|
|
255
270
|
}
|
|
256
271
|
|
|
@@ -378,5 +393,14 @@ export async function runCompassAuditValidate(
|
|
|
378
393
|
data: { strict, dueCount, diagnostics },
|
|
379
394
|
exitCode: hasErrors ? 1 : 0,
|
|
380
395
|
summary: dueCount > 0 ? undefined : `[compass.audit.validate] OK (0 files overdue)`,
|
|
396
|
+
nextSteps:
|
|
397
|
+
dueCount > 0
|
|
398
|
+
? [
|
|
399
|
+
{
|
|
400
|
+
action: `Fix the ${dueCount} overdue file(s) above, then re-run: pnpm exec forge run compass.audit.validate`,
|
|
401
|
+
kind: "required",
|
|
402
|
+
},
|
|
403
|
+
]
|
|
404
|
+
: undefined,
|
|
381
405
|
};
|
|
382
406
|
}
|
|
@@ -278,5 +278,11 @@ export async function runCompassSummaryTrim(
|
|
|
278
278
|
},
|
|
279
279
|
exitCode: 0,
|
|
280
280
|
summary: `[compass.summary.trim] files=${results.length}, removed=${results.reduce((sum, r) => sum + r.removed.length, 0)}`,
|
|
281
|
+
nextSteps: [
|
|
282
|
+
{
|
|
283
|
+
action: `Commit the trimmed headers: pnpm exec forge run ecosystem.commit`,
|
|
284
|
+
kind: "optional",
|
|
285
|
+
},
|
|
286
|
+
],
|
|
281
287
|
};
|
|
282
288
|
}
|
|
@@ -222,6 +222,12 @@ export async function runCompassInventory(
|
|
|
222
222
|
return {
|
|
223
223
|
data: { entries: entries.length, outputPath: INVENTORY_OUTPUT_PATH, summary },
|
|
224
224
|
summary: `[compass.inventory] previewed ${INVENTORY_OUTPUT_PATH}`,
|
|
225
|
+
nextSteps: [
|
|
226
|
+
{
|
|
227
|
+
action: `Write the inventory: pnpm exec forge run compass.inventory`,
|
|
228
|
+
kind: "optional",
|
|
229
|
+
},
|
|
230
|
+
],
|
|
225
231
|
};
|
|
226
232
|
}
|
|
227
233
|
|
|
@@ -232,6 +238,19 @@ export async function runCompassInventory(
|
|
|
232
238
|
return {
|
|
233
239
|
data: { entries: entries.length, outputPath, summary },
|
|
234
240
|
summary: `[compass.inventory] ${context.dryRun ? "previewed" : "wrote"} ${INVENTORY_OUTPUT_PATH}`,
|
|
241
|
+
nextSteps: context.dryRun
|
|
242
|
+
? [
|
|
243
|
+
{
|
|
244
|
+
action: `Write for real: pnpm exec forge run compass.inventory`,
|
|
245
|
+
kind: "optional",
|
|
246
|
+
},
|
|
247
|
+
]
|
|
248
|
+
: [
|
|
249
|
+
{
|
|
250
|
+
action: `Validate compass headers: pnpm exec forge run compass.validate`,
|
|
251
|
+
kind: "optional",
|
|
252
|
+
},
|
|
253
|
+
],
|
|
235
254
|
};
|
|
236
255
|
}
|
|
237
256
|
|
|
@@ -199,12 +199,16 @@ export async function runPackageHealth(
|
|
|
199
199
|
`forge.package.health: all ${packagesChecked} published package(s) healthy.`,
|
|
200
200
|
);
|
|
201
201
|
} else if (passed) {
|
|
202
|
-
logger.
|
|
203
|
-
`forge.package.health: ${packagesChecked} package(s) checked, ${warnings.length} warning
|
|
202
|
+
logger.warn(
|
|
203
|
+
`forge.package.health: ${packagesChecked} package(s) checked, ${warnings.length} warning${warnings.length === 1 ? "" : "s"}.`,
|
|
204
204
|
);
|
|
205
205
|
} else {
|
|
206
|
+
const parts: string[] = [];
|
|
207
|
+
parts.push(`${errors.length} error${errors.length === 1 ? "" : "s"}`);
|
|
208
|
+
if (warnings.length > 0)
|
|
209
|
+
parts.push(`${warnings.length} warning${warnings.length === 1 ? "" : "s"}`);
|
|
206
210
|
logger.error(
|
|
207
|
-
`forge.package.health: ${
|
|
211
|
+
`forge.package.health: ${parts.join(", ")} across ${packagesChecked} package(s).`,
|
|
208
212
|
);
|
|
209
213
|
}
|
|
210
214
|
}
|
|
@@ -220,9 +224,9 @@ export async function runPackageHealth(
|
|
|
220
224
|
exitCode: passed ? 0 : 1,
|
|
221
225
|
summary: passed
|
|
222
226
|
? warnings.length > 0
|
|
223
|
-
? `All ${packagesChecked} package(s) passed with ${warnings.length} warning
|
|
227
|
+
? `All ${packagesChecked} package(s) passed with ${warnings.length} warning${warnings.length === 1 ? "" : "s"}.`
|
|
224
228
|
: `All ${packagesChecked} package(s) healthy.`
|
|
225
|
-
: `${errors.length} error
|
|
229
|
+
: `${errors.length} error${errors.length === 1 ? "" : "s"} found across ${packagesChecked} package(s).`,
|
|
226
230
|
nextSteps: errors.map((e) => ({
|
|
227
231
|
action: e.fixHint ?? e.message,
|
|
228
232
|
kind: "required" as const,
|
|
@@ -283,7 +283,9 @@ export async function runPinnedValidate(
|
|
|
283
283
|
logger.success("pinned.validate: no violations");
|
|
284
284
|
}
|
|
285
285
|
} else {
|
|
286
|
-
logger.error(
|
|
286
|
+
logger.error(
|
|
287
|
+
`pinned.validate: ${remainingViolations.length} violation${remainingViolations.length === 1 ? "" : "s"} found`,
|
|
288
|
+
);
|
|
287
289
|
for (const v of remainingViolations) {
|
|
288
290
|
logger.error(` ${v.operation}: ${v.path} (mode: ${v.mode}) — ${v.reason}`);
|
|
289
291
|
}
|
|
@@ -296,6 +298,6 @@ export async function runPinnedValidate(
|
|
|
296
298
|
summary:
|
|
297
299
|
status === "pass"
|
|
298
300
|
? `No violations${appliedOverrides.length > 0 ? ` (${appliedOverrides.length} override(s) applied)` : ""}`
|
|
299
|
-
: `${remainingViolations.length} violation
|
|
301
|
+
: `${remainingViolations.length} violation${remainingViolations.length === 1 ? "" : "s"} found`,
|
|
300
302
|
};
|
|
301
303
|
}
|
|
@@ -155,5 +155,11 @@ export async function runExplorationArchive(
|
|
|
155
155
|
related,
|
|
156
156
|
},
|
|
157
157
|
summary: `Archived exploration note: ${slug} (${previousStatus} → archived)`,
|
|
158
|
+
nextSteps: [
|
|
159
|
+
{
|
|
160
|
+
action: `Commit the archive: pnpm exec forge run ecosystem.commit`,
|
|
161
|
+
kind: "optional",
|
|
162
|
+
},
|
|
163
|
+
],
|
|
158
164
|
};
|
|
159
165
|
}
|
|
@@ -73,5 +73,14 @@ export async function runExplorationList(
|
|
|
73
73
|
explorations: entries,
|
|
74
74
|
},
|
|
75
75
|
summary: `${entries.length} exploration note(s) found`,
|
|
76
|
+
nextSteps:
|
|
77
|
+
entries.length === 0
|
|
78
|
+
? [
|
|
79
|
+
{
|
|
80
|
+
action: `Create an exploration note: pnpm exec forge run exploration.show --id <slug>`,
|
|
81
|
+
kind: "optional",
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
: undefined,
|
|
76
85
|
};
|
|
77
86
|
}
|
|
@@ -103,5 +103,11 @@ export async function runExplorationShow(
|
|
|
103
103
|
note,
|
|
104
104
|
},
|
|
105
105
|
summary: `Exploration note: ${note.id}`,
|
|
106
|
+
nextSteps: [
|
|
107
|
+
{
|
|
108
|
+
action: `Archive the note when done: pnpm exec forge run exploration.archive --id ${note.id}`,
|
|
109
|
+
kind: "optional",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
106
112
|
};
|
|
107
113
|
}
|
|
@@ -237,6 +237,12 @@ export async function runComplete(
|
|
|
237
237
|
},
|
|
238
238
|
exitCode: 0,
|
|
239
239
|
summary: `program.packet.complete: ${packetId} completed at ${head.slice(0, 8)}`,
|
|
240
|
+
nextSteps: [
|
|
241
|
+
{
|
|
242
|
+
action: `Seal the next packet: pnpm exec forge run program.packet.seal --packet <next-packet-id>`,
|
|
243
|
+
kind: "optional",
|
|
244
|
+
},
|
|
245
|
+
],
|
|
240
246
|
};
|
|
241
247
|
}
|
|
242
248
|
|
|
@@ -390,6 +396,12 @@ async function bootstrapComplete(
|
|
|
390
396
|
},
|
|
391
397
|
exitCode: 0,
|
|
392
398
|
summary: `program.packet.complete: ${packetId} bootstrap completed — program now executing`,
|
|
399
|
+
nextSteps: [
|
|
400
|
+
{
|
|
401
|
+
action: `Seal the first execution packet: pnpm exec forge run program.packet.seal --packet <first-packet-id>`,
|
|
402
|
+
kind: "optional",
|
|
403
|
+
},
|
|
404
|
+
],
|
|
393
405
|
};
|
|
394
406
|
}
|
|
395
407
|
|
|
@@ -414,6 +426,12 @@ function completeFail(
|
|
|
414
426
|
violations,
|
|
415
427
|
},
|
|
416
428
|
exitCode: 1,
|
|
417
|
-
summary: `program.packet.complete: ${packetId} failed with ${violations.length} violation
|
|
429
|
+
summary: `program.packet.complete: ${packetId} failed with ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
430
|
+
nextSteps: [
|
|
431
|
+
{
|
|
432
|
+
action: `Fix the ${violations.length} violation${violations.length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run program.packet.complete --packet ${packetId}`,
|
|
433
|
+
kind: "required",
|
|
434
|
+
},
|
|
435
|
+
],
|
|
418
436
|
};
|
|
419
437
|
}
|
|
@@ -199,6 +199,12 @@ async function leaseStart(
|
|
|
199
199
|
},
|
|
200
200
|
exitCode: 0,
|
|
201
201
|
summary: `program.packet.lease: ${packetId} lease started for ${executor}`,
|
|
202
|
+
nextSteps: [
|
|
203
|
+
{
|
|
204
|
+
action: `Implement the packet, then complete: pnpm exec forge run program.packet.complete --packet ${packetId}`,
|
|
205
|
+
kind: "optional",
|
|
206
|
+
},
|
|
207
|
+
],
|
|
202
208
|
};
|
|
203
209
|
}
|
|
204
210
|
|
|
@@ -428,6 +434,6 @@ function leaseFail(
|
|
|
428
434
|
violations,
|
|
429
435
|
},
|
|
430
436
|
exitCode: 1,
|
|
431
|
-
summary: `program.packet.lease: ${packetId} ${action} failed with ${violations.length} violation
|
|
437
|
+
summary: `program.packet.lease: ${packetId} ${action} failed with ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
432
438
|
};
|
|
433
439
|
}
|
|
@@ -224,6 +224,12 @@ export async function runSeal(
|
|
|
224
224
|
},
|
|
225
225
|
exitCode: 0,
|
|
226
226
|
summary: `program.packet.seal: ${packetId} sealed on ${branch}@${head.slice(0, 8)}`,
|
|
227
|
+
nextSteps: [
|
|
228
|
+
{
|
|
229
|
+
action: `Start the lease: pnpm exec forge run program.packet.lease --packet ${packetId} --action start --executor <executor>`,
|
|
230
|
+
kind: "optional",
|
|
231
|
+
},
|
|
232
|
+
],
|
|
227
233
|
};
|
|
228
234
|
}
|
|
229
235
|
|
|
@@ -242,7 +248,13 @@ function sealFail(
|
|
|
242
248
|
violations,
|
|
243
249
|
},
|
|
244
250
|
exitCode: 1,
|
|
245
|
-
summary: `program.packet.seal: ${packetId} failed with ${violations.length} violation
|
|
251
|
+
summary: `program.packet.seal: ${packetId} failed with ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
252
|
+
nextSteps: [
|
|
253
|
+
{
|
|
254
|
+
action: `Fix the ${violations.length} violation${violations.length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run program.packet.seal --packet ${packetId}`,
|
|
255
|
+
kind: "required",
|
|
256
|
+
},
|
|
257
|
+
],
|
|
246
258
|
};
|
|
247
259
|
}
|
|
248
260
|
|
|
@@ -186,7 +186,7 @@ export async function runValidate(
|
|
|
186
186
|
summary:
|
|
187
187
|
status === "pass"
|
|
188
188
|
? `program.packet.validate: ${packetId} passed (${phase})`
|
|
189
|
-
: `program.packet.validate: ${packetId} failed with ${violations.length} violation
|
|
189
|
+
: `program.packet.validate: ${packetId} failed with ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -208,6 +208,12 @@ function failResult(
|
|
|
208
208
|
violations,
|
|
209
209
|
},
|
|
210
210
|
exitCode: 1,
|
|
211
|
-
summary: `program.packet.validate: ${packetId} failed with ${violations.length} violation
|
|
211
|
+
summary: `program.packet.validate: ${packetId} failed with ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
212
|
+
nextSteps: [
|
|
213
|
+
{
|
|
214
|
+
action: `Fix the ${violations.length} violation${violations.length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run program.packet.validate --packet ${packetId}`,
|
|
215
|
+
kind: "required",
|
|
216
|
+
},
|
|
217
|
+
],
|
|
212
218
|
};
|
|
213
219
|
}
|
package/os/rfc/acceptance.ts
CHANGED
|
@@ -340,5 +340,14 @@ export async function runRfcAcceptanceRun(
|
|
|
340
340
|
data: { command: "rfc.acceptance.run", status, diagnostics, results },
|
|
341
341
|
exitCode: failedCount > 0 ? 1 : 0,
|
|
342
342
|
summary: `rfc.acceptance.run: ${results.length} RFC(s), ${failedCount} failed probe(s)`,
|
|
343
|
+
nextSteps:
|
|
344
|
+
failedCount > 0
|
|
345
|
+
? [
|
|
346
|
+
{
|
|
347
|
+
action: `Fix the ${failedCount} failed acceptance probe(s) above, then re-run: pnpm exec forge run rfc.acceptance.run`,
|
|
348
|
+
kind: "required",
|
|
349
|
+
},
|
|
350
|
+
]
|
|
351
|
+
: undefined,
|
|
343
352
|
};
|
|
344
353
|
}
|
package/os/rfc/dna-trace.ts
CHANGED
|
@@ -233,7 +233,7 @@ export async function runRfcDnaTraceValidate(
|
|
|
233
233
|
diagnostics,
|
|
234
234
|
},
|
|
235
235
|
exitCode: hasErrors ? 1 : 0,
|
|
236
|
-
summary: `rfc.dna.trace.validate: ${registryIds.size} DNA invariants, ${tracedDnaCount} traced, ${diagnostics.filter((d) => d.severity === "error").length} error(s
|
|
236
|
+
summary: `rfc.dna.trace.validate: ${registryIds.size} DNA invariants, ${tracedDnaCount} traced, ${diagnostics.filter((d) => d.severity === "error").length} error${diagnostics.filter((d) => d.severity === "error").length === 1 ? "" : "s"}`,
|
|
237
237
|
};
|
|
238
238
|
}
|
|
239
239
|
|
package/os/rfc/handlers/check.ts
CHANGED
|
@@ -219,7 +219,7 @@ export async function runRfcCheck(
|
|
|
219
219
|
for (const v of violations) {
|
|
220
220
|
logger.error(`[${v.kind}] ${v.rfcId}: ${v.message}`);
|
|
221
221
|
}
|
|
222
|
-
logger.error(`${violations.length} violation
|
|
222
|
+
logger.error(`${violations.length} violation${violations.length === 1 ? "" : "s"} found`);
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -232,7 +232,15 @@ export async function runRfcCheck(
|
|
|
232
232
|
},
|
|
233
233
|
exitCode: hasErrors ? 1 : 0,
|
|
234
234
|
summary: hasErrors
|
|
235
|
-
? `${violations.length} artifact violation
|
|
235
|
+
? `${violations.length} artifact violation${violations.length === 1 ? "" : "s"} found across ${checkedRfcs} RFC(s)`
|
|
236
236
|
: `All ${checkedRfcs} RFC(s) passed artifact check`,
|
|
237
|
+
nextSteps: hasErrors
|
|
238
|
+
? [
|
|
239
|
+
{
|
|
240
|
+
action: `Fix the ${violations.length} artifact violation${violations.length === 1 ? "" : "s"} above, then re-run: pnpm exec forge run rfc.check`,
|
|
241
|
+
kind: "required",
|
|
242
|
+
},
|
|
243
|
+
]
|
|
244
|
+
: undefined,
|
|
237
245
|
};
|
|
238
246
|
}
|
|
@@ -485,6 +485,12 @@ export async function runRfcImplementStamp(
|
|
|
485
485
|
},
|
|
486
486
|
exitCode: 0,
|
|
487
487
|
summary: `rfc.implement.stamp: ${targetId} stamped as implemented`,
|
|
488
|
+
nextSteps: [
|
|
489
|
+
{
|
|
490
|
+
action: `Commit the stamp: pnpm exec forge run ecosystem.commit`,
|
|
491
|
+
kind: "optional",
|
|
492
|
+
},
|
|
493
|
+
],
|
|
488
494
|
};
|
|
489
495
|
} finally {
|
|
490
496
|
await releaseRfcLock(lockPath);
|
|
@@ -510,6 +516,6 @@ function stampFailResult(
|
|
|
510
516
|
violations,
|
|
511
517
|
},
|
|
512
518
|
exitCode: 1,
|
|
513
|
-
summary: `${prefix}rfc.implement.stamp: ${violations.length} violation
|
|
519
|
+
summary: `${prefix}rfc.implement.stamp: ${violations.length} violation${violations.length === 1 ? "" : "s"}`,
|
|
514
520
|
};
|
|
515
521
|
}
|
|
@@ -175,7 +175,7 @@ export async function runRfcIndexValidate(
|
|
|
175
175
|
return {
|
|
176
176
|
data: result,
|
|
177
177
|
exitCode: 1,
|
|
178
|
-
summary: "1 error
|
|
178
|
+
summary: "1 error found",
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
181
|
|
|
@@ -196,7 +196,7 @@ export async function runRfcIndexValidate(
|
|
|
196
196
|
return {
|
|
197
197
|
data: result,
|
|
198
198
|
exitCode: 1,
|
|
199
|
-
summary: "1 error
|
|
199
|
+
summary: "1 error found",
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
202
|
|
|
@@ -221,7 +221,7 @@ export async function runRfcIndexValidate(
|
|
|
221
221
|
for (const v of violations) {
|
|
222
222
|
logger.error(`[${v.rule}] ${v.message}`);
|
|
223
223
|
}
|
|
224
|
-
logger.error(`${violations.length} error
|
|
224
|
+
logger.error(`${violations.length} error${violations.length === 1 ? "" : "s"} found`);
|
|
225
225
|
} else {
|
|
226
226
|
logger.success(`Index valid — ${indexCount} entries match ${fileCount} RFC files.`);
|
|
227
227
|
}
|
|
@@ -231,7 +231,7 @@ export async function runRfcIndexValidate(
|
|
|
231
231
|
data: result,
|
|
232
232
|
exitCode: hasErrors ? 1 : 0,
|
|
233
233
|
summary: hasErrors
|
|
234
|
-
? `${violations.length} error
|
|
234
|
+
? `${violations.length} error${violations.length === 1 ? "" : "s"} found`
|
|
235
235
|
: `Index valid — ${indexCount} entries match ${fileCount} RFC files`,
|
|
236
236
|
};
|
|
237
237
|
}
|
|
@@ -243,7 +243,7 @@ export async function runRfcCommandLifecycleValidate(
|
|
|
243
243
|
},
|
|
244
244
|
exitCode: hasErrors ? 1 : 0,
|
|
245
245
|
summary: hasErrors
|
|
246
|
-
? `${violations.filter((v) => v.severity === "error").length} command lifecycle error(
|
|
246
|
+
? `${violations.filter((v) => v.severity === "error").length} command lifecycle error${violations.filter((v) => v.severity === "error").length === 1 ? "" : "s"} found`
|
|
247
247
|
: `All ${checkedCount} RFC(s) passed command lifecycle validation`,
|
|
248
248
|
};
|
|
249
249
|
}
|
|
@@ -131,6 +131,15 @@ export async function runRfcList(
|
|
|
131
131
|
entries,
|
|
132
132
|
},
|
|
133
133
|
summary: `${entries.length} RFC(s) found`,
|
|
134
|
+
nextSteps:
|
|
135
|
+
entries.length === 0
|
|
136
|
+
? [
|
|
137
|
+
{
|
|
138
|
+
action: `Create a new RFC: pnpm exec forge run rfc.create --title "..."`,
|
|
139
|
+
kind: "optional",
|
|
140
|
+
},
|
|
141
|
+
]
|
|
142
|
+
: undefined,
|
|
134
143
|
};
|
|
135
144
|
}
|
|
136
145
|
|
|
@@ -253,6 +262,12 @@ export async function runRfcCreate(
|
|
|
253
262
|
consultedDecisions,
|
|
254
263
|
},
|
|
255
264
|
summary: `Created ${nextId}: ${title}`,
|
|
265
|
+
nextSteps: [
|
|
266
|
+
{
|
|
267
|
+
action: `Validate the RFC: pnpm exec forge run rfc.validate --file ${relativeFile}`,
|
|
268
|
+
kind: "optional",
|
|
269
|
+
},
|
|
270
|
+
],
|
|
256
271
|
};
|
|
257
272
|
}
|
|
258
273
|
|
|
@@ -292,5 +307,11 @@ export async function runRfcNextId(
|
|
|
292
307
|
scannedFiles: files.length,
|
|
293
308
|
},
|
|
294
309
|
summary: `Next RFC number: ${nextId}`,
|
|
310
|
+
nextSteps: [
|
|
311
|
+
{
|
|
312
|
+
action: `Create the RFC: pnpm exec forge run rfc.create --title "..."`,
|
|
313
|
+
kind: "optional",
|
|
314
|
+
},
|
|
315
|
+
],
|
|
295
316
|
};
|
|
296
317
|
}
|