tickmarkr 1.90.6 → 1.90.8

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.
@@ -102,9 +102,15 @@ export function formatDoctorAge(ageMs) {
102
102
  return `${mins}m old`;
103
103
  return `${Math.floor(mins / 60)}h old`;
104
104
  }
105
- export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels, modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, }) {
105
+ // judge seats travel the editor as the same "adapter:model" strings the pickers list; the model
106
+ // half may itself contain ":" so only the first separator is structural.
107
+ function splitSeat(seat) {
108
+ const at = seat.indexOf(":");
109
+ return { adapter: seat.slice(0, at), model: seat.slice(at + 1) };
110
+ }
111
+ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels, modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, entry = "probe", initialJudge = "", judgeSeats = [], }) {
106
112
  const { exit } = useApp();
107
- const [screen, setScreen] = useState("probe");
113
+ const [screen, setScreen] = useState(entry === "presets" ? "modes" : "probe");
108
114
  const screenRef = useRef(screen);
109
115
  const [cursor, setCursor] = useState(0);
110
116
  const cursorRef = useRef(cursor);
@@ -159,9 +165,19 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
159
165
  const steeringPickerCursorRef = useRef(0);
160
166
  const [steeringPickerCursor, setSteeringPickerCursor] = useState(0);
161
167
  const [, setSteeringPickerRevision] = useState(0);
168
+ const judgeCursorRef = useRef(0);
169
+ const [judgeCursor, setJudgeCursor] = useState(0);
170
+ const judgeSeatRef = useRef(null);
171
+ const [judgeSeat, setJudgeSeat] = useState(null);
162
172
  const reviewRef = useRef(null);
163
173
  const [review, setReview] = useState(null);
164
174
  const doneRef = useRef(false);
175
+ // entry === "presets": the first modes visit is the preset pick (mode → review, custom → the
176
+ // full walk). Once custom is chosen this flips off and modes behaves exactly as in probe entry.
177
+ const presetPickRef = useRef(entry === "presets");
178
+ // type-to-search on the long lists — reset on every screen change (per-screen-visit filter)
179
+ const filterRef = useRef("");
180
+ const [filter, setFilter] = useState("");
165
181
  const enabledModelGroups = () => modelGroups.filter((group) => !denyRef.current?.has(group.adapter));
166
182
  const stagedMap = () => mapRef.current;
167
183
  const currentModelRows = () => {
@@ -180,6 +196,31 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
180
196
  }
181
197
  return rows;
182
198
  };
199
+ // type-to-search over the long lists: plain case-insensitive substring on the row's visible
200
+ // label. Each filterable screen derives its rows through these so input and render agree.
201
+ const matches = (label, f = filterRef.current) => f === "" || label.toLowerCase().includes(f.toLowerCase());
202
+ const filteredModelRows = (f = filterRef.current) => currentModelRows().filter((row) => matches(row.model, f));
203
+ const filteredCandidates = (f = filterRef.current) => candidatesRef.current.filter((candidate) => matches(candidate.label, f));
204
+ const filteredSteeringRows = (f = filterRef.current) => steeringRowsRef.current.filter((option) => matches(option, f));
205
+ const judgeKeepRow = initialJudge ? `(keep default) ${initialJudge}` : "(keep default)";
206
+ const filteredJudgeRows = (f = filterRef.current) => [judgeKeepRow, ...judgeSeats].filter((row) => matches(row, f));
207
+ // Shared filter-edit tail for the filterable screens: hotkeys run first in each screen block,
208
+ // whatever printable input is left appends here (space stays a toggle key, never a filter char).
209
+ const filterInput = (countFor, cursorRef, setCursorState, input, key) => {
210
+ // printable chars only: "\r" reaches here when an emptied list makes key.return a no-op
211
+ const printable = input > " " && !key.ctrl && !key.meta;
212
+ const next = key.backspace || key.delete
213
+ ? filterRef.current.slice(0, -1)
214
+ : (printable ? filterRef.current + input : null);
215
+ if (next === null)
216
+ return false;
217
+ filterRef.current = next;
218
+ setFilter(next);
219
+ const clamped = Math.min(cursorRef.current, Math.max(countFor(next) - 1, 0));
220
+ cursorRef.current = clamped;
221
+ setCursorState(clamped);
222
+ return true;
223
+ };
183
224
  const editorState = () => ({
184
225
  denyAdapters: [...(denyRef.current ?? [])].sort(),
185
226
  denyModels: [...(denyModelsRef.current ?? [])].sort(),
@@ -194,6 +235,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
194
235
  : classification),
195
236
  selectedMode: selectedModeRef.current,
196
237
  map: stagedMap(),
238
+ ...(judgeSeatRef.current ? { judgeSeat: splitSeat(judgeSeatRef.current) } : {}),
197
239
  steering: structuredClone(steeringRef.current),
198
240
  });
199
241
  const finish = (result) => {
@@ -206,9 +248,24 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
206
248
  showScreen("steering");
207
249
  };
208
250
  const showScreen = (next) => {
251
+ filterRef.current = "";
252
+ setFilter("");
209
253
  screenRef.current = next;
210
254
  setScreen(next);
211
255
  };
256
+ // The one review funnel: an empty staged overlay finishes as no-changes, a real diff shows the
257
+ // confirm screen. Reached from the steering enter and, in preset entry, from a mode pick.
258
+ const goReview = () => {
259
+ const nextReview = reviewOverlay(editorState());
260
+ if (nextReview.kind === "empty") {
261
+ finish({ kind: "no-changes" });
262
+ return;
263
+ }
264
+ reviewRef.current = nextReview;
265
+ setReview(reviewRef.current);
266
+ setNotice("");
267
+ showScreen("review");
268
+ };
212
269
  const beginClassification = (group, model) => {
213
270
  tierCursorRef.current = 0;
214
271
  setTierCursor(0);
@@ -248,7 +305,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
248
305
  showScreen("shapes");
249
306
  return;
250
307
  }
251
- if (key.escape && screenRef.current === "steering-prefer") {
308
+ if (key.escape && (screenRef.current === "steering-prefer" || screenRef.current === "judge-pick")) {
252
309
  showScreen("steering");
253
310
  return;
254
311
  }
@@ -257,6 +314,15 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
257
314
  showScreen("models");
258
315
  return;
259
316
  }
317
+ // v1.90.8 (operator field report): inside the init journey, one Esc must never discard the
318
+ // whole walk — from any walk screen it returns HOME to the presets screen; Esc there (or
319
+ // `q`/ctrl+c anywhere) remains the real quit. Sub-screen Escs above keep their tighter backs.
320
+ if (key.escape && entry === "presets" && screenRef.current !== "modes") {
321
+ setReview(null);
322
+ presetPickRef.current = true;
323
+ showScreen("modes");
324
+ return;
325
+ }
260
326
  const typing = screenRef.current === "provenance" || screenRef.current === "add-model";
261
327
  if (key.escape || (!typing && input === "q") || (key.ctrl && input === "c")) {
262
328
  finish({ kind: "quit" });
@@ -304,7 +370,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
304
370
  return;
305
371
  }
306
372
  if (screenRef.current === "models") {
307
- const rows = currentModelRows();
373
+ const rows = filteredModelRows();
308
374
  if (key.downArrow || input === "j") {
309
375
  const next = Math.min(modelCursorRef.current + 1, Math.max(rows.length - 1, 0));
310
376
  modelCursorRef.current = next;
@@ -354,10 +420,16 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
354
420
  setModelGroup(next);
355
421
  modelCursorRef.current = 0;
356
422
  setModelCursor(0);
423
+ filterRef.current = "";
424
+ setFilter("");
357
425
  }
358
426
  else {
359
427
  showScreen("modes");
360
428
  }
429
+ return;
430
+ }
431
+ if (filterInput((f) => filteredModelRows(f).length, modelCursorRef, setModelCursor, input, key)) {
432
+ setNotice("");
361
433
  }
362
434
  return;
363
435
  }
@@ -464,9 +536,11 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
464
536
  }
465
537
  }
466
538
  if (screenRef.current === "modes") {
539
+ // preset entry adds one final `custom` row after the modes — the full-walk escape hatch
540
+ const rowCount = modeOptions.length + (presetPickRef.current ? 1 : 0);
467
541
  const currentModeCursor = modeCursorRef.current ?? 0;
468
542
  if (key.downArrow || input === "j") {
469
- const next = Math.min(currentModeCursor + 1, Math.max(modeOptions.length - 1, 0));
543
+ const next = Math.min(currentModeCursor + 1, Math.max(rowCount - 1, 0));
470
544
  modeCursorRef.current = next;
471
545
  setModeCursor(next);
472
546
  return;
@@ -477,8 +551,20 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
477
551
  setModeCursor(next);
478
552
  return;
479
553
  }
480
- if (key.return && modeOptions[currentModeCursor]) {
554
+ if (key.return) {
555
+ if (presetPickRef.current && currentModeCursor === modeOptions.length) {
556
+ presetPickRef.current = false;
557
+ showScreen("agents");
558
+ return;
559
+ }
560
+ if (!modeOptions[currentModeCursor])
561
+ return;
481
562
  selectedModeRef.current = modeOptions[currentModeCursor].id;
563
+ if (presetPickRef.current) {
564
+ // entry context: a preset pick goes straight to the diff confirm
565
+ goReview();
566
+ return;
567
+ }
482
568
  showScreen("shapes");
483
569
  }
484
570
  return;
@@ -527,8 +613,9 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
527
613
  return;
528
614
  }
529
615
  if (screenRef.current === "candidates") {
616
+ const rows = filteredCandidates();
530
617
  if (key.downArrow || input === "j") {
531
- const next = Math.min(candidateCursorRef.current + 1, Math.max(candidatesRef.current.length - 1, 0));
618
+ const next = Math.min(candidateCursorRef.current + 1, Math.max(rows.length - 1, 0));
532
619
  candidateCursorRef.current = next;
533
620
  setCandidateCursor(next);
534
621
  return;
@@ -539,16 +626,18 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
539
626
  setCandidateCursor(next);
540
627
  return;
541
628
  }
542
- if (key.return && candidatesRef.current[candidateCursorRef.current]) {
629
+ if (key.return && rows[candidateCursorRef.current]) {
543
630
  const shape = shapeRows(selectedModeRef.current, stagedMap())[shapeCursorRef.current]?.id;
544
631
  if (shape) {
545
- const picked = candidatesRef.current[candidateCursorRef.current];
632
+ const picked = rows[candidateCursorRef.current];
546
633
  const nextMap = { ...stagedMap(), [shape]: { pin: picked.pin } };
547
634
  mapRef.current = nextMap;
548
635
  setMap(nextMap);
549
636
  }
550
637
  showScreen("shapes");
638
+ return;
551
639
  }
640
+ filterInput((f) => filteredCandidates(f).length, candidateCursorRef, setCandidateCursor, input, key);
552
641
  return;
553
642
  }
554
643
  if (screenRef.current === "shape-prefer") {
@@ -591,8 +680,9 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
591
680
  return;
592
681
  }
593
682
  if (screenRef.current === "steering") {
683
+ // review.prefer + consult.prefer rows plus the single judge seat as the final row
594
684
  if (key.downArrow || input === "j") {
595
- const next = Math.min(steeringCursorRef.current + 1, STEERING_KEYS.length - 1);
685
+ const next = Math.min(steeringCursorRef.current + 1, STEERING_KEYS.length);
596
686
  steeringCursorRef.current = next;
597
687
  setSteeringCursor(next);
598
688
  return;
@@ -604,6 +694,13 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
604
694
  return;
605
695
  }
606
696
  if (input === "f") {
697
+ if (steeringCursorRef.current === STEERING_KEYS.length) {
698
+ judgeCursorRef.current = 0;
699
+ setJudgeCursor(0);
700
+ setNotice("");
701
+ showScreen("judge-pick");
702
+ return;
703
+ }
607
704
  const which = STEERING_KEYS[steeringCursorRef.current];
608
705
  const current = steeringRef.current?.[which] ?? [];
609
706
  steeringPickerRef.current = which;
@@ -615,22 +712,40 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
615
712
  showScreen("steering-prefer");
616
713
  return;
617
714
  }
618
- if (key.return) {
619
- const nextReview = reviewOverlay(editorState());
620
- if (nextReview.kind === "empty") {
621
- finish({ kind: "no-changes" });
622
- return;
623
- }
624
- reviewRef.current = nextReview;
625
- setReview(nextReview);
626
- setNotice("");
627
- showScreen("review");
715
+ if (key.return)
716
+ goReview();
717
+ return;
718
+ }
719
+ if (screenRef.current === "judge-pick") {
720
+ const rows = filteredJudgeRows();
721
+ if (key.downArrow || input === "j") {
722
+ const next = Math.min(judgeCursorRef.current + 1, Math.max(rows.length - 1, 0));
723
+ judgeCursorRef.current = next;
724
+ setJudgeCursor(next);
725
+ return;
628
726
  }
727
+ if (key.upArrow || input === "k") {
728
+ const next = Math.max(judgeCursorRef.current - 1, 0);
729
+ judgeCursorRef.current = next;
730
+ setJudgeCursor(next);
731
+ return;
732
+ }
733
+ if (key.return && rows[judgeCursorRef.current]) {
734
+ // single-select: one seat or back to the config default — never a chain
735
+ const picked = rows[judgeCursorRef.current];
736
+ const seat = picked === judgeKeepRow ? null : picked;
737
+ judgeSeatRef.current = seat;
738
+ setJudgeSeat(seat);
739
+ showScreen("steering");
740
+ return;
741
+ }
742
+ filterInput((f) => filteredJudgeRows(f).length, judgeCursorRef, setJudgeCursor, input, key);
629
743
  return;
630
744
  }
631
745
  if (screenRef.current === "steering-prefer") {
746
+ const rows = filteredSteeringRows();
632
747
  if (key.downArrow || input === "j") {
633
- const next = Math.min(steeringPickerCursorRef.current + 1, Math.max(steeringRowsRef.current.length - 1, 0));
748
+ const next = Math.min(steeringPickerCursorRef.current + 1, Math.max(rows.length - 1, 0));
634
749
  steeringPickerCursorRef.current = next;
635
750
  setSteeringPickerCursor(next);
636
751
  return;
@@ -641,8 +756,8 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
641
756
  setSteeringPickerCursor(next);
642
757
  return;
643
758
  }
644
- if (input === " " && steeringRowsRef.current[steeringPickerCursorRef.current]) {
645
- const option = steeringRowsRef.current[steeringPickerCursorRef.current];
759
+ if (input === " " && rows[steeringPickerCursorRef.current]) {
760
+ const option = rows[steeringPickerCursorRef.current];
646
761
  const at = steeringChainRef.current.indexOf(option);
647
762
  if (at === -1)
648
763
  steeringChainRef.current.push(option);
@@ -661,7 +776,9 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
661
776
  setSteering(next);
662
777
  setNotice("");
663
778
  showScreen("steering");
779
+ return;
664
780
  }
781
+ filterInput((f) => filteredSteeringRows(f).length, steeringPickerCursorRef, setSteeringPickerCursor, input, key);
665
782
  return;
666
783
  }
667
784
  if (screenRef.current === "review") {
@@ -675,7 +792,7 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
675
792
  setNotice(`fleet: config loader rejects the proposed overlay — ${loadError}`);
676
793
  reviewRef.current = null;
677
794
  setReview(null);
678
- showScreen("steering");
795
+ showScreen(presetPickRef.current ? "modes" : "steering");
679
796
  return;
680
797
  }
681
798
  finish({ kind: "write", review: reviewRef.current });
@@ -699,16 +816,15 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
699
816
  return (_jsx(FleetListScreen, { title: "step 2/6 \u00B7 agent CLIs", legend: "\u2191\u2193/jk move \u00B7 space toggle \u00B7 enter next \u00B7 esc/q quit", rows: rows, cursor: cursor }));
700
817
  }
701
818
  const group = enabledModelGroups()[modelGroup];
702
- const modelRows = currentModelRows();
703
819
  if (screen === "models") {
704
- const rows = modelRows.map((row) => {
820
+ const rows = filteredModelRows().map((row) => {
705
821
  const denied = group ? denyModels.has(`${group.adapter}:${row.model}`) : false;
706
822
  return {
707
823
  id: row.model,
708
824
  content: row.tier ? (_jsxs(_Fragment, { children: [_jsx(ToggleMark, { active: !denied }), _jsx(Text, { children: ` ${row.model} ${row.tier} ${denied ? "denied" : "allowed"}` })] })) : _jsx(Text, { children: `( ) ${row.model} ??? unclassified${row.detectedAt ? ` (${row.detectedAt})` : ""}` }),
709
825
  };
710
826
  });
711
- return (_jsx(FleetListScreen, { title: `step 3/6 · models · ${group?.adapter ?? ""}`, legend: "\u2191\u2193/jk move \u00B7 space toggle \u00B7 t tier \u00B7 n add model \u00B7 enter next \u00B7 esc/q quit", rows: rows, cursor: modelCursor, details: notice ? [notice] : [] }));
827
+ return (_jsx(FleetListScreen, { title: `step 3/6 · models · ${group?.adapter ?? ""}`, legend: "\u2191\u2193 to move \u00B7 Space to toggle \u00B7 t to classify tier \u00B7 n to add model \u00B7 Enter for next \u00B7 Type to search \u00B7 Esc to quit", rows: rows, cursor: modelCursor, details: notice ? [notice] : [], filter: filter }));
712
828
  }
713
829
  if (screen === "add-model")
714
830
  return (_jsx(FleetListScreen, { title: `add model · ${group?.adapter ?? ""}`, legend: "type model id \u00B7 enter classify \u00B7 esc cancel", rows: [{ id: "model", content: _jsx(Text, { children: modelId || "model id (required):" }) }], cursor: 0, details: notice ? [notice] : [] }));
@@ -720,10 +836,18 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
720
836
  if (screen === "provenance")
721
837
  return (_jsx(FleetListScreen, { title: `benchmark provenance · ${pendingClassificationRef.current?.adapter}:${pendingClassificationRef.current?.model}`, legend: "type note \u00B7 enter apply \u00B7 esc cancel", rows: [{ id: "note", content: _jsx(Text, { children: note || "benchmark provenance note (required):" }) }], cursor: 0, details: notice ? [notice] : [] }));
722
838
  if (screen === "modes") {
723
- return (_jsx(FleetListScreen, { title: "step 4/6 \u00B7 routing mode", legend: "\u2191\u2193/jk move \u00B7 enter select \u00B7 esc/q quit", rows: modeOptions.map((option) => ({
724
- id: option.id,
725
- content: (_jsxs(_Fragment, { children: [option.id === initialMode ? _jsx(ToggleMark, { active: true }) : _jsx(Text, { children: " " }), _jsx(Text, { children: ` ${option.id.padEnd(11)} ${option.gloss}` })] })),
726
- })), cursor: modeCursor, details: modePreview(modeOptions[modeCursor].id, map) }));
839
+ const presetPick = presetPickRef.current;
840
+ const rows = modeOptions.map((option) => ({
841
+ id: option.id,
842
+ content: (_jsxs(_Fragment, { children: [option.id === initialMode ? _jsx(ToggleMark, { active: true }) : _jsx(Text, { children: " " }), _jsx(Text, { children: ` ${option.id.padEnd(11)} ${option.gloss}` })] })),
843
+ }));
844
+ if (presetPick) {
845
+ rows.push({
846
+ id: "custom",
847
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsx(Text, { children: ` ${"custom".padEnd(11)} walk the full editor (agents → models → shapes → seats)` })] })),
848
+ });
849
+ }
850
+ return (_jsx(FleetListScreen, { title: presetPick ? "tickmarkr init · act 3 of 3 — fleet · routing presets" : "step 4/6 · routing mode", legend: presetPick ? "↑↓ to move · Enter to apply preset · Enter on custom to walk the editor · Esc inside the walk returns here · Esc here closes" : "↑↓/jk move · enter select · esc/q quit", rows: rows, cursor: modeCursor, details: modeOptions[modeCursor] ? modePreview(modeOptions[modeCursor].id, map) : [] }));
727
851
  }
728
852
  const renderedShapes = shapeRows(selectedModeRef.current, map);
729
853
  if (screen === "shapes") {
@@ -731,10 +855,10 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
731
855
  }
732
856
  const shape = renderedShapes[shapeCursor]?.id;
733
857
  if (screen === "candidates") {
734
- return (_jsx(FleetListScreen, { title: `pick · ${shape}`, legend: "\u2191\u2193/jk move \u00B7 enter pin \u00B7 esc cancel \u00B7 q quit", rows: candidatesRef.current.map((candidate) => ({
858
+ return (_jsx(FleetListScreen, { title: `pick · ${shape}`, legend: "\u2191\u2193 to move \u00B7 Enter to pin \u00B7 Type to search \u00B7 Esc to cancel \u00B7 q to quit", rows: filteredCandidates().map((candidate) => ({
735
859
  id: candidate.id,
736
860
  content: _jsx(Text, { children: candidate.label }),
737
- })), cursor: candidateCursor }));
861
+ })), cursor: candidateCursor, filter: filter }));
738
862
  }
739
863
  if (screen === "shape-prefer")
740
864
  return (_jsx(FleetListScreen, { title: `pick · ${shape}.prefer`, legend: "\u2191\u2193/jk move \u00B7 space add/drop \u00B7 enter apply (empty clears) \u00B7 esc cancel \u00B7 q quit", rows: preferRowsRef.current.map((option) => {
@@ -742,21 +866,34 @@ export function FleetApp({ ageMs, agents, initialDenyAdapters, initialDenyModels
742
866
  return { id: option, content: _jsx(Text, { children: `${at === -1 ? "·" : String(at + 1)} ${option}` }) };
743
867
  }), cursor: preferCursor }));
744
868
  if (screen === "steering") {
745
- return (_jsx(FleetListScreen, { title: "step 6/6 \u00B7 steering", legend: "\u2191\u2193/jk move \u00B7 f prefer \u00B7 enter review \u00B7 esc/q quit", rows: STEERING_KEYS.map((key) => ({
746
- id: key,
747
- content: _jsx(Text, { children: `${key}.prefer → ${steering[key]?.join(", ") ?? "(none)"}` }),
748
- })), cursor: steeringCursor, details: notice ? [notice] : [] }));
869
+ return (_jsx(FleetListScreen, { title: "step 6/6 \u00B7 steering", legend: "\u2191\u2193 to move \u00B7 f to edit \u00B7 Enter to review \u00B7 Esc/q to quit", rows: [
870
+ ...STEERING_KEYS.map((key) => ({
871
+ id: key,
872
+ content: _jsx(Text, { children: `${key}.prefer → ${steering[key]?.join(", ") ?? "(none)"}` }),
873
+ })),
874
+ {
875
+ id: "judge",
876
+ content: _jsx(Text, { children: `judge → ${judgeSeat ?? (initialJudge ? `${initialJudge} (default)` : "(default)")}` }),
877
+ },
878
+ ], cursor: steeringCursor, details: notice ? [notice] : [] }));
879
+ }
880
+ if (screen === "judge-pick") {
881
+ const selected = judgeSeat ?? judgeKeepRow;
882
+ return (_jsx(FleetListScreen, { title: "pick \u00B7 judge", legend: "\u2191\u2193 to move \u00B7 Enter to select \u00B7 Type to search \u00B7 Esc to cancel \u00B7 q to quit", rows: filteredJudgeRows().map((label) => ({
883
+ id: label,
884
+ content: (_jsxs(_Fragment, { children: [label === selected ? _jsx(ToggleMark, { active: true }) : _jsx(Text, { children: " " }), _jsx(Text, { children: ` ${label}` })] })),
885
+ })), cursor: judgeCursor, filter: filter }));
749
886
  }
750
887
  if (screen === "steering-prefer") {
751
888
  const which = steeringPickerRef.current;
752
- return (_jsx(FleetListScreen, { title: `pick · ${which}.prefer`, legend: "\u2191\u2193/jk move \u00B7 space add/drop \u00B7 enter apply (empty clears) \u00B7 esc cancel \u00B7 q quit", rows: steeringRowsRef.current.map((option) => {
889
+ return (_jsx(FleetListScreen, { title: `pick · ${which}.prefer`, legend: "\u2191\u2193 to move \u00B7 Space to add/drop \u00B7 Enter to apply (empty clears) \u00B7 Type to search \u00B7 Esc to cancel \u00B7 q to quit", rows: filteredSteeringRows().map((option) => {
753
890
  const at = steeringChainRef.current.indexOf(option);
754
891
  return { id: option, content: _jsx(Text, { children: `${at === -1 ? "·" : String(at + 1)} ${option}` }) };
755
- }), cursor: steeringPickerCursor }));
892
+ }), cursor: steeringPickerCursor, filter: filter }));
756
893
  }
757
894
  return (_jsx(FleetReviewScreen, { title: "review \u00B7 overlay diff", legend: "y write \u00B7 n discard \u00B7 esc/q quit", diff: review?.diff ?? "" }));
758
895
  }
759
- export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAdapters, initialDenyModels, modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, initialInput = [], input, output, debug = false, }) {
896
+ export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAdapters, initialDenyModels, modelGroups, initialMode, modeOptions, initialMap, modePreview, shapeRows, candidatesForShape, preferOptionsForShape, initialSteering, steeringOptionsFor, reviewOverlay, reloadGuard, entry = "probe", initialJudge = "", judgeSeats = [], initialInput = [], input, output, debug = false, }) {
760
897
  const agents = adapters.flatMap((adapter) => {
761
898
  const state = health[adapter.id];
762
899
  if (!state?.installed)
@@ -774,7 +911,7 @@ export async function runFleetInkEditor({ ageMs, adapters, health, initialDenyAd
774
911
  }));
775
912
  const bridgedInput = inkInput(input, initialInput);
776
913
  const legacyOutput = typeof output.on !== "function" || typeof output.off !== "function";
777
- const app = render(_jsx(FleetApp, { ageMs: ageMs, agents: agents, initialDenyAdapters: initialDenyAdapters, initialDenyModels: initialDenyModels, modelGroups: declaredModelGroups, initialMode: initialMode, modeOptions: modeOptions, initialMap: initialMap, modePreview: modePreview, shapeRows: shapeRows, candidatesForShape: candidatesForShape, preferOptionsForShape: preferOptionsForShape, initialSteering: initialSteering, steeringOptionsFor: steeringOptionsFor, reviewOverlay: reviewOverlay, reloadGuard: reloadGuard }), {
914
+ const app = render(_jsx(FleetApp, { ageMs: ageMs, agents: agents, initialDenyAdapters: initialDenyAdapters, initialDenyModels: initialDenyModels, modelGroups: declaredModelGroups, initialMode: initialMode, modeOptions: modeOptions, initialMap: initialMap, modePreview: modePreview, shapeRows: shapeRows, candidatesForShape: candidatesForShape, preferOptionsForShape: preferOptionsForShape, initialSteering: initialSteering, steeringOptionsFor: steeringOptionsFor, reviewOverlay: reviewOverlay, reloadGuard: reloadGuard, entry: entry, initialJudge: initialJudge, judgeSeats: judgeSeats }), {
778
915
  // FleetIO's injected stream predates Ink and did not require ref/unref.
779
916
  // Real terminal streams pass through unchanged; the compatibility facade
780
917
  // adds only those lifecycle methods and leaves input decoding to Ink.
@@ -0,0 +1,34 @@
1
+ import type { InitConfigOverlay } from "../../config/config.js";
2
+ type Driver = NonNullable<InitConfigOverlay["driver"]>;
3
+ type VisibilityLlm = NonNullable<NonNullable<InitConfigOverlay["visibility"]>["llm"]>;
4
+ export type InitWizardFields = {
5
+ driver: Driver;
6
+ concurrency: number;
7
+ visibilityLlm: VisibilityLlm;
8
+ offerSkills: boolean;
9
+ skillsDefault: boolean;
10
+ };
11
+ export type InitWizardResult = {
12
+ kind: "continue";
13
+ overlay: {
14
+ driver: Driver;
15
+ concurrency: number;
16
+ visibility: {
17
+ llm: VisibilityLlm;
18
+ };
19
+ };
20
+ installSkills: boolean;
21
+ installDocs: boolean;
22
+ } | {
23
+ kind: "quit";
24
+ };
25
+ export declare function InitWizardApp({ fields }: {
26
+ fields: InitWizardFields;
27
+ }): import("react").JSX.Element;
28
+ export declare function runInitWizardApp(opts: {
29
+ fields: InitWizardFields;
30
+ input: NodeJS.ReadStream;
31
+ output: NodeJS.WriteStream;
32
+ initialInput?: string[];
33
+ }): Promise<InitWizardResult>;
34
+ export {};