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
@@ -15,10 +15,34 @@ import {
15
15
  } from "./quick-receipt-contract.mjs";
16
16
  import { captureDependencyEnvironment } from "./dependency-environment.mjs";
17
17
  import { captureWorkspaceSnapshot } from "./workspace-snapshot.mjs";
18
+ import {
19
+ captureCanonicalCandidateIdentityV1,
20
+ captureForeignWorkspaceFilesystemIdentityV1,
21
+ } from "./candidate-identity.mjs";
18
22
 
19
23
  export { validQuickReceiptShape } from "./quick-receipt-contract.mjs";
20
24
 
21
25
  export const SUPPORTED_QUICK_CORE_IDENTITIES = Object.freeze([
26
+ {
27
+ contractVersion: "0.2",
28
+ coreVersion: "0.22.0",
29
+ coreManifestSha256: "sha256:e79d2123d88ada0e2e31f62fabee83b1d661ca02e93a383691a502f721ae1e7e",
30
+ },
31
+ {
32
+ contractVersion: "0.2",
33
+ coreVersion: "0.21.1",
34
+ coreManifestSha256: "sha256:ff9e3756d6f385f1843d842c29baa6525101a84f3273148ad6b00f1187078c6e",
35
+ },
36
+ {
37
+ contractVersion: "0.2",
38
+ coreVersion: "0.21.0",
39
+ coreManifestSha256: "sha256:f85b9bf8c32705d5f5dfebdb653e83ac8d1ac0468214c17f230cbd2de04246fd",
40
+ },
41
+ {
42
+ contractVersion: "0.2",
43
+ coreVersion: "0.20.1",
44
+ coreManifestSha256: "sha256:8af2b9792731efa37f596255a7677dcec6e2fd3cc079dfdb0e6ff29e8017e784",
45
+ },
22
46
  {
23
47
  contractVersion: "0.2",
24
48
  coreVersion: "0.20.0",
@@ -271,19 +295,25 @@ function attestQuickReceiptDetailsFromBytesWithCatalog({
271
295
  const selectedWorkspaceRoot = workspaceRoot === undefined
272
296
  ? undefined
273
297
  : realpathSync(workspaceRoot);
298
+ const foreignReceipt = receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV4";
274
299
  if (selectedWorkspaceRoot === undefined) {
275
300
  issues.push("current_workspace_not_checked");
276
301
  }
277
302
  let receiptWorkspaceRoot;
303
+ let receiptSourceRoot;
278
304
  if (selectedWorkspaceRoot !== undefined) {
279
305
  try {
280
- receiptWorkspaceRoot = realpathSync(
281
- receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV3"
306
+ receiptWorkspaceRoot = realpathSync(foreignReceipt
307
+ ? receipt.controllerWorkspaceRoot
308
+ : receipt.schemaVersion === "OwlCodaQuickVerificationReceiptV3"
282
309
  ? receipt.sourceWorkspaceRoot
283
- : receipt.exactCommand.cwd,
284
- );
310
+ : receipt.exactCommand.cwd);
311
+ receiptSourceRoot = realpathSync(foreignReceipt
312
+ ? receipt.sourceWorkspaceRoot
313
+ : receiptWorkspaceRoot);
285
314
  } catch {
286
315
  receiptWorkspaceRoot = undefined;
316
+ receiptSourceRoot = undefined;
287
317
  }
288
318
  }
289
319
  const commandWorkspaceMatches = selectedWorkspaceRoot !== undefined
@@ -317,10 +347,25 @@ function attestQuickReceiptDetailsFromBytesWithCatalog({
317
347
  const ignoredPaths = receipt.workspaceAfter.ignoredPathsBound === true
318
348
  ? receipt.workspaceAfter.ignoredPathBindings.map(entry => entry.path)
319
349
  : [];
320
- const currentSourceValid = selectedWorkspaceRoot === undefined
321
- || commandWorkspaceMatches
322
- && captureWorkspaceSnapshot(selectedWorkspaceRoot, { ignoredPaths }).sourceFingerprint
323
- === receipt.workspaceAfter.sourceFingerprint;
350
+ let currentSourceValid = selectedWorkspaceRoot === undefined;
351
+ if (selectedWorkspaceRoot !== undefined && commandWorkspaceMatches && receiptSourceRoot !== undefined) {
352
+ try {
353
+ currentSourceValid = captureWorkspaceSnapshot(receiptSourceRoot, { ignoredPaths }).sourceFingerprint
354
+ === receipt.workspaceAfter.sourceFingerprint;
355
+ if (foreignReceipt) {
356
+ const currentCandidate = captureCanonicalCandidateIdentityV1(receiptSourceRoot);
357
+ const currentFilesystem = captureForeignWorkspaceFilesystemIdentityV1(receiptSourceRoot);
358
+ currentSourceValid = currentSourceValid
359
+ && receipt.foreignWorkspace.zeroWriteObserved === true
360
+ && currentCandidate.candidateFingerprint
361
+ === receipt.foreignWorkspace.candidateAfter.candidateFingerprint
362
+ && currentFilesystem.filesystemFingerprint
363
+ === receipt.foreignWorkspace.filesystemAfter.filesystemFingerprint;
364
+ }
365
+ } catch {
366
+ currentSourceValid = false;
367
+ }
368
+ }
324
369
  const dependencyEnvironmentValid = dependencyEnvironmentCurrent(
325
370
  receipt.executionIsolation?.dependencyEnvironment,
326
371
  materials,
@@ -1,8 +1,8 @@
1
1
  {
2
- "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV1",
3
- "status": "release_candidate_unpublished",
2
+ "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV2",
3
+ "status": "release_artifact_registry_gated",
4
4
  "packageName": "owlrunkit",
5
- "candidateVersion": "0.20.0",
5
+ "artifactVersion": "0.22.0",
6
6
  "registry": "https://registry.npmjs.org",
7
7
  "registryRequiredBeforeAdoption": true,
8
8
  "exactVersionRequired": true,
@@ -21,14 +21,13 @@
21
21
  "symlink",
22
22
  "workspace"
23
23
  ],
24
- "currentPublishedRelease": {
24
+ "rollbackRelease": {
25
25
  "packageName": "owlrunkit",
26
- "version": "0.19.2",
27
- "shasum": "f9b0f797fe9f79878374380db0756223accd61dc",
28
- "integrity": "sha512-rFEnbOtPuybztz8EZbcQSY3tGycCAuTkg+qGDwcKaTPjdJRhsXS4OB2HLwDBiILIV6BFyRPSQ7zanObT4jd58g==",
29
- "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.19.2.tgz"
26
+ "version": "0.21.0",
27
+ "shasum": "f9ecfa41ad2ba3140258234b49d98798675651f2",
28
+ "integrity": "sha512-hopLyvN5vp0y3xu0H0jQbMI6DxaDSWcGYcn7tAbCa0m2OqW2G8n5kJvnr217jqPYlArQwJ2TDPRLNmp4vPEhVQ==",
29
+ "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.21.0.tgz"
30
30
  },
31
- "registryRelease": null,
32
31
  "registryEvidenceMustBeExternal": true,
33
32
  "registryEvidenceSchemaVersion": "OwlCodaRunKitRegistryReleaseEvidenceV1",
34
33
  "embeddedAttestComponentVersion": "0.2.0",
package/sbom.spdx.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "owlrunkit-0.20.0",
6
- "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.20.0",
5
+ "name": "owlrunkit-0.22.0",
6
+ "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.22.0",
7
7
  "creationInfo": {
8
8
  "created": "2026-07-29T00:00:00Z",
9
9
  "creators": [
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "name": "owlrunkit",
16
16
  "SPDXID": "SPDXRef-Package-OwlRunKit",
17
- "versionInfo": "0.20.0",
17
+ "versionInfo": "0.22.0",
18
18
  "downloadLocation": "NOASSERTION",
19
19
  "filesAnalyzed": false,
20
20
  "licenseConcluded": "GPL-3.0-or-later",
@@ -24,7 +24,7 @@
24
24
  {
25
25
  "referenceCategory": "PACKAGE-MANAGER",
26
26
  "referenceType": "purl",
27
- "referenceLocator": "pkg:npm/owlrunkit@0.20.0"
27
+ "referenceLocator": "pkg:npm/owlrunkit@0.22.0"
28
28
  }
29
29
  ]
30
30
  }
@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
14
14
  import { parseProjectControlState } from "./project-control-parser.mjs";
15
15
 
16
16
  export const CONTRACT_VERSION = "0.2";
17
- export const CORE_VERSION = "0.20.0";
17
+ export const CORE_VERSION = "0.22.0";
18
18
  export const RUNTIME_ROOT = ".owlcoda/runkit";
19
19
 
20
20
  const CORE_FILES = [
@@ -28,11 +28,13 @@ const CORE_FILES = [
28
28
  "deployment-workflow.mjs",
29
29
  "efficiency-metrics.mjs",
30
30
  "fleet-discovery.mjs",
31
+ "fleet-skill-plan.mjs",
31
32
  "finalize.mjs",
32
33
  "formal-workflow.mjs",
33
34
  "formal-preflight.mjs",
34
35
  "formal-supplemental-evidence.mjs",
35
36
  "human-status.mjs",
37
+ "hook-recovery.mjs",
36
38
  "inspect-presentation.mjs",
37
39
  "install-codex-skill.mjs",
38
40
  "lease-lifecycle.mjs",
@@ -107,11 +109,15 @@ const CORE_FILES = [
107
109
  "schemas/fleet-discovery-v1.schema.json",
108
110
  "schemas/fleet-manifest-v1.schema.json",
109
111
  "schemas/fleet-root-registry-v1.schema.json",
112
+ "schemas/fleet-skill-upgrade-plan-v1.schema.json",
110
113
  "schemas/formal-check-v2.schema.json",
111
114
  "schemas/formal-envelope-preflight-v1.schema.json",
112
115
  "schemas/formal-evidence-summary-v1.schema.json",
113
116
  "schemas/formal-supplemental-evidence-v1.schema.json",
114
117
  "schemas/human-status-v1.schema.json",
118
+ "schemas/hook-recovery-v1.schema.json",
119
+ "schemas/inspect-compact-v1.schema.json",
120
+ "schemas/inspect-compact-v2.schema.json",
115
121
  "schemas/onboarding-bootstrap-plan-v1.schema.json",
116
122
  "schemas/onboarding-bootstrap-receipt-v1.schema.json",
117
123
  "schemas/outcome-summary-v1.schema.json",
@@ -150,8 +156,11 @@ const CORE_FILES = [
150
156
  "schemas/candidate-transfer-packet-v1.schema.json",
151
157
  "schemas/team-acceptance-packet-v2.schema.json",
152
158
  "schemas/team-delivery-status-v1.schema.json",
159
+ "schemas/team-delivery-status-v2.schema.json",
160
+ "schemas/team-delivery-status-v3.schema.json",
153
161
  "schemas/team-packet-validation-v1.schema.json",
154
162
  "schemas/team-recommendation-v1.schema.json",
163
+ "schemas/team-recommendation-v2.schema.json",
155
164
  "schemas/team-task-packet-v2.schema.json",
156
165
  "schemas/visual-smoke-request-v1.schema.json",
157
166
  "schemas/visual-smoke-result-v1.schema.json",
@@ -162,10 +171,15 @@ const CORE_FILES = [
162
171
  "schemas/team-project-event-v3.schema.json",
163
172
  "schemas/team-project-event-v4.schema.json",
164
173
  "schemas/team-project-event-v5.schema.json",
174
+ "schemas/team-project-event-v6.schema.json",
175
+ "schemas/team-project-event-v7.schema.json",
165
176
  "schemas/team-project-successor-receipt-v1.schema.json",
166
177
  "schemas/team-project-status-v1.schema.json",
167
178
  "schemas/team-project-status-v2.schema.json",
168
179
  "schemas/team-project-status-v3.schema.json",
180
+ "schemas/team-project-status-v4.schema.json",
181
+ "schemas/external-gate-v1.schema.json",
182
+ "schemas/delivery-lifecycle-v1.schema.json",
169
183
  "schemas/usage-mode-recommendation-v1.schema.json",
170
184
  "schemas/usage-mode-recommendation-v2.schema.json",
171
185
  "schemas/verification-envelope-v1.schema.json",
@@ -199,10 +213,14 @@ const CORE_FILES = [
199
213
  ];
200
214
 
201
215
  const CORE_DEPENDENCY_FILES = [
216
+ "packages/attest/src/candidate-identity.mjs",
202
217
  "packages/attest/src/dependency-environment.mjs",
218
+ "packages/attest/schemas/canonical-candidate-identity-v1.schema.json",
219
+ "packages/attest/schemas/foreign-workspace-filesystem-identity-v1.schema.json",
203
220
  "packages/attest/schemas/workspace-snapshot-v1.schema.json",
204
221
  "packages/attest/schemas/workspace-snapshot-v2.schema.json",
205
222
  "packages/attest/schemas/quick-verification-receipt-v3.schema.json",
223
+ "packages/attest/schemas/quick-verification-receipt-v4.schema.json",
206
224
  "packages/attest/src/formal.mjs",
207
225
  "packages/attest/src/offline-bundle.mjs",
208
226
  "packages/attest/src/quick-receipt-contract.mjs",
@@ -0,0 +1,223 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import {
5
+ currentCoreIdentity,
6
+ validateProjectConfigV2,
7
+ } from "./core-contract.mjs";
8
+ import { discoverFleet } from "./fleet-discovery.mjs";
9
+ import { inspectInstalledSkillCompatibility } from "./install-codex-skill.mjs";
10
+ import { inspectProjectControlState } from "./project-control-state.mjs";
11
+
12
+ function shellQuote(value) {
13
+ return `'${String(value).replaceAll("'", `'"'"'`)}'`;
14
+ }
15
+
16
+ function fleetSourceArguments({
17
+ workspaceRoots,
18
+ fleetManifestPath,
19
+ fleetRoots,
20
+ fleetRegistryPath,
21
+ }, { install = false } = {}) {
22
+ if (Array.isArray(workspaceRoots)) {
23
+ const flag = install ? "--workspace" : "--workspace-root";
24
+ return workspaceRoots.flatMap(root => [flag, shellQuote(root)]).join(" ");
25
+ }
26
+ if (Array.isArray(fleetRoots)) {
27
+ return fleetRoots.flatMap(root => ["--fleet-root", shellQuote(root)]).join(" ");
28
+ }
29
+ if (typeof fleetManifestPath === "string") {
30
+ return `--fleet-manifest ${shellQuote(fleetManifestPath)}`;
31
+ }
32
+ return typeof fleetRegistryPath === "string"
33
+ ? `--registry ${shellQuote(fleetRegistryPath)}`
34
+ : "";
35
+ }
36
+
37
+ function validLegacyConfigV1(config) {
38
+ return config?.schemaVersion === "OwlCodaRunKitConfigV1"
39
+ && config?.core?.contractVersion === "0.1"
40
+ && config?.authorizationPolicy === "external_explicit_authority_required";
41
+ }
42
+
43
+ async function inspectAffectedProject(workspaceRoot) {
44
+ const blockers = [];
45
+ const control = inspectProjectControlState({ workspaceRoot }).upgradeSafety;
46
+ for (const artifactId of control.activeRunIds) {
47
+ blockers.push({ code: "active_execution", workspaceRoot, artifactId });
48
+ }
49
+ for (const artifactId of control.activeLeaseIds) {
50
+ blockers.push({ code: "active_lease", workspaceRoot, artifactId });
51
+ }
52
+ for (const issue of control.issues) {
53
+ blockers.push({ code: "control_state_invalid", workspaceRoot, detail: issue });
54
+ }
55
+
56
+ const configPath = path.join(workspaceRoot, ".owlcoda/runkit/config.json");
57
+ let config = null;
58
+ try {
59
+ config = JSON.parse((await readFile(configPath)).toString("utf8"));
60
+ } catch (error) {
61
+ blockers.push({
62
+ code: "project_config_invalid",
63
+ workspaceRoot,
64
+ detail: error instanceof Error ? error.message : String(error),
65
+ });
66
+ }
67
+ if (config !== null) {
68
+ const validation = config.schemaVersion === "OwlCodaRunKitConfigV2"
69
+ ? validateProjectConfigV2(config)
70
+ : null;
71
+ if ((validation !== null && !validation.valid)
72
+ || (validation === null && !validLegacyConfigV1(config))) {
73
+ blockers.push({
74
+ code: "project_config_invalid",
75
+ workspaceRoot,
76
+ detail: validation?.issues?.join(",") ?? "unsupported_config",
77
+ });
78
+ }
79
+ }
80
+
81
+ return {
82
+ project: {
83
+ workspaceRoot,
84
+ configPath,
85
+ configCoreVersion: config?.core?.coreVersion ?? null,
86
+ activeRunIds: [...control.activeRunIds],
87
+ activeLeaseIds: [...control.activeLeaseIds],
88
+ upgradeSafe: blockers.length === 0,
89
+ },
90
+ blockers,
91
+ };
92
+ }
93
+
94
+ export async function planFleetSkillUpgradeV1({
95
+ repositoryRoot,
96
+ targetRoot,
97
+ archiveRoot,
98
+ workspaceRoots = null,
99
+ fleetManifestPath = null,
100
+ fleetRoots = null,
101
+ fleetRegistryPath = null,
102
+ } = {}) {
103
+ for (const [name, value] of Object.entries({ repositoryRoot, targetRoot, archiveRoot })) {
104
+ if (typeof value !== "string" || value.length === 0) {
105
+ throw new Error(`${name} is required`);
106
+ }
107
+ }
108
+ const resolvedRepositoryRoot = path.resolve(repositoryRoot);
109
+ const resolvedTargetRoot = path.resolve(targetRoot);
110
+ const resolvedArchiveRoot = path.resolve(archiveRoot);
111
+ const source = { workspaceRoots, fleetManifestPath, fleetRoots, fleetRegistryPath };
112
+ const blockers = [];
113
+ let discovery = null;
114
+ try {
115
+ discovery = await discoverFleet(source);
116
+ } catch (error) {
117
+ blockers.push({
118
+ code: error?.message === "fleet_registry_missing"
119
+ ? "fleet_registry_missing"
120
+ : "fleet_discovery_failed",
121
+ detail: error instanceof Error ? error.message : String(error),
122
+ });
123
+ }
124
+ if (discovery !== null && !discovery.complete) {
125
+ for (const workspaceRoot of discovery.unreachableRoots) {
126
+ blockers.push({ code: "fleet_root_unreachable", workspaceRoot });
127
+ }
128
+ }
129
+
130
+ const affectedProjects = [];
131
+ for (const workspaceRoot of discovery?.workspaceRoots ?? []) {
132
+ const inspected = await inspectAffectedProject(workspaceRoot);
133
+ affectedProjects.push(inspected.project);
134
+ blockers.push(...inspected.blockers);
135
+ }
136
+ affectedProjects.sort((left, right) => (
137
+ left.workspaceRoot < right.workspaceRoot ? -1 : left.workspaceRoot > right.workspaceRoot ? 1 : 0
138
+ ));
139
+
140
+ const sharedSkill = await inspectInstalledSkillCompatibility({
141
+ targetRoot: resolvedTargetRoot,
142
+ });
143
+ if (new Set(["unmanaged", "drifted"]).has(sharedSkill.status)) {
144
+ blockers.push({ code: "shared_skill_integrity_invalid", detail: sharedSkill.status });
145
+ }
146
+ blockers.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right), "en"));
147
+
148
+ const planSourceArgs = fleetSourceArguments(source);
149
+ const installSourceArgs = fleetSourceArguments(source, { install: true });
150
+ const commonPlan = [
151
+ "npx --no-install owlrunkit fleet skill-plan",
152
+ `--skill-root ${shellQuote(resolvedTargetRoot)}`,
153
+ `--archive-root ${shellQuote(resolvedArchiveRoot)}`,
154
+ planSourceArgs,
155
+ ].filter(Boolean).join(" ");
156
+ const installerPath = path.join(
157
+ resolvedRepositoryRoot,
158
+ "scripts/runkit-contract/install-codex-skill.mjs",
159
+ );
160
+ const installCommand = [
161
+ `node ${shellQuote(installerPath)} install`,
162
+ `--repository ${shellQuote(resolvedRepositoryRoot)}`,
163
+ `--target ${shellQuote(resolvedTargetRoot)}`,
164
+ `--archive ${shellQuote(resolvedArchiveRoot)}`,
165
+ installSourceArgs,
166
+ ].filter(Boolean).join(" ");
167
+ const rollbackCommand = [
168
+ `node ${shellQuote(installerPath)} restore`,
169
+ `--target ${shellQuote(resolvedTargetRoot)}`,
170
+ `--archive ${shellQuote(resolvedArchiveRoot)}`,
171
+ "--receipt <upgrade-receipt.json>",
172
+ ].join(" ");
173
+
174
+ return {
175
+ schemaVersion: "OwlCodaRunKitFleetSkillUpgradePlanV1",
176
+ status: blockers.length === 0 ? "ready" : "blocked",
177
+ expectedCore: currentCoreIdentity(),
178
+ sharedSkill: {
179
+ targetRoot: resolvedTargetRoot,
180
+ status: sharedSkill.status,
181
+ installedSkillVersion: sharedSkill.installedSkillVersion ?? null,
182
+ installedConfigCoreVersion: sharedSkill.installedConfigCoreVersion ?? null,
183
+ issues: sharedSkill.issues ?? [],
184
+ },
185
+ discovery: discovery === null ? null : {
186
+ source: discovery.source,
187
+ complete: discovery.complete,
188
+ workspaceCount: discovery.workspaceRoots.length,
189
+ unreachableRoots: discovery.unreachableRoots,
190
+ },
191
+ affectedProjects,
192
+ blockers,
193
+ commands: {
194
+ dryRun: commonPlan,
195
+ install: installCommand,
196
+ rollback: rollbackCommand,
197
+ },
198
+ authorizationGranted: false,
199
+ };
200
+ }
201
+
202
+ export function formatFleetSkillUpgradePlanHumanV1(plan) {
203
+ const lines = [
204
+ `Shared Skill fleet plan: ${plan.status}.`,
205
+ `Expected Core: ${plan.expectedCore.coreVersion} (${plan.expectedCore.coreManifestSha256}).`,
206
+ `Installed Skill: ${plan.sharedSkill.status} (${plan.sharedSkill.installedSkillVersion ?? "unknown"}).`,
207
+ `Affected projects: ${plan.affectedProjects.length}.`,
208
+ ];
209
+ if (plan.blockers.length > 0) {
210
+ lines.push("Blockers:");
211
+ for (const blocker of plan.blockers) {
212
+ lines.push(`- ${blocker.code}${blocker.workspaceRoot ? `: ${blocker.workspaceRoot}` : ""}${blocker.artifactId ? ` (${blocker.artifactId})` : ""}`);
213
+ }
214
+ }
215
+ lines.push(
216
+ `Dry run: ${plan.commands.dryRun}`,
217
+ `Install after blockers clear: ${plan.commands.install}`,
218
+ `Rollback after installation: ${plan.commands.rollback}`,
219
+ "Authority: not granted; no shared Skill or project was modified.",
220
+ "",
221
+ );
222
+ return lines.join("\n");
223
+ }
@@ -1394,7 +1394,9 @@ export function resumeCompletedFormalFinishV1({
1394
1394
  };
1395
1395
  }
1396
1396
  if (
1397
- new Set(["0.19.2", "0.20.0"]).has(closeout.artifact.core?.coreVersion)
1397
+ new Set(["0.19.2", "0.20.0", "0.20.1", "0.21.0", "0.21.1", "0.22.0"]).has(
1398
+ closeout.artifact.core?.coreVersion,
1399
+ )
1398
1400
  && (
1399
1401
  !hasExactKeys(formalEvidenceBinding, [
1400
1402
  "schemaVersion",