mimetic-cli 0.1.2 → 0.1.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.
- package/AGENTS.md +66 -0
- package/CONTRIBUTING.md +39 -0
- package/README.md +4 -1
- package/SECURITY.md +34 -0
- package/dist/core/git-state.d.ts +31 -0
- package/dist/core/git-state.js +142 -0
- package/dist/core/git-state.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/run-primitives.d.ts +66 -0
- package/dist/core/run-primitives.js +120 -0
- package/dist/core/run-primitives.js.map +1 -0
- package/dist/observer-assets.js +1663 -2180
- package/dist/observer-assets.js.map +1 -1
- package/dist/observer-data.d.ts +1 -1
- package/dist/observer-data.js +5 -1
- package/dist/observer-data.js.map +1 -1
- package/dist/observer.js +8 -61
- package/dist/observer.js.map +1 -1
- package/dist/oss-meta-lab.d.ts +50 -0
- package/dist/oss-meta-lab.js +454 -27
- package/dist/oss-meta-lab.js.map +1 -1
- package/dist/program.d.ts +6 -0
- package/dist/program.js +75 -8
- package/dist/program.js.map +1 -1
- package/dist/run.d.ts +19 -6
- package/dist/run.js +1263 -9
- package/dist/run.js.map +1 -1
- package/docs/architecture/github-feedback-loop.md +189 -0
- package/docs/architecture/local-codex-tui-actor.md +210 -0
- package/docs/architecture/observer.md +109 -0
- package/docs/architecture/oss-lab-poc.md +170 -0
- package/docs/architecture/project-layout.md +132 -0
- package/docs/contracts/adapter-fixtures.md +80 -0
- package/docs/contracts/core.md +71 -0
- package/docs/contracts/feedback.md +131 -0
- package/docs/contracts/policy.md +273 -0
- package/docs/contracts/run-bundle.md +110 -0
- package/docs/contracts/schemas.md +511 -0
- package/docs/goals/current.md +163 -0
- package/docs/principles/self-driving-harness.md +129 -0
- package/docs/product/open-source-install-experience.md +138 -0
- package/docs/ramp/README.md +167 -0
- package/docs/release/open-source-readiness.md +171 -0
- package/docs/release/public-readiness-standard.md +205 -0
- package/docs/roadmap/world-class-open-source-v0.md +286 -0
- package/package.json +13 -2
- package/skills/mimetic-cli/SKILL.md +1 -1
package/dist/oss-meta-lab.js
CHANGED
|
@@ -89,6 +89,8 @@ export async function runOssMetaLab(options) {
|
|
|
89
89
|
if (liveRequested && missingKeys.length === 0) {
|
|
90
90
|
try {
|
|
91
91
|
liveDesktops = await launchLiveDesktops(assignments, localPackage ? { localPackage } : {});
|
|
92
|
+
const completionSummary = await pollLiveDesktopCompletions(liveDesktops);
|
|
93
|
+
warnings.push(...completionSummary.warnings);
|
|
92
94
|
}
|
|
93
95
|
catch (error) {
|
|
94
96
|
warnings.push(compactError(error));
|
|
@@ -103,10 +105,14 @@ export async function runOssMetaLab(options) {
|
|
|
103
105
|
const liveDesktopCount = liveDesktops.filter((desktop) => desktop.url).length;
|
|
104
106
|
const failedLiveDesktopCount = liveDesktops.filter((desktop) => desktop.error).length;
|
|
105
107
|
const startedBootstrapCount = liveDesktops.filter((desktop) => desktop.bootstrap?.status === "started").length;
|
|
108
|
+
const terminalCompletionCount = liveDesktops.filter((desktop) => isTerminalCompletion(desktop.completion)).length;
|
|
106
109
|
if (liveDesktops.length > 0) {
|
|
107
110
|
warnings.push(`Launched ${liveDesktopCount}/${liveDesktops.length} live E2B desktop stream${liveDesktops.length === 1 ? "" : "s"}.`);
|
|
108
111
|
if (startedBootstrapCount > 0) {
|
|
109
112
|
warnings.push(`Started ${startedBootstrapCount}/${liveDesktops.length} visible bootstrap terminal${liveDesktops.length === 1 ? "" : "s"} for Codex TUI attempt and nested Mimetic setup.`);
|
|
113
|
+
if (terminalCompletionCount > 0) {
|
|
114
|
+
warnings.push(`Classified ${terminalCompletionCount}/${startedBootstrapCount} bootstrap terminal state${startedBootstrapCount === 1 ? "" : "s"} from remote public-safe evidence.`);
|
|
115
|
+
}
|
|
110
116
|
}
|
|
111
117
|
else {
|
|
112
118
|
warnings.push("Codex TUI injection and nested Mimetic execution remain the next substrate slice behind these live desktops.");
|
|
@@ -142,6 +148,9 @@ export async function runOssMetaLab(options) {
|
|
|
142
148
|
const artifactRoot = path.join(cwd, ".mimetic", "runs", runId);
|
|
143
149
|
const bundlePath = path.join(artifactRoot, "run.json");
|
|
144
150
|
const createdAt = new Date().toISOString();
|
|
151
|
+
await mkdir(artifactRoot, { recursive: true });
|
|
152
|
+
const screenshotSummary = await captureLiveDesktopScreenshots(artifactRoot, liveDesktops);
|
|
153
|
+
warnings.push(...screenshotSummary.warnings);
|
|
145
154
|
const bundle = buildMetaBundle({
|
|
146
155
|
assignments,
|
|
147
156
|
createdAt,
|
|
@@ -152,19 +161,32 @@ export async function runOssMetaLab(options) {
|
|
|
152
161
|
missingKeys,
|
|
153
162
|
runId
|
|
154
163
|
});
|
|
155
|
-
await mkdir(artifactRoot, { recursive: true });
|
|
156
164
|
await writeJson(bundlePath, bundle);
|
|
157
165
|
await writeJson(path.join(artifactRoot, "review.json"), bundle.review);
|
|
158
166
|
await writeFile(path.join(artifactRoot, "review.md"), renderMetaReviewMarkdown(bundle), "utf8");
|
|
159
167
|
await writeFile(path.join(artifactRoot, "events.ndjson"), `${bundle.events.map((event) => JSON.stringify(event)).join("\n")}\n`, "utf8");
|
|
160
168
|
const observer = await renderObserver(cwd, runId, { open: options.open === true });
|
|
169
|
+
const outcome = classifyMetaLabOutcome({
|
|
170
|
+
dryRun,
|
|
171
|
+
liveDesktops,
|
|
172
|
+
liveRequested,
|
|
173
|
+
missingKeys
|
|
174
|
+
});
|
|
161
175
|
return {
|
|
162
176
|
schema: OSS_META_LAB_SCHEMA,
|
|
163
|
-
ok: observer.ok,
|
|
177
|
+
ok: observer.ok && outcome.ok,
|
|
164
178
|
assignments,
|
|
165
179
|
count,
|
|
166
180
|
cwd,
|
|
167
181
|
dryRun,
|
|
182
|
+
...(observer.ok && outcome.ok
|
|
183
|
+
? {}
|
|
184
|
+
: {
|
|
185
|
+
error: {
|
|
186
|
+
code: "MIMETIC_META_RUN_FAILED",
|
|
187
|
+
message: observer.ok ? outcome.reason : observer.error?.message ?? "OSS meta-lab Observer failed."
|
|
188
|
+
}
|
|
189
|
+
}),
|
|
168
190
|
liveRequested,
|
|
169
191
|
observer,
|
|
170
192
|
repos,
|
|
@@ -173,6 +195,18 @@ export async function runOssMetaLab(options) {
|
|
|
173
195
|
warnings: [...warnings, ...observer.warnings]
|
|
174
196
|
};
|
|
175
197
|
}
|
|
198
|
+
export function buildOssMetaBundleFixture(args) {
|
|
199
|
+
return buildMetaBundle({
|
|
200
|
+
assignments: args.assignments,
|
|
201
|
+
createdAt: args.createdAt,
|
|
202
|
+
cwd: args.cwd,
|
|
203
|
+
dryRun: args.dryRun,
|
|
204
|
+
liveDesktops: args.lanes,
|
|
205
|
+
liveRequested: args.liveRequested,
|
|
206
|
+
missingKeys: args.missingKeys,
|
|
207
|
+
runId: args.runId
|
|
208
|
+
});
|
|
209
|
+
}
|
|
176
210
|
function buildMetaBundle(args) {
|
|
177
211
|
const simulations = [];
|
|
178
212
|
const streams = [];
|
|
@@ -189,6 +223,9 @@ function buildMetaBundle(args) {
|
|
|
189
223
|
const prompt = buildCodexBootstrapPrompt(assignment);
|
|
190
224
|
const liveDesktop = args.liveDesktops.find((desktop) => desktop.streamId === assignment.streamId);
|
|
191
225
|
const status = statusForMeta(args, liveDesktop);
|
|
226
|
+
const completion = liveDesktop?.completion;
|
|
227
|
+
const screenshot = liveDesktop?.screenshot;
|
|
228
|
+
const terminalTail = terminalTailForMeta(prompt, liveDesktop);
|
|
192
229
|
simulations.push({
|
|
193
230
|
id: assignment.simId,
|
|
194
231
|
index: assignment.index,
|
|
@@ -196,12 +233,14 @@ function buildMetaBundle(args) {
|
|
|
196
233
|
scenarioId: assignment.scenarioId,
|
|
197
234
|
status,
|
|
198
235
|
streamKind: "browser",
|
|
199
|
-
mode: "
|
|
236
|
+
mode: "browser-sim",
|
|
200
237
|
progress: progressForMeta(status, liveDesktop),
|
|
201
238
|
currentStep: currentStepForMeta(args, assignment),
|
|
202
|
-
summary:
|
|
203
|
-
? `Headed E2B desktop lane assigned to ${assignment.repo};
|
|
204
|
-
:
|
|
239
|
+
summary: completion
|
|
240
|
+
? `Headed E2B desktop lane assigned to ${assignment.repo}; ${completion.reason}`
|
|
241
|
+
: liveDesktop?.bootstrap?.status === "started"
|
|
242
|
+
? `Headed E2B desktop lane assigned to ${assignment.repo}; bootstrap terminal launched to set up Mimetic and open the nested Observer.`
|
|
243
|
+
: `Headed E2B desktop lane assigned to ${assignment.repo}; nested Codex TUI should set up Mimetic and open a nested Observer inside that desktop.`,
|
|
205
244
|
streamIds: [assignment.streamId],
|
|
206
245
|
startedAt: args.createdAt,
|
|
207
246
|
updatedAt: args.createdAt
|
|
@@ -212,12 +251,12 @@ function buildMetaBundle(args) {
|
|
|
212
251
|
kind: "browser",
|
|
213
252
|
label: `E2B desktop - ${assignment.repo}`,
|
|
214
253
|
status,
|
|
215
|
-
transport: liveDesktop?.url ? "sse" : status === "contract_proof_only" ? "snapshot" : "sse",
|
|
254
|
+
transport: screenshot ? "snapshot" : liveDesktop?.url ? "sse" : status === "contract_proof_only" ? "snapshot" : "sse",
|
|
216
255
|
updatedAt: args.createdAt,
|
|
217
|
-
...(liveDesktop?.url ? { url: liveDesktop.url } : {}),
|
|
256
|
+
...(liveDesktop?.url && !screenshot ? { url: liveDesktop.url } : {}),
|
|
218
257
|
embed: {
|
|
219
|
-
kind: liveDesktop?.url ? "iframe" : "placeholder",
|
|
220
|
-
...(liveDesktop?.url ? { url: liveDesktop.url } : {}),
|
|
258
|
+
kind: screenshot ? "screenshot" : liveDesktop?.url ? "iframe" : "placeholder",
|
|
259
|
+
...(liveDesktop?.url && !screenshot ? { url: liveDesktop.url } : {}),
|
|
221
260
|
title: `E2B desktop ${assignment.index}`
|
|
222
261
|
},
|
|
223
262
|
viewport: {
|
|
@@ -229,21 +268,26 @@ function buildMetaBundle(args) {
|
|
|
229
268
|
title: `Codex TUI bootstrap - ${assignment.repo}`,
|
|
230
269
|
format: "plain",
|
|
231
270
|
stdin: liveDesktop?.bootstrap ? "sent" : "planned",
|
|
232
|
-
tail:
|
|
271
|
+
tail: terminalTail
|
|
233
272
|
},
|
|
234
273
|
ui: {
|
|
235
274
|
route: `e2b://desktop/${assignment.repo}`,
|
|
236
275
|
intent: "Watch the headed desktop where Codex clones the repo, sets up Mimetic, and opens the nested Observer.",
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
276
|
+
...(screenshot ? { screenshotUrl: screenshot.observerUrl } : {}),
|
|
277
|
+
state: completion
|
|
278
|
+
? completion.reason
|
|
279
|
+
: liveDesktop?.bootstrap?.status === "started"
|
|
280
|
+
? "bootstrap terminal launched"
|
|
281
|
+
: liveDesktop?.url ? "live E2B desktop" : args.dryRun ? "contract desktop" : "headed E2B desktop"
|
|
240
282
|
},
|
|
283
|
+
...(completion ? { completion: completionForStream(completion) } : {}),
|
|
241
284
|
artifacts: [
|
|
242
285
|
{ label: "run bundle", path: "run.json", kind: "bundle" },
|
|
243
286
|
{ label: "review", path: "review.md", kind: "review" },
|
|
244
287
|
{ label: "events", path: "events.ndjson", kind: "events" },
|
|
245
288
|
...(liveDesktop?.bootstrap?.logPath ? [{ label: "remote bootstrap log", path: liveDesktop.bootstrap.logPath, kind: "log" }] : []),
|
|
246
|
-
...(liveDesktop?.bootstrap?.nestedObserverPath ? [{ label: "nested observer path", path: liveDesktop.bootstrap.nestedObserverPath, kind: "observer" }] : [])
|
|
289
|
+
...(liveDesktop?.bootstrap?.nestedObserverPath ? [{ label: "nested observer path", path: liveDesktop.bootstrap.nestedObserverPath, kind: "observer" }] : []),
|
|
290
|
+
...(screenshot ? [{ label: "desktop screenshot", path: screenshot.path, kind: "screenshot" }] : [])
|
|
247
291
|
]
|
|
248
292
|
});
|
|
249
293
|
events.push({
|
|
@@ -283,6 +327,17 @@ function buildMetaBundle(args) {
|
|
|
283
327
|
simId: assignment.simId,
|
|
284
328
|
streamId: assignment.streamId
|
|
285
329
|
});
|
|
330
|
+
if (completion) {
|
|
331
|
+
events.push({
|
|
332
|
+
id: `event-${String(assignment.index).padStart(3, "0")}-bootstrap-${completion.status}`,
|
|
333
|
+
at: completion.checkedAt,
|
|
334
|
+
level: eventLevelForCompletion(completion.status),
|
|
335
|
+
type: `oss-meta.bootstrap.${completion.status}`,
|
|
336
|
+
message: `${assignment.repo}: ${completion.reason}`,
|
|
337
|
+
simId: assignment.simId,
|
|
338
|
+
streamId: assignment.streamId
|
|
339
|
+
});
|
|
340
|
+
}
|
|
286
341
|
}
|
|
287
342
|
else if (liveDesktop.bootstrap?.status === "failed") {
|
|
288
343
|
events.push({
|
|
@@ -407,6 +462,14 @@ function buildMetaBundle(args) {
|
|
|
407
462
|
function statusForMeta(args, liveDesktop) {
|
|
408
463
|
if (args.dryRun)
|
|
409
464
|
return "contract_proof_only";
|
|
465
|
+
if (liveDesktop?.completion?.status === "passed")
|
|
466
|
+
return "passed";
|
|
467
|
+
if (liveDesktop?.completion?.status === "failed")
|
|
468
|
+
return "failed";
|
|
469
|
+
if (liveDesktop?.completion?.status === "blocked")
|
|
470
|
+
return "blocked";
|
|
471
|
+
if (liveDesktop?.completion?.status === "timed_out")
|
|
472
|
+
return "timed_out";
|
|
410
473
|
if (liveDesktop?.bootstrap?.status === "failed")
|
|
411
474
|
return "failed";
|
|
412
475
|
if (liveDesktop?.url)
|
|
@@ -420,6 +483,12 @@ function statusForMeta(args, liveDesktop) {
|
|
|
420
483
|
function progressForMeta(status, liveDesktop) {
|
|
421
484
|
if (status === "contract_proof_only")
|
|
422
485
|
return 100;
|
|
486
|
+
if (status === "passed")
|
|
487
|
+
return 100;
|
|
488
|
+
if (status === "timed_out")
|
|
489
|
+
return 100;
|
|
490
|
+
if (status === "failed" && liveDesktop?.completion)
|
|
491
|
+
return 100;
|
|
423
492
|
if (status === "blocked")
|
|
424
493
|
return 18;
|
|
425
494
|
if (status === "failed")
|
|
@@ -435,6 +504,9 @@ function currentStepForMeta(args, assignment) {
|
|
|
435
504
|
if (args.dryRun) {
|
|
436
505
|
return `Contract ready for ${assignment.repo}; no E2B desktop launched.`;
|
|
437
506
|
}
|
|
507
|
+
if (liveDesktop?.completion) {
|
|
508
|
+
return liveDesktop.completion.reason;
|
|
509
|
+
}
|
|
438
510
|
if (liveDesktop?.bootstrap?.status === "started") {
|
|
439
511
|
return `Bootstrap terminal launched for ${assignment.repo}; Codex TUI attempt, Mimetic setup, and nested Observer run inside the desktop.`;
|
|
440
512
|
}
|
|
@@ -453,10 +525,15 @@ function currentStepForMeta(args, assignment) {
|
|
|
453
525
|
return `Ready to launch E2B desktop and inject Codex TUI for ${assignment.repo}.`;
|
|
454
526
|
}
|
|
455
527
|
function createMetaReview(args) {
|
|
528
|
+
const started = args.liveDesktops.filter((desktop) => desktop.bootstrap?.status === "started");
|
|
529
|
+
const terminalCompletions = args.liveDesktops.filter((desktop) => isTerminalCompletion(desktop.completion));
|
|
530
|
+
const outcome = classifyMetaLabOutcome(args);
|
|
456
531
|
const gaps = [
|
|
457
|
-
|
|
458
|
-
? "
|
|
459
|
-
:
|
|
532
|
+
started.length > 0 && terminalCompletions.length === started.length
|
|
533
|
+
? "OSS lane terminal states are classified from public-safe remote bootstrap evidence; this still proves nested Mimetic setup rather than target product behavior."
|
|
534
|
+
: args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")
|
|
535
|
+
? "Visible E2B bootstrap terminals are launched and run nested Mimetic setup; completion is watched in the desktop stream rather than polled back into the top-level bundle yet."
|
|
536
|
+
: "Nested Mimetic Observer evidence is represented as a lane contract until Codex TUI injection and nested Mimetic execution land.",
|
|
460
537
|
"The top-level run does not clone, modify, commit, push, or file issues in target repos.",
|
|
461
538
|
"Only public GitHub owner/repo slugs are recorded."
|
|
462
539
|
];
|
|
@@ -468,17 +545,120 @@ function createMetaReview(args) {
|
|
|
468
545
|
}
|
|
469
546
|
return {
|
|
470
547
|
schema: REVIEW_SCHEMA,
|
|
471
|
-
verdict:
|
|
472
|
-
summary:
|
|
473
|
-
?
|
|
474
|
-
: args.
|
|
475
|
-
? "OSS meta-lab
|
|
476
|
-
:
|
|
477
|
-
?
|
|
478
|
-
:
|
|
548
|
+
verdict: outcome.verdict,
|
|
549
|
+
summary: outcome.verdict === "fail" || outcome.verdict === "timed_out" || outcome.verdict === "blocked"
|
|
550
|
+
? outcome.reason
|
|
551
|
+
: args.dryRun
|
|
552
|
+
? "OSS meta-lab dry-run rendered the Observer-of-Observers contract without provider spend."
|
|
553
|
+
: terminalCompletions.length > 0
|
|
554
|
+
? `OSS meta-lab launched live E2B desktop streams and classified ${terminalCompletions.length}/${started.length || terminalCompletions.length} bootstrap terminal state${terminalCompletions.length === 1 ? "" : "s"} from public-safe remote evidence.`
|
|
555
|
+
: args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")
|
|
556
|
+
? "OSS meta-lab launched live E2B desktop streams, injected visible bootstrap terminals, and started nested Mimetic setup inside each desktop."
|
|
557
|
+
: args.liveDesktops.some((desktop) => desktop.url)
|
|
558
|
+
? "OSS meta-lab launched live E2B desktop streams and rendered them in the top-level Observer."
|
|
559
|
+
: "OSS meta-lab rendered the live headed-desktop control surface and marked the missing substrate truth in-lane.",
|
|
479
560
|
gaps
|
|
480
561
|
};
|
|
481
562
|
}
|
|
563
|
+
function classifyMetaLabOutcome(args) {
|
|
564
|
+
if (args.dryRun) {
|
|
565
|
+
return {
|
|
566
|
+
ok: true,
|
|
567
|
+
reason: "OSS meta-lab dry-run rendered the Observer-of-Observers contract without provider spend.",
|
|
568
|
+
verdict: "contract_proof_only"
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
if (args.liveRequested && args.missingKeys.length > 0) {
|
|
572
|
+
return {
|
|
573
|
+
ok: true,
|
|
574
|
+
reason: `Live launch is blocked until ${args.missingKeys.join(", ")} are available in environment.`,
|
|
575
|
+
verdict: "blocked"
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
const launchFailures = args.liveDesktops.filter((desktop) => desktop.error || desktop.bootstrap?.status === "failed");
|
|
579
|
+
if (launchFailures.length > 0) {
|
|
580
|
+
return {
|
|
581
|
+
ok: false,
|
|
582
|
+
reason: `OSS meta-lab failed ${launchFailures.length}/${args.liveDesktops.length} live desktop or bootstrap launch${launchFailures.length === 1 ? "" : "es"}.`,
|
|
583
|
+
verdict: "fail"
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
const failedCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "failed");
|
|
587
|
+
if (failedCompletions.length > 0) {
|
|
588
|
+
return {
|
|
589
|
+
ok: false,
|
|
590
|
+
reason: `OSS meta-lab classified ${failedCompletions.length}/${args.liveDesktops.length} bootstrap terminal state${failedCompletions.length === 1 ? "" : "s"} as failed from public-safe remote evidence.`,
|
|
591
|
+
verdict: "fail"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
const timedOutCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "timed_out");
|
|
595
|
+
if (timedOutCompletions.length > 0) {
|
|
596
|
+
return {
|
|
597
|
+
ok: false,
|
|
598
|
+
reason: `OSS meta-lab timed out waiting for ${timedOutCompletions.length}/${args.liveDesktops.length} bootstrap completion marker${timedOutCompletions.length === 1 ? "" : "s"}.`,
|
|
599
|
+
verdict: "timed_out"
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const blockedCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "blocked");
|
|
603
|
+
if (blockedCompletions.length > 0) {
|
|
604
|
+
return {
|
|
605
|
+
ok: false,
|
|
606
|
+
reason: `OSS meta-lab classified ${blockedCompletions.length}/${args.liveDesktops.length} bootstrap terminal state${blockedCompletions.length === 1 ? "" : "s"} as blocked from public-safe remote evidence.`,
|
|
607
|
+
verdict: "blocked"
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
if (args.liveDesktops.length > 0 && args.liveDesktops.every((desktop) => desktop.completion?.status === "passed")) {
|
|
611
|
+
return {
|
|
612
|
+
ok: true,
|
|
613
|
+
reason: `OSS meta-lab passed ${args.liveDesktops.length}/${args.liveDesktops.length} bootstrap terminal states from public-safe remote evidence.`,
|
|
614
|
+
verdict: "pass"
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
ok: true,
|
|
619
|
+
reason: "OSS meta-lab rendered the live headed-desktop control surface and marked the missing substrate truth in-lane.",
|
|
620
|
+
verdict: "contract_proof_only"
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function terminalTailForMeta(prompt, liveDesktop) {
|
|
624
|
+
if (!liveDesktop?.completion) {
|
|
625
|
+
return liveDesktop?.bootstrap?.tail ?? prompt;
|
|
626
|
+
}
|
|
627
|
+
const lines = [
|
|
628
|
+
`Remote bootstrap ${liveDesktop.completion.status}: ${liveDesktop.completion.reason}`,
|
|
629
|
+
`checked_at: ${liveDesktop.completion.checkedAt}`,
|
|
630
|
+
...(liveDesktop.completion.exitCode === undefined ? [] : [`exit_code: ${liveDesktop.completion.exitCode}`]),
|
|
631
|
+
...(liveDesktop.completion.nestedVerifyPassed === undefined ? [] : [`nested_verify_passed: ${liveDesktop.completion.nestedVerifyPassed ? "true" : "false"}`]),
|
|
632
|
+
...(liveDesktop.completion.nestedObserverPresent === undefined ? [] : [`nested_observer_present: ${liveDesktop.completion.nestedObserverPresent ? "true" : "false"}`]),
|
|
633
|
+
"",
|
|
634
|
+
"public-safe log tail:",
|
|
635
|
+
liveDesktop.completion.logTail?.trim() || "(no log tail captured)"
|
|
636
|
+
];
|
|
637
|
+
return lines.join("\n").trim();
|
|
638
|
+
}
|
|
639
|
+
function completionForStream(completion) {
|
|
640
|
+
return {
|
|
641
|
+
checkedAt: completion.checkedAt,
|
|
642
|
+
...(completion.exitCode === undefined ? {} : { exitCode: completion.exitCode }),
|
|
643
|
+
...(completion.logTail === undefined ? {} : { logTail: completion.logTail }),
|
|
644
|
+
...(completion.nestedObserverPresent === undefined ? {} : { nestedObserverPresent: completion.nestedObserverPresent }),
|
|
645
|
+
...(completion.nestedVerifyPassed === undefined ? {} : { nestedVerifyPassed: completion.nestedVerifyPassed }),
|
|
646
|
+
reason: completion.reason,
|
|
647
|
+
status: completion.status
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function eventLevelForCompletion(status) {
|
|
651
|
+
if (status === "passed")
|
|
652
|
+
return "info";
|
|
653
|
+
if (status === "running")
|
|
654
|
+
return "info";
|
|
655
|
+
if (status === "blocked" || status === "timed_out")
|
|
656
|
+
return "warn";
|
|
657
|
+
return "error";
|
|
658
|
+
}
|
|
659
|
+
function isTerminalCompletion(completion) {
|
|
660
|
+
return completion !== undefined && completion.status !== "running";
|
|
661
|
+
}
|
|
482
662
|
function buildCodexBootstrapPrompt(assignment) {
|
|
483
663
|
return [
|
|
484
664
|
`# Mimetic OSS Meta-Lab Actor ${assignment.index}`,
|
|
@@ -568,6 +748,7 @@ async function launchLiveDesktops(assignments, options = {}) {
|
|
|
568
748
|
});
|
|
569
749
|
return {
|
|
570
750
|
bootstrap,
|
|
751
|
+
desktop,
|
|
571
752
|
repo: assignment.repo,
|
|
572
753
|
sandboxId: desktop.sandboxId,
|
|
573
754
|
simId: assignment.simId,
|
|
@@ -585,6 +766,169 @@ async function launchLiveDesktops(assignments, options = {}) {
|
|
|
585
766
|
}
|
|
586
767
|
}));
|
|
587
768
|
}
|
|
769
|
+
async function pollLiveDesktopCompletions(liveDesktops) {
|
|
770
|
+
const pollable = liveDesktops.filter((desktop) => desktop.desktop
|
|
771
|
+
&& desktop.bootstrap?.status === "started"
|
|
772
|
+
&& desktop.bootstrap.completionPath);
|
|
773
|
+
if (pollable.length === 0) {
|
|
774
|
+
return { warnings: [] };
|
|
775
|
+
}
|
|
776
|
+
const timeoutMs = readNonNegativeInt(process.env.MIMETIC_OSS_META_COMPLETION_TIMEOUT_MS, 240_000);
|
|
777
|
+
const intervalMs = readPositiveInt(process.env.MIMETIC_OSS_META_COMPLETION_INTERVAL_MS, 5_000);
|
|
778
|
+
const requestTimeoutMs = readPositiveInt(process.env.MIMETIC_E2B_REQUEST_TIMEOUT_MS, 60_000);
|
|
779
|
+
const warnings = [];
|
|
780
|
+
if (timeoutMs === 0) {
|
|
781
|
+
warnings.push("OSS meta-lab completion polling skipped because MIMETIC_OSS_META_COMPLETION_TIMEOUT_MS=0.");
|
|
782
|
+
return { warnings };
|
|
783
|
+
}
|
|
784
|
+
const deadline = Date.now() + timeoutMs;
|
|
785
|
+
while (Date.now() <= deadline) {
|
|
786
|
+
await Promise.all(pollable.map(async (desktop) => {
|
|
787
|
+
if (isTerminalCompletion(desktop.completion) || !desktop.desktop || !desktop.bootstrap?.completionPath) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
const completion = await readRemoteCompletion(desktop.desktop, desktop.bootstrap, requestTimeoutMs);
|
|
791
|
+
if (completion) {
|
|
792
|
+
desktop.completion = completion;
|
|
793
|
+
}
|
|
794
|
+
}));
|
|
795
|
+
if (pollable.every((desktop) => isTerminalCompletion(desktop.completion))) {
|
|
796
|
+
return { warnings };
|
|
797
|
+
}
|
|
798
|
+
await wait(Math.min(intervalMs, Math.max(0, deadline - Date.now())));
|
|
799
|
+
}
|
|
800
|
+
await Promise.all(pollable.map(async (desktop) => {
|
|
801
|
+
if (isTerminalCompletion(desktop.completion) || !desktop.desktop || !desktop.bootstrap) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
desktop.completion = {
|
|
805
|
+
checkedAt: new Date().toISOString(),
|
|
806
|
+
logTail: await readRemoteLogTail(desktop.desktop, desktop.bootstrap, requestTimeoutMs),
|
|
807
|
+
reason: `Timed out waiting ${timeoutMs}ms for remote bootstrap completion marker.`,
|
|
808
|
+
status: "timed_out"
|
|
809
|
+
};
|
|
810
|
+
}));
|
|
811
|
+
warnings.push(`Timed out waiting for ${pollable.filter((desktop) => desktop.completion?.status === "timed_out").length}/${pollable.length} OSS meta-lab bootstrap completion marker${pollable.length === 1 ? "" : "s"}.`);
|
|
812
|
+
return { warnings };
|
|
813
|
+
}
|
|
814
|
+
async function readRemoteCompletion(desktop, bootstrap, requestTimeoutMs) {
|
|
815
|
+
if (!bootstrap.completionPath) {
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
const command = `if [ -f ${shellQuote(bootstrap.completionPath)} ]; then cat ${shellQuote(bootstrap.completionPath)}; else exit 3; fi`;
|
|
819
|
+
const result = await desktop.commands.run(`bash -lc ${shellQuote(command)}`, {
|
|
820
|
+
requestTimeoutMs,
|
|
821
|
+
timeoutMs: 30_000
|
|
822
|
+
}).catch(() => null);
|
|
823
|
+
if (!result || (result.exitCode && result.exitCode !== 0) || !result.stdout) {
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
return parseRemoteCompletion(result.stdout);
|
|
827
|
+
}
|
|
828
|
+
async function readRemoteLogTail(desktop, bootstrap, requestTimeoutMs) {
|
|
829
|
+
if (!bootstrap.logPath) {
|
|
830
|
+
return "";
|
|
831
|
+
}
|
|
832
|
+
const command = `tail -n 80 ${shellQuote(bootstrap.logPath)} 2>/dev/null || true`;
|
|
833
|
+
const result = await desktop.commands.run(`bash -lc ${shellQuote(command)}`, {
|
|
834
|
+
requestTimeoutMs,
|
|
835
|
+
timeoutMs: 30_000
|
|
836
|
+
}).catch(() => null);
|
|
837
|
+
return sanitizeRemoteLog(result?.stdout ?? "");
|
|
838
|
+
}
|
|
839
|
+
async function captureLiveDesktopScreenshots(artifactRoot, liveDesktops) {
|
|
840
|
+
const candidates = liveDesktops.filter((desktop) => desktop.desktop && desktop.url);
|
|
841
|
+
if (candidates.length === 0) {
|
|
842
|
+
return { warnings: [] };
|
|
843
|
+
}
|
|
844
|
+
const screenshotRoot = path.join(artifactRoot, "screenshots");
|
|
845
|
+
await mkdir(screenshotRoot, { recursive: true });
|
|
846
|
+
const warnings = [];
|
|
847
|
+
await Promise.all(candidates.map(async (desktop) => {
|
|
848
|
+
if (!desktop.desktop) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
try {
|
|
852
|
+
const bytes = await desktop.desktop.screenshot("bytes");
|
|
853
|
+
const fileName = `${safeArtifactToken(desktop.streamId)}.png`;
|
|
854
|
+
const screenshotPath = path.join(screenshotRoot, fileName);
|
|
855
|
+
await writeFile(screenshotPath, Buffer.from(bytes));
|
|
856
|
+
desktop.screenshot = {
|
|
857
|
+
capturedAt: new Date().toISOString(),
|
|
858
|
+
observerUrl: `../screenshots/${fileName}`,
|
|
859
|
+
path: path.join("screenshots", fileName)
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
catch (error) {
|
|
863
|
+
warnings.push(`Screenshot capture failed for ${desktop.repo}: ${compactError(error)}`);
|
|
864
|
+
}
|
|
865
|
+
}));
|
|
866
|
+
const capturedCount = liveDesktops.filter((desktop) => desktop.screenshot).length;
|
|
867
|
+
if (capturedCount > 0) {
|
|
868
|
+
warnings.push(`Captured ${capturedCount}/${candidates.length} E2B desktop screenshot fallback${candidates.length === 1 ? "" : "s"}.`);
|
|
869
|
+
}
|
|
870
|
+
return { warnings };
|
|
871
|
+
}
|
|
872
|
+
function parseRemoteCompletion(payload) {
|
|
873
|
+
try {
|
|
874
|
+
const parsed = JSON.parse(payload);
|
|
875
|
+
const status = normalizeCompletionStatus(parsed.status);
|
|
876
|
+
if (!status) {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
const nestedVerifyPassed = parsed.nestedVerifyStatus === "passed"
|
|
880
|
+
? true
|
|
881
|
+
: parsed.nestedVerifyStatus === "failed" ? false : undefined;
|
|
882
|
+
return {
|
|
883
|
+
checkedAt: typeof parsed.completedAt === "string" ? parsed.completedAt : new Date().toISOString(),
|
|
884
|
+
...(typeof parsed.exitCode === "number" ? { exitCode: parsed.exitCode } : {}),
|
|
885
|
+
...(typeof parsed.logTail === "string" ? { logTail: sanitizeRemoteLog(parsed.logTail) } : {}),
|
|
886
|
+
...(typeof parsed.nestedObserverPresent === "boolean" ? { nestedObserverPresent: parsed.nestedObserverPresent } : {}),
|
|
887
|
+
...(nestedVerifyPassed === undefined ? {} : { nestedVerifyPassed }),
|
|
888
|
+
reason: typeof parsed.reason === "string" && parsed.reason.trim()
|
|
889
|
+
? sanitizeRemoteLog(parsed.reason).replace(/\s+/g, " ").slice(0, 240)
|
|
890
|
+
: defaultReasonForCompletion(status),
|
|
891
|
+
status
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
catch {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
function normalizeCompletionStatus(value) {
|
|
899
|
+
return value === "running"
|
|
900
|
+
|| value === "passed"
|
|
901
|
+
|| value === "failed"
|
|
902
|
+
|| value === "blocked"
|
|
903
|
+
|| value === "timed_out"
|
|
904
|
+
? value
|
|
905
|
+
: null;
|
|
906
|
+
}
|
|
907
|
+
function defaultReasonForCompletion(status) {
|
|
908
|
+
switch (status) {
|
|
909
|
+
case "passed":
|
|
910
|
+
return "Remote bootstrap completed successfully.";
|
|
911
|
+
case "failed":
|
|
912
|
+
return "Remote bootstrap failed.";
|
|
913
|
+
case "blocked":
|
|
914
|
+
return "Remote bootstrap is blocked.";
|
|
915
|
+
case "timed_out":
|
|
916
|
+
return "Remote bootstrap completion timed out.";
|
|
917
|
+
case "running":
|
|
918
|
+
return "Remote bootstrap is still running.";
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
function sanitizeRemoteLog(value) {
|
|
922
|
+
return value
|
|
923
|
+
.replace(/sk-[A-Za-z0-9_-]{12,}/g, "[redacted-openai-key]")
|
|
924
|
+
.replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
|
|
925
|
+
.replace(/gh[pousr]_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
|
|
926
|
+
.replace(/https?:\/\/[^/\s]*e2b[^)\s]+/gi, "[redacted-e2b-url]")
|
|
927
|
+
.split(/\r?\n/)
|
|
928
|
+
.slice(-80)
|
|
929
|
+
.join("\n")
|
|
930
|
+
.trim();
|
|
931
|
+
}
|
|
588
932
|
async function loadE2BDesktopModule() {
|
|
589
933
|
try {
|
|
590
934
|
return await import("@e2b/desktop");
|
|
@@ -607,6 +951,7 @@ async function startOssBootstrap(desktop, assignment, localPackage, requestTimeo
|
|
|
607
951
|
const bootstrapPath = `${rootDir}/bootstrap.sh`;
|
|
608
952
|
const launcherPath = `${rootDir}/launch-terminal.sh`;
|
|
609
953
|
const logPath = `${rootDir}/bootstrap.log`;
|
|
954
|
+
const completionPath = `${rootDir}/completion.json`;
|
|
610
955
|
const nestedObserverPath = `${rootDir}/repo/.mimetic/runs/nested-${token}/observer/index.html`;
|
|
611
956
|
const title = `Mimetic ${assignment.index} ${assignment.repo}`;
|
|
612
957
|
const baseTail = [
|
|
@@ -614,6 +959,7 @@ async function startOssBootstrap(desktop, assignment, localPackage, requestTimeo
|
|
|
614
959
|
`sandbox: ${desktop.sandboxId}`,
|
|
615
960
|
`remote package: ${localPackage ? remotePackagePath : "npm:mimetic-cli fallback"}`,
|
|
616
961
|
`bootstrap: ${bootstrapPath}`,
|
|
962
|
+
`completion: ${completionPath}`,
|
|
617
963
|
`log: ${logPath}`,
|
|
618
964
|
`nested observer: ${nestedObserverPath}`
|
|
619
965
|
].join("\n");
|
|
@@ -631,6 +977,7 @@ async function startOssBootstrap(desktop, assignment, localPackage, requestTimeo
|
|
|
631
977
|
}
|
|
632
978
|
const bootstrapScript = buildRemoteBootstrapScript({
|
|
633
979
|
assignment,
|
|
980
|
+
completionPath,
|
|
634
981
|
logPath,
|
|
635
982
|
nestedObserverPath,
|
|
636
983
|
rootDir,
|
|
@@ -660,6 +1007,7 @@ async function startOssBootstrap(desktop, assignment, localPackage, requestTimeo
|
|
|
660
1007
|
}).catch(() => undefined);
|
|
661
1008
|
return {
|
|
662
1009
|
codexMode: "tui-attempted",
|
|
1010
|
+
completionPath,
|
|
663
1011
|
launcherPath,
|
|
664
1012
|
logPath,
|
|
665
1013
|
mimeticPackageUploaded: Boolean(localPackage),
|
|
@@ -675,6 +1023,7 @@ async function startOssBootstrap(desktop, assignment, localPackage, requestTimeo
|
|
|
675
1023
|
catch (error) {
|
|
676
1024
|
return {
|
|
677
1025
|
codexMode: "tui-attempted",
|
|
1026
|
+
completionPath,
|
|
678
1027
|
launcherPath,
|
|
679
1028
|
logPath,
|
|
680
1029
|
mimeticPackageUploaded: Boolean(localPackage),
|
|
@@ -698,11 +1047,65 @@ export MIMETIC_PUBLIC_SAFE=1
|
|
|
698
1047
|
ROOT_DIR=${shellQuote(args.rootDir)}
|
|
699
1048
|
APP_DIR="$ROOT_DIR/repo"
|
|
700
1049
|
LOG_PATH=${shellQuote(args.logPath)}
|
|
1050
|
+
COMPLETION_PATH=${shellQuote(args.completionPath)}
|
|
701
1051
|
NESTED_OBSERVER=${shellQuote(args.nestedObserverPath)}
|
|
702
1052
|
REMOTE_PACKAGE=${args.remotePackagePath ? shellQuote(args.remotePackagePath) : "''"}
|
|
703
1053
|
mkdir -p "$ROOT_DIR"
|
|
704
1054
|
touch "$LOG_PATH"
|
|
705
1055
|
exec > >(tee -a "$LOG_PATH") 2>&1
|
|
1056
|
+
NESTED_VERIFY_STATUS=not_run
|
|
1057
|
+
|
|
1058
|
+
write_completion() {
|
|
1059
|
+
local status="$1"
|
|
1060
|
+
local reason="$2"
|
|
1061
|
+
local exit_code="$3"
|
|
1062
|
+
local nested_observer_present=false
|
|
1063
|
+
if [[ -f "$NESTED_OBSERVER" ]]; then
|
|
1064
|
+
nested_observer_present=true
|
|
1065
|
+
fi
|
|
1066
|
+
|
|
1067
|
+
node - "$COMPLETION_PATH" "$LOG_PATH" "$status" "$reason" "$exit_code" "$nested_observer_present" "$NESTED_VERIFY_STATUS" <<'NODE' || true
|
|
1068
|
+
const fs = require("node:fs");
|
|
1069
|
+
const [
|
|
1070
|
+
completionPath,
|
|
1071
|
+
logPath,
|
|
1072
|
+
status,
|
|
1073
|
+
reason,
|
|
1074
|
+
exitCode,
|
|
1075
|
+
nestedObserverPresent,
|
|
1076
|
+
nestedVerifyStatus
|
|
1077
|
+
] = process.argv.slice(2);
|
|
1078
|
+
const rawTail = fs.existsSync(logPath)
|
|
1079
|
+
? fs.readFileSync(logPath, "utf8").split(/\\r?\\n/).slice(-80).join("\\n")
|
|
1080
|
+
: "";
|
|
1081
|
+
const redactedTail = rawTail
|
|
1082
|
+
.replace(/sk-[A-Za-z0-9_-]{12,}/g, "[redacted-openai-key]")
|
|
1083
|
+
.replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
|
|
1084
|
+
.replace(/gh[pousr]_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]");
|
|
1085
|
+
fs.writeFileSync(completionPath, JSON.stringify({
|
|
1086
|
+
schema: "mimetic.oss-meta-bootstrap-completion.v1",
|
|
1087
|
+
status,
|
|
1088
|
+
reason,
|
|
1089
|
+
exitCode: Number(exitCode),
|
|
1090
|
+
nestedObserverPresent: nestedObserverPresent === "true",
|
|
1091
|
+
nestedVerifyStatus,
|
|
1092
|
+
logTail: redactedTail,
|
|
1093
|
+
completedAt: new Date().toISOString()
|
|
1094
|
+
}, null, 2) + "\\n");
|
|
1095
|
+
NODE
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
finish() {
|
|
1099
|
+
local exit_code="$?"
|
|
1100
|
+
trap - EXIT
|
|
1101
|
+
if [[ "$exit_code" -eq 0 ]]; then
|
|
1102
|
+
write_completion "passed" "Nested Mimetic proof completed and nested Observer path was checked." "$exit_code"
|
|
1103
|
+
else
|
|
1104
|
+
write_completion "failed" "Bootstrap exited before nested Mimetic proof completed." "$exit_code"
|
|
1105
|
+
fi
|
|
1106
|
+
exit "$exit_code"
|
|
1107
|
+
}
|
|
1108
|
+
trap finish EXIT
|
|
706
1109
|
|
|
707
1110
|
echo "== mimetic oss meta-lab bootstrap =="
|
|
708
1111
|
echo "repo=${args.assignment.repo}"
|
|
@@ -778,7 +1181,12 @@ npx mimetic init --yes
|
|
|
778
1181
|
echo
|
|
779
1182
|
echo "== nested mimetic proof =="
|
|
780
1183
|
npx mimetic run --dry-run --run-id ${shellQuote(runId)}
|
|
781
|
-
npx mimetic verify --run latest
|
|
1184
|
+
if npx mimetic verify --run latest; then
|
|
1185
|
+
NESTED_VERIFY_STATUS=passed
|
|
1186
|
+
else
|
|
1187
|
+
NESTED_VERIFY_STATUS=failed
|
|
1188
|
+
exit 1
|
|
1189
|
+
fi
|
|
782
1190
|
npx mimetic watch --run latest --detach --no-open
|
|
783
1191
|
|
|
784
1192
|
echo
|
|
@@ -894,7 +1302,9 @@ function shellQuote(value) {
|
|
|
894
1302
|
function formatLiveDesktopForResult(desktop) {
|
|
895
1303
|
return {
|
|
896
1304
|
...(desktop.bootstrap ? { bootstrapStatus: desktop.bootstrap.status } : {}),
|
|
1305
|
+
...(desktop.completion ? { completionReason: desktop.completion.reason, completionStatus: desktop.completion.status } : {}),
|
|
897
1306
|
repo: desktop.repo,
|
|
1307
|
+
...(desktop.screenshot ? { screenshotPresent: true } : {}),
|
|
898
1308
|
...(desktop.sandboxId ? { sandboxId: desktop.sandboxId } : {}),
|
|
899
1309
|
streamId: desktop.streamId,
|
|
900
1310
|
urlPresent: Boolean(desktop.url)
|
|
@@ -910,6 +1320,19 @@ function readPositiveInt(value, fallback) {
|
|
|
910
1320
|
const parsed = Number.parseInt(value, 10);
|
|
911
1321
|
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
912
1322
|
}
|
|
1323
|
+
function readNonNegativeInt(value, fallback) {
|
|
1324
|
+
if (!value || !/^\d+$/.test(value)) {
|
|
1325
|
+
return fallback;
|
|
1326
|
+
}
|
|
1327
|
+
const parsed = Number.parseInt(value, 10);
|
|
1328
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
1329
|
+
}
|
|
1330
|
+
async function wait(ms) {
|
|
1331
|
+
if (ms <= 0) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1335
|
+
}
|
|
913
1336
|
function compactError(error) {
|
|
914
1337
|
const message = error instanceof Error ? error.message : String(error);
|
|
915
1338
|
return message.replace(/\s+/g, " ").slice(0, 240);
|
|
@@ -921,6 +1344,10 @@ function makeMetaRunId() {
|
|
|
921
1344
|
function repoSlugToken(repo) {
|
|
922
1345
|
return repo.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
923
1346
|
}
|
|
1347
|
+
function safeArtifactToken(value) {
|
|
1348
|
+
const token = value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1349
|
+
return token || "artifact";
|
|
1350
|
+
}
|
|
924
1351
|
async function writeJson(filePath, value) {
|
|
925
1352
|
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
926
1353
|
}
|