@deeeed/metamask-harness 0.60.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.61.0 - 2026-09-20
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `status --watch` and `status --task` show child checklist units (Farmslot ADR-060): a unit registered on a row is read from `subtasks/index.json` beside the checklist and printed under the row that owns it, with its id, status, `done/total` and source, and its rows indented one level deeper. Piped output logs a registration, each child row tick and a child status move. Everything comes from the protocol helpers (`subtaskPaths`, `isSettledSubtaskStatus`, `enumerateChecklistCheckboxes`), so the harness parses nothing itself.
|
|
10
|
+
- Pins `@farmslot/protocol` 0.30.0, `@farmslot/agent-runtime` 0.13.0, `@farmslot/recipe-harness` 0.18.0 and `@farmslot/expo-recipe` 0.11.0 together, so one protocol copy serves the harness; a worker produces `subtasks/` once its node runs agent-runtime 0.13.0 (`mark sub`).
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Mobile `ui.screenshot` records the node's `label` on its artifact-manifest entry (simctl and adb paths); the bridge leaf used to stamp the generic `ui.screenshot screenshot` and drop the label the action schema declares, so packaged evidence carried no caption. The Extension path already carried it.
|
|
15
|
+
|
|
5
16
|
## 0.60.0 - 2026-09-19
|
|
6
17
|
|
|
7
18
|
### Changed
|
|
@@ -1494,6 +1505,11 @@ Fresh-install hotfixes found in live validation of 0.5.0.
|
|
|
1494
1505
|
|
|
1495
1506
|
## Unreleased
|
|
1496
1507
|
|
|
1508
|
+
### Added
|
|
1509
|
+
|
|
1510
|
+
- `status --watch` and `status --task` show child checklist units (Farmslot ADR-060): a unit registered on a row is read from `subtasks/index.json` beside the checklist and printed under the row that owns it, with its id, status, `done/total` and source, and its rows indented one level deeper. Piped output logs a registration, each child row tick and a child status move. Everything comes from the protocol helpers (`subtaskPaths`, `isSettledSubtaskStatus`, `enumerateChecklistCheckboxes`), so the harness parses nothing itself.
|
|
1511
|
+
- Pins `@farmslot/protocol` 0.30.0, `@farmslot/agent-runtime` 0.13.0, `@farmslot/recipe-harness` 0.18.0 and `@farmslot/expo-recipe` 0.11.0 together, so one protocol copy serves the harness; a worker produces `subtasks/` once its node runs agent-runtime 0.13.0 (`mark sub`).
|
|
1512
|
+
|
|
1497
1513
|
### Fixed
|
|
1498
1514
|
|
|
1499
1515
|
- **`provision --json` adapter-detection failures emit the standard error envelope** — usage errors now match `doctor`/`launch` (envelope on stdout with `error.userAction`; stderr stays human-only). Previously `--json` callers got empty stdout.
|
|
@@ -2382,6 +2398,11 @@ Fresh-install hotfixes found in live validation of 0.5.0.
|
|
|
2382
2398
|
|
|
2383
2399
|
## Unreleased
|
|
2384
2400
|
|
|
2401
|
+
### Added
|
|
2402
|
+
|
|
2403
|
+
- `status --watch` and `status --task` show child checklist units (Farmslot ADR-060): a unit registered on a row is read from `subtasks/index.json` beside the checklist and printed under the row that owns it, with its id, status, `done/total` and source, and its rows indented one level deeper. Piped output logs a registration, each child row tick and a child status move. Everything comes from the protocol helpers (`subtaskPaths`, `isSettledSubtaskStatus`, `enumerateChecklistCheckboxes`), so the harness parses nothing itself.
|
|
2404
|
+
- Pins `@farmslot/protocol` 0.30.0, `@farmslot/agent-runtime` 0.13.0, `@farmslot/recipe-harness` 0.18.0 and `@farmslot/expo-recipe` 0.11.0 together, so one protocol copy serves the harness; a worker produces `subtasks/` once its node runs agent-runtime 0.13.0 (`mark sub`).
|
|
2405
|
+
|
|
2385
2406
|
### Fixed
|
|
2386
2407
|
|
|
2387
2408
|
- **`provision --json` adapter-detection failures emit the standard error envelope** — usage errors now match `doctor`/`launch` (envelope on stdout with `error.userAction`; stderr stays human-only). Previously `--json` callers got empty stdout.
|
|
@@ -130,6 +130,9 @@ function renderTaskView(view, title, explicitTask = false) {
|
|
|
130
130
|
}
|
|
131
131
|
phase = row.phase;
|
|
132
132
|
lines.push(renderRow(row, view.currentStep, out));
|
|
133
|
+
for (const unit of view.subtasks.filter((entry) => entry.parentStep === row.number)) {
|
|
134
|
+
lines.push(...renderSubtask(unit, out));
|
|
135
|
+
}
|
|
133
136
|
}
|
|
134
137
|
const signal = view.signal;
|
|
135
138
|
if (signal) {
|
|
@@ -171,6 +174,21 @@ function changedLines(previous, next) {
|
|
|
171
174
|
if (!row.checked || before.get(row.number) === true) continue;
|
|
172
175
|
lines.push(`checked ${row.number} ${row.label}${row.durationMs !== void 0 ? ` (${formatDuration(row.durationMs)})` : ""}`);
|
|
173
176
|
}
|
|
177
|
+
const beforeUnits = new Map(previous.subtasks.map((unit) => [unit.id, unit]));
|
|
178
|
+
for (const unit of next.subtasks) {
|
|
179
|
+
const before2 = beforeUnits.get(unit.id);
|
|
180
|
+
if (!before2) {
|
|
181
|
+
lines.push(`subtask ${unit.id} registered on step ${unit.parentStep} (${unit.rows.length} rows)`);
|
|
182
|
+
}
|
|
183
|
+
const beforeRows = new Map((before2?.rows ?? []).map((row) => [row.number, row.checked]));
|
|
184
|
+
for (const row of unit.rows) {
|
|
185
|
+
if (!row.checked || beforeRows.get(row.number) === true) continue;
|
|
186
|
+
lines.push(`subtask ${unit.id} checked ${row.number} ${row.label}`);
|
|
187
|
+
}
|
|
188
|
+
if (before2 && before2.status !== unit.status) {
|
|
189
|
+
lines.push(`subtask ${unit.id} ${unit.status ?? "unknown"}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
174
192
|
if (previous.signal?.step !== next.signal?.step && next.signal?.step) {
|
|
175
193
|
lines.push(`step ${stepLabel(next.signal.step)}`);
|
|
176
194
|
}
|
|
@@ -198,6 +216,20 @@ function renderRow(row, currentStep, out) {
|
|
|
198
216
|
const text = row.checked ? out("dim", label) : out("bold", label);
|
|
199
217
|
return ` ${marker} ${out("dim", number)} ${text}${timing ? ` ${out("dim", timing)}` : ""}`;
|
|
200
218
|
}
|
|
219
|
+
function renderSubtask(unit, out) {
|
|
220
|
+
const done = unit.rows.filter((row) => row.checked).length;
|
|
221
|
+
const header = joinParts([
|
|
222
|
+
`${out("label", "subtask")} ${out("accent", unit.id)}`,
|
|
223
|
+
statusWord(out, unit.status),
|
|
224
|
+
`${done}/${unit.rows.length}`,
|
|
225
|
+
unit.source?.ref && out("dim", unit.source.ref)
|
|
226
|
+
]);
|
|
227
|
+
const current = unit.rows.find((row) => !row.checked);
|
|
228
|
+
return [
|
|
229
|
+
` ${header}`,
|
|
230
|
+
...unit.rows.map((row) => ` ${renderRow(row, current?.number, out)}`)
|
|
231
|
+
];
|
|
232
|
+
}
|
|
201
233
|
function libraryLabel(library) {
|
|
202
234
|
const home = os.homedir();
|
|
203
235
|
const location = home && library.path.startsWith(`${home}/`) ? `~${library.path.slice(home.length)}` : library.path;
|
package/dist/task-view.js
CHANGED
|
@@ -7,8 +7,12 @@ import {
|
|
|
7
7
|
deriveChecklistStepDurations,
|
|
8
8
|
enumerateChecklistCheckboxes,
|
|
9
9
|
INTERACTIVE_CHECKLIST_MARKDOWN,
|
|
10
|
+
isSettledSubtaskStatus,
|
|
10
11
|
isTerminalWorkerSignalStatus,
|
|
11
12
|
READINESS_RECORD,
|
|
13
|
+
SUBTASK_INDEX_FILE,
|
|
14
|
+
SUBTASKS_DIR,
|
|
15
|
+
subtaskPaths,
|
|
12
16
|
WORKER_SIGNAL_FILE
|
|
13
17
|
} from "@farmslot/protocol";
|
|
14
18
|
import { readCommandJournal } from "./command-journal.js";
|
|
@@ -28,7 +32,9 @@ function collectTaskView(target, taskDir, now) {
|
|
|
28
32
|
({ name, root }) => ({ ...name ? { name } : {}, path: root })
|
|
29
33
|
)
|
|
30
34
|
};
|
|
31
|
-
if (!taskDir)
|
|
35
|
+
if (!taskDir) {
|
|
36
|
+
return { ...base, checklist: [], subtasks: [], activity: { ongoing: false, reason: "no-task" } };
|
|
37
|
+
}
|
|
32
38
|
const handoff = readJsonObject(path.join(taskDir, HANDOFF_INPUT));
|
|
33
39
|
const fixtures = readJsonObject(path.join(taskDir, "artifacts", "prepare", "fixtures.json"));
|
|
34
40
|
const sandbox = readJsonObject(path.join(taskDir, "artifacts", READINESS_RECORD)) ?? readJsonObject(path.join(target, recipeRuntimeDir(), READINESS_RECORD));
|
|
@@ -81,6 +87,7 @@ function collectTaskView(target, taskDir, now) {
|
|
|
81
87
|
}),
|
|
82
88
|
sandbox: section({ ready: pickBoolean(sandbox, "ready") }),
|
|
83
89
|
checklist,
|
|
90
|
+
subtasks: readSubtasks(taskDir),
|
|
84
91
|
signal: section({
|
|
85
92
|
status: pickString(signal, "status"),
|
|
86
93
|
step: pickString(signal, "step"),
|
|
@@ -167,6 +174,32 @@ function readChecklistRows(file) {
|
|
|
167
174
|
checked: item.checked
|
|
168
175
|
}));
|
|
169
176
|
}
|
|
177
|
+
function readSubtasks(taskDir) {
|
|
178
|
+
const index = readJsonObject(path.join(taskDir, SUBTASKS_DIR, SUBTASK_INDEX_FILE));
|
|
179
|
+
if (!index) return [];
|
|
180
|
+
const units = index.units;
|
|
181
|
+
if (!Array.isArray(units)) return [];
|
|
182
|
+
const views = [];
|
|
183
|
+
for (const entry of units) {
|
|
184
|
+
const unit = asObject(entry);
|
|
185
|
+
const id = pickString(unit, "id");
|
|
186
|
+
const parentStep = pickNumber(asObject(unit?.parent), "stepNumber");
|
|
187
|
+
if (id === void 0 || parentStep === void 0) continue;
|
|
188
|
+
const paths = subtaskPaths(id);
|
|
189
|
+
const signal = readJsonObject(path.join(taskDir, paths.signal));
|
|
190
|
+
const status = pickString(signal, "status");
|
|
191
|
+
const source = asObject(unit?.source);
|
|
192
|
+
views.push({
|
|
193
|
+
id,
|
|
194
|
+
parentStep,
|
|
195
|
+
...status !== void 0 ? { status } : {},
|
|
196
|
+
settled: isSettledSubtaskStatus(status),
|
|
197
|
+
rows: readChecklistRows(path.join(taskDir, paths.checklist)),
|
|
198
|
+
...section({ kind: pickString(source, "kind"), ref: pickString(source, "ref") }) ? { source: section({ kind: pickString(source, "kind"), ref: pickString(source, "ref") }) } : {}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return views;
|
|
202
|
+
}
|
|
170
203
|
function trimLabel(text) {
|
|
171
204
|
const plain = checklistStepName(text).replace(/\*\*/gu, "").replace(/^\d+\.\s*/u, "").replace(/\s+/gu, " ").trim();
|
|
172
205
|
if (plain.length <= CHECKLIST_LABEL_LIMIT) return plain;
|
|
@@ -927,7 +927,7 @@ export async function simulatorScreenshot(input, relPath) {
|
|
|
927
927
|
path: relative,
|
|
928
928
|
type: 'screenshot',
|
|
929
929
|
nodeId: input.context.nodeId,
|
|
930
|
-
label: input.node?.description || `${input.action} screenshot`,
|
|
930
|
+
label: input.node?.label || input.node?.description || `${input.action} screenshot`,
|
|
931
931
|
category: 'evidence',
|
|
932
932
|
mimeType: 'image/png',
|
|
933
933
|
metadata: {
|
|
@@ -976,7 +976,7 @@ async function androidScreenshot(input, relPath) {
|
|
|
976
976
|
path: relative,
|
|
977
977
|
type: 'screenshot',
|
|
978
978
|
nodeId: input.context.nodeId,
|
|
979
|
-
label: input.node?.description || `${input.action} screenshot`,
|
|
979
|
+
label: input.node?.label || input.node?.description || `${input.action} screenshot`,
|
|
980
980
|
category: 'evidence',
|
|
981
981
|
mimeType: 'image/png',
|
|
982
982
|
metadata: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@farmslot/agent-runtime": "0.
|
|
24
|
-
"@farmslot/expo-recipe": "0.
|
|
23
|
+
"@farmslot/agent-runtime": "0.13.0",
|
|
24
|
+
"@farmslot/expo-recipe": "0.11.0",
|
|
25
25
|
"@farmslot/handoff": "^0.3.1",
|
|
26
|
-
"@farmslot/protocol": "0.
|
|
27
|
-
"@farmslot/recipe-harness": "0.
|
|
26
|
+
"@farmslot/protocol": "0.30.0",
|
|
27
|
+
"@farmslot/recipe-harness": "0.18.0",
|
|
28
28
|
"agent-device": "0.19.3",
|
|
29
29
|
"commander": "^12.0.0",
|
|
30
30
|
"es-module-lexer": "2.3.1",
|