@deeeed/metamask-harness 0.92.21 → 0.92.23

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.
@@ -1,317 +0,0 @@
1
- import os from "node:os";
2
- import path from "node:path";
3
- import { isTerminalWorkerSignalStatus } from "@farmslot/protocol";
4
- import { color, EXIT } from "@farmslot/recipe-cli/harness";
5
- import {
6
- CHECKLIST_LABEL_LIMIT,
7
- collectTaskView,
8
- findTaskDir,
9
- TASK_SILENT_AFTER_MS
10
- } from "../task-view.js";
11
- const REFRESH_MS = 2e3;
12
- const CLEAR_SCREEN = "\x1B[2J\x1B[H";
13
- const HIDE_CURSOR = "\x1B[?25l";
14
- const SHOW_CURSOR = "\x1B[?25h";
15
- async function handleStatusTaskView(options) {
16
- const deps = {
17
- now: () => Date.now(),
18
- wait: (ms) => new Promise((resolve) => {
19
- setTimeout(resolve, ms);
20
- }),
21
- write: (text) => process.stdout.write(text),
22
- isTty: Boolean(process.stdout.isTTY)
23
- };
24
- if (!options.watch || !deps.isTty) return runStatusWatch(options, deps);
25
- const restore = () => deps.write(SHOW_CURSOR);
26
- const interrupt = () => {
27
- restore();
28
- process.exit(EXIT.ok);
29
- };
30
- process.on("SIGINT", interrupt);
31
- deps.write(HIDE_CURSOR);
32
- try {
33
- return await runStatusWatch(options, deps);
34
- } finally {
35
- process.off("SIGINT", interrupt);
36
- restore();
37
- }
38
- }
39
- async function runStatusWatch(options, deps) {
40
- const title = `mm-harness status ${options.watch ? "--watch" : "--task"}`;
41
- let previous;
42
- let sawInProgress = false;
43
- for (; ; ) {
44
- const taskDir = options.taskDir ?? findTaskDir(options.target);
45
- const view = collectTaskView(options.target, taskDir, deps.now());
46
- const changes = changedLines(previous, view);
47
- if (options.json && !options.watch) {
48
- deps.write(`${JSON.stringify(view, null, 2)}
49
- `);
50
- } else if (options.json) {
51
- if (changes.length > 0) deps.write(`${JSON.stringify(view)}
52
- `);
53
- } else if (options.watch && !deps.isTty) {
54
- for (const line of changes) deps.write(`${line}
55
- `);
56
- } else {
57
- deps.write(`${deps.isTty && options.watch ? CLEAR_SCREEN : ""}${renderTaskView(view, title, options.taskDir !== void 0).join("\n")}
58
- `);
59
- }
60
- previous = view;
61
- const terminal = isTerminalWorkerSignalStatus(view.signal?.status);
62
- if (view.activity.ongoing) sawInProgress = true;
63
- if (!options.watch || terminal && (sawInProgress || options.taskDir !== void 0)) return EXIT.ok;
64
- await deps.wait(REFRESH_MS);
65
- }
66
- }
67
- function renderTaskView(view, title, explicitTask = false) {
68
- const out = (style, text) => color(style, text, { stream: process.stdout });
69
- const showTask = view.activity.ongoing || explicitTask;
70
- const lines = [joinParts([
71
- out("label", title),
72
- out("bold", path.basename(view.checkout.target)),
73
- view.checkout.branch && out("info", view.checkout.branch),
74
- view.checkout.head && out("dim", `@${view.checkout.head}`),
75
- showTask && view.elapsedMs !== void 0 && out("dim", `${formatDuration(view.elapsedMs)} elapsed`)
76
- ], " ")];
77
- const isolation = view.isolation;
78
- const device = isolation && joinParts([isolation.platform, isolation.simulator, shortUdid(isolation.simulatorUdid)], " ");
79
- const devServer = isolation?.metroPort ?? isolation?.watcherPort ?? isolation?.devServerPort;
80
- const runtimeLine = joinParts([
81
- isolation?.slotId && `slot ${out("ok", isolation.slotId)}`,
82
- device && out("ok", device),
83
- devServer !== void 0 && `metro ${out("ok", String(devServer))}`,
84
- isolation?.cdpPort !== void 0 && `cdp ${out("ok", String(isolation.cdpPort))}`,
85
- isolation?.extensionId && `extension ${out("ok", isolation.extensionId)}`,
86
- showTask && view.harness?.version && `harness ${out("info", view.harness.version)}${view.harness.sourceKind ? out("dim", ` (${view.harness.sourceKind})`) : ""}`
87
- ]);
88
- if (runtimeLine) lines.push(runtimeLine);
89
- const template = showTask ? view.template : void 0;
90
- const templateLine = joinParts([
91
- template?.id && `template ${out("accent", template.id)}${template.sourceId ? out("dim", ` (${template.sourceId})`) : ""}`,
92
- template?.flow && `flow ${out("info", template.flow)}`,
93
- template?.domain && `domain ${out("info", template.domain)}`,
94
- template?.surface && `via ${out("info", template.surface)}`
95
- ]);
96
- if (templateLine) lines.push(templateLine);
97
- const taskLine = joinParts([
98
- template?.ticket && out("bold", template.ticket),
99
- template?.title && out("info", template.title.trim())
100
- ], " ");
101
- if (taskLine) lines.push(`${out("label", "task")} ${taskLine}`);
102
- const contextLine = joinParts([
103
- view.libraries.length > 0 && `libraries ${out("info", view.libraries.map(libraryLabel).join(" "))}`,
104
- showTask && view.fixture && `fixture ${out("info", path.basename(view.fixture.fixture ?? "unknown"))} ${statusWord(out, view.fixture.status)}${view.fixture.walletReset ? out("warn", " reset") : ""}`,
105
- showTask && (view.prepare ? `sandbox ${out("info", "preparing")}` : view.sandbox?.ready !== void 0 && `sandbox ${view.sandbox.ready ? out("ok", "ready") : out("warn", "not ready")}`)
106
- ]);
107
- if (contextLine) lines.push(contextLine);
108
- if (showTask && view.acceptance?.length) lines.push("", ...renderAcceptanceLines(view));
109
- if (showTask && view.prepare) {
110
- lines.push(`prepare ${out("info", view.prepare.step)} \xB7 ${view.prepare.completed}/${view.prepare.total} steps \xB7 ${formatDuration(view.prepare.elapsedMs)} elapsed`);
111
- }
112
- const last = view.lastCommand;
113
- if (showTask && last) {
114
- lines.push(joinParts([
115
- `last command ${out("info", joinParts([last.command, last.subject], " "))}`,
116
- last.verdict && statusWord(out, last.verdict),
117
- last.ageMs !== void 0 && `${formatDuration(last.ageMs)} ago`
118
- ]));
119
- }
120
- lines.push(...renderOperations(view));
121
- lines.push("");
122
- if (!view.activity.ongoing) {
123
- lines.push(out("warn", "no ongoing task detected"));
124
- lines.push(out("dim", idleReason(view)));
125
- if (!view.taskDir || !explicitTask) return lines;
126
- lines.push("");
127
- }
128
- let phase;
129
- for (const row of view.checklist) {
130
- if (row.phase && row.phase !== phase) {
131
- const inPhase = view.checklist.filter((other) => other.phase === row.phase);
132
- const done = inPhase.filter((other) => other.checked).length;
133
- lines.push(out("dim", ` ${row.phase} ${done}/${inPhase.length}`));
134
- }
135
- phase = row.phase;
136
- lines.push(renderRow(row, view.currentStep, out));
137
- for (const unit of view.subtasks.filter((entry) => entry.parentStep === row.number)) {
138
- lines.push(...renderSubtask(unit, out));
139
- }
140
- }
141
- const signal = view.signal;
142
- if (signal) {
143
- const age = view.checklist.find((row) => row.runningMs !== void 0)?.runningMs;
144
- lines.push("");
145
- lines.push(joinParts([
146
- `signal ${statusWord(out, signal.status)}`,
147
- // SIGNAL.json records the last row ticked, not the row in progress.
148
- signal.step && `last ticked ${out("info", stepLabel(signal.step))}`,
149
- // A cancelled agent leaves status "running"; the age is the only honest hint.
150
- age !== void 0 && `no update for ${out(age > TASK_SILENT_AFTER_MS ? "warn" : "dim", formatDuration(age))}`
151
- ]));
152
- }
153
- return lines;
154
- }
155
- function renderAcceptanceLines(view) {
156
- if (!view.acceptance?.length) return [];
157
- const out = (style, text) => color(style, text, { stream: process.stdout });
158
- const proven = view.acceptance.filter((row) => row.status?.verdict === "proven").length;
159
- return [
160
- `acceptance criteria ${proven}/${view.acceptance.length} proven`,
161
- ...view.acceptance.map((row) => {
162
- const verdict = row.status?.verdict ?? "no verdict";
163
- const style = verdict === "proven" ? "ok" : verdict === "weak" ? "warn" : verdict === "no verdict" ? "dim" : "err";
164
- return ` ${row.id} [${out(style, verdict)}] ${row.text}`;
165
- })
166
- ];
167
- }
168
- function idleReason(view) {
169
- if (!view.taskDir) return "no task directory under temp/tasks";
170
- const { reason, idleMs, branchCarriesTicket } = view.activity;
171
- if (reason === "no-task") return `${path.basename(view.taskDir)} holds no task files yet`;
172
- const what = reason === "finished" ? view.signal?.status ?? "finished" : "silent";
173
- return joinParts([
174
- `last task ${path.basename(view.taskDir)}: ${what}`,
175
- idleMs !== void 0 && `last update ${formatDuration(idleMs)} ago`,
176
- branchCarriesTicket === false && `checkout is on ${view.checkout.branch}, which does not carry ${view.template?.ticket}`
177
- ], ", ");
178
- }
179
- function changedLines(previous, next) {
180
- if (!previous || previous.taskDir !== next.taskDir) {
181
- return [
182
- joinParts([
183
- path.basename(next.checkout.target),
184
- next.taskDir ? path.basename(next.taskDir) : "no-task-dir",
185
- `status=${next.signal?.status ?? "unknown"}`,
186
- `step=${next.signal?.step ? stepLabel(next.signal.step) : "none"}`
187
- ], " "),
188
- ...(next.acceptance ?? []).map((row) => `${row.id} ${row.status?.verdict ?? "no verdict"} ${row.text}`),
189
- ...next.prepare ? [`prepare ${next.prepare.step} started (${next.prepare.completed}/${next.prepare.total} steps)`] : []
190
- ];
191
- }
192
- const lines = [];
193
- for (const operation of next.operations) {
194
- const before2 = previous.operations.find((entry) => entry.id === operation.id);
195
- if (!before2 || before2.status !== operation.status || before2.stage !== operation.stage || before2.ownerAlive !== operation.ownerAlive) {
196
- lines.push(`operation ${operation.command} ${operation.status}${operation.stage ? ` \xB7 ${operation.stage}` : ""} \xB7 log ${operation.logPath}`);
197
- }
198
- }
199
- for (const step of next.prepare?.steps ?? []) {
200
- if (!previous.prepare?.steps.some((prior) => prior.id === step.id && prior.status === step.status)) {
201
- lines.push(`prepare ${step.id} ${step.status} (${formatDuration(step.durationMs)})`);
202
- }
203
- }
204
- if (next.prepare && (previous.prepare?.step !== next.prepare.step || previous.prepare.startedAt !== next.prepare.startedAt)) {
205
- lines.push(`prepare ${next.prepare.step} started (${next.prepare.completed}/${next.prepare.total} steps)`);
206
- }
207
- const before = new Map(previous.checklist.map((row) => [row.number, row.checked]));
208
- const beforeAcceptance = new Map(previous.acceptance?.map((row) => [row.id, row.status?.verdict]));
209
- for (const row of next.acceptance ?? []) {
210
- if (beforeAcceptance.get(row.id) !== row.status?.verdict || !beforeAcceptance.has(row.id)) {
211
- lines.push(`${row.id} ${row.status?.verdict ?? "no verdict"} ${row.text}`);
212
- }
213
- }
214
- for (const row of next.checklist) {
215
- if (!row.checked || before.get(row.number) === true) continue;
216
- lines.push(`checked ${row.number} ${row.label}${row.durationMs !== void 0 ? ` (${formatDuration(row.durationMs)})` : ""}`);
217
- }
218
- const beforeUnits = new Map(previous.subtasks.map((unit) => [unit.id, unit]));
219
- for (const unit of next.subtasks) {
220
- const before2 = beforeUnits.get(unit.id);
221
- if (!before2) {
222
- lines.push(`subtask ${unit.id} registered on step ${unit.parentStep} (${unit.rows.length} rows)`);
223
- }
224
- const beforeRows = new Map((before2?.rows ?? []).map((row) => [row.number, row.checked]));
225
- for (const row of unit.rows) {
226
- if (!row.checked || beforeRows.get(row.number) === true) continue;
227
- lines.push(`subtask ${unit.id} checked ${row.number} ${row.label}`);
228
- }
229
- if (before2 && before2.status !== unit.status) {
230
- lines.push(`subtask ${unit.id} ${unit.status ?? "unknown"}`);
231
- }
232
- }
233
- if (previous.signal?.step !== next.signal?.step && next.signal?.step) {
234
- lines.push(`step ${stepLabel(next.signal.step)}`);
235
- }
236
- if (previous.signal?.status !== next.signal?.status) {
237
- lines.push(`status ${next.signal?.status ?? "unknown"}`);
238
- }
239
- if (next.lastCommand && previous.lastCommand?.at !== next.lastCommand.at) {
240
- lines.push(`command ${joinParts([next.lastCommand.command, next.lastCommand.subject], " ")}${next.lastCommand.verdict ? ` ${next.lastCommand.verdict}` : ""}`);
241
- }
242
- return lines;
243
- }
244
- function formatDuration(ms) {
245
- const total = Math.max(0, Math.round(ms / 1e3));
246
- const seconds = String(total % 60).padStart(2, "0");
247
- const minutes = Math.floor(total / 60) % 60;
248
- const hours = Math.floor(total / 3600);
249
- if (hours === 0) return `${minutes}:${seconds}`;
250
- return `${hours}:${String(minutes).padStart(2, "0")}:${seconds}`;
251
- }
252
- function renderRow(row, currentStep, out) {
253
- const marker = row.checked ? out("ok", "\u2713") : row.number === currentStep ? out("accent", "\u25B6") : out("dim", "\xB7");
254
- const timing = row.durationMs !== void 0 ? formatDuration(row.durationMs) : row.runningMs !== void 0 ? `${formatDuration(row.runningMs)} \u2026` : "";
255
- const number = String(row.number).padStart(2);
256
- const label = timing ? row.label.padEnd(CHECKLIST_LABEL_LIMIT) : row.label;
257
- const text = row.checked ? out("dim", label) : out("bold", label);
258
- return ` ${marker} ${out("dim", number)} ${text}${timing ? ` ${out("dim", timing)}` : ""}`;
259
- }
260
- function renderSubtask(unit, out) {
261
- const done = unit.rows.filter((row) => row.checked).length;
262
- const header = joinParts([
263
- `${out("label", "subtask")} ${out("accent", unit.id)}`,
264
- statusWord(out, unit.status),
265
- `${done}/${unit.rows.length}`,
266
- unit.source?.ref && out("dim", unit.source.ref)
267
- ]);
268
- const current = unit.rows.find((row) => !row.checked);
269
- return [
270
- ` ${header}`,
271
- ...unit.rows.map((row) => ` ${renderRow(row, current?.number, out)}`)
272
- ];
273
- }
274
- function libraryLabel(library) {
275
- const home = os.homedir();
276
- const location = home && library.path.startsWith(`${home}/`) ? `~${library.path.slice(home.length)}` : library.path;
277
- return library.name ? `${library.name}=${location}` : location;
278
- }
279
- function statusWord(out, status) {
280
- if (!status) return out("dim", "unknown");
281
- const style = ["pass", "ready", "complete", "no-change"].includes(status) ? "ok" : ["running", "started"].includes(status) ? "accent" : "err";
282
- return out(style, status);
283
- }
284
- function stepLabel(step) {
285
- return /^\s*(\d+)\./u.exec(step)?.[1] ?? step.trim();
286
- }
287
- function shortUdid(udid) {
288
- if (!udid) return void 0;
289
- return `(${udid.split("-")[0]})`;
290
- }
291
- function joinParts(parts, separator = " \xB7 ") {
292
- return parts.filter((part) => Boolean(part)).join(separator);
293
- }
294
- function renderOperations(view) {
295
- const active = view.operations.filter((operation) => operation.status === "running" && operation.ownerAlive);
296
- const selected = active.length ? active : view.operations.slice(-1);
297
- return selected.flatMap((operation) => {
298
- const elapsed = Date.parse(operation.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString()) - Date.parse(operation.startedAt);
299
- const state = operation.status === "running" ? operation.ownerAlive ? "owner alive" : "owner exited; outcome unknown" : operation.status;
300
- const age = operation.lastOutputAt ? formatDuration(Date.now() - Date.parse(operation.lastOutputAt)) + " ago" : "none recorded";
301
- const quoted = "'" + operation.logPath.replace(/'/g, "'\\''") + "'";
302
- return [
303
- `${operation.parentId ? " " : ""}operation ${operation.command} \xB7 ${state} \xB7 ${formatDuration(elapsed)} elapsed`,
304
- ...operation.stage ? [` stage ${operation.stage}`] : [],
305
- ` last output ${age}`,
306
- ` follow: tail -n 50 -F ${quoted}`
307
- ];
308
- });
309
- }
310
- export {
311
- changedLines,
312
- formatDuration,
313
- handleStatusTaskView,
314
- renderAcceptanceLines,
315
- renderTaskView,
316
- runStatusWatch
317
- };
@@ -1,146 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { featureFlagReport } from "../feature-flags.js";
4
- import { color, contextAdapter, harnessContextField, adapterDetectNext, EXIT, usageOut, optionFlag, optionString, targetPath } from "@farmslot/recipe-cli/harness";
5
- import { collectCheckoutView, renderCheckoutView } from "../checkout-view.js";
6
- import { assertAdapter } from "../paths.js";
7
- import { getAdapterSurface } from "../adapters/surface.js";
8
- import {
9
- applyDeviceTargeting
10
- } from "./device-target.js";
11
- import { handleStatusTaskView, renderAcceptanceLines } from "./status-watch.js";
12
- import { collectTaskView, findTaskDir } from "../task-view.js";
13
- async function handleStatus({ options }) {
14
- const target = targetPath(options);
15
- const json = optionFlag(options, "json");
16
- const watch = optionFlag(options, "watch");
17
- const taskDir = optionString(options, "task");
18
- if (watch || taskDir) {
19
- const resolvedTask = taskDir ? path.resolve(taskDir) : void 0;
20
- if (resolvedTask && !(fs.existsSync(resolvedTask) && fs.statSync(resolvedTask).isDirectory())) {
21
- return usageOut(json, "status", `--task is not a directory: ${resolvedTask}`, "Pass a task directory under temp/tasks, or omit --task to follow the newest one.");
22
- }
23
- return handleStatusTaskView({ target, taskDir: resolvedTask, json, watch });
24
- }
25
- const fast = optionFlag(options, "fast");
26
- const allDevices = optionFlag(options, "allDevices");
27
- const adapter = contextAdapter(target);
28
- if (!adapter) {
29
- return usageOut(json, "status", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
30
- }
31
- assertAdapter(adapter);
32
- const view = collectCheckoutView(target, adapter);
33
- const surface = getAdapterSurface(adapter);
34
- surface.resolveSlotPorts(target);
35
- const { readiness } = surface;
36
- const deviceSource = await readiness.devices?.();
37
- if (deviceSource) {
38
- const dtResult = applyDeviceTargeting("status", adapter, options, { gate: false, rerun: "" });
39
- if ("code" in dtResult) {
40
- return usageOut(json, "status", dtResult.message, dtResult.userAction);
41
- }
42
- }
43
- const next = surface.hints.relaunch;
44
- const pinnedFlags = readiness.pinnedFlags?.(target) ?? null;
45
- const staticFeatureFlags = pinnedFlags ? featureFlagReport(pinnedFlags.overrides, pinnedFlags) : featureFlagReport(null);
46
- const deviceView = deviceSource ? deviceSource.view(allDevices) : null;
47
- const devices = deviceView?.devices ?? [];
48
- const discovery = deviceView?.deviceDiscoveryErrors.length ? { deviceDiscoveryErrors: deviceView.deviceDiscoveryErrors } : {};
49
- const discoveryNext = discovery.deviceDiscoveryErrors?.[0]?.userAction;
50
- if (json) {
51
- const doProbe = !fast && deviceSource && deviceView !== null && deviceView.allConnectedDevices.length > 0;
52
- if (doProbe) {
53
- const liveView = await deviceSource.live(target, deviceView);
54
- console.log(
55
- JSON.stringify(
56
- {
57
- schemaVersion: 1,
58
- command: "status",
59
- adapter,
60
- target,
61
- ...harnessContextField(),
62
- view,
63
- devices: liveView.devicesWithLive,
64
- featureFlags: featureFlagReport(liveView.featureFlagOverrides),
65
- ...discovery,
66
- ...liveView.additionalReachableDevices.length > 0 ? { additionalReachableDevices: liveView.additionalReachableDevices } : {},
67
- ...liveView.androidPortHints.length > 0 ? { androidPortHints: liveView.androidPortHints } : {},
68
- next: discoveryNext ?? deviceSource.nextForLive(next, liveView.liveMap)
69
- },
70
- null,
71
- 2
72
- )
73
- );
74
- } else {
75
- const runtime = !fast && readiness.statusRuntime ? await surface.runtimeStatus(target) : void 0;
76
- console.log(
77
- JSON.stringify(
78
- {
79
- schemaVersion: 1,
80
- command: "status",
81
- adapter,
82
- target,
83
- ...harnessContextField(),
84
- view,
85
- devices,
86
- featureFlags: staticFeatureFlags,
87
- ...discovery,
88
- ...runtime ? { runtime } : {},
89
- next: discoveryNext ?? (runtime ? nextForRuntime(surface.hints.launch, surface.hints.relaunch, runtime) : next)
90
- },
91
- null,
92
- 2
93
- )
94
- );
95
- }
96
- return EXIT.ok;
97
- }
98
- const out = (style, text) => color(style, text, { stream: process.stdout });
99
- console.log(`${out("label", "status")} ${out("bold", adapter)} ${out("dim", target)}`);
100
- console.log(renderCheckoutView(view));
101
- if (!fast) {
102
- const taskView = collectTaskView(target, findTaskDir(target), Date.now());
103
- if (taskView.activity.ongoing && taskView.acceptance?.length) {
104
- console.log(renderAcceptanceLines(taskView).join("\n"));
105
- }
106
- }
107
- if (!deviceSource) renderFeatureFlagLine(staticFeatureFlags, out);
108
- if (deviceSource && deviceView) deviceSource.renderList(deviceView, out);
109
- if (!fast && deviceSource && deviceView !== null && deviceView.allConnectedDevices.length > 0) {
110
- const liveView = await deviceSource.live(target, deviceView);
111
- if (liveView.additionalReachableDevices.length > 0) deviceSource.renderAdditional(liveView.additionalReachableDevices, out);
112
- renderFeatureFlagLine(featureFlagReport(liveView.featureFlagOverrides), out);
113
- deviceSource.renderLive(devices, liveView.liveMap, out);
114
- deviceSource.renderPortHints(liveView.androidPortHints, out);
115
- console.log(`${out("label", "Next:")} ${out("cmd", discoveryNext ?? deviceSource.nextForLive(next, liveView.liveMap))}`);
116
- } else if (!fast && readiness.statusRuntime) {
117
- const runtime = await surface.runtimeStatus(target);
118
- renderRuntimeStatus(runtime, out);
119
- console.log(`${out("label", "Next:")} ${out("cmd", nextForRuntime(surface.hints.launch, surface.hints.relaunch, runtime))}`);
120
- } else {
121
- if (deviceSource) renderFeatureFlagLine(featureFlagReport(null), out);
122
- console.log(`${out("label", "Next:")} ${out("cmd", discoveryNext ?? next)}`);
123
- }
124
- return EXIT.ok;
125
- }
126
- function renderFeatureFlagLine(report, out) {
127
- const style = report.error ? "warn" : (report.overrideCount ?? 0) > 0 ? "warn" : "dim";
128
- console.log(`${out("label", "feature flags:")} ${out(style, report.summary.replace(/^feature flags: /u, ""))}`);
129
- }
130
- function renderRuntimeStatus(runtime, out) {
131
- const decisionStyle = runtime.decision === "ready" ? "ok" : runtime.decision === "blocked" ? "err" : "warn";
132
- const deps = runtime.deps ? ` deps=${out(runtime.deps === "current" ? "ok" : "warn", runtime.deps)}` : "";
133
- const devServer = runtime.devServer ? ` ${runtime.devServer.label}=${out(runtime.devServer.status === "up" ? "ok" : "warn", runtime.devServer.status)}` : "";
134
- console.log(
135
- `${out("label", "runtime:")} decision=${out(decisionStyle, runtime.decision)}${runtime.reasonCode ? ` ${out("dim", `(${runtime.reasonCode})`)}` : ""}${deps}${devServer}`
136
- );
137
- }
138
- function nextForRuntime(launchHint, relaunchHint, runtime) {
139
- if (runtime.nextAction) return runtime.nextAction;
140
- if (runtime.decision === "ready") return "mm-harness logs";
141
- if (runtime.decision === "relaunch") return launchHint;
142
- return relaunchHint;
143
- }
144
- export {
145
- handleStatus
146
- };
@@ -1,49 +0,0 @@
1
- import { harnessExecutable, contextAdapter, EXIT } from "@farmslot/recipe-cli/harness";
2
- import { spawnSync } from "node:child_process";
3
- import { createRequire } from "node:module";
4
- const require2 = createRequire(import.meta.url);
5
- const USAGE = "mm-harness task init <task-dir> --flow f --template id --title t [options]";
6
- function hasOption(argv, name) {
7
- return argv.some((arg) => arg === name || arg.startsWith(`${name}=`));
8
- }
9
- function metamaskDefaults(argv) {
10
- const defaults = [];
11
- if (!hasOption(argv, "--surface")) defaults.push("--surface", "skill");
12
- if (!hasOption(argv, "--mark-command")) {
13
- defaults.push("--mark-command", `${harnessExecutable()} checklist mark`);
14
- }
15
- if (!hasOption(argv, "--platform")) {
16
- const adapter = contextAdapter(process.cwd());
17
- if (adapter) defaults.push("--platform", adapter);
18
- }
19
- return defaults;
20
- }
21
- async function handleTaskInit(argv) {
22
- if (argv[0] !== "init") {
23
- console.error(`usage: ${USAGE}`);
24
- return EXIT.usage;
25
- }
26
- const forwarded = argv.slice(1);
27
- let entrypoint;
28
- try {
29
- entrypoint = require2.resolve("@farmslot/agent-runtime/scripts/task-init-cli.mjs");
30
- } catch (error) {
31
- console.error(
32
- `mm-harness task init: installed @farmslot/agent-runtime does not expose the task-directory command: ${error instanceof Error ? error.message : String(error)}`
33
- );
34
- return EXIT.runtime;
35
- }
36
- const result = spawnSync(
37
- process.execPath,
38
- [entrypoint, ...forwarded, ...metamaskDefaults(forwarded)],
39
- { env: process.env, stdio: "inherit" }
40
- );
41
- if (result.error) {
42
- console.error(`mm-harness task init: ${result.error.message}`);
43
- return EXIT.runtime;
44
- }
45
- return result.status ?? EXIT.runtime;
46
- }
47
- export {
48
- handleTaskInit
49
- };