@documentation-robotics/cli 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -14
- package/dist/analyzers/active-analyzer.js +62 -0
- package/dist/analyzers/active-analyzer.js.map +7 -0
- package/dist/analyzers/cards/build.js +21 -1
- package/dist/analyzers/cards/build.js.map +2 -2
- package/dist/analyzers/cards/extract.js +138 -0
- package/dist/analyzers/cards/extract.js.map +7 -0
- package/dist/analyzers/cards/routes.js +96 -0
- package/dist/analyzers/cards/routes.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +76 -4
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +12 -6
- package/dist/analyzers/cbm-responses.js.map +2 -2
- package/dist/analyzers/code-changes.js +159 -0
- package/dist/analyzers/code-changes.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +6 -2
- package/dist/analyzers/edge-relationships.js.map +2 -2
- package/dist/analyzers/extraction-plan.js +541 -0
- package/dist/analyzers/extraction-plan.js.map +7 -0
- package/dist/analyzers/index-job.js +229 -0
- package/dist/analyzers/index-job.js.map +7 -0
- package/dist/cli.js +12 -10
- package/dist/cli.js.map +2 -2
- package/dist/coding-agents/drbot-mcp.js +120 -18
- package/dist/coding-agents/drbot-mcp.js.map +2 -2
- package/dist/commands/add.js +4 -2
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +35 -35
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +16 -8
- package/dist/commands/changeset-verify.js.map +2 -2
- package/dist/commands/changeset.js +41 -11
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/init.js +9 -26
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +35 -31
- package/dist/commands/mcp.js.map +3 -3
- package/dist/commands/relationship.js +2 -12
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +3 -3
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +14 -13
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +28 -120
- package/dist/commands/upgrade.js.map +2 -2
- package/dist/commands/validate.js +19 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +30 -12
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/annotation-store.js +15 -5
- package/dist/core/annotation-store.js.map +2 -2
- package/dist/core/catalog-migration.js +2 -1
- package/dist/core/catalog-migration.js.map +2 -2
- package/dist/core/changeset-base-index.js +7 -0
- package/dist/core/changeset-base-index.js.map +2 -2
- package/dist/core/changeset-brief-compact.js +256 -0
- package/dist/core/changeset-brief-compact.js.map +7 -0
- package/dist/core/changeset-verify.js +356 -26
- package/dist/core/changeset-verify.js.map +3 -3
- package/dist/core/extraction-observability.js +161 -0
- package/dist/core/extraction-observability.js.map +7 -0
- package/dist/core/migration-registry.js +13 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/project-init.js +53 -0
- package/dist/core/project-init.js.map +7 -0
- package/dist/core/relationship-staging.js +94 -1
- package/dist/core/relationship-staging.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +83 -3
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staging-area.js +85 -8
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/upgrade-plan.js +117 -0
- package/dist/core/upgrade-plan.js.map +7 -0
- package/dist/generated/relationship-index.js +124 -15
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +19 -5
- package/dist/integrations/claude_code/agents/dr-extractor.md +7 -1
- package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
- package/dist/integrations/claude_code/commands/dr-map.md +7 -1
- package/dist/integrations/claude_code/commands/dr-plan.md +42 -16
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +28 -31
- package/dist/integrations/claude_code/docs/README.md +20 -1
- package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
- package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +90 -31
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +5 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +5 -0
- package/dist/integrations/github_copilot/agents/dr-architect.md +2 -0
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +3 -0
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +88 -30
- package/dist/mcp/changeset-only.js +14 -3
- package/dist/mcp/changeset-only.js.map +2 -2
- package/dist/mcp/project-root.js +85 -0
- package/dist/mcp/project-root.js.map +7 -0
- package/dist/mcp/server-instructions.js +27 -0
- package/dist/mcp/server-instructions.js.map +7 -0
- package/dist/mcp/strict-schema.js +52 -0
- package/dist/mcp/strict-schema.js.map +7 -0
- package/dist/mcp/tool-registry.js +39 -5
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +25 -5
- package/dist/mcp/tools/changeset-analysis-tools.js.map +3 -3
- package/dist/mcp/tools/changeset-commit.js +224 -0
- package/dist/mcp/tools/changeset-commit.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +133 -57
- package/dist/mcp/tools/changeset-editing.js.map +3 -3
- package/dist/mcp/tools/changeset-lifecycle.js +1 -1
- package/dist/mcp/tools/changeset-lifecycle.js.map +2 -2
- package/dist/mcp/tools/changeset-verify.js +12 -6
- package/dist/mcp/tools/changeset-verify.js.map +2 -2
- package/dist/mcp/tools/codebase-extract.js +836 -0
- package/dist/mcp/tools/codebase-extract.js.map +7 -0
- package/dist/mcp/tools/codebase-index.js +125 -0
- package/dist/mcp/tools/codebase-index.js.map +7 -0
- package/dist/mcp/tools/codebase-shared.js +265 -0
- package/dist/mcp/tools/codebase-shared.js.map +7 -0
- package/dist/mcp/tools/codebase-verify.js +48 -0
- package/dist/mcp/tools/codebase-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +15 -0
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +189 -73
- package/dist/mcp/tools/model-add.js.map +2 -2
- package/dist/mcp/tools/model-update.js +16 -12
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/model-validate.js +46 -4
- package/dist/mcp/tools/model-validate.js.map +2 -2
- package/dist/mcp/tools/project-status-collectors.js +381 -0
- package/dist/mcp/tools/project-status-collectors.js.map +7 -0
- package/dist/mcp/tools/project-status.js +237 -0
- package/dist/mcp/tools/project-status.js.map +7 -0
- package/dist/mcp/tools/project-tools.js +505 -0
- package/dist/mcp/tools/project-tools.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +89 -20
- package/dist/mcp/tools/relationship-tools.js.map +2 -2
- package/dist/mcp/tools/review-open.js +210 -0
- package/dist/mcp/tools/review-open.js.map +7 -0
- package/dist/mcp/tools/shared.js +10 -2
- package/dist/mcp/tools/shared.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +31 -2
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/schemas/bundled/analyzers/cbm.json +22 -10
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1 -1
- package/dist/schemas/bundled/apm.json +1 -1
- package/dist/schemas/bundled/application.json +1 -1
- package/dist/schemas/bundled/base.json +1 -1
- package/dist/schemas/bundled/business.json +1 -1
- package/dist/schemas/bundled/data-model.json +1 -1
- package/dist/schemas/bundled/data-store.json +1 -1
- package/dist/schemas/bundled/manifest.json +3 -3
- package/dist/schemas/bundled/motivation.json +1 -1
- package/dist/schemas/bundled/navigation.json +1 -1
- package/dist/schemas/bundled/product.json +1 -1
- package/dist/schemas/bundled/security.json +1 -1
- package/dist/schemas/bundled/technology.json +1 -1
- package/dist/schemas/bundled/testing.json +145 -1
- package/dist/schemas/bundled/ux.json +1 -1
- package/dist/server/server.js +508 -237
- package/dist/server/server.js.map +3 -3
- package/dist/server/viewer-registry.js +264 -0
- package/dist/server/viewer-registry.js.map +7 -0
- package/dist/telemetry/index.js +1 -1
- package/dist/utils/id-generator.js +5 -2
- package/dist/utils/id-generator.js.map +2 -2
- package/dist/utils/source-reference.js +58 -27
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +2 -2
- package/dist/utils/spec-version.js.map +1 -1
- package/dist/validators/model-warnings.js +28 -0
- package/dist/validators/model-warnings.js.map +7 -0
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CUOQGGRA.css +1 -0
- package/dist/viewer/assets/main-DvH3gYrI.js +84 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +1 -1
- package/dist/viewer/assets/main-CxzcuU_o.js +0 -84
- package/dist/viewer/assets/main-j-7ULYpm.css +0 -1
|
@@ -9,7 +9,7 @@ async function changesetVerifyCommand(planned, options = {}) {
|
|
|
9
9
|
json ? console.log(JSON.stringify({ status: "error", code: 1, message })) : (console.error(ansis.red(`Error: ${message}`)), hint && console.error(ansis.dim(hint))), process.exit(1);
|
|
10
10
|
};
|
|
11
11
|
try {
|
|
12
|
-
options.against && options.base && fail("Pass either --against <changeset> or --base, not both"), !options.against && !options.base && fail("Nothing to verify against", "Use --against <changeset> to compare with an as-built changeset, or --base to compare with the base model");
|
|
12
|
+
options.against && options.base && fail("Pass either --against <changeset> or --base, not both"), options.extracted && !options.base && fail("--extracted goes with --base"), !options.against && !options.base && fail("Nothing to verify against", "Use --against <changeset> to compare with an as-built changeset, or --base to compare with the base model");
|
|
13
13
|
const model = await Model.load(options.model, { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), load = async (name, role) => {
|
|
14
14
|
const changeset = await manager.load(name);
|
|
15
15
|
return changeset || fail(`${role} changeset '${name}' not found`, "Run 'dr changeset list' to see changesets");
|
|
@@ -18,7 +18,7 @@ async function changesetVerifyCommand(planned, options = {}) {
|
|
|
18
18
|
return fail("No changeset named and none is active", "Pass the planned changeset's name or ID");
|
|
19
19
|
const plannedChangeset = await load(plannedName, "Planned"), asBuilt = options.against ? await load(options.against, "As-built") : void 0, report = await verifyChangesetInModel(model, {
|
|
20
20
|
planned: plannedChangeset,
|
|
21
|
-
against: asBuilt ? { changeset: asBuilt } : { base: !0 },
|
|
21
|
+
against: asBuilt ? { changeset: asBuilt } : { base: !0, extracted: options.extracted === !0 },
|
|
22
22
|
matchBySource: options.matchBySource
|
|
23
23
|
});
|
|
24
24
|
console.log(json ? JSON.stringify(report, null, 2) : formatVerifyReport(report));
|
|
@@ -26,12 +26,18 @@ async function changesetVerifyCommand(planned, options = {}) {
|
|
|
26
26
|
fail(getErrorMessage(error));
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
const rel = (r) => `${r.source} --${r.predicate}--> ${r.target}`, value = (v) => v
|
|
29
|
+
const rel = (r) => `${r.source} --${r.predicate}--> ${r.target}`, value = (v) => v == null ? "(none)" : JSON.stringify(v);
|
|
30
30
|
function formatVerifyReport(report) {
|
|
31
|
-
const lines = [], verdictColor = report.verdict === "match" ? ansis.green : report.verdict === "probable-match" ? ansis.cyan : report.verdict === "diverges" ? ansis.yellow : report.verdict === "incomplete" ? ansis.red : ansis.dim;
|
|
31
|
+
const lines = [], verdictColor = report.verdict === "match" ? ansis.green : report.verdict === "probable-match" ? ansis.cyan : report.verdict === "diverges" ? ansis.yellow : report.verdict === "incomplete" ? ansis.red : ansis.dim, unverifiable = (n) => n > 0 ? `, ${n} unverifiable` : "";
|
|
32
32
|
lines.push(ansis.bold(`Verify: ${report.planned.label} vs ${report.against.label}`)), lines.push(verdictColor(`${report.verdict}: ${report.verdictText}`));
|
|
33
33
|
const e = report.summary.elements, r = report.summary.relationships;
|
|
34
|
-
lines.push(ansis.dim(`Elements: ${e.planned} planned, ${e.matched} matched (${e.divergent} with differences), ${e.missing} missing, ${e.unplanned} unplanned, ${e.deletionsNotDone} deletions not done (${e.probable} probable)`)), lines.push(ansis.dim(`Relationships: ${r.planned} planned, ${r.matched} matched (${r.divergent} with differences), ${r.missing} missing, ${r.unplanned} unplanned, ${r.deletionsNotDone} deletions not done (${r.probable} probable)`));
|
|
34
|
+
lines.push(ansis.dim(`Elements: ${e.planned} planned, ${e.matched} matched (${e.divergent} with differences), ${e.missing} missing${unverifiable(e.unverifiable)}, ${e.unplanned} unplanned, ${e.deletionsNotDone} deletions not done (${e.probable} probable)`)), lines.push(ansis.dim(`Relationships: ${r.planned} planned, ${r.matched} matched (${r.divergent} with differences), ${r.missing} missing${unverifiable(r.unverifiable)}, ${r.unplanned} unplanned, ${r.deletionsNotDone} deletions not done (${r.probable} probable)`));
|
|
35
|
+
const share = report.extraction?.asBuilt;
|
|
36
|
+
if (share) {
|
|
37
|
+
const provenance = Object.entries(share.elements.byProvenance).map(([k, n]) => `${n} ${k}`).join(", ");
|
|
38
|
+
lines.push(ansis.dim(`As-built: ${share.elements.total} elements (${provenance || "none"} declared; ${share.elements.fromExtraction} from extraction, ${share.elements.agentAdded} added by the agent), ${share.relationships.total} relationships (${share.relationships.betweenExtracted} between extracted elements)`));
|
|
39
|
+
}
|
|
40
|
+
report.warning && lines.push(ansis.yellow(`Warning: ${report.warning}`));
|
|
35
41
|
const section = (title, items) => {
|
|
36
42
|
if (items.length !== 0) {
|
|
37
43
|
lines.push("", ansis.bold(title));
|
|
@@ -41,10 +47,12 @@ function formatVerifyReport(report) {
|
|
|
41
47
|
}, probable = (m) => m.match === "probable" ? ansis.cyan(` [probable: ${m.reason}]`) : "";
|
|
42
48
|
return section("Missing elements (planned, not built)", report.elements.missing.map((m) => `${ansis.red("-")} ${m.planned} (${m.op}): ${m.reason}` + (m.candidates ? `
|
|
43
49
|
candidates: ${m.candidates.join(", ")}` : "") + (m.fields ? m.fields.map((f) => `
|
|
44
|
-
${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join("") : ""))), section("Divergent elements", report.elements.divergent.map((d) => `${ansis.yellow("~")} ${d.planned}${d.built !== d.planned ? ` \u2192 ${d.built}` : ""}${probable(d)}` + d.fields.map((f) => `
|
|
50
|
+
${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join("") : ""))), section("Unverifiable elements (extraction can't see them)", report.elements.unverifiable.map((u) => `${ansis.dim("?")} ${u.planned} (${u.op}): ${u.reason}`)), section("Divergent elements", report.elements.divergent.map((d) => `${ansis.yellow("~")} ${d.planned}${d.built !== d.planned ? ` \u2192 ${d.built}` : ""}${probable(d)}` + d.fields.map((f) => `
|
|
45
51
|
${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join(""))), section("Planned deletions that still exist", report.elements.deletionsNotDone.map((d) => `${ansis.red("!")} ${d.built}`)), section("Unplanned elements (built, not planned)", report.elements.unplanned.map((u) => `${ansis.yellow("+")} ${u.id} (${u.change})`)), section("Matched elements", report.elements.matched.map((m) => `${ansis.green("\u2713")} ${m.planned}${m.built !== m.planned ? ` \u2192 ${m.built}` : ""} (${m.op})${probable(m)}` + (m.lifecycle ?? []).map((f) => ansis.dim(`
|
|
46
|
-
${f.field}: ${value(f.planned)} \u2192 ${value(f.built)} (lifecycle)`)).join("")
|
|
47
|
-
|
|
52
|
+
${f.field}: ${value(f.planned)} \u2192 ${value(f.built)} (lifecycle)`)).join("") + (m.notes ?? []).map((f) => ansis.dim(`
|
|
53
|
+
${f.field} differs (note): built ${value(f.built)}`)).join("") + (m.unverifiableFields ?? []).map((f) => ansis.dim(`
|
|
54
|
+
${f.field}: planned ${value(f.planned)} (extraction doesn't write it)`)).join(""))), section("Missing relationships", report.relationships.missing.map((m) => `${ansis.red("-")} ${rel(m.planned)}: ${m.reason}` + (m.candidates ? `
|
|
55
|
+
candidates: ${m.candidates.map(rel).join(", ")}` : ""))), section("Unverifiable relationships (extraction can't see them)", report.relationships.unverifiable.map((u) => `${ansis.dim("?")} ${rel(u.planned)}: ${u.reason}`)), section("Divergent relationships", report.relationships.divergent.map((d) => `${ansis.yellow("~")} ${rel(d.planned)} built as ${rel(d.built)}${probable(d)}` + d.fields.map((f) => `
|
|
48
56
|
${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join(""))), section("Planned relationship deletions that still exist", report.relationships.deletionsNotDone.map((d) => `${ansis.red("!")} ${rel(d.built)}`)), section("Unplanned relationships", report.relationships.unplanned.map((u) => `${ansis.yellow("+")} ${rel(u)} (${u.change})`)), section("Matched relationships", report.relationships.matched.map((m) => `${ansis.green("\u2713")} ${rel(m.built)} (${m.op})${probable(m)}`)), section("Notes", report.notes.map((n) => ansis.dim(n))), lines.join(`
|
|
49
57
|
`);
|
|
50
58
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/changeset-verify.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * dr changeset verify \u2014 compare a planned changeset with what was built (another changeset, or the\n * base model). The same comparison as the `changeset_verify` MCP tool; see\n * `cli/src/core/changeset-verify.ts`.\n */\n\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { verifyChangesetInModel, type VerifyReport } from \"../core/changeset-verify.js\";\nimport type { Changeset } from \"../core/changeset.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { isJson } from \"../utils/globals.js\";\n\nexport interface ChangesetVerifyOptions {\n model?: string;\n against?: string;\n base?: boolean;\n json?: boolean;\n matchBySource?: boolean;\n}\n\nexport async function changesetVerifyCommand(\n planned: string | undefined,\n options: ChangesetVerifyOptions = {}\n): Promise<void> {\n const json = options.json === true || isJson();\n const fail = (message: string, hint?: string): never => {\n if (json) {\n console.log(JSON.stringify({ status: \"error\", code: 1, message }));\n } else {\n console.error(ansis.red(`Error: ${message}`));\n if (hint) console.error(ansis.dim(hint));\n }\n process.exit(1);\n };\n\n try {\n if (options.against && options.base) {\n fail(\"Pass either --against <changeset> or --base, not both\");\n }\n if (!options.against && !options.base) {\n fail(\n \"Nothing to verify against\",\n \"Use --against <changeset> to compare with an as-built changeset, or --base to compare with the base model\"\n );\n }\n\n const model = await Model.load(options.model, { lazyLoad: false });\n const manager = new StagingAreaManager(model.rootPath, model);\n const load = async (name: string, role: string): Promise<Changeset> => {\n const changeset = await manager.load(name);\n if (!changeset) return fail(`${role} changeset '${name}' not found`, \"Run 'dr changeset list' to see changesets\");\n return changeset;\n };\n\n const plannedName = planned ?? (await manager.getActiveId());\n if (!plannedName) {\n return fail(\"No changeset named and none is active\", \"Pass the planned changeset's name or ID\");\n }\n const plannedChangeset = await load(plannedName, \"Planned\");\n const asBuilt = options.against ? await load(options.against, \"As-built\") : undefined;\n\n const report = await verifyChangesetInModel(model, {\n planned: plannedChangeset,\n against: asBuilt ? { changeset: asBuilt } : { base: true },\n matchBySource: options.matchBySource,\n });\n\n if (json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(formatVerifyReport(report));\n }\n } catch (error) {\n fail(getErrorMessage(error));\n }\n}\n\nconst rel = (r: { source: string; predicate: string; target: string }) => `${r.source} --${r.predicate}--> ${r.target}`;\nconst value = (v: unknown) => (v === undefined ? \"(none)\" : JSON.stringify(v));\n\n/** Human-readable rendering of a verify report. */\nexport function formatVerifyReport(report: VerifyReport): string {\n const lines: string[] = [];\n const verdictColor =\n report.verdict === \"match\"\n ? ansis.green\n : report.verdict === \"probable-match\"\n ? ansis.cyan\n : report.verdict === \"diverges\"\n ? ansis.yellow\n : report.verdict === \"incomplete\"\n ? ansis.red\n : ansis.dim;\n\n lines.push(ansis.bold(`Verify: ${report.planned.label} vs ${report.against.label}`));\n lines.push(verdictColor(`${report.verdict}: ${report.verdictText}`));\n const e = report.summary.elements;\n const r = report.summary.relationships;\n lines.push(\n ansis.dim(\n `Elements: ${e.planned} planned, ${e.matched} matched (${e.divergent} with differences), ${e.missing} missing
|
|
5
|
-
"mappings": "AAMA,OAAO,WAAW;AAClB,SAAS,aAAa;AACtB,SAAS,0BAA0B;AACnC,SAAS,8BAAiD;AAE1D,SAAS,uBAAuB;AAChC,SAAS,cAAc;
|
|
4
|
+
"sourcesContent": ["/**\n * dr changeset verify \u2014 compare a planned changeset with what was built (another changeset, or the\n * base model). The same comparison as the `changeset_verify` MCP tool; see\n * `cli/src/core/changeset-verify.ts`.\n */\n\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { verifyChangesetInModel, type VerifyReport } from \"../core/changeset-verify.js\";\nimport type { Changeset } from \"../core/changeset.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { isJson } from \"../utils/globals.js\";\n\nexport interface ChangesetVerifyOptions {\n model?: string;\n against?: string;\n base?: boolean;\n /** With base: apply the extraction rule (the as-built side landed from codebase_extract). */\n extracted?: boolean;\n json?: boolean;\n matchBySource?: boolean;\n}\n\nexport async function changesetVerifyCommand(\n planned: string | undefined,\n options: ChangesetVerifyOptions = {}\n): Promise<void> {\n const json = options.json === true || isJson();\n const fail = (message: string, hint?: string): never => {\n if (json) {\n console.log(JSON.stringify({ status: \"error\", code: 1, message }));\n } else {\n console.error(ansis.red(`Error: ${message}`));\n if (hint) console.error(ansis.dim(hint));\n }\n process.exit(1);\n };\n\n try {\n if (options.against && options.base) {\n fail(\"Pass either --against <changeset> or --base, not both\");\n }\n if (options.extracted && !options.base) {\n fail(\"--extracted goes with --base\");\n }\n if (!options.against && !options.base) {\n fail(\n \"Nothing to verify against\",\n \"Use --against <changeset> to compare with an as-built changeset, or --base to compare with the base model\"\n );\n }\n\n const model = await Model.load(options.model, { lazyLoad: false });\n const manager = new StagingAreaManager(model.rootPath, model);\n const load = async (name: string, role: string): Promise<Changeset> => {\n const changeset = await manager.load(name);\n if (!changeset) return fail(`${role} changeset '${name}' not found`, \"Run 'dr changeset list' to see changesets\");\n return changeset;\n };\n\n const plannedName = planned ?? (await manager.getActiveId());\n if (!plannedName) {\n return fail(\"No changeset named and none is active\", \"Pass the planned changeset's name or ID\");\n }\n const plannedChangeset = await load(plannedName, \"Planned\");\n const asBuilt = options.against ? await load(options.against, \"As-built\") : undefined;\n\n const report = await verifyChangesetInModel(model, {\n planned: plannedChangeset,\n against: asBuilt ? { changeset: asBuilt } : { base: true, extracted: options.extracted === true },\n matchBySource: options.matchBySource,\n });\n\n if (json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(formatVerifyReport(report));\n }\n } catch (error) {\n fail(getErrorMessage(error));\n }\n}\n\nconst rel = (r: { source: string; predicate: string; target: string }) => `${r.source} --${r.predicate}--> ${r.target}`;\nconst value = (v: unknown) => (v === undefined || v === null ? \"(none)\" : JSON.stringify(v));\n\n/** Human-readable rendering of a verify report. */\nexport function formatVerifyReport(report: VerifyReport): string {\n const lines: string[] = [];\n const verdictColor =\n report.verdict === \"match\"\n ? ansis.green\n : report.verdict === \"probable-match\"\n ? ansis.cyan\n : report.verdict === \"diverges\"\n ? ansis.yellow\n : report.verdict === \"incomplete\"\n ? ansis.red\n : ansis.dim;\n const unverifiable = (n: number) => (n > 0 ? `, ${n} unverifiable` : \"\");\n\n lines.push(ansis.bold(`Verify: ${report.planned.label} vs ${report.against.label}`));\n lines.push(verdictColor(`${report.verdict}: ${report.verdictText}`));\n const e = report.summary.elements;\n const r = report.summary.relationships;\n lines.push(\n ansis.dim(\n `Elements: ${e.planned} planned, ${e.matched} matched (${e.divergent} with differences), ${e.missing} missing` +\n `${unverifiable(e.unverifiable)}, ${e.unplanned} unplanned, ${e.deletionsNotDone} deletions not done (${e.probable} probable)`\n )\n );\n lines.push(\n ansis.dim(\n `Relationships: ${r.planned} planned, ${r.matched} matched (${r.divergent} with differences), ${r.missing} missing` +\n `${unverifiable(r.unverifiable)}, ${r.unplanned} unplanned, ${r.deletionsNotDone} deletions not done (${r.probable} probable)`\n )\n );\n const share = report.extraction?.asBuilt;\n if (share) {\n const provenance = Object.entries(share.elements.byProvenance)\n .map(([k, n]) => `${n} ${k}`)\n .join(\", \");\n lines.push(\n ansis.dim(\n `As-built: ${share.elements.total} elements (${provenance || \"none\"} declared; ${share.elements.fromExtraction} ` +\n `from extraction, ${share.elements.agentAdded} added by the agent), ${share.relationships.total} relationships ` +\n `(${share.relationships.betweenExtracted} between extracted elements)`\n )\n );\n }\n if (report.warning) lines.push(ansis.yellow(`Warning: ${report.warning}`));\n\n const section = (title: string, items: string[]) => {\n if (items.length === 0) return;\n lines.push(\"\", ansis.bold(title));\n for (const item of items) lines.push(` ${item}`);\n };\n const probable = (m: { match: string; reason?: string }) => (m.match === \"probable\" ? ansis.cyan(` [probable: ${m.reason}]`) : \"\");\n\n section(\n \"Missing elements (planned, not built)\",\n report.elements.missing.map(\n (m) =>\n `${ansis.red(\"-\")} ${m.planned} (${m.op}): ${m.reason}` +\n (m.candidates ? `\\n candidates: ${m.candidates.join(\", \")}` : \"\") +\n (m.fields ? m.fields.map((f) => `\\n ${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join(\"\") : \"\")\n )\n );\n section(\n \"Unverifiable elements (extraction can't see them)\",\n report.elements.unverifiable.map((u) => `${ansis.dim(\"?\")} ${u.planned} (${u.op}): ${u.reason}`)\n );\n section(\n \"Divergent elements\",\n report.elements.divergent.map(\n (d) =>\n `${ansis.yellow(\"~\")} ${d.planned}${d.built !== d.planned ? ` \u2192 ${d.built}` : \"\"}${probable(d)}` +\n d.fields.map((f) => `\\n ${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join(\"\")\n )\n );\n section(\n \"Planned deletions that still exist\",\n report.elements.deletionsNotDone.map((d) => `${ansis.red(\"!\")} ${d.built}`)\n );\n section(\n \"Unplanned elements (built, not planned)\",\n report.elements.unplanned.map((u) => `${ansis.yellow(\"+\")} ${u.id} (${u.change})`)\n );\n section(\n \"Matched elements\",\n report.elements.matched.map(\n (m) =>\n `${ansis.green(\"\u2713\")} ${m.planned}${m.built !== m.planned ? ` \u2192 ${m.built}` : \"\"} (${m.op})${probable(m)}` +\n (m.lifecycle ?? []).map((f) => ansis.dim(`\\n ${f.field}: ${value(f.planned)} \u2192 ${value(f.built)} (lifecycle)`)).join(\"\") +\n (m.notes ?? []).map((f) => ansis.dim(`\\n ${f.field} differs (note): built ${value(f.built)}`)).join(\"\") +\n (m.unverifiableFields ?? [])\n .map((f) => ansis.dim(`\\n ${f.field}: planned ${value(f.planned)} (extraction doesn't write it)`))\n .join(\"\")\n )\n );\n\n section(\n \"Missing relationships\",\n report.relationships.missing.map(\n (m) =>\n `${ansis.red(\"-\")} ${rel(m.planned)}: ${m.reason}` +\n (m.candidates ? `\\n candidates: ${m.candidates.map(rel).join(\", \")}` : \"\")\n )\n );\n section(\n \"Unverifiable relationships (extraction can't see them)\",\n report.relationships.unverifiable.map((u) => `${ansis.dim(\"?\")} ${rel(u.planned)}: ${u.reason}`)\n );\n section(\n \"Divergent relationships\",\n report.relationships.divergent.map(\n (d) =>\n `${ansis.yellow(\"~\")} ${rel(d.planned)} built as ${rel(d.built)}${probable(d)}` +\n d.fields.map((f) => `\\n ${f.field}: planned ${value(f.planned)}, built ${value(f.built)}`).join(\"\")\n )\n );\n section(\n \"Planned relationship deletions that still exist\",\n report.relationships.deletionsNotDone.map((d) => `${ansis.red(\"!\")} ${rel(d.built)}`)\n );\n section(\n \"Unplanned relationships\",\n report.relationships.unplanned.map((u) => `${ansis.yellow(\"+\")} ${rel(u)} (${u.change})`)\n );\n section(\n \"Matched relationships\",\n report.relationships.matched.map((m) => `${ansis.green(\"\u2713\")} ${rel(m.built)} (${m.op})${probable(m)}`)\n );\n\n section(\n \"Notes\",\n report.notes.map((n) => ansis.dim(n))\n );\n return lines.join(\"\\n\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,7 +8,7 @@ import { Option } from "commander";
|
|
|
8
8
|
import * as prompts from "@clack/prompts";
|
|
9
9
|
import path from "path";
|
|
10
10
|
import { isTelemetryEnabled, startSpan, endSpan, startActiveSpan } from "../telemetry/index.js";
|
|
11
|
-
import { getErrorMessage, handleSuccess, handleInfo, handleWarning } from "../utils/errors.js";
|
|
11
|
+
import { CLIError, ErrorCategory, getErrorMessage, handleSuccess, handleInfo, handleWarning } from "../utils/errors.js";
|
|
12
12
|
import { isJson } from "../utils/globals.js";
|
|
13
13
|
import { findElementLayer } from "../utils/element-utils.js";
|
|
14
14
|
import { changesetVerifyCommand } from "./changeset-verify.js";
|
|
@@ -543,9 +543,29 @@ Diff: Base Model vs Staged Changes
|
|
|
543
543
|
endSpan(span);
|
|
544
544
|
}
|
|
545
545
|
}
|
|
546
|
-
async function changesetCommitCommand(options) {
|
|
546
|
+
async function changesetCommitCommand(nameOrId, options) {
|
|
547
|
+
let restoreActive = null;
|
|
548
|
+
const restore = async () => {
|
|
549
|
+
if (!restoreActive)
|
|
550
|
+
return;
|
|
551
|
+
const { rootPath, previous } = restoreActive;
|
|
552
|
+
restoreActive = null;
|
|
553
|
+
const probe = await Model.load(rootPath, { lazyLoad: !0 }), manager = new StagingAreaManager(probe.rootPath, probe), prior = previous ? await manager.load(previous) : null;
|
|
554
|
+
prior?.status === "staged" ? (await manager.setActive(previous), isJson() || console.log(ansis.dim(`Changeset '${prior.name}' is active again.`))) : await manager.clearActive();
|
|
555
|
+
};
|
|
547
556
|
await startActiveSpan("changeset.commit", async (span) => {
|
|
548
557
|
try {
|
|
558
|
+
if (nameOrId) {
|
|
559
|
+
const probe = await Model.load(options?.model, { lazyLoad: !0 }), probeManager = new StagingAreaManager(probe.rootPath, probe), target = await probeManager.load(nameOrId);
|
|
560
|
+
if (!target || !target.id)
|
|
561
|
+
throw new CLIError(`Changeset '${nameOrId}' not found`, ErrorCategory.USER, [
|
|
562
|
+
'Run "dr changeset list" to see changesets by name and id'
|
|
563
|
+
]);
|
|
564
|
+
if (target.status !== "staged")
|
|
565
|
+
throw new CLIError(`Changeset '${target.name}' is ${target.status}; only a staged changeset can be committed`, ErrorCategory.USER, ['Run "dr changeset list" to find a staged changeset']);
|
|
566
|
+
const activeId = await probeManager.getActiveId();
|
|
567
|
+
activeId !== target.id && (restoreActive = { rootPath: probe.rootPath, previous: activeId }, await probeManager.setActive(target.id));
|
|
568
|
+
}
|
|
549
569
|
const model = await Model.load(options?.model, { lazyLoad: !1 }), stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId();
|
|
550
570
|
if (!activeChangesetId) {
|
|
551
571
|
isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span.setStatus({ code: 2, message: "No active changeset" });
|
|
@@ -559,7 +579,7 @@ async function changesetCommitCommand(options) {
|
|
|
559
579
|
name: changeset.name,
|
|
560
580
|
changesetId: activeChangesetId,
|
|
561
581
|
stagedChanges: 0
|
|
562
|
-
}, { verbose: !0 }), isTelemetryEnabled && span.setStatus({ code: 0 });
|
|
582
|
+
}, { verbose: !0 }), await restore(), isTelemetryEnabled && span.setStatus({ code: 0 });
|
|
563
583
|
return;
|
|
564
584
|
}
|
|
565
585
|
isJson() || (console.log(ansis.bold(`
|
|
@@ -583,15 +603,20 @@ Committing changeset: ${ansis.cyan(changeset.name)}`)), console.log(ansis.dim(`S
|
|
|
583
603
|
const unaccounted = changeCount - accountedFor;
|
|
584
604
|
commitDetails.unaccountedChanges = unaccounted, isJson() || console.log(ansis.yellow(`\u26A0 Warning: ${unaccounted} staged change(s) were not applied, skipped, or reported as failed. This is unexpected \u2014 check the changeset log for details.`));
|
|
585
605
|
}
|
|
586
|
-
result.driftWarning && (commitDetails.driftDetected = !0, isJson() || console.log(ansis.yellow("\u26A0 Warning: Model had drifted since changeset creation (--force was used)")), isTelemetryEnabled && span.setAttribute("commit.driftDetected", !0)), isTelemetryEnabled && span.setStatus({ code: 0 }), handleSuccess(`Committed ${result.committed} change(s)`, commitDetails, { verbose: !0 }), isJson() || console.log();
|
|
606
|
+
result.driftWarning && (commitDetails.driftDetected = !0, isJson() || console.log(ansis.yellow("\u26A0 Warning: Model had drifted since changeset creation (--force was used)")), isTelemetryEnabled && span.setAttribute("commit.driftDetected", !0)), isTelemetryEnabled && span.setStatus({ code: 0 }), handleSuccess(`Committed ${result.committed} change(s)`, commitDetails, { verbose: !0 }), await restore(), isJson() || console.log();
|
|
587
607
|
} catch (error) {
|
|
588
608
|
throw isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: `Commit failed and rolled back: ${getErrorMessage(error)}` })) : console.log(ansis.red(`\u2717 Commit failed and rolled back: ${getErrorMessage(error)}`)), isTelemetryEnabled && span.setAttribute("commit.rolledBack", !0), error;
|
|
589
609
|
}
|
|
590
610
|
} catch (error) {
|
|
591
|
-
isTelemetryEnabled && (span.recordException(error), span.setStatus({
|
|
611
|
+
if (isTelemetryEnabled && (span.recordException(error), span.setStatus({
|
|
592
612
|
code: 2,
|
|
593
613
|
message: getErrorMessage(error)
|
|
594
|
-
})), isJson()
|
|
614
|
+
})), isJson())
|
|
615
|
+
console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) }));
|
|
616
|
+
else if (console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), error instanceof CLIError && error.suggestions?.length)
|
|
617
|
+
for (const suggestion of error.suggestions)
|
|
618
|
+
console.error(ansis.dim(` ${suggestion}`));
|
|
619
|
+
await restore().catch((restoreError) => console.error(ansis.red(`Error: could not reactivate the previous changeset: ${getErrorMessage(restoreError)}`))), span.end(), process.exit(1);
|
|
595
620
|
}
|
|
596
621
|
}, {
|
|
597
622
|
"commit.validate": options?.validate !== !1,
|
|
@@ -744,16 +769,20 @@ Examples:
|
|
|
744
769
|
$ dr changeset diff
|
|
745
770
|
$ dr changeset diff --layer api`).action(async (options) => {
|
|
746
771
|
await changesetDiffCommand(options);
|
|
747
|
-
}), changesetGroup.command("commit").description("Apply
|
|
772
|
+
}), changesetGroup.command("commit [changeset]").description("Apply a changeset's staged changes to the base model (the active one, or the one named)").allowExcessArguments(!1).option("--model <path>", "Path to model root (contains model/manifest.yaml)").addOption(new Option("--validate", "Run validation before commit (default)").hideHelp()).option("--no-validate", "Skip validation before commit (validation runs by default; only errors the changeset introduces block, errors already in the base model are reported as a count)").option("--force", "Commit despite drift warnings (does not skip validation)", !1).addHelpText("after", `
|
|
748
773
|
Validation compares the model with and without the changeset. Errors the
|
|
749
774
|
changeset introduces block the commit; errors the base model already had are
|
|
750
775
|
not counted against it, and the output says how many there were.
|
|
751
776
|
|
|
777
|
+
A named changeset (id or name) need not be active: it is activated for the
|
|
778
|
+
commit, and the changeset that was active before is active again afterwards.
|
|
779
|
+
|
|
752
780
|
Examples:
|
|
753
781
|
$ dr changeset commit
|
|
782
|
+
$ dr changeset commit add-order-api # commit the changeset named add-order-api
|
|
754
783
|
$ dr changeset commit --force # commit despite drift
|
|
755
|
-
$ dr changeset commit --no-validate # skip validation entirely`).action(async (options) => {
|
|
756
|
-
await changesetCommitCommand(options);
|
|
784
|
+
$ dr changeset commit --no-validate # skip validation entirely`).action(async (name, options) => {
|
|
785
|
+
await changesetCommitCommand(name, options);
|
|
757
786
|
}), changesetGroup.command("export <changeset-id>").description("Export changeset to portable file").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Export format (yaml|json|patch)", "yaml").addHelpText("after", `
|
|
758
787
|
Examples:
|
|
759
788
|
$ dr changeset export api-updates
|
|
@@ -767,12 +796,13 @@ Examples:
|
|
|
767
796
|
$ dr changeset import ../team-changes.json
|
|
768
797
|
$ dr changeset import changes.yaml --force`).action(async (file, options) => {
|
|
769
798
|
await changesetImportCommand(file, options);
|
|
770
|
-
}), changesetGroup.command("verify [planned]").description("Compare a planned changeset with what was built (an as-built changeset, or the base model)").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--against <changeset>", "As-built changeset (ID or name) to compare with").option("--base", "Compare with the base model").option("--no-match-by-source", "Do not match elements by shared source file").option("--json", "Output as JSON").addHelpText("after", `
|
|
799
|
+
}), changesetGroup.command("verify [planned]").description("Compare a planned changeset with what was built (an as-built changeset, or the base model)").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--against <changeset>", "As-built changeset (ID or name) to compare with").option("--base", "Compare with the base model").option("--extracted", "With --base: the as-built side landed from codebase_extract, so planned parts extraction can't observe are unverifiable, not missing").option("--no-match-by-source", "Do not match elements by shared source file").option("--json", "Output as JSON").addHelpText("after", `
|
|
771
800
|
The planned changeset defaults to the active one.
|
|
772
801
|
|
|
773
802
|
Examples:
|
|
774
803
|
$ dr changeset verify export-orders --against export-orders-as-built
|
|
775
|
-
$ dr changeset verify export-orders --base --json
|
|
804
|
+
$ dr changeset verify export-orders --base --json
|
|
805
|
+
$ dr changeset verify export-orders --base --extracted`).action(async (planned, options) => {
|
|
776
806
|
await changesetVerifyCommand(planned, options);
|
|
777
807
|
}), changesetGroup.showSuggestionAfterError();
|
|
778
808
|
}
|