owlrunkit 0.20.0 → 0.22.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 (50) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +102 -10
  3. package/docs/architecture/OWLCODA_RUNKIT_0201_RELEASE_TRUTH_AND_PROFILE_NORMALIZATION_PATCH_DECISION_20260813.md +95 -0
  4. package/docs/architecture/OWLCODA_RUNKIT_021_TEAM_DELIVERY_PHASE2_PRODUCT_DECISION_20260813.md +249 -0
  5. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +117 -12
  6. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  7. package/package.json +1 -1
  8. package/packages/attest/README.md +7 -1
  9. package/packages/attest/consumer-surface-v3.json +275 -0
  10. package/packages/attest/distribution-manifest-v1.json +24 -0
  11. package/packages/attest/schemas/canonical-candidate-identity-v1.schema.json +112 -0
  12. package/packages/attest/schemas/foreign-workspace-filesystem-identity-v1.schema.json +32 -0
  13. package/packages/attest/schemas/quick-verification-receipt-v4.schema.json +226 -0
  14. package/packages/attest/src/candidate-identity.mjs +454 -0
  15. package/packages/attest/src/index.mjs +11 -0
  16. package/packages/attest/src/quick-receipt-contract.mjs +126 -5
  17. package/packages/attest/src/quick.mjs +53 -8
  18. package/{registry-release-policy-v1.json → registry-release-policy-v2.json} +8 -9
  19. package/sbom.spdx.json +4 -4
  20. package/scripts/runkit-contract/core-contract.mjs +19 -1
  21. package/scripts/runkit-contract/fleet-skill-plan.mjs +223 -0
  22. package/scripts/runkit-contract/formal-workflow.mjs +3 -1
  23. package/scripts/runkit-contract/hook-recovery.mjs +496 -0
  24. package/scripts/runkit-contract/inspect-presentation.mjs +187 -0
  25. package/scripts/runkit-contract/install-codex-skill.mjs +1 -0
  26. package/scripts/runkit-contract/onboarding-bootstrap.mjs +15 -0
  27. package/scripts/runkit-contract/onboarding-doctor.mjs +378 -9
  28. package/scripts/runkit-contract/profile-onboarding.mjs +6 -0
  29. package/scripts/runkit-contract/project-cli-resolver.mjs +17 -1
  30. package/scripts/runkit-contract/quick-metrics.mjs +9 -5
  31. package/scripts/runkit-contract/quick-verify.mjs +108 -24
  32. package/scripts/runkit-contract/registry-adoption-gate.mjs +12 -3
  33. package/scripts/runkit-contract/registry-adoption.mjs +10 -5
  34. package/scripts/runkit-contract/runkit-bootstrap.mjs +1 -0
  35. package/scripts/runkit-contract/runkit-cli.mjs +332 -30
  36. package/scripts/runkit-contract/schemas/delivery-lifecycle-v1.schema.json +91 -0
  37. package/scripts/runkit-contract/schemas/external-gate-v1.schema.json +68 -0
  38. package/scripts/runkit-contract/schemas/fleet-skill-upgrade-plan-v1.schema.json +140 -0
  39. package/scripts/runkit-contract/schemas/hook-recovery-v1.schema.json +592 -0
  40. package/scripts/runkit-contract/schemas/inspect-compact-v1.schema.json +93 -0
  41. package/scripts/runkit-contract/schemas/inspect-compact-v2.schema.json +122 -0
  42. package/scripts/runkit-contract/schemas/team-delivery-status-v2.schema.json +219 -0
  43. package/scripts/runkit-contract/schemas/team-delivery-status-v3.schema.json +113 -0
  44. package/scripts/runkit-contract/schemas/team-project-event-v6.schema.json +82 -0
  45. package/scripts/runkit-contract/schemas/team-project-event-v7.schema.json +80 -0
  46. package/scripts/runkit-contract/schemas/team-project-status-v4.schema.json +208 -0
  47. package/scripts/runkit-contract/schemas/team-recommendation-v2.schema.json +120 -0
  48. package/scripts/runkit-contract/sync-release-identity.mjs +87 -0
  49. package/scripts/runkit-contract/team-delivery.mjs +203 -3
  50. package/scripts/runkit-contract/team-project.mjs +1032 -11
@@ -13,6 +13,7 @@ import {
13
13
  writeFileSync,
14
14
  } from "node:fs";
15
15
  import path from "node:path";
16
+ import { fileURLToPath } from "node:url";
16
17
 
17
18
  import {
18
19
  CORE_VERSION,
@@ -85,7 +86,12 @@ import {
85
86
  verifySourceCandidateV1,
86
87
  verifySourceCandidateV2,
87
88
  } from "./source-candidate.mjs";
88
- import { buildInspectSummary, formatInspectHuman } from "./inspect-presentation.mjs";
89
+ import {
90
+ buildInspectCompactV2,
91
+ buildInspectSummary,
92
+ formatInspectHuman,
93
+ } from "./inspect-presentation.mjs";
94
+ import { buildHookRecoveryV1 } from "./hook-recovery.mjs";
89
95
  import { attestQuickReceiptDetails } from "./quick-attest.mjs";
90
96
  import { readLocalQuickMetrics } from "./quick-metrics.mjs";
91
97
  import { runQuickEvidenceReuse } from "./quick-evidence-reuse.mjs";
@@ -119,6 +125,10 @@ import {
119
125
  replaceFleetRegistry,
120
126
  rollbackFleetRegistry,
121
127
  } from "./fleet-discovery.mjs";
128
+ import {
129
+ formatFleetSkillUpgradePlanHumanV1,
130
+ planFleetSkillUpgradeV1,
131
+ } from "./fleet-skill-plan.mjs";
122
132
  import {
123
133
  RUNKIT_RISK_CATEGORIES,
124
134
  routeRunKitAssuranceV2,
@@ -154,9 +164,10 @@ import {
154
164
  } from "./core-successor.mjs";
155
165
  import {
156
166
  formatDoctorHuman,
167
+ inspectLocalMaintenanceV1,
157
168
  readAdoptionReadiness,
158
169
  readProfileLauncherReadiness,
159
- runDoctor,
170
+ runDoctorV3,
160
171
  } from "./onboarding-doctor.mjs";
161
172
  import {
162
173
  applyOnboardingBootstrapV1,
@@ -171,8 +182,9 @@ import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
171
182
  import {
172
183
  appendTeamProjectEventV1,
173
184
  assignTeamProjectV1,
174
- buildTeamProjectTakeoverV3,
185
+ buildTeamProjectTakeoverV4,
175
186
  checkpointTeamProjectV1,
187
+ checkpointTeamProjectFromQuickReceiptV1,
176
188
  closeTeamProjectVerificationV1,
177
189
  deferTeamProjectVerificationV1,
178
190
  formatTeamProjectStatusHumanV2,
@@ -183,10 +195,14 @@ import {
183
195
  openTeamProjectDecisionV1,
184
196
  readTeamProjectStatusV2,
185
197
  readTeamProjectStatusV3,
198
+ readTeamProjectStatusV4,
199
+ reconcileExternalGateV1,
200
+ recordDeliveryLifecycleV1,
186
201
  rejectAndReturnTeamProjectV1,
187
202
  reopenUpstreamTeamProjectV1,
188
203
  resolveTeamProjectDecisionV1,
189
204
  reviseTeamProjectWorkItemScopeV1,
205
+ setWorkItemEvidenceRequirementV1,
190
206
  transferTeamProjectV1,
191
207
  } from "./team-project.mjs";
192
208
  import {
@@ -198,11 +214,11 @@ import {
198
214
  importExternalDeliveryV1,
199
215
  } from "./project-external-delivery.mjs";
200
216
  import {
201
- formatTeamDeliveryRecommendationHumanV1,
202
- formatTeamDeliveryStatusHumanV1,
217
+ formatTeamDeliveryRecommendationHumanV2,
218
+ formatTeamDeliveryStatusHumanV3,
203
219
  formatTeamPacketValidationHumanV1,
204
- readTeamDeliveryStatusV1,
205
- recommendTeamDeliveryV1,
220
+ readTeamDeliveryStatusV3,
221
+ recommendTeamDeliveryV2,
206
222
  validateTeamPacketFileV1,
207
223
  } from "./team-delivery.mjs";
208
224
 
@@ -238,14 +254,14 @@ Fleet and status
238
254
  npx --no-install owlrunkit fleet <register-root|inspect-registry> [options]
239
255
  npx --no-install owlrunkit fleet replace-registry --request <file> --receipt <file> [--dry-run]
240
256
  npx --no-install owlrunkit fleet rollback-registry --receipt <file> --rollback-receipt <file>
257
+ npx --no-install owlrunkit fleet skill-plan --skill-root <directory> --archive-root <directory>
241
258
  npx --no-install owlrunkit fleet discover; npx --no-install owlrunkit status --workspace .
242
-
259
+ npx --no-install owlrunkit hook recovery --workspace . --json
243
260
  Agent team projects
244
- npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|decision|verification|capture|target-snapshot|import-delivery|status|takeover|successor> [options]
261
+ npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|work-item require-evidence|reconcile|delivery record|decision|verification|capture|target-snapshot|import-delivery|status|takeover|successor> [options]
245
262
  npx --no-install owlrunkit team <recommend|status|packet validate> [options]
246
263
  Durable project truth plus read-only Team recommendation and packet validation. No Agent dispatch.
247
- Core successor
248
- npx --no-install owlrunkit core-successor <plan|apply|resume> --workspace . [...]
264
+ Core successor: npx --no-install owlrunkit core-successor <plan|apply|resume> --workspace . [...]
249
265
  Other onboarding commands:
250
266
  npx --no-install owlrunkit profiles validate --workspace .; npx --no-install owlrunkit profiles impact --workspace . --changed <path>
251
267
  npx --no-install owlrunkit inspect --workspace . --json
@@ -271,6 +287,47 @@ validation, exact registry adoption, and doctor readback. Failed apply restores
271
287
  the governed preimage and retains a failure receipt. Shared Skill drift is
272
288
  diagnosed only; bootstrap never silently refreshes user or fleet Skills and
273
289
  grants no Git, release, deployment, production, or business authority.
290
+ `,
291
+ inspect: `Usage:
292
+ npx --no-install owlrunkit inspect --workspace <directory> [--json]
293
+ npx --no-install owlrunkit inspect --workspace <directory> --json --compact
294
+ npx --no-install owlrunkit inspect --workspace <directory> --history [--json]
295
+ npx --no-install owlrunkit inspect --workspace <directory> --run-id <id> [--verbose] [--json]
296
+
297
+ --compact returns only current project truth, progress, dominant gap, owner,
298
+ separate lifecycle/project/maintenance actions, actionable warning groups,
299
+ advisories, execution counts, and the authority boundary.
300
+ It never grants Git, release, deployment, production, or business authority.
301
+ `,
302
+ hook: `Usage:
303
+ npx --no-install owlrunkit hook recovery --workspace <directory> --json
304
+
305
+ Returns a deterministic, read-only, strictly bounded recovery projection for
306
+ SessionStart(source=compact). Project text remains escaped untrusted data.
307
+ The consumer must compare its current Goal/Done-when with projectId and the
308
+ objective digest/preview before considering nextAction. This command never
309
+ changes project, execution, lease, assurance, Agent, Git, release, deployment,
310
+ production, or business state.
311
+ `,
312
+ "hook recovery": `Usage:
313
+ npx --no-install owlrunkit hook recovery --workspace <directory> --json
314
+
315
+ Returns a deterministic, read-only, strictly bounded recovery projection for
316
+ SessionStart(source=compact). Project text remains escaped untrusted data.
317
+ The consumer must compare its current Goal/Done-when with projectId and the
318
+ objective digest/preview before considering nextAction. This command never
319
+ changes project, execution, lease, assurance, Agent, Git, release, deployment,
320
+ production, or business state.
321
+ `,
322
+
323
+ doctor: `Usage:
324
+ npx --no-install owlrunkit doctor --workspace <directory>
325
+ [--registry <url>] [--timeout-ms <milliseconds>]
326
+ [--skill-root <installed-skill-directory>] [--json]
327
+
328
+ Checks the project package, Core, registry, profiles, adoption, lifecycle, and
329
+ process-level shared Skill independently. Shared Skill drift is diagnostic and
330
+ non-blocking; it never changes project authority.
274
331
  `,
275
332
  adopt: `Usage:
276
333
  npx --no-install owlrunkit adopt --workspace <directory> --exact owlrunkit@${CORE_VERSION}
@@ -337,6 +394,41 @@ Single ordinary lanes and uninitialized projects remain off. This is read-only.
337
394
  npx --no-install owlrunkit team status --workspace <directory> [--json]
338
395
 
339
396
  Reads a Team Delivery projection from Project Driver. No second graph is stored.
397
+ `,
398
+ "project reconcile": `Usage:
399
+ npx --no-install owlrunkit project reconcile --workspace <directory>
400
+ --reconciliation-id <id> --at <ISO-UTC> --gate-id <id> --title <text>
401
+ --required-for <source|integration|materialization|deployment|live_readback|product_acceptance>
402
+ --gate-status <pending|passed|blocked|deferred> --owner-agent <id>
403
+ --source-adapter <id> --source-ref <ref> --source-sha256 <sha256:hex>
404
+ --summary <text> --evidence <ref> [--evidence <ref> ...] [--json]
405
+
406
+ Records one domain-adapter-produced ExternalGateV1 observation. RunKit validates
407
+ the typed source binding but does not parse domain contracts. It grants no Git,
408
+ release, deployment, production, business, or Agent-dispatch authority;
409
+ authorizationGranted remains false.
410
+ `,
411
+ "project delivery record": `Usage:
412
+ npx --no-install owlrunkit project delivery record --workspace <directory>
413
+ --record-id <id> --at <ISO-UTC>
414
+ --stage <source|integration|materialization|deployment|live_readback|product_acceptance>
415
+ --stage-status <stage-specific-outcome> --owner-agent <id> --summary <text>
416
+ --evidence <ref> [--evidence <ref> ...]
417
+ [--external-gate <id> ...] [--json]
418
+
419
+ Records one evidence-bound delivery lifecycle fact. The command never performs
420
+ the underlying integration, materialization, deployment, readback, or product acceptance and
421
+ grants no authority for those actions; authorizationGranted remains false.
422
+ `,
423
+ "project work-item require-evidence": `Usage:
424
+ npx --no-install owlrunkit project work-item require-evidence --workspace <directory>
425
+ --policy-id <id> --at <ISO-UTC> --work-item <id> --owner-agent <id>
426
+ --requirement <none|quick> --reason <text>
427
+ --evidence <ref> [--evidence <ref> ...] [--json]
428
+
429
+ Records an explicit WorkItem evidence requirement without selecting or raising
430
+ assurance automatically. Existing WorkItems remain requirement=none until this
431
+ typed action is invoked; authorizationGranted remains false.
340
432
  `,
341
433
  "team packet validate": `Usage:
342
434
  npx --no-install owlrunkit team packet validate --workspace <directory>
@@ -353,6 +445,7 @@ It never grants repository or business authority.
353
445
  `,
354
446
  "quick-verify": `Usage:
355
447
  npx --no-install owlrunkit quick-verify --workspace <directory>
448
+ [--foreign-workspace <frozen-git-worktree>]
356
449
  [--isolate] [--dependency-root <directory>] [--bind-ignored <relative-path> ...]
357
450
  [--stdin-file <file>] [--capture-runtime] [--attest] [--json]
358
451
  -- <executable> [args...]
@@ -365,6 +458,10 @@ attests the saved receipt without merging Quick and attestation semantics.
365
458
  --dependency-root binds and projects an existing dependency environment without
366
459
  installing anything. Ignored workspace bytes are bound only by explicit,
367
460
  repeatable --bind-ignored literal paths.
461
+ --foreign-workspace keeps the exact project-local CLI and receipt store in the
462
+ controller --workspace, copies the foreign source into a disposable consumer,
463
+ and binds its canonical candidate and whole-tree before/after identities. It
464
+ never initializes or writes RunKit state in the foreign worktree.
368
465
  --capture-runtime sets OWLRUNKIT_RUNTIME_REPORT for the exact command and binds
369
466
  one strict command-reported external transition without conflating it with
370
467
  workspace mutation. Missing or inconsistent runtime truth fails closed while
@@ -428,6 +525,7 @@ non-Formal and grants no Git, release, deployment, production, or business autho
428
525
  npx --no-install owlrunkit fleet replace-registry --request <file> --receipt <file> [--registry <file>] [--dry-run]
429
526
  npx --no-install owlrunkit fleet rollback-registry --receipt <file> --rollback-receipt <file> [--registry <file>]
430
527
  npx --no-install owlrunkit fleet discover [--fleet-root <directory>] [--fleet-manifest <file>]
528
+ npx --no-install owlrunkit fleet skill-plan --skill-root <directory> --archive-root <directory>
431
529
  `,
432
530
  "fleet register-root": `Usage:
433
531
  npx --no-install owlrunkit fleet register-root --fleet-root <directory>
@@ -457,6 +555,16 @@ Restores the exact preimage recorded by a replacement receipt.
457
555
  [--workspace-root <directory>]
458
556
 
459
557
  With no source option, discovers the complete fleet inside registered roots.
558
+ `,
559
+ "fleet skill-plan": `Usage:
560
+ npx --no-install owlrunkit fleet skill-plan --skill-root <installed-skill-directory>
561
+ --archive-root <skill-archive-directory>
562
+ [--workspace-root <directory> ... | --fleet-root <directory> ... |
563
+ --fleet-manifest <file> | --registry <file>] [--json]
564
+
565
+ Reads the shared Skill and complete fleet, then reports affected projects,
566
+ active execution or lease blockers, and copyable dry-run, install, and rollback
567
+ commands. It never updates the Skill or any project.
460
568
  `,
461
569
  profiles: `Usage:
462
570
  npx --no-install owlrunkit profiles detect --workspace <directory> [--dry-run | --apply]
@@ -616,7 +724,8 @@ action without granting any authority.
616
724
  --state <active|waiting_dependency|waiting_decision|verifying|ready_to_integrate|completed|failed>
617
725
  --summary <text> [--completed-units <nonnegative-int>]
618
726
  [--evidence <ref> ...] [--blocker <ref> ...] [--decision <id> ...]
619
- [--next <text>] [--source-fingerprint <sha256>] [--json]
727
+ [--next <text>] [--source-fingerprint <sha256>]
728
+ [--from-quick-receipt <receipt.json>] [--json]
620
729
  npx --no-install owlrunkit project verification --workspace <directory> --defer --verification-id <id> --at <ISO-UTC>
621
730
  --work-item <id> --owner-agent <id> --check <check-id> [--check <check-id> ...]
622
731
  --reason <text> --due-gate <gate-id> [--json]
@@ -648,6 +757,9 @@ No self-reported percentage is accepted.
648
757
  Measured WorkItems require --completed-units on every checkpoint. A completed
649
758
  checkpoint must use the WorkItem's declared total. Example:
650
759
  npx --no-install owlrunkit project checkpoint --workspace . --checkpoint-id checkpoint-x --at 2026-08-11T00:00:00.000Z --assignment-id assign-x --work-item x --state completed --summary 'Completed x.' --completed-units 5 --evidence receipt:quick
760
+
761
+ --from-quick-receipt re-attests and atomically binds one current GO Quick
762
+ receipt. It is required only when an explicit WorkItem evidence policy says so.
651
763
  `,
652
764
  "project init": `Usage:
653
765
  npx --no-install owlrunkit project init --workspace <directory>
@@ -1832,6 +1944,10 @@ function inspect(options) {
1832
1944
  if (options.history && requestedRunId) throw new Error("inspect --history cannot be combined with --run-id.");
1833
1945
  if (options.verbose && !requestedRunId) throw new Error("inspect --verbose requires --run-id.");
1834
1946
  if (options.history && options.verbose) throw new Error("inspect --history cannot be combined with --verbose.");
1947
+ if (options.compact && options.json !== true) throw new Error("inspect --compact requires --json.");
1948
+ if (options.compact && (options.history || options.verbose || requestedRunId)) {
1949
+ throw new Error("inspect --compact cannot be combined with --history, --verbose, or --run-id.");
1950
+ }
1835
1951
  const controlIssues = [];
1836
1952
  const configPath = runtimePath(root, "config.json");
1837
1953
  const candidateConfig = readJsonForInspection(root, configPath, "Project config", controlIssues);
@@ -2055,6 +2171,13 @@ function inspect(options) {
2055
2171
  const projectDriver = pathEntryExists(projectDefinitionPath)
2056
2172
  ? readTeamProjectStatusV3({ workspaceRoot: root })
2057
2173
  : null;
2174
+ const localMaintenance = options.compact === true
2175
+ ? inspectLocalMaintenanceV1({
2176
+ workspaceRoot: root,
2177
+ packageRoot: path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."),
2178
+ sharedSkillRoot: process.env.OWLCODA_RUNKIT_PROCESS_SKILL_ROOT,
2179
+ })
2180
+ : null;
2058
2181
  const summary = buildInspectSummary(result, {
2059
2182
  maintenanceNextAction: onboarding.maintenanceNextAction ?? null,
2060
2183
  projectDriver,
@@ -2069,13 +2192,15 @@ function inspect(options) {
2069
2192
  execution: executions.find(execution => execution.runId === requestedRunId),
2070
2193
  }
2071
2194
  : { mode: "summary" };
2072
- return {
2195
+ const inspected = {
2073
2196
  ...result,
2074
2197
  summary,
2075
2198
  view,
2076
2199
  onboarding,
2200
+ ...(localMaintenance === null ? {} : { localMaintenance }),
2077
2201
  ...(projectDriver === null ? {} : { projectDriver }),
2078
2202
  };
2203
+ return options.compact === true ? buildInspectCompactV2(inspected) : inspected;
2079
2204
  }
2080
2205
 
2081
2206
  function closeout(options) {
@@ -2339,6 +2464,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2339
2464
  "efficiency",
2340
2465
  "fleet",
2341
2466
  "formal",
2467
+ "hook",
2342
2468
  "lease",
2343
2469
  "mode",
2344
2470
  "profiles",
@@ -2351,6 +2477,16 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2351
2477
  action = "work-item revise-scope";
2352
2478
  nestedOptions = nestedOptions.slice(1);
2353
2479
  }
2480
+ if (command === "project" && action === "work-item"
2481
+ && nestedOptions[0] === "require-evidence") {
2482
+ action = "work-item require-evidence";
2483
+ nestedOptions = nestedOptions.slice(1);
2484
+ }
2485
+ if (command === "project" && action === "delivery"
2486
+ && nestedOptions[0] === "record") {
2487
+ action = "delivery record";
2488
+ nestedOptions = nestedOptions.slice(1);
2489
+ }
2354
2490
  if (command === "team" && action === "packet"
2355
2491
  && nestedOptions[0] === "validate") {
2356
2492
  action = "packet validate";
@@ -2382,7 +2518,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2382
2518
  ? ["allow-path"]
2383
2519
  : command === "profiles" && action === "impact"
2384
2520
  ? ["changed"]
2385
- : (command === "fleet" && action === "discover")
2521
+ : (command === "fleet" && new Set(["discover", "skill-plan"]).has(action))
2386
2522
  || (command === "core-successor" && action === "plan")
2387
2523
  ? ["fleet-root", "workspace-root"]
2388
2524
  : (command === "lease" && action === "acquire")
@@ -2409,6 +2545,12 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2409
2545
  ? ["blocking-work-item", "option", "evidence"]
2410
2546
  : command === "project" && action === "work-item revise-scope"
2411
2547
  ? ["owned-path", "evidence"]
2548
+ : command === "project" && action === "work-item require-evidence"
2549
+ ? ["evidence"]
2550
+ : command === "project" && action === "reconcile"
2551
+ ? ["evidence"]
2552
+ : command === "project" && action === "delivery record"
2553
+ ? ["evidence", "external-gate"]
2412
2554
  : command === "efficiency" && action === "record"
2413
2555
  ? ["evidence"]
2414
2556
  : [],
@@ -2434,8 +2576,10 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2434
2576
  ? ["json"]
2435
2577
  : command === "team"
2436
2578
  ? ["json"]
2579
+ : command === "hook"
2580
+ ? ["json"]
2437
2581
  : command === "inspect"
2438
- ? ["json", "verbose", "history"]
2582
+ ? ["json", "compact", "verbose", "history"]
2439
2583
  : command === "init"
2440
2584
  ? ["json"]
2441
2585
  : command === "bootstrap"
@@ -2448,7 +2592,9 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2448
2592
  ? ["json", "defer", "close"]
2449
2593
  : command === "project" && action === "work-item revise-scope"
2450
2594
  ? ["json", "unmeasured"]
2451
- : command === "project" && new Set(["init", "assign", "handoff", "reject-and-return", "reopen-upstream", "transfer", "checkpoint", "integrate", "capture", "status", "takeover", "successor"]).has(action)
2595
+ : command === "project" && action === "work-item require-evidence"
2596
+ ? ["json"]
2597
+ : command === "project" && new Set(["init", "assign", "handoff", "reject-and-return", "reopen-upstream", "transfer", "checkpoint", "integrate", "capture", "reconcile", "delivery record", "status", "takeover", "successor"]).has(action)
2452
2598
  ? ["json"]
2453
2599
  : command === "project" && new Set(["target-snapshot", "import-delivery"]).has(action)
2454
2600
  ? ["json", "dry-run", "apply"]
@@ -2456,6 +2602,8 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2456
2602
  ? ["json"]
2457
2603
  : command === "profiles"
2458
2604
  ? ["json", "dry-run", "apply"]
2605
+ : command === "fleet" && action === "skill-plan"
2606
+ ? ["json"]
2459
2607
  : command === "fleet" && action === "replace-registry"
2460
2608
  ? ["dry-run"]
2461
2609
  : command === "candidate"
@@ -2503,16 +2651,24 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2503
2651
  : withHumanOutput(result, formatOnboardingBootstrapHumanV1(result));
2504
2652
  }
2505
2653
  if (command === "doctor") {
2654
+ assertOnlyOptions(options, [
2655
+ "workspace", "registry", "timeout-ms", "skill-root", "json",
2656
+ ]);
2506
2657
  const timeoutMs = options["timeout-ms"] === undefined
2507
2658
  ? 1_500
2508
2659
  : Number.parseInt(options["timeout-ms"], 10);
2509
2660
  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 25 || timeoutMs > 10_000) {
2510
2661
  throw new Error("--timeout-ms must be an integer from 25 to 10000.");
2511
2662
  }
2512
- const report = await runDoctor({
2663
+ const report = await runDoctorV3({
2513
2664
  workspaceRoot: requireOption(options, "workspace"),
2665
+ sharedSkillRoot: options["skill-root"],
2666
+ discoverSharedSkill: true,
2514
2667
  registryUrl: options.registry ?? OFFICIAL_NPM_REGISTRY,
2515
2668
  timeoutMs,
2669
+ ...(options["skill-root"] === undefined
2670
+ ? {}
2671
+ : { skillRoot: options["skill-root"] }),
2516
2672
  });
2517
2673
  report.exitCode = report.status === "ready" ? 0 : 2;
2518
2674
  return options.json === true
@@ -2639,20 +2795,20 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2639
2795
  const root = workspace(options);
2640
2796
  if (action === "recommend") {
2641
2797
  assertOnlyOptions(options, ["workspace", "json"]);
2642
- const recommendation = recommendTeamDeliveryV1({ workspaceRoot: root });
2798
+ const recommendation = recommendTeamDeliveryV2({ workspaceRoot: root });
2643
2799
  return options.json === true
2644
2800
  ? recommendation
2645
2801
  : withHumanOutput(
2646
2802
  recommendation,
2647
- formatTeamDeliveryRecommendationHumanV1(recommendation),
2803
+ formatTeamDeliveryRecommendationHumanV2(recommendation),
2648
2804
  );
2649
2805
  }
2650
2806
  if (action === "status") {
2651
2807
  assertOnlyOptions(options, ["workspace", "json"]);
2652
- const status = readTeamDeliveryStatusV1({ workspaceRoot: root });
2808
+ const status = readTeamDeliveryStatusV3({ workspaceRoot: root });
2653
2809
  return options.json === true
2654
2810
  ? status
2655
- : withHumanOutput(status, formatTeamDeliveryStatusHumanV1(status));
2811
+ : withHumanOutput(status, formatTeamDeliveryStatusHumanV3(status));
2656
2812
  }
2657
2813
  if (action === "packet validate") {
2658
2814
  assertOnlyOptions(options, ["workspace", "packet", "json"]);
@@ -2669,6 +2825,33 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2669
2825
  );
2670
2826
  }
2671
2827
  if (command === "fleet") {
2828
+ if (action === "skill-plan") {
2829
+ assertOnlyOptions(options, [
2830
+ "skill-root",
2831
+ "archive-root",
2832
+ "workspace-root",
2833
+ "fleet-root",
2834
+ "fleet-manifest",
2835
+ "registry",
2836
+ "json",
2837
+ ]);
2838
+ const plan = await planFleetSkillUpgradeV1({
2839
+ repositoryRoot: path.resolve(
2840
+ path.dirname(fileURLToPath(import.meta.url)),
2841
+ "../..",
2842
+ ),
2843
+ targetRoot: requireOption(options, "skill-root"),
2844
+ archiveRoot: requireOption(options, "archive-root"),
2845
+ workspaceRoots: options["workspace-root"] ?? null,
2846
+ fleetRoots: options["fleet-root"] ?? null,
2847
+ fleetManifestPath: options["fleet-manifest"] ?? null,
2848
+ fleetRegistryPath: options.registry ?? null,
2849
+ });
2850
+ const result = { ...plan, exitCode: plan.status === "ready" ? 0 : 2 };
2851
+ return options.json === true
2852
+ ? result
2853
+ : withHumanOutput(result, formatFleetSkillUpgradePlanHumanV1(plan));
2854
+ }
2672
2855
  if (action === "register-root") {
2673
2856
  const registered = await registerFleetCoverageRoot({
2674
2857
  fleetRoot: requireOption(options, "fleet-root"),
@@ -2709,7 +2892,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2709
2892
  };
2710
2893
  }
2711
2894
  if (action !== "discover") {
2712
- throw new Error("Usage: npx --no-install owlrunkit fleet <register-root|inspect-registry|replace-registry|rollback-registry|discover>");
2895
+ throw new Error("Usage: npx --no-install owlrunkit fleet <register-root|inspect-registry|replace-registry|rollback-registry|discover|skill-plan>");
2713
2896
  }
2714
2897
  const discovered = await discoverFleet({
2715
2898
  fleetRoots: options["fleet-root"] ?? null,
@@ -3438,6 +3621,15 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3438
3621
  const root = workspace(options);
3439
3622
  return withControlTransaction(root, () => plan(options));
3440
3623
  }
3624
+ if (command === "hook") {
3625
+ if (action !== "recovery") {
3626
+ throw new Error("Usage: npx --no-install owlrunkit hook recovery --workspace <directory> --json");
3627
+ }
3628
+ assertOnlyOptions(options, ["workspace", "json"]);
3629
+ return buildHookRecoveryV1({
3630
+ workspaceRoot: requireOption(options, "workspace"),
3631
+ });
3632
+ }
3441
3633
  if (command === "inspect") return inspect(options);
3442
3634
  if (command === "status") {
3443
3635
  const inspected = inspect({ ...options, json: true });
@@ -3488,6 +3680,19 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3488
3680
  "owner-agent", "owned-path", "measurable-unit", "measurable-total",
3489
3681
  "unmeasured", "reason", "evidence", "json",
3490
3682
  ],
3683
+ "work-item require-evidence": [
3684
+ "workspace", "policy-id", "at", "work-item", "owner-agent",
3685
+ "requirement", "reason", "evidence", "json",
3686
+ ],
3687
+ reconcile: [
3688
+ "workspace", "reconciliation-id", "at", "gate-id", "title",
3689
+ "required-for", "gate-status", "owner-agent", "source-adapter",
3690
+ "source-ref", "source-sha256", "summary", "evidence", "json",
3691
+ ],
3692
+ "delivery record": [
3693
+ "workspace", "record-id", "at", "stage", "stage-status",
3694
+ "owner-agent", "summary", "evidence", "external-gate", "json",
3695
+ ],
3491
3696
  decision: [
3492
3697
  "workspace", "request", "open", "resolve", "decision-id", "at", "title",
3493
3698
  "question", "owner-agent", "blocking-work-item", "option", "resolution",
@@ -3496,7 +3701,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3496
3701
  checkpoint: [
3497
3702
  "workspace", "request", "checkpoint-id", "at", "assignment-id", "work-item",
3498
3703
  "state", "summary", "completed-units", "evidence", "blocker", "decision",
3499
- "next", "source-fingerprint", "json",
3704
+ "next", "source-fingerprint", "from-quick-receipt", "json",
3500
3705
  ],
3501
3706
  verification: [
3502
3707
  "workspace", "request", "defer", "close", "verification-id", "at",
@@ -3764,6 +3969,83 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3764
3969
  "",
3765
3970
  ].join("\n"));
3766
3971
  }
3972
+ if (action === "work-item require-evidence") {
3973
+ const evidenceRefs = options.evidence ?? [];
3974
+ if (evidenceRefs.length === 0) {
3975
+ throw new Error("WorkItem evidence requirement requires at least one --evidence.");
3976
+ }
3977
+ const policy = setWorkItemEvidenceRequirementV1({
3978
+ workspaceRoot: root,
3979
+ policyId: requireOption(options, "policy-id"),
3980
+ occurredAt: requireOption(options, "at"),
3981
+ workItemId: requireOption(options, "work-item"),
3982
+ ownerAgentId: requireOption(options, "owner-agent"),
3983
+ requirement: requireOption(options, "requirement"),
3984
+ reason: requireOption(options, "reason"),
3985
+ evidenceRefs,
3986
+ });
3987
+ return options.json === true
3988
+ ? policy
3989
+ : withHumanOutput(policy, [
3990
+ `WorkItem ${policy.workItemId} evidence requirement: ${policy.requirement}.`,
3991
+ "Assurance was not changed and authority was not granted.",
3992
+ "",
3993
+ ].join("\n"));
3994
+ }
3995
+ if (action === "reconcile") {
3996
+ const evidenceRefs = options.evidence ?? [];
3997
+ if (evidenceRefs.length === 0) {
3998
+ throw new Error("Project reconcile requires at least one --evidence.");
3999
+ }
4000
+ const reconciled = reconcileExternalGateV1({
4001
+ workspaceRoot: root,
4002
+ reconciliationId: requireOption(options, "reconciliation-id"),
4003
+ occurredAt: requireOption(options, "at"),
4004
+ gateId: requireOption(options, "gate-id"),
4005
+ title: requireOption(options, "title"),
4006
+ requiredFor: requireOption(options, "required-for"),
4007
+ gateStatus: requireOption(options, "gate-status"),
4008
+ ownerAgentId: requireOption(options, "owner-agent"),
4009
+ sourceAdapterId: requireOption(options, "source-adapter"),
4010
+ sourceRef: requireOption(options, "source-ref"),
4011
+ sourceSha256: requireOption(options, "source-sha256"),
4012
+ summary: requireOption(options, "summary"),
4013
+ evidenceRefs,
4014
+ });
4015
+ return options.json === true
4016
+ ? reconciled
4017
+ : withHumanOutput(reconciled, [
4018
+ `External Gate ${reconciled.gateId}: ${reconciled.gateStatus}.`,
4019
+ `Next: ${reconciled.nextAction ?? "none"}.`,
4020
+ "Authority: not granted.",
4021
+ "",
4022
+ ].join("\n"));
4023
+ }
4024
+ if (action === "delivery record") {
4025
+ const evidenceRefs = options.evidence ?? [];
4026
+ if (evidenceRefs.length === 0) {
4027
+ throw new Error("Project delivery record requires at least one --evidence.");
4028
+ }
4029
+ const recorded = recordDeliveryLifecycleV1({
4030
+ workspaceRoot: root,
4031
+ recordId: requireOption(options, "record-id"),
4032
+ occurredAt: requireOption(options, "at"),
4033
+ stage: requireOption(options, "stage"),
4034
+ stageStatus: requireOption(options, "stage-status"),
4035
+ ownerAgentId: requireOption(options, "owner-agent"),
4036
+ summary: requireOption(options, "summary"),
4037
+ evidenceRefs,
4038
+ externalGateIds: options["external-gate"] ?? [],
4039
+ });
4040
+ return options.json === true
4041
+ ? recorded
4042
+ : withHumanOutput(recorded, [
4043
+ `Delivery stage ${recorded.stage}: ${recorded.stageStatus}.`,
4044
+ `Next: ${recorded.nextAction ?? "none"}.`,
4045
+ "Authority: not granted.",
4046
+ "",
4047
+ ].join("\n"));
4048
+ }
3767
4049
  if (action === "decision") {
3768
4050
  const directDecisionFields = [
3769
4051
  "open",
@@ -3950,6 +4232,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3950
4232
  "decision",
3951
4233
  "next",
3952
4234
  "source-fingerprint",
4235
+ "from-quick-receipt",
3953
4236
  ];
3954
4237
  const hasDirectCheckpointFields = directCheckpointFields.some(
3955
4238
  name => options[name] !== undefined,
@@ -3978,7 +4261,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3978
4261
  : parseCanonicalNonnegativeSafeInteger(options["completed-units"], "completed-units");
3979
4262
  let checkpointed;
3980
4263
  try {
3981
- checkpointed = checkpointTeamProjectV1({
4264
+ const checkpointInput = {
3982
4265
  workspaceRoot: root,
3983
4266
  checkpointId,
3984
4267
  occurredAt,
@@ -3992,7 +4275,13 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
3992
4275
  decisionRefs: options.decision ?? [],
3993
4276
  nextAction: options.next ?? null,
3994
4277
  sourceFingerprint: options["source-fingerprint"],
3995
- });
4278
+ };
4279
+ checkpointed = options["from-quick-receipt"] === undefined
4280
+ ? checkpointTeamProjectV1(checkpointInput)
4281
+ : checkpointTeamProjectFromQuickReceiptV1({
4282
+ ...checkpointInput,
4283
+ receiptPath: options["from-quick-receipt"],
4284
+ });
3996
4285
  } catch (error) {
3997
4286
  if (error instanceof Error
3998
4287
  && error.message === "Measured work item checkpoint requires completedUnits.") {
@@ -4054,19 +4343,31 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
4054
4343
  "External source delivery events require verified intake; use project import-delivery.",
4055
4344
  );
4056
4345
  }
4346
+ if (new Set([
4347
+ "external_gate_reconciled",
4348
+ "delivery_lifecycle_recorded",
4349
+ "work_item_evidence_requirement_set",
4350
+ "checkpoint_receipt_bound",
4351
+ ])
4352
+ .has(requestedEvent?.type)) {
4353
+ throw new Error(
4354
+ "Phase 2 facts require typed project reconcile, project delivery record, "
4355
+ + "project work-item require-evidence, or project checkpoint intake.",
4356
+ );
4357
+ }
4057
4358
  return appendTeamProjectEventV1({
4058
4359
  workspaceRoot: root,
4059
4360
  event: requestedEvent,
4060
4361
  });
4061
4362
  }
4062
4363
  if (action === "status") {
4063
- const status = readTeamProjectStatusV3({ workspaceRoot: root });
4364
+ const status = readTeamProjectStatusV4({ workspaceRoot: root });
4064
4365
  return options.json === true
4065
4366
  ? status
4066
4367
  : withHumanOutput(status, formatTeamProjectStatusHumanV2(status));
4067
4368
  }
4068
4369
  if (action === "takeover") {
4069
- const takeover = buildTeamProjectTakeoverV3({
4370
+ const takeover = buildTeamProjectTakeoverV4({
4070
4371
  workspaceRoot: root,
4071
4372
  agentId: requireOption(options, "agent"),
4072
4373
  });
@@ -4087,7 +4388,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
4087
4388
  ? successor
4088
4389
  : withHumanOutput(successor, formatTeamProjectSuccessorHumanV1(successor));
4089
4390
  }
4090
- throw new Error("Usage: npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|decision|verification|integrate|capture|target-snapshot|import-delivery|status|takeover|successor> [options]");
4391
+ throw new Error("Usage: npx --no-install owlrunkit project <init|assign|checkpoint|handoff|reject-and-return|reopen-upstream|transfer|work-item revise-scope|reconcile|delivery record|decision|verification|integrate|capture|target-snapshot|import-delivery|status|takeover|successor> [options]");
4091
4392
  }
4092
4393
  if (command === "profiles") {
4093
4394
  const root = requireOption(options, "workspace");
@@ -4173,6 +4474,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
4173
4474
  }
4174
4475
  const verification = await runQuickVerification({
4175
4476
  workspaceRoot: workspace(options),
4477
+ foreignWorkspaceRoot: options["foreign-workspace"],
4176
4478
  commandArgv,
4177
4479
  stdinFile: options["stdin-file"],
4178
4480
  isolate: options.isolate === true,
@@ -4330,7 +4632,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
4330
4632
  return withControlTransaction(root, () => closeout(options));
4331
4633
  }
4332
4634
  if (command === "finish") return finishExecution(options);
4333
- throw new Error("Usage: npx --no-install owlrunkit <bootstrap|init|doctor|adopt|mode|team|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-reuse|quick-runtime-verify|quick-attest|quick-metrics|efficiency|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
4635
+ throw new Error("Usage: npx --no-install owlrunkit <bootstrap|init|doctor|adopt|mode|team|hook|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-reuse|quick-runtime-verify|quick-attest|quick-metrics|efficiency|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
4334
4636
  } catch (error) {
4335
4637
  return {
4336
4638
  status: "invalid_input",
@@ -4352,7 +4654,7 @@ if (isDirectExecution(import.meta.url)) {
4352
4654
  },
4353
4655
  });
4354
4656
  const inspectOptions = argv[0] === "inspect" && result.status === "inspected"
4355
- ? parseOptions(argv.slice(1), { boolean: ["json", "verbose", "history"] })
4657
+ ? parseOptions(argv.slice(1), { boolean: ["json", "compact", "verbose", "history"] })
4356
4658
  : null;
4357
4659
  const humanInspect = inspectOptions !== null && inspectOptions.json !== true;
4358
4660
  const onboardingHumanCommand = new Set(["bootstrap", "init", "doctor", "adopt", "profiles"]).has(argv[0]);