owlrunkit 0.18.2 → 0.18.3

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 (26) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +41 -7
  3. package/docs/architecture/OWLCODA_RUNKIT_018_PROJECT_DRIVER_PRODUCT_DEFINITION.md +16 -5
  4. package/docs/architecture/OWLCODA_RUNKIT_USAGE_MODE_SELECTION_PRODUCT_DECISION_20260811.md +53 -3
  5. package/docs/architecture/OWLCODA_RUN_KIT_CONTRACT_V0_2.md +7 -0
  6. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +28 -9
  7. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  8. package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.1.md +160 -0
  9. package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.2.md +545 -0
  10. package/package.json +1 -1
  11. package/packages/attest/README.md +4 -3
  12. package/packages/attest/consumer-surface-v1.json +1 -0
  13. package/packages/attest/distribution-manifest-v1.json +7 -1
  14. package/packages/attest/schemas/quick-verification-receipt-v2.schema.json +232 -0
  15. package/packages/attest/src/index.mjs +4 -1
  16. package/packages/attest/src/quick-receipt-contract.mjs +13 -3
  17. package/packages/attest/src/quick.mjs +16 -2
  18. package/registry-release-policy-v1.json +5 -5
  19. package/sbom.spdx.json +5 -5
  20. package/scripts/runkit-contract/core-contract.mjs +2 -1
  21. package/scripts/runkit-contract/quick-metrics.mjs +3 -3
  22. package/scripts/runkit-contract/quick-receipt.mjs +79 -12
  23. package/scripts/runkit-contract/quick-verify.mjs +88 -11
  24. package/scripts/runkit-contract/runkit-cli.mjs +91 -9
  25. package/scripts/runkit-contract/schemas/team-project-event-v2.schema.json +128 -0
  26. package/scripts/runkit-contract/team-project.mjs +310 -45
@@ -0,0 +1,232 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://owlcoda.dev/schemas/runkit/trust/quick-verification-receipt-v2.schema.json",
4
+ "title": "OwlCoda Quick Verification Receipt V2",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schemaVersion",
9
+ "receiptId",
10
+ "assurance",
11
+ "authorizationGranted",
12
+ "coreIdentity",
13
+ "workspaceBefore",
14
+ "exactCommand",
15
+ "inputArtifacts",
16
+ "verificationContext",
17
+ "startedAt",
18
+ "finishedAt",
19
+ "exitResult",
20
+ "outputArtifacts",
21
+ "workspaceAfter",
22
+ "mutationDecision",
23
+ "issueCodes"
24
+ ],
25
+ "properties": {
26
+ "schemaVersion": {
27
+ "const": "OwlCodaQuickVerificationReceiptV2"
28
+ },
29
+ "receiptId": {
30
+ "type": "string",
31
+ "minLength": 1
32
+ },
33
+ "assurance": {
34
+ "const": "captured_verification"
35
+ },
36
+ "authorizationGranted": {
37
+ "const": false
38
+ },
39
+ "coreIdentity": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": [
43
+ "contractVersion",
44
+ "coreVersion",
45
+ "coreManifestSha256"
46
+ ],
47
+ "properties": {
48
+ "contractVersion": {
49
+ "type": "string",
50
+ "minLength": 1
51
+ },
52
+ "coreVersion": {
53
+ "type": "string",
54
+ "minLength": 1
55
+ },
56
+ "coreManifestSha256": {
57
+ "type": "string",
58
+ "pattern": "^sha256:[0-9a-f]{64}$"
59
+ }
60
+ }
61
+ },
62
+ "workspaceBefore": {
63
+ "$ref": "workspace-snapshot-v1.schema.json"
64
+ },
65
+ "exactCommand": {
66
+ "type": "object",
67
+ "additionalProperties": false,
68
+ "required": [
69
+ "executable",
70
+ "argv",
71
+ "cwd"
72
+ ],
73
+ "properties": {
74
+ "executable": {
75
+ "type": "string",
76
+ "minLength": 1
77
+ },
78
+ "argv": {
79
+ "type": "array",
80
+ "items": {
81
+ "type": "string"
82
+ }
83
+ },
84
+ "cwd": {
85
+ "type": "string",
86
+ "minLength": 1
87
+ }
88
+ }
89
+ },
90
+ "inputArtifacts": {
91
+ "type": "object",
92
+ "additionalProperties": false,
93
+ "required": [
94
+ "stdin"
95
+ ],
96
+ "properties": {
97
+ "stdin": {
98
+ "$ref": "#/$defs/materialArtifact"
99
+ }
100
+ }
101
+ },
102
+ "verificationContext": {
103
+ "type": "object",
104
+ "additionalProperties": false,
105
+ "required": [
106
+ "platform",
107
+ "architecture",
108
+ "runtime"
109
+ ],
110
+ "properties": {
111
+ "platform": {
112
+ "type": "string",
113
+ "minLength": 1
114
+ },
115
+ "architecture": {
116
+ "type": "string",
117
+ "minLength": 1
118
+ },
119
+ "runtime": {
120
+ "type": "string",
121
+ "minLength": 1
122
+ }
123
+ }
124
+ },
125
+ "startedAt": {
126
+ "type": "string",
127
+ "format": "date-time"
128
+ },
129
+ "finishedAt": {
130
+ "type": "string",
131
+ "format": "date-time"
132
+ },
133
+ "exitResult": {
134
+ "type": "object",
135
+ "additionalProperties": false,
136
+ "required": [
137
+ "exitCode",
138
+ "signal"
139
+ ],
140
+ "properties": {
141
+ "exitCode": {
142
+ "type": [
143
+ "integer",
144
+ "null"
145
+ ]
146
+ },
147
+ "signal": {
148
+ "type": [
149
+ "string",
150
+ "null"
151
+ ]
152
+ }
153
+ }
154
+ },
155
+ "outputArtifacts": {
156
+ "type": "object",
157
+ "additionalProperties": false,
158
+ "required": [
159
+ "stdout",
160
+ "stderr"
161
+ ],
162
+ "properties": {
163
+ "stdout": {
164
+ "$ref": "#/$defs/materialArtifact"
165
+ },
166
+ "stderr": {
167
+ "$ref": "#/$defs/materialArtifact"
168
+ }
169
+ }
170
+ },
171
+ "workspaceAfter": {
172
+ "$ref": "workspace-snapshot-v1.schema.json"
173
+ },
174
+ "mutationDecision": {
175
+ "enum": [
176
+ "source_unchanged",
177
+ "invalidated_by_command_source_mutation"
178
+ ]
179
+ },
180
+ "issueCodes": {
181
+ "type": "array",
182
+ "uniqueItems": true,
183
+ "items": {
184
+ "type": "string",
185
+ "minLength": 1
186
+ }
187
+ },
188
+ "signatureRef": {
189
+ "type": "object",
190
+ "additionalProperties": false,
191
+ "required": [
192
+ "path",
193
+ "sha256"
194
+ ],
195
+ "properties": {
196
+ "path": {
197
+ "type": "string",
198
+ "minLength": 1
199
+ },
200
+ "sha256": {
201
+ "type": "string",
202
+ "pattern": "^sha256:[0-9a-f]{64}$"
203
+ }
204
+ }
205
+ }
206
+ },
207
+ "$defs": {
208
+ "materialArtifact": {
209
+ "type": "object",
210
+ "additionalProperties": false,
211
+ "required": [
212
+ "path",
213
+ "sha256",
214
+ "sizeBytes"
215
+ ],
216
+ "properties": {
217
+ "path": {
218
+ "type": "string",
219
+ "minLength": 1
220
+ },
221
+ "sha256": {
222
+ "type": "string",
223
+ "pattern": "^sha256:[0-9a-f]{64}$"
224
+ },
225
+ "sizeBytes": {
226
+ "type": "integer",
227
+ "minimum": 0
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
@@ -41,7 +41,10 @@ function readSubject(subjectPath) {
41
41
 
42
42
  export function attestFile({ subjectPath, workspaceRoot }) {
43
43
  const subject = readSubject(subjectPath);
44
- if (subject.value.schemaVersion === "OwlCodaQuickVerificationReceiptV1") {
44
+ if (new Set([
45
+ "OwlCodaQuickVerificationReceiptV1",
46
+ "OwlCodaQuickVerificationReceiptV2",
47
+ ]).has(subject.value.schemaVersion)) {
45
48
  const details = attestQuickReceiptDetailsFromBytes({
46
49
  receiptPath: subject.absolutePath,
47
50
  receiptBytes: subject.bytes,
@@ -110,10 +110,14 @@ function validOutputArtifact(value) {
110
110
  }
111
111
 
112
112
  export function validQuickReceiptShape(receipt) {
113
- if (!hasExactKeys(receipt, RECEIPT_REQUIRED_KEYS, ["signatureRef"])) return false;
113
+ const receiptV1 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV1";
114
+ const receiptV2 = receipt?.schemaVersion === "OwlCodaQuickVerificationReceiptV2";
115
+ const requiredKeys = receiptV2
116
+ ? [...RECEIPT_REQUIRED_KEYS, "inputArtifacts"]
117
+ : RECEIPT_REQUIRED_KEYS;
118
+ if (!(receiptV1 || receiptV2) || !hasExactKeys(receipt, requiredKeys, ["signatureRef"])) return false;
114
119
  if (
115
- receipt.schemaVersion !== "OwlCodaQuickVerificationReceiptV1"
116
- || typeof receipt.receiptId !== "string"
120
+ typeof receipt.receiptId !== "string"
117
121
  || receipt.receiptId.length === 0
118
122
  || receipt.assurance !== "captured_verification"
119
123
  || receipt.authorizationGranted !== false
@@ -145,6 +149,12 @@ export function validQuickReceiptShape(receipt) {
145
149
  ) {
146
150
  return false;
147
151
  }
152
+ if (receiptV2 && (
153
+ !hasExactKeys(receipt.inputArtifacts, ["stdin"])
154
+ || !validOutputArtifact(receipt.inputArtifacts.stdin)
155
+ )) {
156
+ return false;
157
+ }
148
158
  if (receipt.signatureRef !== undefined) {
149
159
  if (!hasExactKeys(receipt.signatureRef, ["path", "sha256"])
150
160
  || typeof receipt.signatureRef.path !== "string"
@@ -18,6 +18,11 @@ import { captureWorkspaceSnapshot } from "./workspace-snapshot.mjs";
18
18
  export { validQuickReceiptShape } from "./quick-receipt-contract.mjs";
19
19
 
20
20
  export const SUPPORTED_QUICK_CORE_IDENTITIES = Object.freeze([
21
+ {
22
+ contractVersion: "0.2",
23
+ coreVersion: "0.18.3",
24
+ coreManifestSha256: "sha256:cc7a923649592084150828f24f0d90f280af92514bafdbc4999f4015b3175d5c",
25
+ },
21
26
  {
22
27
  contractVersion: "0.2",
23
28
  coreVersion: "0.18.2",
@@ -194,7 +199,11 @@ export function attestQuickReceiptDetailsFromBytes({
194
199
  throw error;
195
200
  }
196
201
 
197
- const issues = [...receipt.issueCodes, "signature_absent", "anchor_absent"];
202
+ const issues = [
203
+ ...receipt.issueCodes.filter((issue) => issue !== "quick_ignored_artifact_unbound"),
204
+ "signature_absent",
205
+ "anchor_absent",
206
+ ];
198
207
  const materials = [];
199
208
  let materialMissing = false;
200
209
  let materialMismatch = false;
@@ -233,7 +242,12 @@ export function attestQuickReceiptDetailsFromBytes({
233
242
  const commandWorkspaceMatches = selectedWorkspaceRoot !== undefined
234
243
  && receiptWorkspaceRoot === selectedWorkspaceRoot;
235
244
  if (commandWorkspaceMatches) {
236
- for (const artifact of [receipt.outputArtifacts.stdout, receipt.outputArtifacts.stderr]) {
245
+ const boundArtifacts = [
246
+ ...(receipt.inputArtifacts === undefined ? [] : [receipt.inputArtifacts.stdin]),
247
+ receipt.outputArtifacts.stdout,
248
+ receipt.outputArtifacts.stderr,
249
+ ];
250
+ for (const artifact of boundArtifacts) {
237
251
  try {
238
252
  const materialPath = resolveBoundMaterial(receiptWorkspaceRoot, artifact.path);
239
253
  const { bytes } = readFileBytesBounded(materialPath);
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": "OwlCodaRunKitRegistryReleasePolicyV1",
3
3
  "status": "release_candidate_unpublished",
4
4
  "packageName": "owlrunkit",
5
- "candidateVersion": "0.18.2",
5
+ "candidateVersion": "0.18.3",
6
6
  "registry": "https://registry.npmjs.org",
7
7
  "registryRequiredBeforeAdoption": true,
8
8
  "exactVersionRequired": true,
@@ -23,10 +23,10 @@
23
23
  ],
24
24
  "currentPublishedRelease": {
25
25
  "packageName": "owlrunkit",
26
- "version": "0.18.1",
27
- "shasum": "6d35c15f90ed775c583356754b831856d1a3c0a6",
28
- "integrity": "sha512-07wWnSfY6RUavcb+ZpUbZ1S0nBjN7/8VIFHyP6blOB+PIrDnnST/8f7CoLgADYpfwjZiF5gR9U6XFwXa0kgVrg==",
29
- "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.1.tgz"
26
+ "version": "0.18.2",
27
+ "shasum": "4a85e31dad306260e4a6b1fcbccb3807e8647a0a",
28
+ "integrity": "sha512-Clpr8UQdNitzMMmQHUtjs9mesmukUqZrQ5nrda+Ryo8SuvECH8eBiis378NnzV1lI79kmljv49ToRRe867zlBg==",
29
+ "tarballUrl": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.2.tgz"
30
30
  },
31
31
  "registryRelease": null,
32
32
  "registryEvidenceMustBeExternal": true,
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.18.2",
6
- "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.18.2",
5
+ "name": "owlrunkit-0.18.3",
6
+ "documentNamespace": "https://owlcoda.com/spdx/owlrunkit/0.18.3",
7
7
  "creationInfo": {
8
8
  "created": "2026-07-29T00:00:00Z",
9
9
  "creators": [
@@ -14,8 +14,8 @@
14
14
  {
15
15
  "name": "owlrunkit",
16
16
  "SPDXID": "SPDXRef-Package-OwlRunKit",
17
- "versionInfo": "0.18.2",
18
- "downloadLocation": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.2.tgz",
17
+ "versionInfo": "0.18.3",
18
+ "downloadLocation": "https://registry.npmjs.org/owlrunkit/-/owlrunkit-0.18.3.tgz",
19
19
  "filesAnalyzed": false,
20
20
  "licenseConcluded": "GPL-3.0-or-later",
21
21
  "licenseDeclared": "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.18.2"
27
+ "referenceLocator": "pkg:npm/owlrunkit@0.18.3"
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.18.2";
17
+ export const CORE_VERSION = "0.18.3";
18
18
  export const RUNTIME_ROOT = ".owlcoda/runkit";
19
19
 
20
20
  const CORE_FILES = [
@@ -126,6 +126,7 @@ const CORE_FILES = [
126
126
  "schemas/verification-context-v1.schema.json",
127
127
  "schemas/team-project-definition-v1.schema.json",
128
128
  "schemas/team-project-event-v1.schema.json",
129
+ "schemas/team-project-event-v2.schema.json",
129
130
  "schemas/team-project-successor-receipt-v1.schema.json",
130
131
  "schemas/team-project-status-v1.schema.json",
131
132
  "schemas/usage-mode-recommendation-v1.schema.json",
@@ -59,7 +59,7 @@ function trustedReceiptRoot(workspaceRoot) {
59
59
  return { status: "valid", root };
60
60
  }
61
61
 
62
- export function readLocalQuickMetrics(workspaceRoot) {
62
+ export function readLocalQuickMetrics(workspaceRoot, { verbose = false } = {}) {
63
63
  const selected = trustedReceiptRoot(workspaceRoot);
64
64
  if (selected.status === "invalid") {
65
65
  return {
@@ -68,7 +68,7 @@ export function readLocalQuickMetrics(workspaceRoot) {
68
68
  schemaVersion: "OwlCodaRunKitLocalMetricsV1",
69
69
  telemetry: false,
70
70
  networkRequests: 0,
71
- inputs: [],
71
+ ...(verbose ? { inputs: [] } : {}),
72
72
  quick: {
73
73
  total: 0,
74
74
  passed: 0,
@@ -117,7 +117,7 @@ export function readLocalQuickMetrics(workspaceRoot) {
117
117
  schemaVersion: "OwlCodaRunKitLocalMetricsV1",
118
118
  telemetry: false,
119
119
  networkRequests: 0,
120
- inputs: receiptPaths,
120
+ ...(verbose ? { inputs: receiptPaths } : {}),
121
121
  quick: totals,
122
122
  authorizationGranted: false,
123
123
  };
@@ -97,20 +97,36 @@ function cleanOutputLine(line) {
97
97
  .trim();
98
98
  }
99
99
 
100
- function summarizeOutputBytes(bytes) {
101
- const start = Math.max(0, bytes.byteLength - OUTPUT_SUMMARY_BYTES);
102
- let text = bytes.subarray(start).toString("utf8");
103
- if (start > 0) {
104
- const firstLineBreak = text.indexOf("\n");
105
- if (firstLineBreak >= 0) text = text.slice(firstLineBreak + 1);
106
- }
107
- const lines = text
100
+ function cleanOutputLines(text) {
101
+ return text
108
102
  .split(/\r?\n/u)
109
103
  .map(cleanOutputLine)
110
104
  .filter(Boolean);
105
+ }
106
+
107
+ function summarizeOutputBytes(bytes) {
108
+ if (bytes.byteLength <= OUTPUT_SUMMARY_BYTES) {
109
+ const lines = cleanOutputLines(bytes.toString("utf8"));
110
+ return {
111
+ headLines: lines.slice(0, OUTPUT_SUMMARY_LINES),
112
+ tailLines: lines.slice(-OUTPUT_SUMMARY_LINES),
113
+ truncated: lines.length > OUTPUT_SUMMARY_LINES * 2,
114
+ };
115
+ }
116
+
117
+ const windowBytes = Math.floor(OUTPUT_SUMMARY_BYTES / 2);
118
+ let headText = bytes.subarray(0, windowBytes).toString("utf8");
119
+ const lastHeadBreak = headText.lastIndexOf("\n");
120
+ if (lastHeadBreak >= 0) headText = headText.slice(0, lastHeadBreak + 1);
121
+
122
+ let tailText = bytes.subarray(bytes.byteLength - windowBytes).toString("utf8");
123
+ const firstTailBreak = tailText.indexOf("\n");
124
+ if (firstTailBreak >= 0) tailText = tailText.slice(firstTailBreak + 1);
125
+
111
126
  return {
112
- lines: lines.slice(-OUTPUT_SUMMARY_LINES),
113
- truncated: start > 0 || lines.length > OUTPUT_SUMMARY_LINES,
127
+ headLines: cleanOutputLines(headText).slice(0, OUTPUT_SUMMARY_LINES),
128
+ tailLines: cleanOutputLines(tailText).slice(-OUTPUT_SUMMARY_LINES),
129
+ truncated: true,
114
130
  };
115
131
  }
116
132
 
@@ -145,10 +161,59 @@ function validateQuickReceiptStore(workspaceRoot, store) {
145
161
  assertStorePath(root, store.receiptRoot, store.receiptRootIdentity, "directory");
146
162
  assertStorePath(root, store.stdoutPath, store.stdoutIdentity, "file");
147
163
  assertStorePath(root, store.stderrPath, store.stderrIdentity, "file");
164
+ if (store.stdinPath !== undefined) {
165
+ assertStorePath(root, store.stdinPath, store.stdinIdentity, "file");
166
+ const bytes = readFileSync(store.stdinPath);
167
+ if (
168
+ bytes.byteLength !== store.stdinArtifact.sizeBytes
169
+ || sha256Bytes(bytes) !== store.stdinArtifact.sha256
170
+ ) {
171
+ throw new Error(`Quick receipt store stdin material changed: ${store.stdinPath}`);
172
+ }
173
+ }
174
+ }
175
+
176
+ export function persistQuickInputArtifact({ workspaceRoot, store, bytes }) {
177
+ if (!Buffer.isBuffer(bytes)) throw new Error("Quick stdin material must be bytes.");
178
+ validateQuickReceiptStore(workspaceRoot, store);
179
+ const stdinPath = path.join(store.receiptRoot, "stdin.bin");
180
+ writeFileSync(stdinPath, bytes, { flag: "wx", mode: 0o600 });
181
+ const stat = lstatSync(stdinPath);
182
+ if (stat.isSymbolicLink() || !stat.isFile()) {
183
+ throw new Error(`Quick receipt store stdin material is not trusted: ${stdinPath}`);
184
+ }
185
+ const root = realpathSync(workspaceRoot);
186
+ const resolved = realpathSync(stdinPath);
187
+ if (!withinRoot(root, resolved)) {
188
+ throw new Error(`Quick receipt store stdin material escapes the workspace: ${stdinPath}`);
189
+ }
190
+ store.stdinPath = stdinPath;
191
+ store.stdinIdentity = { dev: stat.dev, ino: stat.ino };
192
+ store.stdinArtifact = {
193
+ path: path.relative(root, resolved).split(path.sep).join("/"),
194
+ sha256: sha256Bytes(bytes),
195
+ sizeBytes: bytes.byteLength,
196
+ };
197
+ return {
198
+ artifact: store.stdinArtifact,
199
+ inputPath: stdinPath,
200
+ };
148
201
  }
149
202
 
150
203
  export function persistQuickReceipt({ workspaceRoot, store, receipt }) {
151
204
  validateQuickReceiptStore(workspaceRoot, store);
205
+ const receiptStdin = receipt.inputArtifacts?.stdin;
206
+ if (
207
+ (store.stdinArtifact === undefined) !== (receiptStdin === undefined)
208
+ || store.stdinArtifact !== undefined
209
+ && (
210
+ receiptStdin.path !== store.stdinArtifact.path
211
+ || receiptStdin.sha256 !== store.stdinArtifact.sha256
212
+ || receiptStdin.sizeBytes !== store.stdinArtifact.sizeBytes
213
+ )
214
+ ) {
215
+ throw new Error("Quick receipt stdin binding does not match the persisted material.");
216
+ }
152
217
  const stdout = outputArtifact(workspaceRoot, store.stdoutPath);
153
218
  const stderr = outputArtifact(workspaceRoot, store.stderrPath);
154
219
  const complete = {
@@ -164,8 +229,10 @@ export function persistQuickReceipt({ workspaceRoot, store, receipt }) {
164
229
  receiptPath: store.receiptPath,
165
230
  receiptSha256: sha256Bytes(readFileSync(store.receiptPath)),
166
231
  outputSummary: {
167
- stdoutTail: stdout.summary.lines,
168
- stderrTail: stderr.summary.lines,
232
+ stdoutHead: stdout.summary.headLines,
233
+ stdoutTail: stdout.summary.tailLines,
234
+ stderrHead: stderr.summary.headLines,
235
+ stderrTail: stderr.summary.tailLines,
169
236
  stdoutTruncated: stdout.summary.truncated,
170
237
  stderrTruncated: stderr.summary.truncated,
171
238
  },