@sdd-method/author-cli 0.1.0 → 0.2.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/NOTICE CHANGED
@@ -2,7 +2,7 @@ sdd-cli
2
2
  Copyright 2026 Tom Foster
3
3
 
4
4
  This product includes software developed as part of the SDD method
5
- distribution (https://github.com/tomfosteruk/sdd-method).
5
+ distribution.
6
6
 
7
7
  Licensed under the Apache License, Version 2.0 (the "License");
8
8
  you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@ import { registerPlan } from "./verbs/plan.js";
26
26
  import { registerRender } from "./verbs/render.js";
27
27
  import { registerScaffold } from "./verbs/scaffold.js";
28
28
  import { registerSnapshot } from "./verbs/snapshot.js";
29
- const SPEC_URL = "https://github.com/tomfosteruk/sdd-method/blob/main/docs/method/cli/sdd-cli-specification.md";
29
+ const SPEC_URL = "docs/method/cli/sdd-cli-specification.md (in the method distribution)";
30
30
  /** The verbs the author adds to verify, as `<verb>` or `<verb> <subcommand>` (M-ADR 0220 §4.2). Asserted by test. */
31
31
  export const AUTHOR_ONLY_SURFACE = [
32
32
  "scaffold domain",
@@ -1158,7 +1158,7 @@ async function collectRows(schema, manifest, findings, sddPath, snapshotStore) {
1158
1158
  out.set("repo_dependency", await buildRepoDependencies({ sddPath, configs: reposResult.configs, knownRepoIds: knownRepoIdsFinal, findings }));
1159
1159
  // 15. C4 systems + containers + components (L1 + L2 + L3). The L3 walker
1160
1160
  // shipped per `coordination/c4-l3-walker-and-path-convention-coordination.md`
1161
- // (sdd-method-gov, 2026-05-29) — forward-method authoring path reading
1161
+ // (method governance, 2026-05-29) — forward-method authoring path reading
1162
1162
  // `c4-l3-*.mermaid.md` files alongside the L2 layout. The earlier Path-B
1163
1163
  // deferral assumed reverse-method code-walking; this walker is the
1164
1164
  // forward-method analogue, granularity-agnostic (per-container or
@@ -6,7 +6,7 @@
6
6
  //
7
7
  // Mirrors c4-containers.ts at one level down. Source convention per
8
8
  // `coordination/c4-l3-walker-and-path-convention-coordination.md`
9
- // (sdd-method-gov, 2026-05-29). The walker is granularity-agnostic — both
9
+ // (method governance, 2026-05-29). The walker is granularity-agnostic — both
10
10
  // per-container files (one `Container_Boundary` block per file) and
11
11
  // per-domain rollup files (multiple `Container_Boundary` blocks per file)
12
12
  // produce identical row output. Adopters pick the file shape that suits
@@ -219,7 +219,7 @@ function slugify(s) {
219
219
  }
220
220
  /**
221
221
  * F21: two technology strings flatly contradict when both are present and
222
- * share no token — ".NET 6 (in Linton)" vs "Java" needs no NLP. Absent or
222
+ * share no token — ".NET 6 (in Kestrel)" vs "Java" needs no NLP. Absent or
223
223
  * overlapping strings are NOT a contradiction (silence, not a guess).
224
224
  */
225
225
  export function techContradicts(a, b) {
@@ -20,7 +20,7 @@
20
20
  // personas instead of the sibling's. c4-external-systems UNIONS every
21
21
  // existing L1 file rather than picking one, so candidate order is irrelevant
22
22
  // there; it shares these paths only to avoid a divergent copy.
23
- // See sdd-method-gov/coordination/persona-c4system-l1-priority-bug-coordination.md.
23
+ // See the method's coordination record persona-c4system-l1-priority-bug.
24
24
  import { readdir, stat } from "node:fs/promises";
25
25
  import { join } from "node:path";
26
26
  /** Own-L1 candidates usable by ANY SDD, in priority order. */
@@ -121,7 +121,7 @@ export async function buildContainerDependency(inputs) {
121
121
  * SAME referent and fired. The predicate was inverted on the two
122
122
  * name-shapes the estate actually uses.
123
123
  *
124
- * The independent channel is the technology string: ".NET 6 (in Linton)"
124
+ * The independent channel is the technology string: ".NET 6 (in Kestrel)"
125
125
  * against "Java" is a flat contradiction and needs no NLP. A dual-use
126
126
  * entry-id (Container + System_Ext in one SDD) whose technologies
127
127
  * contradict draws the finding REGARDLESS of what the names say — name
@@ -71,7 +71,7 @@ export function collectTableLines(lines, startIdx) {
71
71
  return null;
72
72
  }
73
73
  // ADR 0164: map a Data Store Mapping `Store` cell (a physical engine such as
74
- // "MySQL (fleet-db)", "MongoDB", "DynamoDB", "Kinesis") to the canonical
74
+ // "MySQL (orders-db)", "MongoDB", "DynamoDB", "Kinesis") to the canonical
75
75
  // `entities.persistence_kind` classification. This mirrors the services
76
76
  // builder's deriveLanguage (a normalised token derived from a raw cell) —
77
77
  // faithful classification, not a verbatim engine. The raw engine string is
@@ -35,7 +35,7 @@ const STRING_RE = /"[^"]*"|'[^']*'/g;
35
35
  * line-structure-preserving) so call-head lexing can never fire on quoted
36
36
  * content — `Table("Odometer (km)")` must not mint a phantom `Odometer`
37
37
  * component, and `"total (sum)"` must not false-fire the lowercase-call-head
38
- * finding (tomfosteruk/sdd-cli#1). Quote characters are kept; newlines inside
38
+ * finding (sdd-cli issue 1). Quote characters are kept; newlines inside
39
39
  * a span survive. The grammar defines no escape sequences (a quote always
40
40
  * closes the literal), matching STRING_RE and stripLineComment.
41
41
  *
@@ -171,7 +171,7 @@ export const RUBRIC_ELIGIBILITY = [
171
171
  joinColumn: "id",
172
172
  refTransform: null,
173
173
  eligibilityFilter: null,
174
- eligibilityNote: "NO local population, measured rather than assumed. Refs are '<domain>-feature-grounding-<slug>' and the tails are SIBLING SDD SLUGS (app-shell, cold-chain, connect-rapide), not rows in this SDD: 0/15 against products, applications, features and repositories, and 1/15 against capabilities — a coincidence, not a join. A cross-SDD reference the member tier cannot resolve, so its coverage is declared unmeasurable rather than given a transform that would produce plausible wrong numbers.",
174
+ eligibilityNote: "NO local population, measured rather than assumed. Refs are '<domain>-feature-grounding-<slug>' and the tails are SIBLING SDD SLUGS (app-shell, gift-cards, storefront-express), not rows in this SDD: 0/15 against products, applications, features and repositories, and 1/15 against capabilities — a coincidence, not a join. A cross-SDD reference the member tier cannot resolve, so its coverage is declared unmeasurable rather than given a transform that would produce plausible wrong numbers.",
175
175
  },
176
176
  {
177
177
  rubricId: "reverse-contract-quality",
@@ -27,7 +27,7 @@
27
27
  * # services). Use when the federated SDD lacks a services.csv to
28
28
  * # gate emission and consumes rows would otherwise dangle at the
29
29
  * # aggregator with unresolved service_id.
30
- * - postman-tacho
30
+ * - postman-stock
31
31
  * - smoke-tests
32
32
  *
33
33
  * same_product_inference:
@@ -66,6 +66,8 @@ export function serialiseLockFile(lock) {
66
66
  ...(lock.ciRunner !== undefined ? [`ci_runner: "${lock.ciRunner}"`] : []),
67
67
  ...(lock.ciWorkflowBlockSha256 !== undefined ? [`ci_workflow_block_sha256: "${lock.ciWorkflowBlockSha256}"`] : []),
68
68
  ...(lock.ciModuleSha256 !== undefined ? [`ci_module_sha256: "${lock.ciModuleSha256}"`] : []),
69
+ ...(lock.cliSource !== undefined ? [`cli_source: ${lock.cliSource}`] : []),
70
+ ...(lock.cliPackage !== undefined ? [`cli_package: "${lock.cliPackage}"`] : []),
69
71
  "bundles:",
70
72
  ];
71
73
  for (const b of lock.bundles) {
@@ -117,6 +119,8 @@ function parseVersioned(raw) {
117
119
  let ciBinding;
118
120
  let ciRunner;
119
121
  let ciModuleSha256;
122
+ let cliSource;
123
+ let cliPackage;
120
124
  const bundles = [];
121
125
  let inBundles = false;
122
126
  let inPaths = false;
@@ -186,6 +190,10 @@ function parseVersioned(raw) {
186
190
  ciRunner = stripQuotes(value);
187
191
  else if (key === "ci_module_sha256")
188
192
  ciModuleSha256 = stripQuotes(value);
193
+ else if (key === "cli_source")
194
+ cliSource = stripQuotes(value);
195
+ else if (key === "cli_package")
196
+ cliPackage = stripQuotes(value);
189
197
  }
190
198
  continue;
191
199
  }
@@ -313,6 +321,8 @@ function parseVersioned(raw) {
313
321
  ...(ciRunner !== undefined ? { ciRunner } : {}),
314
322
  ...(ciWorkflowBlockSha256 !== undefined ? { ciWorkflowBlockSha256 } : {}),
315
323
  ...(ciModuleSha256 !== undefined ? { ciModuleSha256 } : {}),
324
+ ...(cliSource !== undefined ? { cliSource } : {}),
325
+ ...(cliPackage !== undefined ? { cliPackage } : {}),
316
326
  };
317
327
  }
318
328
  function migrateV1(raw, legacyBundleName) {
@@ -68,7 +68,7 @@ export function routeFinding(f, artefacts, shared = new Set()) {
68
68
  const targets = new Map();
69
69
  const paths = [...f.files.added, ...f.files.removed, ...f.files.modified].filter(citable);
70
70
  // The key alone, or in export-folder form (`<key>-master@<rev>`): a hyphen may
71
- // follow it only as a branch suffix, so `tcu` never matches inside `tcu-collector`.
71
+ // follow it only as a branch suffix, so `scanner` never matches inside `scanner-collector`.
72
72
  const keyRe = new RegExp(`(^|[^A-Za-z0-9_-])${f.member.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(-(master|main|develop|trunk)@|[^A-Za-z0-9_-]|$)`);
73
73
  const cites = (text, p) => shared.has(p) ? text.split("\n").some((line) => line.includes(p) && keyRe.test(line)) : text.includes(p);
74
74
  // Folder-qualified — `<key>-<branch>@<rev>/<path>` — names the member AND the file,
@@ -25,7 +25,7 @@ const TITLES = {
25
25
  // CI has no platform checkout, so this step runs the app-only checks; the met gate needs the platform beside it.
26
26
  "app-dependencies": "Validate app dependencies (app-only checks; no platform checkout in CI)",
27
27
  };
28
- export function methodValidationPlan(profile) {
28
+ export function methodValidationPlan(profile, opts = {}) {
29
29
  const steps = validatorsForProfile(profile)
30
30
  .filter((v) => v.optional !== true)
31
31
  .map((v) => ({
@@ -38,12 +38,15 @@ export function methodValidationPlan(profile) {
38
38
  if (profile === "platform") {
39
39
  steps.push({ id: "cascade-completeness", title: "Validate cascade completeness", tool: "bash", args: ["orchestration/scripts/validate-cascade-completeness.sh", "all"], advisory: false }, { id: "architecture-alignment", title: "Validate architecture alignment", tool: "bash", args: ["orchestration/scripts/validate-architecture-alignment.sh"], advisory: false });
40
40
  }
41
+ const gating = opts.catalogueRebuild === true;
41
42
  steps.push({
42
43
  id: "catalogue-freshness",
43
- title: "Check catalogues reproduce from the specs (advisory)",
44
+ title: gating
45
+ ? "Check catalogues reproduce from the specs (gating: the pipeline rebuilt them)"
46
+ : "Check catalogues reproduce from the specs (advisory)",
44
47
  tool: "sdd-maintain",
45
48
  args: ["catalogue", "build", "--check", "--sdd-path", "."],
46
- advisory: true,
49
+ advisory: !gating,
47
50
  });
48
51
  return steps;
49
52
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.2.0",
3
- "built_against_sdd_cli": "1.43.0"
2
+ "version": "0.3.0",
3
+ "built_against_sdd_cli": "1.44.0"
4
4
  }
@@ -5,7 +5,7 @@ export function registerPlan(program) {
5
5
  .command("plan")
6
6
  .description("Scaffold a plan markdown file from a method-distributed template. Currently supports --pilot for pilot-kickoff plans; future subcommands may add --initiative / --migration.")
7
7
  .option("--pilot", "scaffold a pilot-kickoff plan (requires --service, --capability, --domain)", false)
8
- .option("--service <name>", "service / pilot name, e.g. party-management")
8
+ .option("--service <name>", "service / pilot name, e.g. customer-management")
9
9
  .option("--capability <name>", "capability under test, e.g. organization-management")
10
10
  .option("--domain <name>", "domain the capability belongs to, e.g. party")
11
11
  .option("--workspace-root <path>", "SDD root (defaults to cwd)", resolvePathOption)
@@ -14,7 +14,12 @@ export function registerValidate(program) {
14
14
  .option("--strict", "treat warnings as failures")
15
15
  .option("--list", "print the method-managed validation job for this repo's profile as JSON (the plan every CI executor runs, the Dagger module included) and run nothing")
16
16
  .option("--profile <profile>", "with --list: the profile to list, instead of reading .sdd-repo-kind (platform | application | integration)")
17
+ .option("--catalogue-rebuild", "with --list: the pipeline rebuilt the catalogues on this run (M-ADR 0220 §4.4), so the catalogue freshness step gates instead of advising")
17
18
  .action(async (opts) => {
19
+ if (opts.catalogueRebuild === true && opts.list !== true) {
20
+ process.stderr.write("--catalogue-rebuild only applies with --list\n");
21
+ process.exit(2);
22
+ }
18
23
  if (opts.list === true) {
19
24
  let profile;
20
25
  if (opts.profile !== undefined) {
@@ -32,7 +37,7 @@ export function registerValidate(program) {
32
37
  }
33
38
  profile = profileFromRepoKind(kind);
34
39
  }
35
- process.stdout.write(JSON.stringify({ profile, steps: methodValidationPlan(profile) }, null, 2) + "\n");
40
+ process.stdout.write(JSON.stringify({ profile, steps: methodValidationPlan(profile, { catalogueRebuild: opts.catalogueRebuild === true }) }, null, 2) + "\n");
36
41
  return;
37
42
  }
38
43
  const { exitCode } = await runValidate({
@@ -29,7 +29,7 @@ import { registerCatalogueBaselineCheck, registerCatalogueImpact, registerCatalo
29
29
  import { registerList } from "./verbs/list.js";
30
30
  import { registerPackValidate } from "./verbs/pack-validate.js";
31
31
  import { registerValidate } from "./verbs/validate.js";
32
- const SPEC_URL = "https://github.com/tomfosteruk/sdd-method/blob/main/docs/method/cli/sdd-cli-specification.md";
32
+ const SPEC_URL = "docs/method/cli/sdd-cli-specification.md (in the method distribution)";
33
33
  /** The full surface, as `<verb>` or `<verb> <subcommand>`. Asserted by test. */
34
34
  export const VERIFY_SURFACE = [
35
35
  "validate",
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.2.0",
3
- "built_against_sdd_cli": "1.43.0"
2
+ "version": "1.3.0",
3
+ "built_against_sdd_cli": "1.44.0"
4
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sdd-method/author-cli",
3
- "version": "0.1.0",
4
- "sddCliVersion": "1.43.0",
3
+ "version": "0.2.0",
4
+ "sddCliVersion": "1.44.0",
5
5
  "description": "Re-author one SDD's content — scaffold, plan, contracts, conformance, api-surface, snapshots, briefings, catalogue check — plus every read-only verify verb. Ships only the code those verbs reach; it cannot sync the baseline or rebuild the catalogues. Maintenance is in @sdd-method/maintain-cli, administration in @sdd-method/sdd-cli.",
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
@@ -17,10 +17,6 @@
17
17
  "zod": "^4.3.6",
18
18
  "@duckdb/node-api": "^1.5.5-r.3"
19
19
  },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/tomfosteruk/sdd-cli.git"
23
- },
24
20
  "publishConfig": {
25
21
  "access": "public"
26
22
  },