owlrunkit 0.18.2 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +159 -52
- package/docs/architecture/OWLCODA_RUNKIT_0184_EXTERNAL_DELIVERY_INTAKE_PRODUCT_DECISION_20260812.md +209 -0
- package/docs/architecture/OWLCODA_RUNKIT_018_PROJECT_DRIVER_PRODUCT_DEFINITION.md +16 -5
- package/docs/architecture/OWLCODA_RUNKIT_USAGE_MODE_SELECTION_PRODUCT_DECISION_20260811.md +54 -3
- package/docs/architecture/OWLCODA_RUN_KIT_CONTRACT_V0_2.md +7 -0
- package/integrations/codex/skills/owlcoda-runkit/SKILL.md +125 -74
- package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
- package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.1.md +160 -0
- package/integrations/codex/skills/owlcoda-runkit/references/contract-v0.2.md +545 -0
- package/package.json +1 -1
- package/packages/attest/README.md +4 -3
- package/packages/attest/consumer-surface-v1.json +1 -0
- package/packages/attest/distribution-manifest-v1.json +12 -1
- package/packages/attest/schemas/quick-verification-receipt-v2.schema.json +232 -0
- package/packages/attest/src/index.mjs +4 -1
- package/packages/attest/src/quick-receipt-contract.mjs +16 -6
- package/packages/attest/src/quick.mjs +21 -2
- package/packages/attest/src/workspace-snapshot.mjs +10 -1
- package/registry-release-policy-v1.json +5 -5
- package/sbom.spdx.json +5 -5
- package/scripts/runkit-contract/assurance-router.mjs +25 -6
- package/scripts/runkit-contract/core-contract.mjs +10 -1
- package/scripts/runkit-contract/onboarding-doctor.mjs +1 -1
- package/scripts/runkit-contract/profile-onboarding.mjs +263 -15
- package/scripts/runkit-contract/project-cli-resolver.mjs +6 -0
- package/scripts/runkit-contract/project-external-delivery.mjs +707 -0
- package/scripts/runkit-contract/quick-metrics.mjs +3 -3
- package/scripts/runkit-contract/quick-receipt.mjs +79 -12
- package/scripts/runkit-contract/quick-verify.mjs +89 -12
- package/scripts/runkit-contract/runkit-bootstrap.mjs +6 -1
- package/scripts/runkit-contract/runkit-cli.mjs +363 -143
- package/scripts/runkit-contract/schemas/assurance-route-v2.schema.json +26 -0
- package/scripts/runkit-contract/schemas/profile-detection-v3.schema.json +170 -0
- package/scripts/runkit-contract/schemas/team-project-event-v2.schema.json +128 -0
- package/scripts/runkit-contract/schemas/team-project-event-v3.schema.json +146 -0
- package/scripts/runkit-contract/schemas/team-project-status-v2.schema.json +85 -0
- package/scripts/runkit-contract/schemas/usage-mode-recommendation-v2.schema.json +136 -0
- package/scripts/runkit-contract/team-project.mjs +782 -55
- package/scripts/runkit-contract/usage-mode.mjs +28 -7
|
@@ -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
|
|
101
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
-
|
|
168
|
-
|
|
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
|
},
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
closeSync,
|
|
4
|
+
constants,
|
|
5
|
+
openSync,
|
|
6
|
+
realpathSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import path from "node:path";
|
|
3
9
|
|
|
10
|
+
import { readFileBytesBounded } from "../../packages/attest/src/formal.mjs";
|
|
4
11
|
import { currentCoreIdentity } from "./core-contract.mjs";
|
|
5
12
|
import {
|
|
6
13
|
closeQuickOutputFiles,
|
|
7
14
|
createQuickReceiptStore,
|
|
15
|
+
persistQuickInputArtifact,
|
|
8
16
|
persistQuickReceipt,
|
|
9
17
|
} from "./quick-receipt.mjs";
|
|
10
18
|
import { captureWorkspaceSnapshot } from "./quick-workspace-snapshot.mjs";
|
|
@@ -14,18 +22,34 @@ function shellQuote(value) {
|
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
function quickAttestCommand(workspaceRoot, receiptPath) {
|
|
17
|
-
return `owlrunkit quick-attest --workspace ${shellQuote(workspaceRoot)} --receipt ${shellQuote(receiptPath)}`;
|
|
25
|
+
return `npx --no-install owlrunkit quick-attest --workspace ${shellQuote(workspaceRoot)} --receipt ${shellQuote(receiptPath)}`;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
|
-
function runExactCommand({ executable, argv, cwd, stdoutFd, stderrFd }) {
|
|
28
|
+
function runExactCommand({ executable, argv, cwd, stdinPath, stdoutFd, stderrFd }) {
|
|
21
29
|
return new Promise((resolve) => {
|
|
22
30
|
let settled = false;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
let stdinFd;
|
|
32
|
+
let child;
|
|
33
|
+
try {
|
|
34
|
+
stdinFd = stdinPath === undefined
|
|
35
|
+
? undefined
|
|
36
|
+
: openSync(stdinPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
37
|
+
child = spawn(executable, argv, {
|
|
38
|
+
cwd,
|
|
39
|
+
shell: false,
|
|
40
|
+
stdio: [stdinFd ?? "ignore", stdoutFd, stderrFd],
|
|
41
|
+
env: process.env,
|
|
42
|
+
});
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (stdinFd !== undefined) closeSync(stdinFd);
|
|
45
|
+
resolve({
|
|
46
|
+
exitCode: null,
|
|
47
|
+
signal: null,
|
|
48
|
+
launchError: error instanceof Error ? error.message : String(error),
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (stdinFd !== undefined) closeSync(stdinFd);
|
|
29
53
|
child.once("error", (error) => {
|
|
30
54
|
if (settled) return;
|
|
31
55
|
settled = true;
|
|
@@ -39,7 +63,13 @@ function runExactCommand({ executable, argv, cwd, stdoutFd, stderrFd }) {
|
|
|
39
63
|
});
|
|
40
64
|
}
|
|
41
65
|
|
|
42
|
-
|
|
66
|
+
function inputArtifactResult(stdinArtifact) {
|
|
67
|
+
return stdinArtifact === null
|
|
68
|
+
? {}
|
|
69
|
+
: { inputArtifacts: { stdin: stdinArtifact } };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function runQuickVerification({ workspaceRoot, commandArgv, stdinFile }) {
|
|
43
73
|
if (!Array.isArray(commandArgv) || commandArgv.length === 0 || !commandArgv.every((value) => typeof value === "string")) {
|
|
44
74
|
return {
|
|
45
75
|
status: "quick_verification_input_invalid",
|
|
@@ -60,12 +90,49 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
60
90
|
};
|
|
61
91
|
}
|
|
62
92
|
|
|
93
|
+
let stdinBytes;
|
|
94
|
+
if (stdinFile !== undefined) {
|
|
95
|
+
if (typeof stdinFile !== "string" || stdinFile.length === 0) {
|
|
96
|
+
return {
|
|
97
|
+
status: "quick_verification_input_invalid",
|
|
98
|
+
exitCode: 3,
|
|
99
|
+
issues: ["--stdin-file requires a non-empty regular file path."],
|
|
100
|
+
authorizationGranted: false,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const selected = path.isAbsolute(stdinFile)
|
|
105
|
+
? stdinFile
|
|
106
|
+
: path.resolve(root, stdinFile);
|
|
107
|
+
stdinBytes = readFileBytesBounded(selected).bytes;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
status: "quick_verification_input_invalid",
|
|
111
|
+
exitCode: 3,
|
|
112
|
+
issues: [`Quick stdin file is invalid: ${error instanceof Error ? error.message : String(error)}`],
|
|
113
|
+
authorizationGranted: false,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
63
118
|
let workspaceBefore;
|
|
64
119
|
let store;
|
|
120
|
+
let stdinArtifact = null;
|
|
121
|
+
let persistedStdinPath;
|
|
65
122
|
try {
|
|
66
123
|
workspaceBefore = captureWorkspaceSnapshot(root);
|
|
67
124
|
store = createQuickReceiptStore(root);
|
|
125
|
+
if (stdinBytes !== undefined) {
|
|
126
|
+
const persistedInput = persistQuickInputArtifact({
|
|
127
|
+
workspaceRoot: root,
|
|
128
|
+
store,
|
|
129
|
+
bytes: stdinBytes,
|
|
130
|
+
});
|
|
131
|
+
stdinArtifact = persistedInput.artifact;
|
|
132
|
+
persistedStdinPath = persistedInput.inputPath;
|
|
133
|
+
}
|
|
68
134
|
} catch (error) {
|
|
135
|
+
if (store !== undefined) closeQuickOutputFiles(store);
|
|
69
136
|
return {
|
|
70
137
|
status: "quick_verification_input_invalid",
|
|
71
138
|
exitCode: 3,
|
|
@@ -80,6 +147,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
80
147
|
executable,
|
|
81
148
|
argv,
|
|
82
149
|
cwd: root,
|
|
150
|
+
stdinPath: persistedStdinPath,
|
|
83
151
|
stdoutFd: store.stdoutFd,
|
|
84
152
|
stderrFd: store.stderrFd,
|
|
85
153
|
});
|
|
@@ -101,7 +169,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
101
169
|
}
|
|
102
170
|
|
|
103
171
|
const sourceMutated = workspaceBefore.sourceFingerprint !== workspaceAfter.sourceFingerprint;
|
|
104
|
-
const issueCodes = [
|
|
172
|
+
const issueCodes = [];
|
|
105
173
|
if (sourceMutated) issueCodes.push("source_mutated_during_verification");
|
|
106
174
|
let persisted;
|
|
107
175
|
try {
|
|
@@ -109,7 +177,9 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
109
177
|
workspaceRoot: root,
|
|
110
178
|
store,
|
|
111
179
|
receipt: {
|
|
112
|
-
schemaVersion:
|
|
180
|
+
schemaVersion: stdinArtifact === null
|
|
181
|
+
? "OwlCodaQuickVerificationReceiptV1"
|
|
182
|
+
: "OwlCodaQuickVerificationReceiptV2",
|
|
113
183
|
receiptId: store.receiptId,
|
|
114
184
|
assurance: "captured_verification",
|
|
115
185
|
authorizationGranted: false,
|
|
@@ -124,6 +194,9 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
124
194
|
argv,
|
|
125
195
|
cwd: root,
|
|
126
196
|
},
|
|
197
|
+
...(stdinArtifact === null
|
|
198
|
+
? {}
|
|
199
|
+
: { inputArtifacts: { stdin: stdinArtifact } }),
|
|
127
200
|
verificationContext: {
|
|
128
201
|
platform: process.platform,
|
|
129
202
|
architecture: process.arch,
|
|
@@ -154,6 +227,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
154
227
|
? "invalidated_by_command_source_mutation"
|
|
155
228
|
: "source_unchanged",
|
|
156
229
|
issueCodes: [...issueCodes, "quick_receipt_store_invalid"],
|
|
230
|
+
...inputArtifactResult(stdinArtifact),
|
|
157
231
|
issues: [error instanceof Error ? error.message : String(error)],
|
|
158
232
|
nextAllowedAction: "repair_quick_receipt_store_and_rerun",
|
|
159
233
|
authorizationGranted: false,
|
|
@@ -173,6 +247,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
173
247
|
commandExitCode: execution.exitCode,
|
|
174
248
|
mutationDecision: "invalidated_by_command_source_mutation",
|
|
175
249
|
issueCodes,
|
|
250
|
+
...inputArtifactResult(stdinArtifact),
|
|
176
251
|
outputSummary,
|
|
177
252
|
attestCommand,
|
|
178
253
|
issues: [],
|
|
@@ -191,6 +266,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
191
266
|
commandExitCode: execution.exitCode,
|
|
192
267
|
mutationDecision: "source_unchanged",
|
|
193
268
|
issueCodes,
|
|
269
|
+
...inputArtifactResult(stdinArtifact),
|
|
194
270
|
outputSummary,
|
|
195
271
|
attestCommand,
|
|
196
272
|
issues: execution.launchError ? [execution.launchError] : [],
|
|
@@ -208,6 +284,7 @@ export async function runQuickVerification({ workspaceRoot, commandArgv }) {
|
|
|
208
284
|
commandExitCode: 0,
|
|
209
285
|
mutationDecision: "source_unchanged",
|
|
210
286
|
issueCodes,
|
|
287
|
+
...inputArtifactResult(stdinArtifact),
|
|
211
288
|
outputSummary,
|
|
212
289
|
attestCommand,
|
|
213
290
|
issues: [],
|
|
@@ -22,6 +22,10 @@ function comparablePath(value) {
|
|
|
22
22
|
return existsSync(resolved) ? realpathSync(resolved) : resolved;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function shellQuote(value) {
|
|
26
|
+
return `'${String(value).replaceAll("'", `'"'"'`)}'`;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
function workspaceFromArgv(argv, cwd) {
|
|
26
30
|
const index = argv.indexOf("--workspace");
|
|
27
31
|
if (index < 0) return path.resolve(cwd);
|
|
@@ -103,7 +107,8 @@ export function runBootstrapV1({
|
|
|
103
107
|
`project_local_cli_unavailable:${selected.binding.issueCodes.join(",")}.`,
|
|
104
108
|
"The current/global package did not execute this project command.",
|
|
105
109
|
"Repair the exact dependency, lockfile, and local install binding,",
|
|
106
|
-
|
|
110
|
+
"or use the bootstrap recovery path: npx --no-install owlrunkit init "
|
|
111
|
+
+ `--workspace ${shellQuote(selected.workspaceRoot)}`,
|
|
107
112
|
].join(" "));
|
|
108
113
|
}
|
|
109
114
|
const commandArgv = selected.commandArgv ?? [
|