owlrunkit 0.18.4 → 0.19.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 (49) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +102 -4
  3. package/docs/architecture/OWLCODA_RUNKIT_0190_CONSOLIDATED_DAILY_USE_PRODUCT_DECISION_20260812.md +97 -0
  4. package/docs/architecture/OWLCODA_RUN_KIT_CONTRACT_V0_2.md +57 -0
  5. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +28 -4
  6. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  7. package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.2.md +57 -0
  8. package/package.json +1 -1
  9. package/packages/attest/README.md +9 -5
  10. package/packages/attest/consumer-surface-v2.json +263 -0
  11. package/packages/attest/distribution-manifest-v1.json +9 -1
  12. package/packages/attest/schemas/quick-verification-receipt-v3.schema.json +244 -0
  13. package/packages/attest/schemas/workspace-snapshot-v2.schema.json +114 -0
  14. package/packages/attest/src/dependency-environment.mjs +128 -0
  15. package/packages/attest/src/index.mjs +1 -0
  16. package/packages/attest/src/quick-receipt-contract.mjs +202 -9
  17. package/packages/attest/src/quick.mjs +40 -4
  18. package/packages/attest/src/workspace-snapshot.mjs +133 -6
  19. package/registry-release-policy-v1.json +5 -5
  20. package/sbom.spdx.json +5 -5
  21. package/scripts/runkit-contract/core-contract.mjs +21 -1
  22. package/scripts/runkit-contract/efficiency-metrics.mjs +559 -0
  23. package/scripts/runkit-contract/evidence-store.mjs +130 -0
  24. package/scripts/runkit-contract/onboarding-bootstrap.mjs +685 -0
  25. package/scripts/runkit-contract/onboarding-doctor.mjs +2 -1
  26. package/scripts/runkit-contract/outcome-presentation.mjs +171 -0
  27. package/scripts/runkit-contract/profile-onboarding.mjs +22 -2
  28. package/scripts/runkit-contract/project-cli-resolver.mjs +23 -5
  29. package/scripts/runkit-contract/quick-evidence-reuse.mjs +590 -0
  30. package/scripts/runkit-contract/quick-isolation.mjs +314 -0
  31. package/scripts/runkit-contract/quick-metrics.mjs +51 -3
  32. package/scripts/runkit-contract/quick-receipt.mjs +31 -1
  33. package/scripts/runkit-contract/quick-verify.mjs +216 -25
  34. package/scripts/runkit-contract/quick-workspace-snapshot.mjs +1 -0
  35. package/scripts/runkit-contract/runkit-bootstrap.mjs +1 -0
  36. package/scripts/runkit-contract/runkit-cli.mjs +330 -18
  37. package/scripts/runkit-contract/runtime-transition.mjs +478 -0
  38. package/scripts/runkit-contract/schemas/efficiency-event-v1.schema.json +56 -0
  39. package/scripts/runkit-contract/schemas/efficiency-metrics-v1.schema.json +220 -0
  40. package/scripts/runkit-contract/schemas/external-runtime-report-v1.schema.json +125 -0
  41. package/scripts/runkit-contract/schemas/onboarding-bootstrap-plan-v1.schema.json +168 -0
  42. package/scripts/runkit-contract/schemas/onboarding-bootstrap-receipt-v1.schema.json +130 -0
  43. package/scripts/runkit-contract/schemas/outcome-summary-v1.schema.json +83 -0
  44. package/scripts/runkit-contract/schemas/quick-evidence-reuse-plan-v1.schema.json +59 -0
  45. package/scripts/runkit-contract/schemas/quick-evidence-reuse-receipt-v1.schema.json +79 -0
  46. package/scripts/runkit-contract/schemas/runtime-transition-receipt-v1.schema.json +185 -0
  47. package/scripts/runkit-contract/schemas/team-project-event-v4.schema.json +142 -0
  48. package/scripts/runkit-contract/team-project.mjs +704 -16
  49. package/scripts/runkit-contract/verification-envelope.mjs +15 -18
@@ -0,0 +1,130 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ closeSync,
5
+ constants,
6
+ existsSync,
7
+ fstatSync,
8
+ linkSync,
9
+ lstatSync,
10
+ mkdirSync,
11
+ openSync,
12
+ readSync,
13
+ realpathSync,
14
+ rmSync,
15
+ writeFileSync,
16
+ } from "node:fs";
17
+ import path from "node:path";
18
+
19
+ const EVIDENCE_ROOT = ".owlcoda/runkit/evidence";
20
+ const STORAGE_DIRECTORIES = Object.freeze({
21
+ raw: "raw-sha256",
22
+ base64_json: "encoded-sha256",
23
+ });
24
+
25
+ function sha256Hex(bytes) {
26
+ return createHash("sha256").update(bytes).digest("hex");
27
+ }
28
+
29
+ function withinRoot(root, candidate) {
30
+ const relative = path.relative(root, candidate);
31
+ return relative !== ""
32
+ && relative !== ".."
33
+ && !relative.startsWith(`..${path.sep}`)
34
+ && !path.isAbsolute(relative);
35
+ }
36
+
37
+ function ensureDirectoryChain(workspaceRoot, relativeDirectory) {
38
+ const root = realpathSync(workspaceRoot);
39
+ let current = root;
40
+ for (const segment of relativeDirectory.split("/")) {
41
+ current = path.join(current, segment);
42
+ if (!existsSync(current)) {
43
+ try {
44
+ mkdirSync(current);
45
+ } catch (error) {
46
+ if (error?.code !== "EEXIST") throw error;
47
+ }
48
+ }
49
+ const stat = lstatSync(current);
50
+ if (stat.isSymbolicLink() || !stat.isDirectory()) {
51
+ throw new Error(`Evidence store component must be a real directory: ${current}`);
52
+ }
53
+ const resolved = realpathSync(current);
54
+ if (!withinRoot(root, resolved)) {
55
+ throw new Error(`Evidence store component escapes the workspace: ${current}`);
56
+ }
57
+ }
58
+ return { root, directory: current };
59
+ }
60
+
61
+ function storedBytes(bytes, encoding) {
62
+ if (encoding === "raw") return bytes;
63
+ return Buffer.from(`${JSON.stringify({ encoding: "base64", data: bytes.toString("base64") })}\n`);
64
+ }
65
+
66
+ function verifyExistingObject({ root, objectPath, expectedBytes }) {
67
+ const stat = lstatSync(objectPath);
68
+ if (stat.isSymbolicLink() || !stat.isFile() || !withinRoot(root, realpathSync(objectPath))) {
69
+ throw new Error("Evidence object must be a regular in-workspace file.");
70
+ }
71
+ const descriptor = openSync(objectPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
72
+ try {
73
+ const metadata = fstatSync(descriptor);
74
+ if (!metadata.isFile() || metadata.size !== expectedBytes.byteLength) {
75
+ throw new Error("Evidence object byte conflict for an existing SHA-256 path.");
76
+ }
77
+ const actual = Buffer.allocUnsafe(expectedBytes.byteLength + 1);
78
+ let offset = 0;
79
+ while (offset < actual.byteLength) {
80
+ const bytesRead = readSync(descriptor, actual, offset, actual.byteLength - offset, null);
81
+ if (bytesRead === 0) break;
82
+ offset += bytesRead;
83
+ }
84
+ if (offset !== expectedBytes.byteLength || !actual.subarray(0, offset).equals(expectedBytes)) {
85
+ throw new Error("Evidence object byte conflict for an existing SHA-256 path.");
86
+ }
87
+ } finally {
88
+ closeSync(descriptor);
89
+ }
90
+ }
91
+
92
+ export function persistEvidenceBytes({ workspaceRoot, bytes, encoding = "raw" }) {
93
+ if (!Buffer.isBuffer(bytes)) throw new Error("Evidence object requires bytes.");
94
+ const storageDirectory = STORAGE_DIRECTORIES[encoding];
95
+ if (storageDirectory === undefined) throw new Error("Evidence object encoding is unsupported.");
96
+ const { root, directory } = ensureDirectoryChain(
97
+ workspaceRoot,
98
+ `${EVIDENCE_ROOT}/${storageDirectory}`,
99
+ );
100
+ const digest = sha256Hex(bytes);
101
+ const objectPath = path.join(directory, digest);
102
+ const expectedBytes = storedBytes(bytes, encoding);
103
+ let created = false;
104
+ if (!existsSync(objectPath)) {
105
+ const temporaryPath = path.join(directory, `.tmp-${process.pid}-${randomUUID()}`);
106
+ try {
107
+ writeFileSync(temporaryPath, expectedBytes, { flag: "wx", mode: 0o400 });
108
+ chmodSync(temporaryPath, 0o400);
109
+ try {
110
+ linkSync(temporaryPath, objectPath);
111
+ created = true;
112
+ } catch (error) {
113
+ if (error?.code !== "EEXIST") throw error;
114
+ }
115
+ } finally {
116
+ rmSync(temporaryPath, { force: true });
117
+ }
118
+ }
119
+ verifyExistingObject({ root, objectPath, expectedBytes });
120
+ return {
121
+ schemaVersion: "OwlCodaRunKitEvidenceObjectRefV1",
122
+ storage: `create_only_${encoding}_sha256`,
123
+ path: path.relative(root, objectPath).split(path.sep).join("/"),
124
+ absolutePath: objectPath,
125
+ sha256: `sha256:${digest}`,
126
+ digest,
127
+ sizeBytes: bytes.byteLength,
128
+ created,
129
+ };
130
+ }