@sdd-method/verify-cli 0.4.0 → 1.1.0-rc.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.
@@ -7,7 +7,7 @@
7
7
  # Emitted by sdd-cli's YAML emitter with no line folding; the three header scalars are quoted for the
8
8
  # textual readers downstream. The one deliberate difference from the authored form is schema_status:
9
9
  # the authored form says canonical; a projection never does.
10
- schema_version: "3.19.0"
10
+ schema_version: "3.20.0"
11
11
  schema_owner: "sdd-method"
12
12
  schema_status: "generated"
13
13
  enums:
@@ -606,6 +606,13 @@ enums:
606
606
  - value: no-canonical-home
607
607
  description: "The platform has no canonical field for the item: platform contract work."
608
608
  description: Why an unsupported feature is unsupported, and so whose work the gap is.
609
+ repo_dependency_kind:
610
+ values:
611
+ - value: library
612
+ description: Linked or packaged at build time.
613
+ - value: generated-from
614
+ description: Its content was produced from the other repository's templates.
615
+ description: How one repository depends on another's code (M-ADR 0217 §4.1).
609
616
  catalogues:
610
617
  domains:
611
618
  primary_key: id
@@ -688,6 +695,10 @@ catalogues:
688
695
  type: string
689
696
  nullable: true
690
697
  description: "`true` when this SDD is a reference exemplar — it demonstrates a profile shape rather than modelling a real product or provider relationship. Empty otherwise, which is the unmarked norm (absent in the manifest = a real SDD, no finding). From the manifest's `exemplar:` field (sdd-manifest-schema 1.8.0). PROFILE-AGNOSTIC, unlike surface/packaging/application_archetype which are application-product-only — the first exemplar cohort found was integration-products. DERIVED, not authorable: this column and `integrations.exemplar` both come from the one manifest field, so they cannot disagree; two independently authored copies could, which is the failure mode the trait exists to remove. No builder branches on it — it is emitted to be filterable and nothing consumes it, because an implicit exclusion inside a rollup is much harder to remove than to add. Added in 2.46.0."
698
+ - name: shared_library
699
+ type: string
700
+ nullable: true
701
+ description: "`true` when this SDD exists to provide code other SDDs build from or generate from (M-ADR 0217 §4.4). Empty otherwise, the unmarked norm. From the SDD manifest's `shared_library:` field. PROFILE-AGNOSTIC, like `exemplar`. DERIVED, not authorable: this column and its twin on the other catalogue come from the one manifest field, so they cannot disagree. No builder branches on it; a rollup filters on it. Added in 3.20.0."
691
702
  - name: surface
692
703
  type: string
693
704
  nullable: true
@@ -778,6 +789,10 @@ catalogues:
778
789
  type: string
779
790
  nullable: true
780
791
  description: "`true` when this SDD is a reference exemplar — it demonstrates a profile shape rather than modelling a real product or provider relationship. Empty otherwise, which is the unmarked norm (absent in the manifest = a real SDD, no finding). From the manifest's `exemplar:` field (sdd-manifest-schema 1.8.0). PROFILE-AGNOSTIC, unlike surface/packaging/application_archetype which are application-product-only — the first exemplar cohort found was integration-products. DERIVED, not authorable: this column and `integrations.exemplar` both come from the one manifest field, so they cannot disagree; two independently authored copies could, which is the failure mode the trait exists to remove. No builder branches on it — it is emitted to be filterable and nothing consumes it, because an implicit exclusion inside a rollup is much harder to remove than to add. Added in 2.46.0."
792
+ - name: shared_library
793
+ type: string
794
+ nullable: true
795
+ description: "`true` when this SDD exists to provide code other SDDs build from or generate from (M-ADR 0217 §4.4). Empty otherwise, the unmarked norm. From the SDD manifest's `shared_library:` field. PROFILE-AGNOSTIC, like `exemplar`. DERIVED, not authorable: this column and its twin on the other catalogue come from the one manifest field, so they cannot disagree. No builder branches on it; a rollup filters on it. Added in 3.20.0."
781
796
  - name: surface
782
797
  type: string
783
798
  nullable: true
@@ -871,6 +886,10 @@ catalogues:
871
886
  type: string
872
887
  nullable: true
873
888
  description: "`true` when the emitting SDD is a reference exemplar (demonstrates a profile shape rather than modelling a real provider relationship); empty otherwise. Derived from the SDD manifest's `exemplar:` field (sdd-manifest-schema 1.8.0), same source as `products.exemplar` — neither column is independently authorable. Carried on `sub_integrations` rows too, INHERITED from the emitting SDD. That deliberately differs from `ingestion_pattern`/`invocation_pattern`, which are empty on sub rows, and the difference is the point: a pattern is a MECHANISM (how this integration acquires data), genuinely one per SDD, whereas `exemplar` is a REALITY STATUS that propagates to everything the SDD emits — if the SDD is a demonstration then every provider relationship it declares is a demonstration. Leaving sub rows empty would flag the umbrella and count its demonstration sub-providers as real, reproducing the rollup overcount this column exists to fix one level down. Do not normalise it to match the pattern columns. The trade accepted: a real SDD with one demonstration sub-provider is unexpressible — a state that should not exist. Added in 2.46.0."
889
+ - name: shared_library
890
+ type: string
891
+ nullable: true
892
+ description: "`true` when this SDD exists to provide code other SDDs build from or generate from (M-ADR 0217 §4.4). Empty otherwise, the unmarked norm. From the SDD manifest's `shared_library:` field. PROFILE-AGNOSTIC, like `exemplar`. DERIVED, not authorable: this column and its twin on the other catalogue come from the one manifest field, so they cannot disagree. No builder branches on it; a rollup filters on it. Added in 3.20.0."
874
893
  - name: source_sdd_id
875
894
  type: string
876
895
  nullable: true
@@ -4050,3 +4069,49 @@ catalogues:
4050
4069
  references: repositories.id
4051
4070
  nullable: false
4052
4071
  external: true
4072
+ repo_dependency:
4073
+ primary_key: id
4074
+ columns:
4075
+ - name: id
4076
+ type: string
4077
+ nullable: false
4078
+ description: <from_repo_id>__<to_repo_id>__<kind>.
4079
+ - name: from_repo_id
4080
+ type: string
4081
+ nullable: false
4082
+ description: The dependent repository; one of this SDD's own.
4083
+ - name: to_repo_id
4084
+ type: string
4085
+ nullable: false
4086
+ description: The repository depended on, in this SDD or another. External at build; it must resolve at aggregation, and is never renamed or guessed to make it resolve.
4087
+ - name: kind
4088
+ type: string
4089
+ nullable: false
4090
+ description: Bound to repo_dependency_kind.
4091
+ - name: version
4092
+ type: string
4093
+ nullable: true
4094
+ description: The version or reference depended on, where the source states one; empty otherwise. The declared source wins over the derived one.
4095
+ - name: declared_in
4096
+ type: string
4097
+ nullable: false
4098
+ description: The file the row came from, relative to the SDD root; the declared source when both name the dependency.
4099
+ - name: source_sdd_id
4100
+ type: string
4101
+ nullable: true
4102
+ description: Originating SDD slug. Populated by the aggregator per M-ADR 0134.
4103
+ - name: platform_sdd_id
4104
+ type: string
4105
+ nullable: true
4106
+ description: The platform this row belongs to — sdd_id of its platform-root. Stamped by the aggregator (M-ADR 0208 §4.4).
4107
+ description: "Edge: a repository depends on another repository's code without either being a running service — a library linked at build time, or a template family it was generated from (M-ADR 0217). The depended-on repository may belong to another SDD, which describes it; this row only references it."
4108
+ foreign_keys:
4109
+ - column: from_repo_id
4110
+ references: repositories.id
4111
+ nullable: false
4112
+ - column: to_repo_id
4113
+ references: repositories.id
4114
+ nullable: false
4115
+ external: true
4116
+ column_enums:
4117
+ kind: enums.repo_dependency_kind
@@ -2,9 +2,9 @@
2
2
  * sdd-cli version constant, used in error messages from the catalogue
3
3
  * builder + aggregator + validate subcommands.
4
4
  *
5
- * Read from package.json via getPackageVersion() to guarantee the
5
+ * Read from package.json via getSddCliVersion() (the ENGINE version, also in a persona package) to guarantee the
6
6
  * constant cannot drift from the published version.
7
7
  */
8
- import { getPackageVersion } from "../package-version.js";
9
- export const CLI_VERSION = getPackageVersion();
8
+ import { getSddCliVersion } from "../package-version.js";
9
+ export const CLI_VERSION = getSddCliVersion();
10
10
  //# sourceMappingURL=cli-version.js.map
@@ -215,6 +215,9 @@ const ManifestSchema = z.object({
215
215
  // application-product. Absent reads as a real SDD, the unmarked norm, with no
216
216
  // finding. Only `true` is meaningful; `false` is redundant but accepted.
217
217
  exemplar: z.boolean().optional(),
218
+ // Shared-library trait (sdd-manifest-schema 1.12.0, M-ADR 0217 §4.4). Profile-agnostic,
219
+ // like `exemplar`; absent is the unmarked norm, no finding.
220
+ shared_library: z.boolean().optional(),
218
221
  // Application-product archetype trait (M-ADR 0191, sdd-manifest-schema
219
222
  // 1.2.0). RESOLVED enum, not fixed: the loader validates only the slug
220
223
  // shape here. Whether the value resolves against the active vocabulary
@@ -374,6 +377,7 @@ export async function loadSddManifest(sddPath, options) {
374
377
  ...(parsed.data.surface !== undefined ? { surface: parsed.data.surface } : {}),
375
378
  ...(parsed.data.packaging !== undefined ? { packaging: parsed.data.packaging } : {}),
376
379
  ...(parsed.data.exemplar !== undefined ? { exemplar: parsed.data.exemplar } : {}),
380
+ ...(parsed.data.shared_library !== undefined ? { sharedLibrary: parsed.data.shared_library } : {}),
377
381
  ...(parsed.data.application_archetype !== undefined
378
382
  ? { applicationArchetype: parsed.data.application_archetype }
379
383
  : {}),
@@ -859,3 +859,13 @@ coverage:
859
859
  repo_id:
860
860
  class: xref
861
861
  impact_flow: toward-source
862
+ repo_dependency:
863
+ kind: edge
864
+ scoring: predicate
865
+ class: dependency
866
+ impact_flow: toward-source
867
+ instrument: "FK resolution against repositories at aggregation: a dependency naming no repository fails like any other foreign key (M-ADR 0217 §4.1)"
868
+ repo_dependency_kind:
869
+ kind: enum
870
+ scoring: not-applicable
871
+ reason: closed vocabulary, not an artefact
@@ -62,6 +62,9 @@ export function serialiseLockFile(lock) {
62
62
  const lines = [
63
63
  `method_repo: ${lock.methodRepo}`,
64
64
  `lock_version: ${lock.lockVersion}`,
65
+ ...(lock.ciBinding !== undefined ? [`ci_binding: ${lock.ciBinding}`] : []),
66
+ ...(lock.ciWorkflowBlockSha256 !== undefined ? [`ci_workflow_block_sha256: "${lock.ciWorkflowBlockSha256}"`] : []),
67
+ ...(lock.ciModuleSha256 !== undefined ? [`ci_module_sha256: "${lock.ciModuleSha256}"`] : []),
65
68
  "bundles:",
66
69
  ];
67
70
  for (const b of lock.bundles) {
@@ -109,6 +112,9 @@ function stripQuotes(value) {
109
112
  function parseVersioned(raw) {
110
113
  let methodRepo;
111
114
  let lockVersion;
115
+ let ciWorkflowBlockSha256;
116
+ let ciBinding;
117
+ let ciModuleSha256;
112
118
  const bundles = [];
113
119
  let inBundles = false;
114
120
  let inPaths = false;
@@ -170,6 +176,12 @@ function parseVersioned(raw) {
170
176
  methodRepo = stripQuotes(value);
171
177
  else if (key === "lock_version")
172
178
  lockVersion = Number(stripQuotes(value));
179
+ else if (key === "ci_workflow_block_sha256")
180
+ ciWorkflowBlockSha256 = stripQuotes(value);
181
+ else if (key === "ci_binding")
182
+ ciBinding = stripQuotes(value);
183
+ else if (key === "ci_module_sha256")
184
+ ciModuleSha256 = stripQuotes(value);
173
185
  }
174
186
  continue;
175
187
  }
@@ -289,7 +301,14 @@ function parseVersioned(raw) {
289
301
  ? ` — the lock was written by a newer sdd-cli; upgrade rather than downgrading the lock.`
290
302
  : `.`));
291
303
  }
292
- return { methodRepo, lockVersion: LOCK_VERSION, bundles };
304
+ return {
305
+ methodRepo,
306
+ lockVersion: LOCK_VERSION,
307
+ bundles,
308
+ ...(ciBinding !== undefined ? { ciBinding } : {}),
309
+ ...(ciWorkflowBlockSha256 !== undefined ? { ciWorkflowBlockSha256 } : {}),
310
+ ...(ciModuleSha256 !== undefined ? { ciModuleSha256 } : {}),
311
+ };
293
312
  }
294
313
  function migrateV1(raw, legacyBundleName) {
295
314
  const scalars = new Map();
@@ -4,7 +4,7 @@
4
4
  // (M-ADR 0212 §4.3b). `index.ts` re-exports it, so existing imports are unchanged.
5
5
  import { validateSeed } from "./schema.js";
6
6
  import { loadSeed } from "./seed.js";
7
- import { getPackageVersion } from "../package-version.js";
7
+ import { getSddCliVersion } from "../package-version.js";
8
8
  import { fail, info, pass, section } from "./log.js";
9
9
  export async function runPackValidate(opts, stdout = (s) => process.stdout.write(s)) {
10
10
  stdout(section("Pack validate"));
@@ -21,7 +21,7 @@ export async function runPackValidate(opts, stdout = (s) => process.stdout.write
21
21
  // than itself, exactly as for `.sdd/sdd-manifest.yaml`. Silence here is what let an
22
22
  // adopter follow the schema and get a clean validation with no effect.
23
23
  if (seed.unknownKeys && seed.unknownKeys.length > 0) {
24
- stdout(info(`${seed.unknownKeys.length} seed key(s) not understood by sdd-cli ${getPackageVersion()} ` +
24
+ stdout(info(`${seed.unknownKeys.length} seed key(s) not understood by sdd-cli ${getSddCliVersion()} ` +
25
25
  `and therefore IGNORED: ${seed.unknownKeys.join(", ")}. If the seed follows a newer ` +
26
26
  `context-pack-seed-schema than this build, upgrade sdd-cli; otherwise remove or correct the key.`));
27
27
  }
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
2
+ import { dirname, resolve, sep } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  /**
5
5
  * Read the package version from package.json at runtime so the various
@@ -13,6 +13,25 @@ import { fileURLToPath } from "node:url";
13
13
  * Cached on first call.
14
14
  */
15
15
  let cached;
16
+ let cachedEngine;
17
+ /**
18
+ * The version of the sdd-cli ENGINE this code is. In @sdd-method/sdd-cli it is the package
19
+ * version. In a persona package (verify-cli, maintain-cli) the package version is the
20
+ * persona's own (0.1.0, 1.0.0), while every check and stamp that means "which sdd-cli is
21
+ * this" (a bundle's minimum_sdd_cli_version, the CLI version stamped into catalogues, the
22
+ * MCP server identity) must see the engine it was built from. The persona build writes that
23
+ * as `sddCliVersion` in the package's package.json. Found by maintain-cli's acceptance run:
24
+ * its sync refused every bundle because 0.1.0 < 1.41.0.
25
+ */
26
+ export function getSddCliVersion() {
27
+ if (cachedEngine !== undefined)
28
+ return cachedEngine;
29
+ const here = dirname(fileURLToPath(import.meta.url));
30
+ const pkg = JSON.parse(readFileSync(resolve(here, "..", "..", "package.json"), "utf8"));
31
+ cachedEngine = pkg.sddCliVersion ?? pkg.version;
32
+ return cachedEngine;
33
+ }
34
+ /** The package's own version: what `--version` prints. For the engine version, use getSddCliVersion. */
16
35
  export function getPackageVersion() {
17
36
  if (cached !== undefined)
18
37
  return cached;
@@ -22,4 +41,52 @@ export function getPackageVersion() {
22
41
  cached = pkg.version;
23
42
  return cached;
24
43
  }
44
+ /**
45
+ * The @sdd-method/verify-cli version released WITH this sdd-cli (M-ADR 0212
46
+ * §6.1 Phase 1). The method-managed CI workflow installs exactly this version,
47
+ * so the CLI that syncs a repository decides which verifier judges it.
48
+ *
49
+ * Read from dist/verify-version.json, which the build copies from
50
+ * scripts/verify-version.json. Never from scripts/ in a built layout: the global
51
+ * `sdd-cli` on the method's machines is a link into the checkout, so reading the
52
+ * committed file live would render a version bumped in source but not yet
53
+ * published into every workflow synced that day, while dist/ still lagged.
54
+ * Source layout (tests) has no copy and reads scripts/ directly.
55
+ *
56
+ * Throws rather than defaults: a missing version must not render a floating install.
57
+ */
58
+ const cachedPersona = {};
59
+ /**
60
+ * One exact npm version: X.Y.Z, optionally with a prerelease tag (1.1.0-rc.0), which a release
61
+ * candidate published under the `next` dist-tag needs so hosted CI can run it before the release.
62
+ * Never a range, a tag name or a wildcard.
63
+ */
64
+ export const EXACT_VERSION = /^\d+\.\d+\.\d+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$/;
65
+ function personaVersion(persona) {
66
+ const hit = cachedPersona[persona];
67
+ if (hit !== undefined)
68
+ return hit;
69
+ const here = dirname(fileURLToPath(import.meta.url));
70
+ const fromSource = here.endsWith(`${sep}src${sep}lib`);
71
+ const file = fromSource
72
+ ? resolve(here, "..", "..", "scripts", `${persona}-version.json`)
73
+ : resolve(here, "..", `${persona}-version.json`);
74
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
75
+ if (typeof parsed.version !== "string" || !EXACT_VERSION.test(parsed.version)) {
76
+ throw new Error(`${file} has no semver \`version\`; refusing to render an unpinned ${persona}-cli install`);
77
+ }
78
+ cachedPersona[persona] = parsed.version;
79
+ return parsed.version;
80
+ }
81
+ export function getVerifyCliVersion() {
82
+ return personaVersion("verify");
83
+ }
84
+ /**
85
+ * The @sdd-method/maintain-cli version released WITH this sdd-cli. The managed CI workflow's
86
+ * catalogue freshness step installs exactly this version (M-ADR 0218 §5; ruled 2026-10-15, sdm-jts.6).
87
+ * Read the same way as the verify version, for the same reason (dist/ copy, never scripts/ live).
88
+ */
89
+ export function getMaintainCliVersion() {
90
+ return personaVersion("maintain");
91
+ }
25
92
  //# sourceMappingURL=package-version.js.map
@@ -11,7 +11,7 @@
11
11
  // read 0 (the scores-coverage precedent, M-ADR 0205 §4.5).
12
12
  import { readLockFile, findForwardBase } from "../lock-file.js";
13
13
  import { loadSddManifest, } from "../catalogue/manifest-loader.js";
14
- import { getPackageVersion } from "../package-version.js";
14
+ import { getSddCliVersion } from "../package-version.js";
15
15
  /**
16
16
  * Manifest profile → the forward base that profile expects. Profiles with no
17
17
  * entry (support-repo, organisation-profile) carry no expectation — silence,
@@ -37,7 +37,7 @@ export async function checkBundleCoherence(targetRepo) {
37
37
  let profile;
38
38
  try {
39
39
  const manifest = await loadSddManifest(targetRepo, {
40
- cliVersion: getPackageVersion(),
40
+ cliVersion: getSddCliVersion(),
41
41
  });
42
42
  profile = manifest.profile;
43
43
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The method-managed validation job, as DATA (bead sdm-dd6.2; Dagger ruling sdm-s48, 2026-10-15).
3
+ *
4
+ * One ordered plan per profile: every default validator, the platform's script-only checks, then the
5
+ * advisory catalogue freshness check. Every executor renders or runs THIS: the GitHub workflow
6
+ * generator (ci-workflow.ts) and the Dagger module (via `sdd-verify validate --list`). The job list
7
+ * drifted once when CI kept a hand copy of the suite (2026-10-01: three validators never reached CI),
8
+ * so no executor may keep its own list.
9
+ */
10
+ import { validatorsForProfile } from "./dispatch.js";
11
+ /** Titles kept from the hand-kept list, so step names stay readable. */
12
+ const TITLES = {
13
+ "adr-structure": "Validate ADR metadata",
14
+ "spec-lifecycle": "Validate spec lifecycle",
15
+ "no-bare-adr": "Reject bare ADR references",
16
+ traceability: "Validate traceability",
17
+ "runway-classification": "Validate runway classification",
18
+ "corpus-consistency": "Validate corpus consistency",
19
+ config: "Validate configuration",
20
+ "app-docs": "Validate app documentation",
21
+ "integration-docs": "Validate integration documentation",
22
+ "yaml-parse": "Validate that tracked YAML parses",
23
+ "gate-readiness": "Validate gate readiness",
24
+ "bundle-coherence": "Report bundle coherence",
25
+ // CI has no platform checkout, so this step runs the app-only checks; the met gate needs the platform beside it.
26
+ "app-dependencies": "Validate app dependencies (app-only checks; no platform checkout in CI)",
27
+ };
28
+ export function methodValidationPlan(profile) {
29
+ const steps = validatorsForProfile(profile)
30
+ .filter((v) => v.optional !== true)
31
+ .map((v) => ({
32
+ id: v.name,
33
+ title: TITLES[v.name] ?? `Validate ${v.name}`,
34
+ tool: "sdd-verify",
35
+ args: ["validate", "--target-repo", ".", "--validator", v.name],
36
+ advisory: false,
37
+ }));
38
+ if (profile === "platform") {
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
+ }
41
+ steps.push({
42
+ id: "catalogue-freshness",
43
+ title: "Check catalogues reproduce from the specs (advisory)",
44
+ tool: "sdd-maintain",
45
+ args: ["catalogue", "build", "--check", "--sdd-path", "."],
46
+ advisory: true,
47
+ });
48
+ return steps;
49
+ }
50
+ /** The shell form of a step, as a CI host's `run:` line writes it. */
51
+ export function stepCommand(step) {
52
+ return [step.tool, ...step.args].join(" ");
53
+ }
54
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": "0.1.0-rc.0",
3
+ "built_against_sdd_cli": "1.42.0"
4
+ }
@@ -1,4 +1,8 @@
1
1
  import { runValidate } from "../lib/validate/index.js";
2
+ import { methodValidationPlan } from "../lib/validate/plan.js";
3
+ import { profileFromRepoKind, readRepoKind } from "../lib/repo-kind.js";
4
+ const LISTABLE = ["platform", "application", "integration"];
5
+ const isListable = (p) => LISTABLE.includes(p);
2
6
  import { resolvePathOption } from "./path-option.js";
3
7
  export function registerValidate(program) {
4
8
  program
@@ -8,7 +12,29 @@ export function registerValidate(program) {
8
12
  .option("--platform-root <dir>", "path to the sdd-method (or platform) repo, required for app-dependencies", resolvePathOption)
9
13
  .option("--validator <name>", "run only the named validator")
10
14
  .option("--strict", "treat warnings as failures")
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
+ .option("--profile <profile>", "with --list: the profile to list, instead of reading .sdd-repo-kind (platform | application | integration)")
11
17
  .action(async (opts) => {
18
+ if (opts.list === true) {
19
+ let profile;
20
+ if (opts.profile !== undefined) {
21
+ if (!isListable(opts.profile)) {
22
+ process.stderr.write(`--profile must be platform, application or integration (got: ${opts.profile})\n`);
23
+ process.exit(2);
24
+ }
25
+ profile = opts.profile;
26
+ }
27
+ else {
28
+ const kind = await readRepoKind(opts.targetRepo);
29
+ if (kind === null) {
30
+ process.stderr.write(`Not an SDD repo (no .sdd-repo-kind in ${opts.targetRepo}); pass --profile\n`);
31
+ process.exit(1);
32
+ }
33
+ profile = profileFromRepoKind(kind);
34
+ }
35
+ process.stdout.write(JSON.stringify({ profile, steps: methodValidationPlan(profile) }, null, 2) + "\n");
36
+ return;
37
+ }
12
38
  const { exitCode } = await runValidate({
13
39
  targetRepo: opts.targetRepo,
14
40
  ...(opts.platformRoot ? { platformRoot: opts.platformRoot } : {}),
@@ -49,7 +49,7 @@ const OUTSIDE = "is not part of sdd-verify, which cannot write to the repository
49
49
  * this binary exists to prevent. So an excluded verb fails, loudly, whatever
50
50
  * flags accompany it.
51
51
  */
52
- export function rejectOutsideSurface(program, argv) {
52
+ export function rejectOutsideSurface(program, argv, outside = OUTSIDE) {
53
53
  const words = argv.filter((a) => !a.startsWith("-"));
54
54
  if (words.length === 0)
55
55
  return;
@@ -58,10 +58,10 @@ export function rejectOutsideSurface(program, argv) {
58
58
  return;
59
59
  const cmd = program.commands.find((c) => c.name() === verb);
60
60
  if (!cmd)
61
- throw new Error(`'${verb}' ${OUTSIDE}`);
61
+ throw new Error(`'${verb}' ${outside}`);
62
62
  const subs = cmd.commands.map((c) => c.name()).filter((n) => n !== "help");
63
63
  if (subs.length > 0 && sub !== undefined && sub !== "help" && !subs.includes(sub)) {
64
- throw new Error(`'${verb} ${sub}' ${OUTSIDE}`);
64
+ throw new Error(`'${verb} ${sub}' ${outside}`);
65
65
  }
66
66
  }
67
67
  export async function runVerify(argv) {
@@ -97,6 +97,14 @@ export function buildVerifyProgram() {
97
97
  writeOut: (str) => process.stdout.write(str),
98
98
  writeErr: (str) => process.stderr.write(str),
99
99
  });
100
+ registerVerifySurface(program);
101
+ return program;
102
+ }
103
+ /**
104
+ * The verify verbs, registered onto any program. sdd-verify calls it; sdd-maintain calls it too,
105
+ * which is what makes the personas nest structurally: whatever verify ships, maintain ships.
106
+ */
107
+ export function registerVerifySurface(program) {
100
108
  registerValidate(program);
101
109
  registerList(program);
102
110
  const pack = program
@@ -110,6 +118,5 @@ export function buildVerifyProgram() {
110
118
  registerCatalogueImpact(catalogue);
111
119
  registerCatalogueBaselineCheck(catalogue);
112
120
  registerCatalogueVersion(catalogue);
113
- return program;
114
121
  }
115
122
  //# sourceMappingURL=verify-program.js.map
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": "1.1.0-rc.0",
3
+ "built_against_sdd_cli": "1.42.0"
4
+ }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@sdd-method/verify-cli",
3
- "version": "0.4.0",
4
- "description": "Verify an SDD repository without changing it — validate, list, and read-only catalogue and pack checks. Ships only the code those verbs reach; it cannot write to the repository it is pointed at. Authoring and maintenance are in @sdd-method/sdd-cli.",
3
+ "version": "1.1.0-rc.0",
4
+ "sddCliVersion": "1.42.0",
5
+ "description": "Verify an SDD repository without changing it \u2014 validate, list, and read-only catalogue and pack checks. Ships only the code those verbs reach; it cannot write to the repository it is pointed at. Authoring and maintenance are in @sdd-method/sdd-cli.",
5
6
  "license": "Apache-2.0",
6
7
  "type": "module",
7
8
  "bin": {