@uwmd/core 1.7.0 → 1.9.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.
Files changed (107) hide show
  1. package/dist/agents/bancroft.js +4 -1
  2. package/dist/agents/bancroft.js.map +1 -1
  3. package/dist/asset-class.d.ts +98 -0
  4. package/dist/asset-class.d.ts.map +1 -0
  5. package/dist/asset-class.js +226 -0
  6. package/dist/asset-class.js.map +1 -0
  7. package/dist/browser.d.ts +26 -8
  8. package/dist/browser.d.ts.map +1 -1
  9. package/dist/browser.js +25 -5
  10. package/dist/browser.js.map +1 -1
  11. package/dist/calc/errors.d.ts +1 -1
  12. package/dist/calc/errors.d.ts.map +1 -1
  13. package/dist/calc/errors.js.map +1 -1
  14. package/dist/calc/evaluator.js +25 -1
  15. package/dist/calc/evaluator.js.map +1 -1
  16. package/dist/calc/prng.d.ts +59 -0
  17. package/dist/calc/prng.d.ts.map +1 -0
  18. package/dist/calc/prng.js +181 -0
  19. package/dist/calc/prng.js.map +1 -0
  20. package/dist/calc/sensitivity.d.ts +76 -0
  21. package/dist/calc/sensitivity.d.ts.map +1 -0
  22. package/dist/calc/sensitivity.js +160 -0
  23. package/dist/calc/sensitivity.js.map +1 -0
  24. package/dist/calc/stochastic.d.ts +97 -0
  25. package/dist/calc/stochastic.d.ts.map +1 -0
  26. package/dist/calc/stochastic.js +265 -0
  27. package/dist/calc/stochastic.js.map +1 -0
  28. package/dist/cascade.d.ts.map +1 -1
  29. package/dist/cascade.js +8 -4
  30. package/dist/cascade.js.map +1 -1
  31. package/dist/cli-args.d.ts +37 -0
  32. package/dist/cli-args.d.ts.map +1 -0
  33. package/dist/cli-args.js +93 -0
  34. package/dist/cli-args.js.map +1 -0
  35. package/dist/cli.js +155 -75
  36. package/dist/cli.js.map +1 -1
  37. package/dist/editor.d.ts +18 -1
  38. package/dist/editor.d.ts.map +1 -1
  39. package/dist/editor.js +68 -7
  40. package/dist/editor.js.map +1 -1
  41. package/dist/format-rules.d.ts +46 -0
  42. package/dist/format-rules.d.ts.map +1 -0
  43. package/dist/format-rules.js +134 -0
  44. package/dist/format-rules.js.map +1 -0
  45. package/dist/format.d.ts +4 -0
  46. package/dist/format.d.ts.map +1 -1
  47. package/dist/format.js +34 -4
  48. package/dist/format.js.map +1 -1
  49. package/dist/index.d.ts +27 -9
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +26 -5
  52. package/dist/index.js.map +1 -1
  53. package/dist/init.d.ts.map +1 -1
  54. package/dist/init.js +16 -4
  55. package/dist/init.js.map +1 -1
  56. package/dist/integrity-canonical.d.ts.map +1 -1
  57. package/dist/integrity-canonical.js +10 -2
  58. package/dist/integrity-canonical.js.map +1 -1
  59. package/dist/integrity.d.ts +92 -4
  60. package/dist/integrity.d.ts.map +1 -1
  61. package/dist/integrity.js +195 -9
  62. package/dist/integrity.js.map +1 -1
  63. package/dist/lease-up.d.ts +134 -0
  64. package/dist/lease-up.d.ts.map +1 -0
  65. package/dist/lease-up.js +196 -0
  66. package/dist/lease-up.js.map +1 -0
  67. package/dist/migrate-source-tags.d.ts +34 -0
  68. package/dist/migrate-source-tags.d.ts.map +1 -0
  69. package/dist/migrate-source-tags.js +179 -0
  70. package/dist/migrate-source-tags.js.map +1 -0
  71. package/dist/module-runtime.d.ts +57 -0
  72. package/dist/module-runtime.d.ts.map +1 -0
  73. package/dist/module-runtime.js +167 -0
  74. package/dist/module-runtime.js.map +1 -0
  75. package/dist/module-signing.d.ts +85 -0
  76. package/dist/module-signing.d.ts.map +1 -0
  77. package/dist/module-signing.js +136 -0
  78. package/dist/module-signing.js.map +1 -0
  79. package/dist/modules.d.ts +42 -0
  80. package/dist/modules.d.ts.map +1 -1
  81. package/dist/modules.js +124 -1
  82. package/dist/modules.js.map +1 -1
  83. package/dist/parser.d.ts.map +1 -1
  84. package/dist/parser.js +28 -1
  85. package/dist/parser.js.map +1 -1
  86. package/dist/protocol.d.ts +249 -24
  87. package/dist/protocol.d.ts.map +1 -1
  88. package/dist/protocol.js +387 -33
  89. package/dist/protocol.js.map +1 -1
  90. package/dist/renderer.d.ts +10 -0
  91. package/dist/renderer.d.ts.map +1 -1
  92. package/dist/renderer.js +72 -8
  93. package/dist/renderer.js.map +1 -1
  94. package/dist/runner.d.ts.map +1 -1
  95. package/dist/runner.js +9 -3
  96. package/dist/runner.js.map +1 -1
  97. package/dist/types.d.ts +124 -5
  98. package/dist/types.d.ts.map +1 -1
  99. package/dist/types.js +44 -0
  100. package/dist/types.js.map +1 -1
  101. package/dist/validator.d.ts +26 -2
  102. package/dist/validator.d.ts.map +1 -1
  103. package/dist/validator.js +336 -19
  104. package/dist/validator.js.map +1 -1
  105. package/dist/version.d.ts +1 -1
  106. package/dist/version.js +1 -1
  107. package/package.json +6 -2
package/dist/cli.js CHANGED
@@ -3,10 +3,11 @@
3
3
  // Commands: parse, validate, compact, diff, init, summary, render
4
4
  // Usage: uwmd <command> <file> [options]
5
5
  import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync } from 'node:fs';
6
- import { resolve, basename, dirname } from 'node:path';
6
+ import { resolve, basename } from 'node:path';
7
7
  import { parseUWFile } from './parser.js';
8
8
  import { validateUWFile } from './validator.js';
9
9
  import { compact, diff } from './compactor.js';
10
+ import { migrateSourceTags } from './migrate-source-tags.js';
10
11
  import { generateBlankUWFile } from './init.js';
11
12
  import { render } from './renderer.js';
12
13
  import { renderReportHtml } from './report.js';
@@ -14,8 +15,9 @@ import { stringifyUWEnvelope } from './uwjson.js';
14
15
  import { stampEnvelopeDigest, toUWEnvelope, } from './envelope.js';
15
16
  import { CORE_CODEC_REGISTRY } from './codecs.js';
16
17
  import { writeAgentBlock } from './runner.js';
17
- import { applyEdit } from './editor.js';
18
+ import { applyEdit, applyEditAsync } from './editor.js';
18
19
  import { verifyChain, verifyProvenance } from './integrity.js';
20
+ import { REFERENCE_IMPLEMENTATION_MANIFEST } from './protocol.js';
19
21
  import { loadModuleManifest, createModuleRegistry, ModuleRegistryError } from './modules.js';
20
22
  import { cmdLeaseValidate, cmdLeaseProject, cmdPackageCreate, cmdPackageVerify, cmdPackageList, cmdPackageToContext, cmdPackageContextValidate, cmdPackageEdges, } from './cli-packages.js';
21
23
  import { evaluateCalc } from './calc/index.js';
@@ -34,6 +36,7 @@ import { detectUWSourceRepresentation, UWX_REPRESENTATION_ID, UW_LITE_SOURCE_DES
34
36
  import { parseUWLite } from './lite.js';
35
37
  import { compileUWLite, projectUWEnvelopeToLite, stringifyUWX, } from './lite-bridge.js';
36
38
  import { UW_LITE_REPRESENTATION_ID } from './source-representation.js';
39
+ import { parseFlags, extractPositionals, replaceUWExtension, hostTierFlag, defaultPartsDir, readManifestFile, } from './cli-args.js';
37
40
  const [, , command, ...args] = process.argv;
38
41
  function readFile(path) {
39
42
  const resolved = resolve(path);
@@ -54,30 +57,6 @@ function loadInstitutionConfig(path) {
54
57
  return undefined;
55
58
  }
56
59
  }
57
- function parseFlags(rawArgs) {
58
- const flags = {};
59
- for (let i = 0; i < rawArgs.length; i++) {
60
- const arg = rawArgs[i];
61
- if (arg.startsWith('--')) {
62
- const body = arg.slice(2);
63
- const eqIdx = body.indexOf('=');
64
- if (eqIdx >= 0) {
65
- flags[body.slice(0, eqIdx)] = body.slice(eqIdx + 1);
66
- continue;
67
- }
68
- const key = body;
69
- const next = rawArgs[i + 1];
70
- if (next && !next.startsWith('--')) {
71
- flags[key] = next;
72
- i++;
73
- }
74
- else {
75
- flags[key] = true;
76
- }
77
- }
78
- }
79
- return flags;
80
- }
81
60
  // ─── Commands ─────────────────────────────────────────────────────────────────
82
61
  function cmdParse(file, flags) {
83
62
  const content = readFile(file);
@@ -96,11 +75,24 @@ function cmdParse(file, flags) {
96
75
  for (const warning of detection.warnings)
97
76
  console.warn(`Warning: ${warning}`);
98
77
  const parsed = parseUWFile(content, { strict: flags['strict'] === true });
78
+ // The whole ParsedUWFile minus `raw` (which is just the input echoed back).
79
+ // Four fields — custom_calculations, custom_scenarios, extensions, and the
80
+ // full `superseded` blocks — used to be dropped here, so a caller that
81
+ // trusted `uwmd parse` to be "the parsed file" silently lost every custom
82
+ // calculation and every x_* extension in the document.
83
+ //
84
+ // `superseded_blocks` is kept alongside `superseded` for compatibility: it
85
+ // carries only each prior block's `content`, where `superseded` carries the
86
+ // whole block. New callers should read `superseded`.
99
87
  const output = {
100
88
  frontmatter: parsed.frontmatter,
101
89
  sections: Object.fromEntries(Object.entries(parsed.sections).map(([id, block]) => [id, block])),
102
90
  prose: parsed.prose,
103
91
  pipeline_log: parsed.pipeline_log.map(b => b.content),
92
+ custom_calculations: parsed.custom_calculations,
93
+ custom_scenarios: parsed.custom_scenarios,
94
+ extensions: parsed.extensions,
95
+ superseded: parsed.superseded,
104
96
  superseded_blocks: Object.fromEntries(Object.entries(parsed.superseded).map(([id, blocks]) => [id, blocks.map(b => b.content)])),
105
97
  };
106
98
  console.log(JSON.stringify(output, null, flags['compact'] ? 0 : 2));
@@ -171,6 +163,40 @@ function cmdValidate(file, flags) {
171
163
  console.log('');
172
164
  process.exit(result.errors.length > 0 ? 1 : 0);
173
165
  }
166
+ /**
167
+ * Build the `verifyChain` options from `--signing --keystore=<path>`.
168
+ *
169
+ * `@uwmd/signing` is reached by dynamic import and declared as an optional peer
170
+ * - the same arrangement `@anthropic-ai/sdk` gets. `@uwmd/core` must not take a
171
+ * crypto dependency to satisfy a flag most invocations never pass, and the
172
+ * layering invariant (core depends on no sibling package) forbids a static
173
+ * import outright.
174
+ */
175
+ async function signingOptions(flags) {
176
+ if (!flags['signing'])
177
+ return {};
178
+ const keystore = flags['keystore'];
179
+ if (typeof keystore !== 'string' || keystore.length === 0) {
180
+ console.error('--signing requires --keystore=<path> to a JSON key store.');
181
+ process.exit(1);
182
+ }
183
+ let signing;
184
+ try {
185
+ signing = (await import('@uwmd/signing'));
186
+ }
187
+ catch {
188
+ console.error('--signing needs the optional @uwmd/signing package. Install it with `npm i @uwmd/signing`.');
189
+ process.exit(1);
190
+ }
191
+ try {
192
+ const store = await signing.loadKeyStoreFile(resolve(keystore));
193
+ return { signatureVerifier: signing.createBlockSignatureVerifier(store) };
194
+ }
195
+ catch (error) {
196
+ console.error(error.message);
197
+ process.exit(1);
198
+ }
199
+ }
174
200
  async function cmdVerify(file, flags) {
175
201
  const content = readFile(file);
176
202
  // --resolved verifies the assembled record. Without it an externalized
@@ -191,8 +217,8 @@ async function cmdVerify(file, flags) {
191
217
  }
192
218
  let chain;
193
219
  let prov;
194
- if (runAll || onlyIntegrity) {
195
- chain = await verifyChain(parsed);
220
+ if (runAll || onlyIntegrity || flags['signing']) {
221
+ chain = await verifyChain(parsed, await signingOptions(flags));
196
222
  sections['integrity'] = chain;
197
223
  if (!chain.ok)
198
224
  hadError = true;
@@ -219,6 +245,12 @@ async function cmdVerify(file, flags) {
219
245
  }
220
246
  if (chain) {
221
247
  console.log(`\nIntegrity: ${chain.ok ? 'ok' : 'FAIL'} — chains_with_hashes=${chain.chains_with_hashes}, chains_verified=${chain.chains_verified}`);
248
+ if (chain.signatures_present > 0) {
249
+ const checked = flags['signing']
250
+ ? `${chain.signatures_verified} verified`
251
+ : 'not checked (pass --signing --keystore=<path>)';
252
+ console.log(`Signatures: ${chain.signatures_present} present, ${checked}`);
253
+ }
222
254
  for (const issue of chain.issues) {
223
255
  console.log(` [${issue.severity.toUpperCase()}] ${issue.code}${issue.section ? ` [${issue.section}]` : ''}: ${issue.message}`);
224
256
  }
@@ -253,6 +285,24 @@ function cmdCompact(file, flags) {
253
285
  writeFileSync(outPath, compacted, 'utf-8');
254
286
  console.log(`Compacted ${totalSuperseded} superseded block(s). Wrote to: ${outPath}`);
255
287
  }
288
+ function cmdMigrateSourceTags(file, flags) {
289
+ const content = readFile(file);
290
+ const result = migrateSourceTags(content);
291
+ for (const source of result.unmapped) {
292
+ console.error(`[unmapped] _meta.source '${source}' was left in place — rewrite it by hand.`);
293
+ }
294
+ if (result.changed === 0) {
295
+ console.log(`No legacy _meta.source values found in ${basename(file)} — nothing to migrate.`);
296
+ return;
297
+ }
298
+ if (flags['dry-run']) {
299
+ console.log(`Would migrate ${result.changed} block(s) in ${basename(file)} (RFC 0031 actor/resolution split).`);
300
+ return;
301
+ }
302
+ const outPath = flags['output'] ? resolve(flags['output']) : resolve(file);
303
+ writeFileSync(outPath, result.content, 'utf-8');
304
+ console.log(`Migrated ${result.changed} block(s). Wrote to: ${outPath}`);
305
+ }
256
306
  function cmdDiff(fileA, fileB) {
257
307
  const contentA = readFile(fileA);
258
308
  const contentB = readFile(fileB);
@@ -402,14 +452,6 @@ async function loadEnvelope(file) {
402
452
  * rather than `deal.uw.json`. (`.uw.md` does not match a `.uwx.md` filename —
403
453
  * the suffixes genuinely differ — so it was silently a no-op, not a mis-match.)
404
454
  */
405
- function replaceUWExtension(file, extension) {
406
- const lower = file.toLowerCase();
407
- for (const suffix of [UWX_EXTENSION, '.uw.csv.zip', '.uw.md', '.uw.json', '.uw.xml']) {
408
- if (lower.endsWith(suffix))
409
- return `${file.slice(0, -suffix.length)}${extension}`;
410
- }
411
- return `${file}${extension}`;
412
- }
413
455
  async function cmdConvert(file, flags) {
414
456
  const requested = flags['to'];
415
457
  if (typeof requested !== 'string') {
@@ -488,18 +530,6 @@ async function cmdReceiptIssue(file, flags) {
488
530
  console.log('A receipt attests that these outputs follow from this record. It does not attest that the inputs are true.');
489
531
  }
490
532
  // ─── Modules ──────────────────────────────────────────────────────────────────
491
- function readManifestFile(path) {
492
- try {
493
- return { ok: true, manifest: JSON.parse(readFileSync(resolve(path), 'utf-8')) };
494
- }
495
- catch (e) {
496
- return { ok: false, message: e instanceof Error ? e.message : String(e) };
497
- }
498
- }
499
- function hostTierFlag(flags) {
500
- const tier = flags['tier'];
501
- return typeof tier === 'string' ? tier : undefined;
502
- }
503
533
  function cmdModulesValidate(files, flags) {
504
534
  const hostTier = hostTierFlag(flags);
505
535
  const reports = files.map((file) => {
@@ -809,16 +839,7 @@ function cmdRefine(file, flags) {
809
839
  }
810
840
  // ─── Router ───────────────────────────────────────────────────────────────────
811
841
  const flags = parseFlags(args);
812
- // Positional args: non-flag tokens that don't immediately follow a --flag
813
- const positional = [];
814
- for (let _i = 0; _i < args.length; _i++) {
815
- const a = args[_i];
816
- if (a.startsWith('--')) {
817
- _i++;
818
- continue;
819
- } // skip flag + its value
820
- positional.push(a);
821
- }
842
+ const positional = extractPositionals(args);
822
843
  // ─── Composition (RFC 0021) ──────────────────────────────────────────────────
823
844
  /** Load every `.uwpart.md` in a directory, keyed by `part_id`. */
824
845
  function loadPartsDir(dir) {
@@ -836,10 +857,6 @@ function loadPartsDir(dir) {
836
857
  }
837
858
  return parts;
838
859
  }
839
- /** Where fragments live for a record, unless told otherwise. */
840
- function defaultPartsDir(file) {
841
- return resolve(dirname(resolve(file)), 'parts');
842
- }
843
860
  function cmdCompose(file, flags) {
844
861
  const section = flags['externalize'];
845
862
  if (typeof section !== 'string') {
@@ -969,7 +986,7 @@ function withResolved(parsed, file, flags) {
969
986
  break;
970
987
  case 'verify':
971
988
  if (!positional[0]) {
972
- console.error('Usage: uwmd verify <file> [--validate] [--integrity] [--policy] [--resolved] [--json]');
989
+ console.error('Usage: uwmd verify <file> [--validate] [--integrity] [--policy] [--signing --keystore=<path>] [--resolved] [--json]');
973
990
  process.exit(1);
974
991
  }
975
992
  await cmdVerify(positional[0], flags);
@@ -988,6 +1005,13 @@ function withResolved(parsed, file, flags) {
988
1005
  }
989
1006
  cmdDiff(positional[0], positional[1]);
990
1007
  break;
1008
+ case 'migrate':
1009
+ if (!positional[0] || !flags['source-tags']) {
1010
+ console.error('Usage: uwmd migrate <file> --source-tags [--output <file>] [--dry-run]');
1011
+ process.exit(1);
1012
+ }
1013
+ cmdMigrateSourceTags(positional[0], flags);
1014
+ break;
991
1015
  case 'render': {
992
1016
  if (!positional[0]) {
993
1017
  console.error('Usage: uwmd render <file> [--format <json|csv|chat|summary>] [--profile <summary|live|compact|full|relevant>] [--sections a,b,c] [--max-tokens 12000] [--no-meta] [--output <file>] [--tier screener|analyst]');
@@ -1153,7 +1177,7 @@ function withResolved(parsed, file, flags) {
1153
1177
  break;
1154
1178
  case 'edit': {
1155
1179
  if (!positional[0] || !positional[1]) {
1156
- console.error('Usage: uwmd edit <file> <operation.json> [--actor <name>] [--source <pattern>] [--agent-id <id>] [--agent-version <v>] [--confidence high|medium|low] [--output <file>]');
1180
+ console.error('Usage: uwmd edit <file> <operation.json> [--actor <name>] [--source <pattern>] [--agent-id <id>] [--agent-version <v>] [--confidence high|medium|low] [--output <file>] [--capability-token <jwt> --coord-key <keystore.json>]');
1157
1181
  process.exit(1);
1158
1182
  }
1159
1183
  const fileContent = readFile(positional[0]);
@@ -1174,7 +1198,47 @@ function withResolved(parsed, file, flags) {
1174
1198
  agentVersion: flags['agent-version'] ?? null,
1175
1199
  confidence: flags['confidence'] ?? 'medium',
1176
1200
  };
1177
- const result = applyEdit(fileContent, parsedFile, op, ctx);
1201
+ // Capability enforcement (Protocol §XIV, RFC 0011). Same optional-peer
1202
+ // dynamic-import arrangement as `--signing` above: core takes no crypto
1203
+ // dependency to satisfy a flag most invocations never pass.
1204
+ let result;
1205
+ const capToken = flags['capability-token'];
1206
+ if (typeof capToken === 'string' && capToken.length > 0) {
1207
+ const coordKey = flags['coord-key'];
1208
+ if (typeof coordKey !== 'string' || coordKey.length === 0) {
1209
+ console.error('--capability-token requires --coord-key=<path> to the coordinator\'s JSON key store.');
1210
+ process.exit(1);
1211
+ }
1212
+ let signing;
1213
+ try {
1214
+ signing = (await import('@uwmd/signing'));
1215
+ }
1216
+ catch {
1217
+ console.error('--capability-token needs the optional @uwmd/signing package. Install it with `npm i @uwmd/signing`.');
1218
+ process.exit(1);
1219
+ }
1220
+ try {
1221
+ const store = await signing.loadKeyStoreFile(resolve(coordKey));
1222
+ ctx.capability_token = capToken;
1223
+ result = await applyEditAsync(fileContent, parsedFile, op, ctx, undefined, {
1224
+ capabilityVerifier: signing.createCapabilityVerifier(store),
1225
+ });
1226
+ }
1227
+ catch (error) {
1228
+ console.error(error.message);
1229
+ process.exit(1);
1230
+ }
1231
+ }
1232
+ else {
1233
+ result = applyEdit(fileContent, parsedFile, op, ctx);
1234
+ }
1235
+ // --json reports the edit instead of performing it: the conformance driver
1236
+ // needs the resulting content, and a driver that rewrote fixtures as a side
1237
+ // effect of reading them would corrupt the corpus it is testing.
1238
+ if (flags['json']) {
1239
+ console.log(JSON.stringify(result, null, 2));
1240
+ process.exit(result.ok ? 0 : 1);
1241
+ }
1178
1242
  if (!result.ok || !result.content) {
1179
1243
  console.error(`Edit rejected: [${result.error?.code}] ${result.error?.message}`);
1180
1244
  if (result.error?.pointer)
@@ -1214,16 +1278,21 @@ function withResolved(parsed, file, flags) {
1214
1278
  locale: 'en-US',
1215
1279
  };
1216
1280
  const results = decls.map((d) => evaluateCalc(d, ctx));
1217
- for (const r of results) {
1218
- if (r.ok) {
1219
- console.log(`${r.calc_id} = ${r.display ?? String(r.value)}`);
1220
- }
1221
- else {
1222
- console.log(`${r.calc_id} ERROR [${r.error?.code}] ${r.error?.message}`);
1223
- }
1224
- }
1281
+ // Under --json, stdout is exactly one JSON document — the conformance CLI
1282
+ // protocol (§II.6a) depends on that, and printing the human lines first
1283
+ // would make every calc response unparseable.
1225
1284
  if (flags['json']) {
1226
- console.log(JSON.stringify(results, null, 2));
1285
+ console.log(JSON.stringify(results.length === 1 ? results[0] : results, null, 2));
1286
+ }
1287
+ else {
1288
+ for (const r of results) {
1289
+ if (r.ok) {
1290
+ console.log(`${r.calc_id} = ${r.display ?? String(r.value)}`);
1291
+ }
1292
+ else {
1293
+ console.log(`${r.calc_id} ERROR [${r.error?.code}] ${r.error?.message}`);
1294
+ }
1295
+ }
1227
1296
  }
1228
1297
  if (results.some((r) => !r.ok))
1229
1298
  process.exit(1);
@@ -1402,6 +1471,11 @@ function withResolved(parsed, file, flags) {
1402
1471
  }
1403
1472
  break;
1404
1473
  }
1474
+ case 'manifest':
1475
+ // The conformance CLI protocol's identity call (§II.6a). Emitted with no
1476
+ // surrounding prose so a driver can read it without a parser.
1477
+ console.log(JSON.stringify(REFERENCE_IMPLEMENTATION_MANIFEST, null, 2));
1478
+ break;
1405
1479
  case 'receipt': {
1406
1480
  const sub = positional[0];
1407
1481
  if (sub === 'issue') {
@@ -1432,11 +1506,14 @@ Commands:
1432
1506
  parse <file> Parse file and output JSON
1433
1507
  validate <file> Run all validation checks
1434
1508
  verify <file> Validate + verify integrity (hashes) + provenance (actor/policy)
1509
+ --signing --keystore=<path> also checks block signatures (RFC 0010,
1510
+ via the optional @uwmd/signing package)
1435
1511
  render <file> Render to output format (see --format)
1436
1512
  run <file> Invoke a Bancroft agent (see --agent)
1437
1513
  edit <file> <op.json> Apply an EditOperation (Tier-2)
1438
1514
  compact <file> Strip superseded blocks
1439
1515
  diff <file-a> <file-b> Compare two files section by section
1516
+ migrate <file> --source-tags Rewrite legacy _meta.source values into the actor/resolution split (RFC 0031)
1440
1517
  calc <file> <calc.json> Evaluate a calc declaration or inline formula (Tier-3)
1441
1518
  init Generate a blank .uwx.md file
1442
1519
  summary <file> Print quick metrics to terminal
@@ -1452,16 +1529,19 @@ Commands:
1452
1529
  modules validate|list Validate module manifest files, or list the registry they form
1453
1530
  lease validate|project Validate a lease abstract, or project it to a rent-roll row (RFC 0018)
1454
1531
  package create|verify|... Build, verify, list, or project a UW Deal Package (RFC 0018)
1532
+ manifest Print this implementation's ImplementationManifest (conformance protocol)
1455
1533
  layers List Bancroft agent layers
1456
1534
 
1457
1535
  Options:
1458
1536
  --output <path> Output file path (compact, init)
1459
1537
  --dry-run Show what would change without writing (compact)
1460
- --json JSON output (validate)
1538
+ --json JSON output on stdout, nothing else (validate, calc, edit)
1461
1539
  --strict Throw on parse errors instead of collecting
1462
1540
  --format <f> Render format: json|csv|chat|summary (render, default: summary)
1463
1541
  --no-superseded Drop append-only history from the .uw.json export (export)
1464
1542
  --resolved Resolve externalized sections first (verify, export)
1543
+ --signing Check _meta.signature on every block (verify; requires --keystore)
1544
+ --keystore <path> JSON key store mapping kid to public key (verify --signing)
1465
1545
  --parts <dir> Fragment directory (compose, resolve, --resolved; default: ./parts)
1466
1546
  --externalize <s> Section to split into fragments (compose)
1467
1547
  --collection-key <k> Row identity field (compose, default: unit_id)