mdkg 0.2.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -6,7 +6,50 @@ This project follows a pragmatic changelog style inspired by Keep a Changelog. V
6
6
 
7
7
  mdkg is pre-v1 public alpha software. Command, graph, cache, bundle, and DAL contracts may change quickly while the project converges on a stable v1 surface.
8
8
 
9
- ## 0.2.0 - Unreleased
9
+ ## 0.3.0 - Unreleased
10
+
11
+ ### Added
12
+
13
+ - Added optional `SPEC.md` reusable capability records with strict validation
14
+ for supported `spec_kind` values and diagnostics that reject documentation-only
15
+ misuse while keeping repos without SPEC files valid.
16
+ - Added focused `mdkg spec list/show/validate` commands for optional SPEC
17
+ capability discovery alongside the broader `mdkg capability ...` surface.
18
+ - Added a dogfood mdkg CLI `SPEC.md` and linked `WORK.md` contract so the CLI's
19
+ graph, project DB, skill, and tool capabilities are discoverable through the
20
+ same capability index used by downstream repos.
21
+ - Added deterministic `mdkg work trigger`, `mdkg work order status`, and
22
+ `mdkg work receipt verify` helpers for creating submitted work-order mirrors,
23
+ reviewing order/receipt linkage, and validating receipt evidence without
24
+ executing work.
25
+ - Added optional `mdkg work trigger --enqueue <queue>` delivery bridging to the
26
+ public local project DB queue surface. The bridge requires an initialized,
27
+ migrated, verified DB and an explicitly created active queue, records
28
+ delivery refs, and still does not execute work.
29
+ - Added read-only SPEC/WORK capability linkage arrays for related specs, work
30
+ contracts, work orders, and receipts.
31
+ - Added packed `smoke:work-invocation` coverage for trigger-to-order-to-receipt
32
+ verification plus queue bridge delivery from an installed tarball.
33
+
34
+ ### Changed
35
+
36
+ - Hardened default SPEC, WORK, WORK_ORDER, and RECEIPT templates with capability
37
+ metadata, payload hashes, queue refs, evidence hashes, redaction policies, and
38
+ explicit semantic-mirror boundaries.
39
+ - Updated README, command matrix, help snapshots, init assets, and upgrade
40
+ smokes for optional SPEC adoption, work invocation helpers, queue bridge
41
+ behavior, capability linkage, and no-SPEC backward compatibility.
42
+ - Strengthened init and upgrade smokes so fresh workspaces can remain SPEC-free
43
+ while optional SPEC/WORK templates can be created and validated on demand.
44
+
45
+ ### Security
46
+
47
+ - Audited templates, docs, dogfood mirrors, and work invocation command paths for
48
+ no-secret and semantic-mirror boundaries before the 0.3.0 release metadata
49
+ bump. No raw secret, credential, payment, ledger, or canonical production
50
+ state values were identified.
51
+
52
+ ## 0.2.0 - 2026-06-06
10
53
 
11
54
  Release numbering note: future project DB materializer/profile release planning
12
55
  should follow `0.1.9 -> 0.2.0` rather than continuing the line as `0.1.10`
package/README.md CHANGED
@@ -167,8 +167,16 @@ mdkg index
167
167
  mdkg capability list --kind skill --json
168
168
  mdkg capability search "image worker" --kind work --json
169
169
  mdkg capability show <id-or-qid-or-slug> --json
170
+ mdkg spec list --json
171
+ mdkg spec show <id-or-qid-or-alias> --json
170
172
  ```
171
173
 
174
+ `SPEC.md` is optional. Repos with no SPEC files still validate; when present,
175
+ SPEC records describe reusable capability surfaces rather than general planning
176
+ notes. `mdkg spec list/show/validate` is the focused SPEC command family, while
177
+ `mdkg capability ...` remains the broader read-only discovery surface for
178
+ skills, SPECs, WORK contracts, core docs, and design docs.
179
+
172
180
  Register source and artifact files as committed archive sidecars:
173
181
 
174
182
  ```bash
@@ -181,11 +189,20 @@ Create semantic mirror work contracts, orders, receipts, and artifacts:
181
189
 
182
190
  ```bash
183
191
  mdkg work contract new "generate image" --id work.generate-image --agent-id agent.image-worker --kind image_generation --inputs prompt:text:required --outputs image_url:url:required
184
- mdkg work order new "generate image request" --id order.generate-image-1 --work-id work.generate-image --requester user://example --input-refs archive://archive.key-input-doc
192
+ mdkg work trigger work.generate-image --id order.generate-image-1 --requester user://example
193
+ mdkg work order status order.generate-image-1 --json
185
194
  mdkg work receipt new "generate image receipt" --id receipt.generate-image-1 --work-order-id order.generate-image-1 --outcome success --receipt-status recorded
195
+ mdkg work receipt verify receipt.generate-image-1 --json
186
196
  mdkg work artifact add receipt.generate-image-1 ./outputs/image.png --id archive.generated-image --kind artifact
187
197
  ```
188
198
 
199
+ Create a manual order instead of a trigger-created order when you need to supply
200
+ input refs at order creation time:
201
+
202
+ ```bash
203
+ mdkg work order new "generate image request" --id order.generate-image-manual --work-id work.generate-image --requester user://example --input-refs archive://archive.key-input-doc
204
+ ```
205
+
189
206
  Receipt statuses are `recorded`, `verified`, `rejected`, and `superseded`.
190
207
  Update and artifact commands accept local ids or local qids; subgraph qids are read-only and must be changed in their source workspace.
191
208
 
@@ -254,6 +271,7 @@ These are the commands new users and agents should learn first:
254
271
  - `mdkg pack`
255
272
  - `mdkg skill`
256
273
  - `mdkg capability`
274
+ - `mdkg spec`
257
275
  - `mdkg archive`
258
276
  - `mdkg work`
259
277
  - `mdkg goal`
@@ -326,7 +344,7 @@ mdkg maintains `.mdkg/index/capabilities.json` as a derived access cache for det
326
344
 
327
345
  The capability cache is not the full graph and is not source of truth. Normal tasks, epics, bugs, tests, feats, and checkpoints remain in the standard graph index. Markdown remains authoritative; deleting the cache is recoverable with `mdkg index` or by running a capability command when auto-reindex is enabled.
328
346
 
329
- Capability records aggregate enabled registered workspaces and include deterministic source metadata such as `workspace`, `visibility`, `kind`, `id`, `qid`, `path`, headings, refs, source hash, and `indexed_at`. Workspace `visibility` also feeds mdkg's export safety checks for public/internal packs and public bundles. This is a CLI safety layer, not secret scanning, body redaction, or a replacement for private git hosting.
347
+ Capability records aggregate enabled registered workspaces and include deterministic source metadata such as `workspace`, `visibility`, `kind`, `id`, `qid`, `path`, headings, refs, source hash, and `indexed_at`. SPEC and WORK records also expose read-only `linkage` arrays when related work contracts, work orders, and receipts exist, so an orchestrator can discover a capability from reusable surface to invocation evidence without loading the full graph. Workspace `visibility` also feeds mdkg's export safety checks for public/internal packs and public bundles. This is a CLI safety layer, not secret scanning, body redaction, or a replacement for private git hosting.
330
348
 
331
349
  ## Index backends and parallel safety
332
350
 
@@ -360,6 +378,9 @@ rows are durable local project DB history; receipts, reducers, writer leases,
360
378
  and materializers remain internal helper surfaces in this release, with no
361
379
  public `mdkg db event`, `mdkg db reducer`, `mdkg db lease`, or
362
380
  `mdkg db materializer` CLI yet.
381
+ `mdkg work trigger --enqueue <queue>` can bridge a submitted work order mirror
382
+ into an explicitly created active project DB queue; it writes local delivery
383
+ state only and never executes work.
363
384
  Use `mdkg db verify` for non-mutating health checks over config, layout,
364
385
  runtime SQLite integrity, migration metadata, and transient runtime files. Use
365
386
  `mdkg db stats` for deterministic table counts, DB size, migration state,
@@ -401,7 +422,7 @@ Use `mdkg new spec|work|work_order|receipt|feedback|dispute|proposal "<title>"`
401
422
 
402
423
  Relational templates contain editable placeholder refs. `spec` and `work` scaffold as validation-clean standalone docs; `work_order`, `receipt`, `feedback`, `dispute`, and `proposal` need real refs before strict `mdkg validate` passes.
403
424
 
404
- For executable or purchasable capability mirrors, prefer the lifecycle helpers under `mdkg work ...`. They create and update `WORK.md`, `WORK_ORDER.md`, and `RECEIPT.md` semantic mirror files only. Production order state, receipt state, feedback, disputes, payments, ledgers, marketplace inventory, fulfillment records, and execution state remain canonical outside mdkg, such as in Postgres or another application database. Do not store raw secrets, credentials, live payment state, ledger mutations, canonical marketplace state, or bulky raw payloads in these mirrors.
425
+ For executable or purchasable capability mirrors, prefer the lifecycle helpers under `mdkg work ...`. They create and update `WORK.md`, `WORK_ORDER.md`, and `RECEIPT.md` semantic mirror files only. `mdkg work trigger` creates a deterministic submitted `WORK_ORDER.md` from a WORK contract or a SPEC with exactly one resolvable work contract. `mdkg work order status` and `mdkg work receipt verify` are read-only review helpers for deterministic closeout. `mdkg work trigger --enqueue <queue>` optionally writes a local project DB queue delivery message after the queue has been explicitly created and is active; it still does not execute work. Production order state, receipt state, feedback, disputes, payments, ledgers, marketplace inventory, fulfillment records, and execution state remain canonical outside mdkg, such as in Postgres or another application database. Do not store raw secrets, credentials, live payment state, ledger mutations, canonical marketplace state, or bulky raw payloads in these mirrors.
405
426
 
406
427
  ## Archive sidecars
407
428
 
@@ -423,6 +444,7 @@ This release includes:
423
444
  - root-only published init seed config
424
445
  - skills indexing and search/show/list support
425
446
  - JSON capability cache for skills, `SPEC.md`, `WORK.md`, core docs, and design docs
447
+ - optional `mdkg spec list/show/validate` for reusable SPEC capability records
426
448
  - SQLite index backend for fresh workspaces using built-in `node:sqlite`
427
449
  - mutation locking and atomic writes for parallel mdkg calls
428
450
  - first-class `goal` nodes and `mdkg goal show/next/evaluate/pause/resume/done`
@@ -436,7 +458,7 @@ This release includes:
436
458
  - shared `AGENT_START.md` startup guidance
437
459
  - conservative `mdkg upgrade` with mode-aware init manifests
438
460
  - archive sidecars with deterministic ZIP caches
439
- - semantic mirror helpers under `mdkg work ...`
461
+ - semantic mirror helpers under `mdkg work ...`, including trigger/order status/receipt verification
440
462
  - explicit public/internal/private visibility enforcement for packs, bundles, archives, imports, validation, and doctor diagnostics
441
463
  - strict archive ZIP payload integrity checks during validation
442
464
 
package/dist/cli.js CHANGED
@@ -20,6 +20,7 @@ const format_1 = require("./commands/format");
20
20
  const doctor_1 = require("./commands/doctor");
21
21
  const db_1 = require("./commands/db");
22
22
  const capability_1 = require("./commands/capability");
23
+ const spec_1 = require("./commands/spec");
23
24
  const archive_1 = require("./commands/archive");
24
25
  const bundle_1 = require("./commands/bundle");
25
26
  const subgraph_1 = require("./commands/subgraph");
@@ -63,6 +64,7 @@ function printUsage(log) {
63
64
  log(" pack Generate a context pack");
64
65
  log(" skill Create, list, show, search, and validate skills");
65
66
  log(" capability List, search, show, and resolve cached capability surfaces");
67
+ log(" spec List, show, and validate optional SPEC.md capability records");
66
68
  log(" archive Add, list, show, verify, and compress archive sidecars");
67
69
  log(" bundle Create, list, show, and verify full graph snapshot bundles");
68
70
  log(" subgraph Register, sync, materialize, and verify read-only child graph snapshots");
@@ -435,6 +437,41 @@ function printCapabilityHelp(log, subcommand) {
435
437
  printGlobalOptions(log);
436
438
  }
437
439
  }
440
+ function printSpecHelp(log, subcommand) {
441
+ switch ((subcommand ?? "").toLowerCase()) {
442
+ case "list":
443
+ log("Usage:");
444
+ log(" mdkg spec list [--json]");
445
+ log("\nNotes:");
446
+ log(" SPEC.md is optional and declares reusable capability surfaces.");
447
+ printGlobalOptions(log);
448
+ return;
449
+ case "show":
450
+ log("Usage:");
451
+ log(" mdkg spec show <id-or-qid-or-alias> [--json]");
452
+ log("\nNotes:");
453
+ log(" Shows one optional SPEC.md capability record from the capability index.");
454
+ printGlobalOptions(log);
455
+ return;
456
+ case "validate":
457
+ log("Usage:");
458
+ log(" mdkg spec validate [<id-or-qid-or-alias>] [--json]");
459
+ log("\nNotes:");
460
+ log(" With no reference, validates the graph and all optional SPEC.md capability records.");
461
+ log(" With a reference, also ensures that specific SPEC.md capability exists.");
462
+ printGlobalOptions(log);
463
+ return;
464
+ default:
465
+ log("Usage:");
466
+ log(" mdkg spec list [--json]");
467
+ log(" mdkg spec show <id-or-qid-or-alias> [--json]");
468
+ log(" mdkg spec validate [<id-or-qid-or-alias>] [--json]");
469
+ log("\nNotes:");
470
+ log(" SPEC.md is optional and reusable-capability oriented.");
471
+ log(" Use `mdkg capability ...` for broader skill, SPEC.md, WORK.md, core-doc, and design-doc discovery.");
472
+ printGlobalOptions(log);
473
+ }
474
+ }
438
475
  function printArchiveHelp(log, subcommand) {
439
476
  switch ((subcommand ?? "").toLowerCase()) {
440
477
  case "add":
@@ -580,15 +617,31 @@ function printWorkHelp(log, subcommand) {
580
617
  log("Usage:");
581
618
  log(' mdkg work contract new "<title>" --id <work.id> --agent-id <agent.id> --kind <kind> --inputs <...> --outputs <...> [--required-capabilities <...>] [--pricing-model <...>] [--json]');
582
619
  break;
620
+ case "trigger":
621
+ log("Usage:");
622
+ log(' mdkg work trigger <work-or-capability-ref> [--id <order.id>] [--title "<title>"] [--requester <ref>] [--enqueue <queue>] [--json]');
623
+ log("\nExample:");
624
+ log(" mdkg work trigger work.example --id order.example-1 --requester user://example --json");
625
+ log("\nNotes:");
626
+ log(" Accepted targets: direct WORK.md ref, or SPEC.md ref with exactly one resolvable work contract.");
627
+ log(" Creates a deterministic WORK_ORDER.md semantic mirror and does not execute work.");
628
+ log(" Queue enqueue requires a valid project DB plus an explicitly created active queue and never executes work.");
629
+ break;
583
630
  case "order":
584
631
  log("Usage:");
585
- log(' mdkg work order new "<title>" --id <order.id> --work-id <work.id> --requester <ref> [--request-ref <ref>] [--input-refs <...>] [--requested-outputs <...>] [--json]');
586
- log(" mdkg work order update <id-or-qid> [--status <status>] [--add-input-refs <...>] [--add-artifacts <...>] [--json]");
632
+ log(' mdkg work order new "<title>" --id <order.id> --work-id <work.id> --requester <ref> [--request-ref <ref>] [--trigger-ref <ref>] [--payload-hash <sha256:...>] [--input-refs <...>] [--queue-refs <...>] [--requested-outputs <...>] [--json]');
633
+ log(" mdkg work order status <id-or-qid> [--json]");
634
+ log(" mdkg work order update <id-or-qid> [--status <status>] [--add-input-refs <...>] [--add-queue-refs <...>] [--add-artifacts <...>] [--json]");
635
+ log("\nNotes:");
636
+ log(" work order status is read-only and reports deterministic JSON order state plus linked receipts.");
587
637
  break;
588
638
  case "receipt":
589
639
  log("Usage:");
590
- log(' mdkg work receipt new "<title>" --id <receipt.id> --work-order-id <order.id> --outcome success|partial|failure [--receipt-status recorded|verified|rejected|superseded] [--json]');
591
- log(" mdkg work receipt update <id-or-qid> [--receipt-status <status>] [--add-artifacts <...>] [--add-proof-refs <...>] [--add-attestation-refs <...>] [--json]");
640
+ log(' mdkg work receipt new "<title>" --id <receipt.id> --work-order-id <order.id> --outcome success|partial|failure [--receipt-status recorded|verified|rejected|superseded] [--redaction-policy refs_and_hashes_only|redacted_summary|external_private] [--evidence-hashes <sha256:...>] [--json]');
641
+ log(" mdkg work receipt verify <id-or-qid> [--json]");
642
+ log(" mdkg work receipt update <id-or-qid> [--receipt-status <status>] [--add-artifacts <...>] [--add-proof-refs <...>] [--add-attestation-refs <...>] [--add-evidence-hashes <sha256:...>] [--json]");
643
+ log("\nNotes:");
644
+ log(" work receipt verify is read-only and reports deterministic JSON linkage, evidence, hash, outcome, and redaction checks.");
592
645
  break;
593
646
  case "artifact":
594
647
  log("Usage:");
@@ -597,8 +650,9 @@ function printWorkHelp(log, subcommand) {
597
650
  default:
598
651
  log("Usage:");
599
652
  log(" mdkg work contract new ...");
600
- log(" mdkg work order new|update ...");
601
- log(" mdkg work receipt new|update ...");
653
+ log(" mdkg work trigger <work-or-capability-ref> ...");
654
+ log(" mdkg work order new|status|update ...");
655
+ log(" mdkg work receipt new|verify|update ...");
602
656
  log(" mdkg work artifact add ...");
603
657
  log("\nNotes:");
604
658
  log(" - work commands mutate semantic mirror files only");
@@ -837,6 +891,9 @@ function printCommandHelp(log, command, subcommand) {
837
891
  case "capability":
838
892
  printCapabilityHelp(log, subcommand);
839
893
  return;
894
+ case "spec":
895
+ printSpecHelp(log, subcommand);
896
+ return;
840
897
  case "archive":
841
898
  printArchiveHelp(log, subcommand);
842
899
  return;
@@ -1353,6 +1410,45 @@ function runCapabilitySubcommand(parsed, root) {
1353
1410
  throw new errors_1.UsageError("capability requires list/search/show/resolve");
1354
1411
  }
1355
1412
  }
1413
+ function runSpecSubcommand(parsed, root) {
1414
+ const subcommand = (parsed.positionals[1] ?? "").toLowerCase();
1415
+ switch (subcommand) {
1416
+ case "list": {
1417
+ if (parsed.positionals.length > 2) {
1418
+ throw new errors_1.UsageError("spec list does not accept positional arguments");
1419
+ }
1420
+ const json = parseBooleanFlag("--json", parsed.flags["--json"]);
1421
+ const noCache = parseBooleanFlag("--no-cache", parsed.flags["--no-cache"]);
1422
+ const noReindex = parseBooleanFlag("--no-reindex", parsed.flags["--no-reindex"]);
1423
+ (0, spec_1.runSpecListCommand)({ root, json, noCache, noReindex });
1424
+ return 0;
1425
+ }
1426
+ case "show": {
1427
+ const id = parsed.positionals[2];
1428
+ if (!id || parsed.positionals.length > 3) {
1429
+ throw new errors_1.UsageError("spec show requires <id-or-qid-or-alias>");
1430
+ }
1431
+ const json = parseBooleanFlag("--json", parsed.flags["--json"]);
1432
+ const noCache = parseBooleanFlag("--no-cache", parsed.flags["--no-cache"]);
1433
+ const noReindex = parseBooleanFlag("--no-reindex", parsed.flags["--no-reindex"]);
1434
+ (0, spec_1.runSpecShowCommand)({ root, id, json, noCache, noReindex });
1435
+ return 0;
1436
+ }
1437
+ case "validate": {
1438
+ const id = parsed.positionals[2];
1439
+ if (parsed.positionals.length > 3) {
1440
+ throw new errors_1.UsageError("spec validate accepts at most one SPEC reference");
1441
+ }
1442
+ const json = parseBooleanFlag("--json", parsed.flags["--json"]);
1443
+ const noCache = parseBooleanFlag("--no-cache", parsed.flags["--no-cache"]);
1444
+ const noReindex = parseBooleanFlag("--no-reindex", parsed.flags["--no-reindex"]);
1445
+ (0, spec_1.runSpecValidateCommand)({ root, id, json, noCache, noReindex });
1446
+ return 0;
1447
+ }
1448
+ default:
1449
+ throw new errors_1.UsageError("spec requires list/show/validate");
1450
+ }
1451
+ }
1356
1452
  function runArchiveSubcommand(parsed, root) {
1357
1453
  const subcommand = (parsed.positionals[1] ?? "").toLowerCase();
1358
1454
  switch (subcommand) {
@@ -1587,6 +1683,18 @@ function runWorkSubcommand(parsed, root) {
1587
1683
  const action = (parsed.positionals[2] ?? "").toLowerCase();
1588
1684
  const ws = requireFlagValue("--ws", parsed.flags["--ws"]);
1589
1685
  const json = parseBooleanFlag("--json", parsed.flags["--json"]);
1686
+ if (domain === "trigger") {
1687
+ const targetRef = parsed.positionals[2];
1688
+ if (!targetRef || parsed.positionals.length > 3) {
1689
+ throw new errors_1.UsageError("work trigger requires <work-or-capability-ref>");
1690
+ }
1691
+ const id = requireFlagValue("--id", parsed.flags["--id"]);
1692
+ const title = requireFlagValue("--title", parsed.flags["--title"]);
1693
+ const requester = requireFlagValue("--requester", parsed.flags["--requester"]);
1694
+ const enqueue = requireFlagValue("--enqueue", parsed.flags["--enqueue"]);
1695
+ (0, work_1.runWorkTriggerCommand)({ root, ws, targetRef, id, title, requester, enqueue, json });
1696
+ return 0;
1697
+ }
1590
1698
  if (domain === "contract" && action === "new") {
1591
1699
  const title = parsed.positionals.slice(3).join(" ");
1592
1700
  const id = requireFlagValue("--id", parsed.flags["--id"]);
@@ -1623,7 +1731,10 @@ function runWorkSubcommand(parsed, root) {
1623
1731
  throw new errors_1.UsageError("work order new requires title, --id, --work-id, and --requester");
1624
1732
  }
1625
1733
  const requestRef = requireFlagValue("--request-ref", parsed.flags["--request-ref"]);
1734
+ const triggerRef = requireFlagValue("--trigger-ref", parsed.flags["--trigger-ref"]);
1735
+ const payloadHash = requireFlagValue("--payload-hash", parsed.flags["--payload-hash"]);
1626
1736
  const inputRefs = requireFlagValue("--input-refs", parsed.flags["--input-refs"]);
1737
+ const queueRefs = requireFlagValue("--queue-refs", parsed.flags["--queue-refs"]);
1627
1738
  const requestedOutputs = requireFlagValue("--requested-outputs", parsed.flags["--requested-outputs"]);
1628
1739
  const constraintRefs = requireFlagValue("--constraint-refs", parsed.flags["--constraint-refs"]);
1629
1740
  (0, work_1.runWorkOrderNewCommand)({
@@ -1634,7 +1745,10 @@ function runWorkSubcommand(parsed, root) {
1634
1745
  workId,
1635
1746
  requester,
1636
1747
  requestRef,
1748
+ triggerRef,
1749
+ payloadHash,
1637
1750
  inputRefs,
1751
+ queueRefs,
1638
1752
  requestedOutputs,
1639
1753
  constraintRefs,
1640
1754
  json,
@@ -1648,8 +1762,17 @@ function runWorkSubcommand(parsed, root) {
1648
1762
  }
1649
1763
  const status = requireFlagValue("--status", parsed.flags["--status"]);
1650
1764
  const addInputRefs = requireFlagValue("--add-input-refs", parsed.flags["--add-input-refs"]);
1765
+ const addQueueRefs = requireFlagValue("--add-queue-refs", parsed.flags["--add-queue-refs"]);
1651
1766
  const addArtifacts = requireFlagValue("--add-artifacts", parsed.flags["--add-artifacts"]);
1652
- (0, work_1.runWorkOrderUpdateCommand)({ root, ws, id, status, addInputRefs, addArtifacts, json });
1767
+ (0, work_1.runWorkOrderUpdateCommand)({ root, ws, id, status, addInputRefs, addQueueRefs, addArtifacts, json });
1768
+ return 0;
1769
+ }
1770
+ if (domain === "order" && action === "status") {
1771
+ const id = parsed.positionals[3];
1772
+ if (!id || parsed.positionals.length > 4) {
1773
+ throw new errors_1.UsageError("work order status requires <id-or-qid>");
1774
+ }
1775
+ (0, work_1.runWorkOrderStatusCommand)({ root, ws, id, json });
1653
1776
  return 0;
1654
1777
  }
1655
1778
  if (domain === "receipt" && action === "new") {
@@ -1662,9 +1785,11 @@ function runWorkSubcommand(parsed, root) {
1662
1785
  }
1663
1786
  const receiptStatus = requireFlagValue("--receipt-status", parsed.flags["--receipt-status"]);
1664
1787
  const costRef = requireFlagValue("--cost-ref", parsed.flags["--cost-ref"]);
1788
+ const redactionPolicy = requireFlagValue("--redaction-policy", parsed.flags["--redaction-policy"]);
1665
1789
  const artifacts = requireFlagValue("--artifacts", parsed.flags["--artifacts"]);
1666
1790
  const proofRefs = requireFlagValue("--proof-refs", parsed.flags["--proof-refs"]);
1667
1791
  const attestationRefs = requireFlagValue("--attestation-refs", parsed.flags["--attestation-refs"]);
1792
+ const evidenceHashes = requireFlagValue("--evidence-hashes", parsed.flags["--evidence-hashes"]);
1668
1793
  const inputHashes = requireFlagValue("--input-hashes", parsed.flags["--input-hashes"]);
1669
1794
  const outputHashes = requireFlagValue("--output-hashes", parsed.flags["--output-hashes"]);
1670
1795
  (0, work_1.runWorkReceiptNewCommand)({
@@ -1676,9 +1801,11 @@ function runWorkSubcommand(parsed, root) {
1676
1801
  outcome,
1677
1802
  receiptStatus,
1678
1803
  costRef,
1804
+ redactionPolicy,
1679
1805
  artifacts,
1680
1806
  proofRefs,
1681
1807
  attestationRefs,
1808
+ evidenceHashes,
1682
1809
  inputHashes,
1683
1810
  outputHashes,
1684
1811
  json,
@@ -1694,6 +1821,7 @@ function runWorkSubcommand(parsed, root) {
1694
1821
  const addArtifacts = requireFlagValue("--add-artifacts", parsed.flags["--add-artifacts"]);
1695
1822
  const addProofRefs = requireFlagValue("--add-proof-refs", parsed.flags["--add-proof-refs"]);
1696
1823
  const addAttestationRefs = requireFlagValue("--add-attestation-refs", parsed.flags["--add-attestation-refs"]);
1824
+ const addEvidenceHashes = requireFlagValue("--add-evidence-hashes", parsed.flags["--add-evidence-hashes"]);
1697
1825
  (0, work_1.runWorkReceiptUpdateCommand)({
1698
1826
  root,
1699
1827
  ws,
@@ -1702,10 +1830,19 @@ function runWorkSubcommand(parsed, root) {
1702
1830
  addArtifacts,
1703
1831
  addProofRefs,
1704
1832
  addAttestationRefs,
1833
+ addEvidenceHashes,
1705
1834
  json,
1706
1835
  });
1707
1836
  return 0;
1708
1837
  }
1838
+ if (domain === "receipt" && action === "verify") {
1839
+ const id = parsed.positionals[3];
1840
+ if (!id || parsed.positionals.length > 4) {
1841
+ throw new errors_1.UsageError("work receipt verify requires <id-or-qid>");
1842
+ }
1843
+ (0, work_1.runWorkReceiptVerifyCommand)({ root, ws, id, json });
1844
+ return 0;
1845
+ }
1709
1846
  if (domain === "artifact" && action === "add") {
1710
1847
  const targetId = parsed.positionals[3];
1711
1848
  const file = parsed.positionals[4];
@@ -2175,6 +2312,8 @@ function runCommand(parsed, root, runtime) {
2175
2312
  return runSkillSubcommand(parsed, root);
2176
2313
  case "capability":
2177
2314
  return runCapabilitySubcommand(parsed, root);
2315
+ case "spec":
2316
+ return runSpecSubcommand(parsed, root);
2178
2317
  case "archive":
2179
2318
  return runArchiveSubcommand(parsed, root);
2180
2319
  case "bundle":
@@ -1,5 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadCapabilityRecords = loadCapabilityRecords;
4
+ exports.filterCapabilityRecords = filterCapabilityRecords;
5
+ exports.resolveCapabilityRecord = resolveCapabilityRecord;
3
6
  exports.runCapabilityListCommand = runCapabilityListCommand;
4
7
  exports.runCapabilitySearchCommand = runCapabilitySearchCommand;
5
8
  exports.runCapabilityShowCommand = runCapabilityShowCommand;
@@ -29,7 +32,7 @@ function normalizeVisibility(value) {
29
32
  }
30
33
  throw new errors_1.UsageError(`--visibility must be one of ${capabilities_indexer_1.CAPABILITY_VISIBILITIES.join(", ")}`);
31
34
  }
32
- function loadRecords(options) {
35
+ function loadCapabilityRecords(options) {
33
36
  const config = (0, config_1.loadConfig)(options.root);
34
37
  const { index, stale, rebuilt } = (0, capabilities_index_cache_1.loadCapabilitiesIndex)({
35
38
  root: options.root,
@@ -46,7 +49,7 @@ function loadRecords(options) {
46
49
  }
47
50
  return [...index.records, ...subgraph.records];
48
51
  }
49
- function applyFilters(records, options) {
52
+ function filterCapabilityRecords(records, options) {
50
53
  const kind = normalizeKind(options.kind);
51
54
  const visibility = normalizeVisibility(options.visibility);
52
55
  return records.filter((record) => {
@@ -78,6 +81,7 @@ function capabilitySearchText(record) {
78
81
  ...record.headings.map((heading) => heading.text),
79
82
  JSON.stringify(record.spec ?? {}),
80
83
  JSON.stringify(record.work ?? {}),
84
+ JSON.stringify(record.linkage ?? {}),
81
85
  JSON.stringify(record.skill ?? {}),
82
86
  ]
83
87
  .filter((value) => typeof value === "string" && value.length > 0)
@@ -117,6 +121,7 @@ function requirementMatch(record, required) {
117
121
  ...record.tags,
118
122
  JSON.stringify(record.spec ?? {}),
119
123
  JSON.stringify(record.work ?? {}),
124
+ JSON.stringify(record.linkage ?? {}),
120
125
  JSON.stringify(record.skill ?? {}),
121
126
  ]
122
127
  .join(" ")
@@ -199,7 +204,7 @@ function printCapabilityList(records, json, query) {
199
204
  console.log(`${record.qid} | ${record.kind} | ${record.visibility} | ${label} | ${record.title}`);
200
205
  }
201
206
  }
202
- function resolveCapability(records, id) {
207
+ function resolveCapabilityRecord(records, id) {
203
208
  const normalized = id.toLowerCase();
204
209
  const exact = records.find((record) => record.qid === id || record.id === id);
205
210
  if (exact) {
@@ -233,19 +238,19 @@ function printCapability(record, json) {
233
238
  console.log(`path: ${record.path}`);
234
239
  }
235
240
  function runCapabilityListCommand(options) {
236
- const records = applyFilters(loadRecords(options), options);
241
+ const records = filterCapabilityRecords(loadCapabilityRecords(options), options);
237
242
  printCapabilityList(records, options.json);
238
243
  }
239
244
  function runCapabilitySearchCommand(options) {
240
- const records = applyFilters(loadRecords(options), options).filter((record) => matchesQuery(record, options.query));
245
+ const records = filterCapabilityRecords(loadCapabilityRecords(options), options).filter((record) => matchesQuery(record, options.query));
241
246
  printCapabilityList(records, options.json, options.query);
242
247
  }
243
248
  function runCapabilityShowCommand(options) {
244
- const records = loadRecords(options);
245
- printCapability(resolveCapability(records, options.id), options.json);
249
+ const records = loadCapabilityRecords(options);
250
+ printCapability(resolveCapabilityRecord(records, options.id), options.json);
246
251
  }
247
252
  function runCapabilityResolveCommand(options) {
248
- const records = applyFilters(loadRecords(options), options);
253
+ const records = filterCapabilityRecords(loadCapabilityRecords(options), options);
249
254
  const items = resolveCapabilities(records, options).map((record, rank) => ({
250
255
  rank: rank + 1,
251
256
  score: resolveScore(record, options),
@@ -37,7 +37,7 @@ const EXTERNAL_REF_LIST_KEYS = new Set([
37
37
  "proof_refs",
38
38
  "attestation_refs",
39
39
  ]);
40
- const HASH_REF_LIST_KEYS = new Set(["input_hashes", "output_hashes"]);
40
+ const HASH_REF_LIST_KEYS = new Set(["evidence_hashes", "input_hashes", "output_hashes"]);
41
41
  function isValidId(value) {
42
42
  return (0, id_1.isCanonicalId)(value);
43
43
  }
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runSpecListCommand = runSpecListCommand;
4
+ exports.runSpecShowCommand = runSpecShowCommand;
5
+ exports.runSpecValidateCommand = runSpecValidateCommand;
6
+ const capability_1 = require("./capability");
7
+ const validate_1 = require("./validate");
8
+ const errors_1 = require("../util/errors");
9
+ function sortSpecRecords(records) {
10
+ return [...records].sort((a, b) => {
11
+ const qidDelta = a.qid.localeCompare(b.qid);
12
+ if (qidDelta !== 0) {
13
+ return qidDelta;
14
+ }
15
+ return a.path.localeCompare(b.path);
16
+ });
17
+ }
18
+ function loadSpecRecords(options) {
19
+ const listOptions = {
20
+ root: options.root,
21
+ kind: "spec",
22
+ noCache: options.noCache,
23
+ noReindex: options.noReindex,
24
+ };
25
+ return sortSpecRecords((0, capability_1.filterCapabilityRecords)((0, capability_1.loadCapabilityRecords)(listOptions), listOptions));
26
+ }
27
+ function matchesSpecRef(record, id) {
28
+ const normalized = id.toLowerCase();
29
+ return (record.id === id ||
30
+ record.qid === id ||
31
+ record.path === id ||
32
+ record.id.toLowerCase() === normalized ||
33
+ record.qid.toLowerCase() === normalized ||
34
+ record.path.toLowerCase() === normalized ||
35
+ record.aliases.some((alias) => alias.toLowerCase() === normalized));
36
+ }
37
+ function resolveSpecRecord(records, id) {
38
+ const matches = records.filter((record) => matchesSpecRef(record, id));
39
+ if (matches.length === 1) {
40
+ return matches[0];
41
+ }
42
+ if (matches.length > 1) {
43
+ throw new errors_1.UsageError(`SPEC reference is ambiguous: ${id}`);
44
+ }
45
+ throw new errors_1.NotFoundError(`SPEC not found: ${id}`);
46
+ }
47
+ function stringValue(value) {
48
+ return typeof value === "string" ? value : undefined;
49
+ }
50
+ function stringArrayValue(value) {
51
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
52
+ }
53
+ function printSpecList(records, json) {
54
+ if (json) {
55
+ console.log(JSON.stringify({
56
+ kind: "spec",
57
+ count: records.length,
58
+ items: records,
59
+ }, null, 2));
60
+ return;
61
+ }
62
+ if (records.length === 0) {
63
+ console.log("no SPEC.md capabilities found");
64
+ return;
65
+ }
66
+ console.log(`SPEC.md capabilities: ${records.length}`);
67
+ for (const record of records) {
68
+ const kind = stringValue(record.spec?.spec_kind);
69
+ const kindLabel = kind ? ` | ${kind}` : "";
70
+ console.log(`${record.qid} | ${record.visibility}${kindLabel} | ${record.title}`);
71
+ }
72
+ }
73
+ function printSpec(record, json) {
74
+ if (json) {
75
+ console.log(JSON.stringify({ kind: "spec", item: record }, null, 2));
76
+ return;
77
+ }
78
+ console.log(`${record.qid} | ${record.visibility}`);
79
+ console.log(`title: ${record.title}`);
80
+ const specKind = stringValue(record.spec?.spec_kind);
81
+ if (specKind) {
82
+ console.log(`spec_kind: ${specKind}`);
83
+ }
84
+ console.log(`path: ${record.path}`);
85
+ const requestedCapabilities = stringArrayValue(record.spec?.requested_capabilities);
86
+ if (requestedCapabilities.length > 0) {
87
+ console.log(`requested_capabilities: ${requestedCapabilities.join(", ")}`);
88
+ }
89
+ }
90
+ function runSpecListCommand(options) {
91
+ printSpecList(loadSpecRecords(options), options.json);
92
+ }
93
+ function runSpecShowCommand(options) {
94
+ printSpec(resolveSpecRecord(loadSpecRecords(options), options.id), options.json);
95
+ }
96
+ function runSpecValidateCommand(options) {
97
+ if (options.id) {
98
+ resolveSpecRecord(loadSpecRecords(options), options.id);
99
+ }
100
+ (0, validate_1.runValidateCommand)({ root: options.root, json: options.json });
101
+ }