tickmarkr 2.5.5 → 2.5.6
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/README.md +3 -1
- package/dist/cli/commands/approve.js +64 -3
- package/dist/cli/commands/doctor.d.ts +10 -0
- package/dist/cli/commands/fleet.js +4 -0
- package/dist/cli/commands/plan.js +20 -4
- package/dist/cli/commands/verify.js +102 -81
- package/dist/config/config.d.ts +11 -0
- package/dist/config/config.js +21 -12
- package/dist/config/fleet-overlay.js +55 -17
- package/dist/drivers/index.js +2 -1
- package/dist/drivers/orca.d.ts +21 -1
- package/dist/drivers/orca.js +209 -27
- package/dist/gates/baseline.d.ts +14 -3
- package/dist/gates/baseline.js +61 -14
- package/dist/gates/cache.d.ts +14 -13
- package/dist/gates/cache.js +17 -5
- package/dist/gates/llm.d.ts +3 -0
- package/dist/gates/llm.js +11 -0
- package/dist/gates/review.d.ts +28 -3
- package/dist/gates/review.js +106 -14
- package/dist/gates/run-gates.d.ts +6 -1
- package/dist/gates/run-gates.js +299 -101
- package/dist/gates/test-manifest.d.ts +30 -1
- package/dist/gates/test-manifest.js +113 -39
- package/dist/gates/test-reporter.js +14 -6
- package/dist/graph/graph.d.ts +2 -0
- package/dist/graph/graph.js +45 -1
- package/dist/run/consult.js +5 -4
- package/dist/run/daemon.d.ts +2 -0
- package/dist/run/daemon.js +480 -99
- package/dist/run/execution-budget.d.ts +25 -0
- package/dist/run/execution-budget.js +142 -0
- package/dist/run/git.d.ts +40 -0
- package/dist/run/git.js +89 -4
- package/dist/run/journal.d.ts +3 -1
- package/dist/run/journal.js +38 -16
- package/dist/run/lease.d.ts +44 -0
- package/dist/run/lease.js +226 -3
- package/dist/run/recovery.d.ts +8 -0
- package/dist/run/recovery.js +25 -0
- package/dist/run/repair-selection.d.ts +12 -0
- package/dist/run/repair-selection.js +56 -0
- package/dist/run/stall.d.ts +6 -1
- package/dist/run/stall.js +60 -3
- package/dist/tui/ink/fleet-app.d.ts +10 -2
- package/dist/tui/ink/fleet-app.js +33 -15
- package/package.json +2 -2
- package/skills/tickmarkr-overseer/scripts/grade-ci.sh +29 -2
|
@@ -25,7 +25,7 @@ function splitSeat(seat) {
|
|
|
25
25
|
const at = seat.indexOf(":");
|
|
26
26
|
return { adapter: seat.slice(0, at), model: seat.slice(at + 1) };
|
|
27
27
|
}
|
|
28
|
-
export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels, initialDenyWorkersAdapters = [], initialDenyWorkersModels = [], modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, stagedRouting, entry = "probe", initialJudge = "", judgeSeats = [], viewRows = Number.POSITIVE_INFINITY, frameColumns = 100, frameRows, }) {
|
|
28
|
+
export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels, initialAllowOut = [], initialDenyWorkersAdapters = [], initialDenyWorkersModels = [], modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, stagedRouting, entry = "probe", initialJudge = "", judgeSeats = [], viewRows = Number.POSITIVE_INFINITY, frameColumns = 100, frameRows, }) {
|
|
29
29
|
const { exit } = useApp();
|
|
30
30
|
const [, setRevision] = useState(0);
|
|
31
31
|
const uiRef = useRef(null);
|
|
@@ -45,6 +45,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
45
45
|
lastEdit: null,
|
|
46
46
|
deny: new Set(initialDenyAdapters),
|
|
47
47
|
denyModels: new Set(initialDenyModels),
|
|
48
|
+
allowOut: new Set(initialAllowOut),
|
|
48
49
|
denyWorkersAdapters: new Set(initialDenyWorkersAdapters),
|
|
49
50
|
denyWorkersModels: new Set(initialDenyWorkersModels),
|
|
50
51
|
classifications: [],
|
|
@@ -64,6 +65,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
64
65
|
// chip, and the empty-`w` notice all read it. Counts staged EDITS, not diff hunks.
|
|
65
66
|
const initialDenySet = new Set(initialDenyAdapters);
|
|
66
67
|
const initialDenyModelSet = new Set(initialDenyModels);
|
|
68
|
+
const initialAllowOutSet = new Set(initialAllowOut);
|
|
67
69
|
const initialDenyWorkersAdapterSet = new Set(initialDenyWorkersAdapters);
|
|
68
70
|
const initialDenyWorkersModelSet = new Set(initialDenyWorkersModels);
|
|
69
71
|
const stagedCount = () => {
|
|
@@ -82,6 +84,9 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
82
84
|
for (const model of initialDenyModelSet)
|
|
83
85
|
if (!ui.denyModels.has(model))
|
|
84
86
|
n += 1;
|
|
87
|
+
for (const key of initialAllowOutSet)
|
|
88
|
+
if (!ui.allowOut.has(key))
|
|
89
|
+
n += 1;
|
|
85
90
|
for (const adapter of ui.denyWorkersAdapters)
|
|
86
91
|
if (!initialDenyWorkersAdapterSet.has(adapter))
|
|
87
92
|
n += 1;
|
|
@@ -218,6 +223,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
218
223
|
models: [...ui.denyModels].sort(),
|
|
219
224
|
workersAdapters: [...ui.denyWorkersAdapters].sort(),
|
|
220
225
|
workersModels: [...ui.denyWorkersModels].sort(),
|
|
226
|
+
allowOut: [...ui.allowOut].sort(),
|
|
221
227
|
});
|
|
222
228
|
const shapeList = () => shapeRows(ui.selectedMode, ui.map, stagedDeny());
|
|
223
229
|
const steeringList = () => [
|
|
@@ -245,6 +251,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
245
251
|
const editorState = () => ({
|
|
246
252
|
denyAdapters: [...ui.deny].sort(),
|
|
247
253
|
denyModels: [...ui.denyModels].sort(),
|
|
254
|
+
allowOut: [...ui.allowOut].sort(),
|
|
248
255
|
denyWorkersAdapters: [...ui.denyWorkersAdapters].sort(),
|
|
249
256
|
denyWorkersModels: [...ui.denyWorkersModels].sort(),
|
|
250
257
|
classifications: ui.classifications.map((classification) => classification.vendor && classification.channel
|
|
@@ -940,12 +947,18 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
940
947
|
if (agents.find((agent) => agent.id === id)?.authed === false) {
|
|
941
948
|
ui.notice = `${id} is not authed — Space only toggles fleet membership; re-auth the ${id} CLI, then run tickmarkr doctor`;
|
|
942
949
|
}
|
|
943
|
-
|
|
944
|
-
if (
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
950
|
+
// OBS-1046: an adapter routing.allow leaves out comes back in by clearing THAT reason
|
|
951
|
+
if (ui.allowOut.has(id)) {
|
|
952
|
+
ui.allowOut = new Set([...ui.allowOut].filter((key) => key !== id));
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
const next = new Set(ui.deny);
|
|
956
|
+
if (next.has(id))
|
|
957
|
+
next.delete(id);
|
|
958
|
+
else
|
|
959
|
+
next.add(id);
|
|
960
|
+
ui.deny = next;
|
|
961
|
+
}
|
|
949
962
|
clampList();
|
|
950
963
|
bump();
|
|
951
964
|
return;
|
|
@@ -1048,12 +1061,14 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
1048
1061
|
ui.lastEdit = { id, text: `space: moved ${entry} to routing.deny.models` };
|
|
1049
1062
|
}
|
|
1050
1063
|
else {
|
|
1051
|
-
// round 2 finding 2: either flat list may carry this channel's own reason
|
|
1064
|
+
// round 2 finding 2: either flat list may carry this channel's own reason; OBS-1046: an
|
|
1065
|
+
// allow exclusion is the LAST reason cleared, and never together with an authored deny
|
|
1052
1066
|
const fromModels = select(ui.denyModels, true);
|
|
1053
1067
|
const fromAdapters = fromModels === undefined ? select(ui.deny, true) : undefined;
|
|
1054
|
-
const
|
|
1068
|
+
const fromAllow = fromModels === undefined && fromAdapters === undefined ? select(ui.allowOut, true) : undefined;
|
|
1069
|
+
const entry = fromModels ?? fromAdapters ?? fromAllow;
|
|
1055
1070
|
if (entry === undefined) {
|
|
1056
|
-
const shared = ui.deny.has(row.adapter)
|
|
1071
|
+
const shared = ui.deny.has(row.adapter) || ui.allowOut.has(row.adapter)
|
|
1057
1072
|
? `every ${row.adapter} channel is out together — take the adapter back in on the rail`
|
|
1058
1073
|
: "a shared entry covers other channels too";
|
|
1059
1074
|
ui.notice = `${id} stays out — ${row.reasons.join("; ")} — Space edits only this channel's own entries; ${shared}`;
|
|
@@ -1062,9 +1077,12 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
1062
1077
|
}
|
|
1063
1078
|
if (fromModels !== undefined)
|
|
1064
1079
|
ui.denyModels = new Set([...ui.denyModels].filter((staged) => staged !== entry));
|
|
1065
|
-
else
|
|
1080
|
+
else if (fromAdapters !== undefined)
|
|
1066
1081
|
ui.deny = new Set([...ui.deny].filter((staged) => staged !== entry));
|
|
1067
|
-
|
|
1082
|
+
else
|
|
1083
|
+
ui.allowOut = new Set([...ui.allowOut].filter((staged) => staged !== entry));
|
|
1084
|
+
const scope = fromModels !== undefined ? "routing.deny.models" : fromAdapters !== undefined ? "routing.deny.adapters" : "routing.allow";
|
|
1085
|
+
ui.lastEdit = { id, text: `space: cleared ${entry} from ${scope}` };
|
|
1068
1086
|
}
|
|
1069
1087
|
bump();
|
|
1070
1088
|
return;
|
|
@@ -1333,7 +1351,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
1333
1351
|
const railAdapter = (index, railIndex) => {
|
|
1334
1352
|
const group = modelGroups[index];
|
|
1335
1353
|
const agent = agents.find((candidate) => candidate.id === group.adapter);
|
|
1336
|
-
const denied = ui.deny.has(group.adapter);
|
|
1354
|
+
const denied = ui.deny.has(group.adapter) || ui.allowOut.has(group.adapter);
|
|
1337
1355
|
const active = ui.view === "models" && ui.adapterAt === index;
|
|
1338
1356
|
const selected = ui.focus === "rail" && ui.railAt === railIndex;
|
|
1339
1357
|
return (_jsxs(Text, { children: [selected ? _jsx(Text, { color: INK.brand, children: "❯ " }) : _jsx(Text, { children: " " }), denied ? _jsx(Glyph, { kind: "off" }) : agent?.authed === false ? _jsx(Glyph, { kind: "fail" }) : _jsx(Glyph, { kind: "on" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: active, color: active ? INK.brand : undefined, dimColor: denied, children: padCell(group.adapter, 12) }), _jsx(Text, { dimColor: true, children: padCellStart(String(visibleCount(index)), 4) })] }, group.adapter));
|
|
@@ -1578,7 +1596,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
|
|
|
1578
1596
|
? _jsx(Text, { color: INK.warn, children: ` ! ${clip(ui.notice, width - 4)}` })
|
|
1579
1597
|
: details.map((line) => _jsx(Text, { dimColor: true, children: ` ${clip(line, width - 2)}` }, line)), _jsx(KeyBar, { binds: keyBinds() })] }));
|
|
1580
1598
|
}
|
|
1581
|
-
export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAdapters, initialDenyModels, initialDenyWorkersAdapters = [], initialDenyWorkersModels = [], modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, stagedRouting, entry = "probe", initialJudge = "", judgeSeats = [], initialInput = [], input, output, debug = false, }) {
|
|
1599
|
+
export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAdapters, initialDenyModels, initialAllowOut = [], initialDenyWorkersAdapters = [], initialDenyWorkersModels = [], modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, stagedRouting, entry = "probe", initialJudge = "", judgeSeats = [], initialInput = [], input, output, debug = false, }) {
|
|
1582
1600
|
const agents = adapters.flatMap((adapter) => {
|
|
1583
1601
|
const state = health[adapter.id];
|
|
1584
1602
|
if (!state?.installed)
|
|
@@ -1602,7 +1620,7 @@ export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAd
|
|
|
1602
1620
|
// rebuilt from output.columns/rows so a pane resize re-renders at the new size. Same root
|
|
1603
1621
|
// element type on every rerender ⇒ React keeps the component instance, so staged edits,
|
|
1604
1622
|
// cursor, and overlays all survive the resize.
|
|
1605
|
-
const editorElement = () => (_jsx(FleetApp, { ageMs: ageMs, agents: agents, initialDenyAdapters: initialDenyAdapters, initialDenyModels: initialDenyModels, initialDenyWorkersAdapters: initialDenyWorkersAdapters, initialDenyWorkersModels: initialDenyWorkersModels, modelGroups: declaredModelGroups, initialMode: initialMode, modeOptions: modeOptions, initialMap: initialMap, modePreview: modePreview, shapeRows: shapeRows, candidatesForShape: candidatesForShape, preferOptionsForShape: preferOptionsForShape, initialSteering: initialSteering, steeringOptionsFor: steeringOptionsFor, reviewOverlay: reviewOverlay, reloadGuard: reloadGuard, stagedRouting: stagedRouting, entry: entry, initialJudge: initialJudge, judgeSeats: judgeSeats,
|
|
1623
|
+
const editorElement = () => (_jsx(FleetApp, { ageMs: ageMs, agents: agents, initialDenyAdapters: initialDenyAdapters, initialDenyModels: initialDenyModels, initialAllowOut: initialAllowOut, initialDenyWorkersAdapters: initialDenyWorkersAdapters, initialDenyWorkersModels: initialDenyWorkersModels, modelGroups: declaredModelGroups, initialMode: initialMode, modeOptions: modeOptions, initialMap: initialMap, modePreview: modePreview, shapeRows: shapeRows, candidatesForShape: candidatesForShape, preferOptionsForShape: preferOptionsForShape, initialSteering: initialSteering, steeringOptionsFor: steeringOptionsFor, reviewOverlay: reviewOverlay, reloadGuard: reloadGuard, stagedRouting: stagedRouting, entry: entry, initialJudge: initialJudge, judgeSeats: judgeSeats,
|
|
1606
1624
|
// v1.90.9: cap every list to the terminal minus chrome so the cursor and header can
|
|
1607
1625
|
// never scroll off-screen (omp's 218-model list did exactly that pre-cap).
|
|
1608
1626
|
// OBS-523: chrome is ≤12 rows worst case (header, borders, padding, scope+search,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tickmarkr",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.6",
|
|
4
4
|
"description": "Spec in, verified work out.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/alzahrani-khalid/tickmarkr",
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=20"
|
|
20
|
+
"node": ">=20.3"
|
|
21
21
|
},
|
|
22
22
|
"bin": {
|
|
23
23
|
"tickmarkr": "dist/cli/index.js",
|
|
@@ -50,14 +50,41 @@ while IFS=$'\t' read -r id name status conclusion; do
|
|
|
50
50
|
skipped=$(printf '%s\n' "$files" | grep -oE '[0-9]+ skipped' | awk '{s+=$1} END{print s+0}')
|
|
51
51
|
failed=$(printf '%s\n' "$files" | grep -oE '[0-9]+ failed' | awk '{s+=$1} END{print s+0}')
|
|
52
52
|
timedout=$(grep -cE 'Test timed out|Error: Hook timed out' "$log" || true)
|
|
53
|
+
# Vitest reports errors thrown outside any test (unhandled rejections, worker crashes) in an
|
|
54
|
+
# "Unhandled Errors" block that leaves the file summary green and the count oracle satisfied;
|
|
55
|
+
# its own tally line names how many. Any unhandled error is RED, never a green suite.
|
|
56
|
+
unhandled=$(grep -oE 'Vitest caught [0-9]+ unhandled error' "$log" | grep -oE '[0-9]+' | awk '{s+=$1} END{print s+0}')
|
|
57
|
+
if [ "$unhandled" -eq 0 ]; then
|
|
58
|
+
unhandled=$(grep -cE 'Unhandled Errors' "$log" || true)
|
|
59
|
+
fi
|
|
60
|
+
# OBS-1058 (RULING-231-17 precedent, v2.5.5 close R115 add.7): a vitest-worker RPC timeout
|
|
61
|
+
# ("Timeout calling \"onTaskUpdate\"") is the starved runner talking, not a test — every green
|
|
62
|
+
# release run has carried one. Only a timeout that is ITSELF an unhandled entry counts: the first
|
|
63
|
+
# payload line under a per-error header, nothing later. The header is Vitest's own structural line —
|
|
64
|
+
# a run of ⎯ on each side of "Unhandled Error", ANSI stripped (both the raw ESC byte and gh's `^[` rendering of it), nothing else on the line — so prose that
|
|
65
|
+
# merely contains the words never opens a window — and the payload must be Vitest's whole line
|
|
66
|
+
# (`Error: [vitest-worker]: Timeout calling "<method>"`), so an assertion quoting it stays RED. Per-error headers are honoured only inside Vitest's own block —
|
|
67
|
+
# after its structural "Unhandled Errors" line and "Vitest caught N" tally, until the file summary — and
|
|
68
|
+
# the count never exceeds N, so a test that prints a header and a timeout to stdout forges nothing. A stray diagnostic elsewhere in the log never
|
|
69
|
+
# offsets a real unhandled error; anything else under a header stays RED.
|
|
70
|
+
esc=$(printf '\033')
|
|
71
|
+
rpc=$(awk -v esc="$esc" '{ line = $0; gsub(/\^\[\[[0-9;]*m/, "", line); gsub(esc "\\[[0-9;]*m", "", line); sub(/^[^\t]*\t[^\t]*\t[0-9T:.-]+Z[ ]?/, "", line) }
|
|
72
|
+
line ~ /^(⎯)+ Unhandled Errors (⎯)+[ \t]*$/ { opening = 1; next }
|
|
73
|
+
opening && line !~ /[^ \t]/ { next }
|
|
74
|
+
opening { opening = 0; if (line ~ /^Vitest caught [0-9]+ unhandled error/) { armed = 1; cap = line; sub(/^Vitest caught /, "", cap); sub(/ .*$/, "", cap) } }
|
|
75
|
+
armed && line ~ /^[ \t]*Test Files / { armed = 0 }
|
|
76
|
+
armed && line ~ /^(⎯)+ Unhandled Error (⎯)+[ \t]*$/ { pending = 1; next }
|
|
77
|
+
pending && line ~ /[^ \t]/ { pending = 0; if (line ~ /^Error: \[vitest-worker\]: Timeout calling "[A-Za-z]+"[ \t]*$/) n++ }
|
|
78
|
+
END { if (n > cap + 0) n = cap + 0; print n + 0 }' "$log")
|
|
79
|
+
if [ "$rpc" -gt 0 ] && [ "$unhandled" -ge "$rpc" ]; then unhandled=$((unhandled - rpc)); fi
|
|
53
80
|
errors=$(grep -oE '##\[error\].*' "$log" | sort | uniq -c | sed 's/^ *//' | tr '\n' ';')
|
|
54
81
|
|
|
55
|
-
echo "$name: oracle=[${oracle:-MISSING}] files=[$(printf '%s' "$files" | tr '\n' '|')] passed=$passed skipped=$skipped failed=$failed timedout=$timedout errors=[$errors]"
|
|
82
|
+
echo "$name: oracle=[${oracle:-MISSING}] files=[$(printf '%s' "$files" | tr '\n' '|')] passed=$passed skipped=$skipped failed=$failed timedout=$timedout unhandled=$unhandled runner_rpc_timeouts=${rpc:-0} errors=[$errors]"
|
|
56
83
|
if [ -z "$oracle" ] || [ -z "$files" ]; then
|
|
57
84
|
echo "$name: UNREADABLE"
|
|
58
85
|
mark_unreadable
|
|
59
86
|
elif [ "$oracle" = "COUNT_ORACLE GREEN expected=$expected actual=$expected" ] \
|
|
60
|
-
&& [ "$failed" -eq 0 ] && [ "$timedout" -eq 0 ] \
|
|
87
|
+
&& [ "$failed" -eq 0 ] && [ "$timedout" -eq 0 ] && [ "$unhandled" -eq 0 ] \
|
|
61
88
|
&& [ $((passed + skipped)) -eq "$expected" ]; then
|
|
62
89
|
echo "$name: GREEN"
|
|
63
90
|
else
|