@wrongstack/tui 0.291.0 → 0.291.1

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/dist/index.js CHANGED
@@ -617,6 +617,7 @@ function createInitialState(options) {
617
617
  family,
618
618
  keyTail,
619
619
  sessionId,
620
+ profile,
620
621
  autonomyAgents,
621
622
  restoredEntries,
622
623
  restoredCheckpoints,
@@ -639,6 +640,7 @@ function createInitialState(options) {
639
640
  family,
640
641
  keyTail,
641
642
  sessionId,
643
+ profile,
642
644
  autonomyAgents
643
645
  }
644
646
  ] : [],
@@ -2677,23 +2679,20 @@ var ITEM_LINE = {
2677
2679
  time: 1,
2678
2680
  tokens: 1,
2679
2681
  version: 1,
2680
- working_dir: 1,
2681
2682
  yolo: 1,
2682
- // Line 2 — session context: memory pressure (RAM/heap), git, mode label,
2683
- // goals, countdowns, tools. RAM/heap sampling is slower than the line 1
2684
- // runtime counters and is more useful grouped alongside session-context
2685
- // chips that the user inspects together when something goes wrong.
2683
+ // Line 2 — session context: workdir/project first, then mode, git, goals,
2684
+ // memory pressure (RAM/heap), countdowns, tools.
2686
2685
  auto_proceed: 2,
2687
2686
  eternal_stage: 2,
2688
2687
  git: 2,
2689
2688
  goal: 2,
2690
2689
  memory: 2,
2691
2690
  mode: 2,
2692
- project: 1,
2693
- // kept on line 1 by render parity — see comment near project
2691
+ project: 2,
2694
2692
  sessions: 2,
2695
2693
  token_saving: 2,
2696
2694
  tools: 2,
2695
+ working_dir: 2,
2697
2696
  // Line 3 — active work + connectivity
2698
2697
  brain: 3,
2699
2698
  debug_stream: 3,
@@ -2719,15 +2718,15 @@ var STATUSLINE_ITEMS = [
2719
2718
  "index",
2720
2719
  "model",
2721
2720
  "processes",
2722
- "project",
2723
2721
  "queue",
2724
2722
  "state",
2725
2723
  "time",
2726
2724
  "tokens",
2727
2725
  "version",
2728
- "working_dir",
2729
2726
  "yolo",
2730
- // Line 2
2727
+ // Line 2 — workdir/project first, then session context
2728
+ "project",
2729
+ "working_dir",
2731
2730
  "auto_proceed",
2732
2731
  "eternal_stage",
2733
2732
  "git",
@@ -6062,7 +6061,6 @@ function StatusBar({
6062
6061
  " process",
6063
6062
  processCount === 1 ? "" : "es"
6064
6063
  ] }) : null,
6065
- memoryStatusChip,
6066
6064
  hint && showChip("hint") ? /* @__PURE__ */ jsx9(Text, { dimColor: !isNoColor, children: hint }) : null,
6067
6065
  indexState?.indexing && showChip("index") ? /* @__PURE__ */ jsxs8(Text, { color: isNoColor ? void 0 : theme.warn, children: [
6068
6066
  glyphs.index,
@@ -6086,7 +6084,7 @@ function StatusBar({
6086
6084
  })() : null
6087
6085
  ].filter((chip) => chip !== null);
6088
6086
  const modeChips = [
6089
- // Line 1 runtime chips: YOLO, autonomy, project/workdir, provider/model,
6087
+ // Line 1 runtime chips: YOLO, autonomy, provider/model,
6090
6088
  // then the context meter and remaining runtime details.
6091
6089
  yolo && showChip("yolo") ? /* @__PURE__ */ jsx9(Text, { color: chipColor(theme.error, isNoColor), bold: true, children: isNoColor ? "YOLO" : `${glyphs.warning} YOLO` }) : null,
6092
6090
  autonomy && autonomy !== "off" && showChip("autonomy") ? /* @__PURE__ */ jsx9(
@@ -6100,8 +6098,6 @@ function StatusBar({
6100
6098
  children: isNoColor ? autonomy.toUpperCase() : `\u221E ${autonomy.toUpperCase()}`
6101
6099
  }
6102
6100
  ) : null,
6103
- projectName && showChip("project") ? /* @__PURE__ */ jsx9(Text, { color: chipColor(theme.accent, isNoColor), children: isNoColor ? truncateChip(projectName, 24) : `${glyphs.folder} ${truncateChip(projectName, 24)}` }) : null,
6104
- workingDir && showChip("working_dir") ? /* @__PURE__ */ jsx9(Text, { color: chipColor(theme.accent, isNoColor), children: isNoColor ? truncateChip(workingDir, 28) : `${glyphs.workingDirectory} ${truncateChip(workingDir, 28)}` }) : null,
6105
6101
  modelStatusChip,
6106
6102
  ...primaryChips,
6107
6103
  stateStatusChip,
@@ -6255,6 +6251,8 @@ function StatusBar({
6255
6251
  PowerlineRail,
6256
6252
  {
6257
6253
  segments: [
6254
+ projectName && showChip("project") ? /* @__PURE__ */ jsx9(Text, { color: chipColor(theme.accent, isNoColor), children: isNoColor ? truncateChip(projectName, 24) : `${glyphs.folder} ${truncateChip(projectName, 24)}` }) : null,
6255
+ workingDir && showChip("working_dir") ? /* @__PURE__ */ jsx9(Text, { color: chipColor(theme.accent, isNoColor), children: isNoColor ? truncateChip(workingDir, 28) : `${glyphs.workingDirectory} ${truncateChip(workingDir, 28)}` }) : null,
6258
6256
  git && showChip("git") ? /* @__PURE__ */ jsxs8(Text, { children: [
6259
6257
  /* @__PURE__ */ jsxs8(Text, { color: theme.monitor.agents, children: [
6260
6258
  glyphs.gitBranch,
@@ -6274,7 +6272,8 @@ function StatusBar({
6274
6272
  sessionCount != null && sessionCount > 0 && showChip("sessions") ? /* @__PURE__ */ jsx9(Text, { color: isNoColor ? void 0 : theme.accent, children: isNoColor ? `${sessionCount} session${sessionCount === 1 ? "" : "s"}` : `${glyphs.sessions} ${sessionCount} session${sessionCount === 1 ? "" : "s"}` }) : null,
6275
6273
  toolCount != null && showChip("tools") ? /* @__PURE__ */ jsx9(Text, { color: isNoColor ? void 0 : theme.accent, children: isNoColor ? `${toolCount} tool${toolCount === 1 ? "" : "s"}` : `${glyphs.tools} ${toolCount} tool${toolCount === 1 ? "" : "s"}` }) : null,
6276
6274
  tokenSavingMode !== void 0 && tokenSavingMode !== "off" && showChip("token_saving") ? /* @__PURE__ */ jsx9(Text, { color: isNoColor ? void 0 : theme.warn, bold: true, children: isNoColor ? tokenSavingMode : `${glyphs.save} ${tokenSavingMode}` }) : null,
6277
- sideEffectCount > 0 ? /* @__PURE__ */ jsx9(Text, { color: isNoColor ? void 0 : theme.warn, children: isNoColor ? `${sideEffectCount} audit${sideEffectCount === 1 ? "" : "s"}` : `${glyphs.audit} ${sideEffectCount} audit${sideEffectCount === 1 ? "" : "s"}` }) : null
6275
+ sideEffectCount > 0 ? /* @__PURE__ */ jsx9(Text, { color: isNoColor ? void 0 : theme.warn, children: isNoColor ? `${sideEffectCount} audit${sideEffectCount === 1 ? "" : "s"}` : `${glyphs.audit} ${sideEffectCount} audit${sideEffectCount === 1 ? "" : "s"}` }) : null,
6276
+ memoryStatusChip
6278
6277
  ].filter((c) => c !== null),
6279
6278
  budget: Math.max(12, termWidth),
6280
6279
  monochrome: isNoColor,
@@ -15356,7 +15355,18 @@ function Banner({
15356
15355
  contentWidth,
15357
15356
  compact
15358
15357
  }
15359
- )
15358
+ ),
15359
+ entry.profile ? /* @__PURE__ */ jsx40(
15360
+ InfoRow,
15361
+ {
15362
+ icon: "\u2699",
15363
+ label: "profile",
15364
+ value: entry.profile,
15365
+ contentWidth,
15366
+ compact,
15367
+ accent: true
15368
+ }
15369
+ ) : null
15360
15370
  ] }),
15361
15371
  /* @__PURE__ */ jsx40(Footer, { contentWidth, compact }),
15362
15372
  entry.autonomyAgents && entry.autonomyAgents.length > 0 ? /* @__PURE__ */ jsx40(
@@ -16515,6 +16525,957 @@ var Input = memo2(function Input2({
16515
16525
  ] });
16516
16526
  });
16517
16527
 
16528
+ // src/input-validation.ts
16529
+ var MAX_INPUT_BUFFER_CHARS = 1e5;
16530
+ var MAX_ENTRY_TEXT_CHARS = 5e5;
16531
+ var MAX_HISTORY_ENTRIES = 400;
16532
+ var MAX_BATCHED_ACTIONS = 500;
16533
+ var MAX_ACTION_STRING_FIELD = 1e4;
16534
+ var MAX_FLEET_ENTRIES = 200;
16535
+ var MAX_ACTION_DEPTH = 8;
16536
+ var MAX_HOST_STRING_FIELD = 500;
16537
+ var MAX_PICKER_MATCHES = 500;
16538
+ var ALLOWED_ACTION_TYPES = [
16539
+ "addEntry",
16540
+ "compactHistory",
16541
+ "setBuffer",
16542
+ "clearInput",
16543
+ "clearHistory",
16544
+ "replaceHistory",
16545
+ "replaceEntry",
16546
+ "historyRoll",
16547
+ "setHistoryIndex",
16548
+ "setHistoryDraft",
16549
+ "scrollBy",
16550
+ "scrollTo",
16551
+ "scrollPage",
16552
+ "scrollToBottom",
16553
+ "scrollToTop",
16554
+ "setMeasuredLines",
16555
+ "setViewportRows",
16556
+ "pickerOpen",
16557
+ "pickerMove",
16558
+ "pickerClose",
16559
+ "pickerQuery",
16560
+ "pickerSetMatches",
16561
+ "slashPickerOpen",
16562
+ "slashPickerMove",
16563
+ "slashPickerClose",
16564
+ "slashPickerQuery",
16565
+ "slashPickerSetMatches",
16566
+ "modelPickerOpen",
16567
+ "modelPickerMove",
16568
+ "modelPickerClose",
16569
+ "modelPickerSelect",
16570
+ "modelPickerSetProviders",
16571
+ "autonomyPickerOpen",
16572
+ "autonomyPickerMove",
16573
+ "autonomyPickerClose",
16574
+ "autonomyPickerSelect",
16575
+ "cancelSend",
16576
+ "submit",
16577
+ "afterSubmit",
16578
+ "streamStart",
16579
+ "streamToken",
16580
+ "streamToolUse",
16581
+ "streamToolResult",
16582
+ "streamEnd",
16583
+ "setMode",
16584
+ "toggleHelp",
16585
+ "toggleMonitor",
16586
+ "toggleAgentsMonitor",
16587
+ "toggleTodosMonitor",
16588
+ "toggleQueuePanel",
16589
+ "toggleProcessList",
16590
+ "toggleCronMonitor",
16591
+ "toggleAuditPanel",
16592
+ "togglePlanPanel",
16593
+ "closeAllPanels",
16594
+ "toggleKanbanPanel",
16595
+ "toggleGoalPanel",
16596
+ "toggleGoalKanbanPanel",
16597
+ "toggleContextPanel",
16598
+ "toggleSessionsPanel",
16599
+ "sessionsPanelSet",
16600
+ "sessionsPanelMove",
16601
+ "sessionsPanelBusy",
16602
+ "sessionResumeConfirmSet",
16603
+ "sessionResumeConfirmClear",
16604
+ "settingsPickerOpen",
16605
+ "settingsPickerMove",
16606
+ "settingsPickerClose",
16607
+ "settingsPick",
16608
+ "statuslinePickerOpen",
16609
+ "statuslinePickerMove",
16610
+ "statuslinePickerClose",
16611
+ "pluginPickerOpen",
16612
+ "pluginPickerMove",
16613
+ "pluginPickerClose",
16614
+ "mcpPickerOpen",
16615
+ "mcpPickerMove",
16616
+ "mcpPickerClose",
16617
+ "toolsPickerOpen",
16618
+ "toolsPickerMove",
16619
+ "toolsPickerClose",
16620
+ "projectPickerOpen",
16621
+ "projectPickerMove",
16622
+ "projectPickerClose",
16623
+ "projectPickerSelect",
16624
+ "projectPickerSetItems",
16625
+ "fKeyPickerOpen",
16626
+ "fKeyPickerMove",
16627
+ "fKeyPickerClose",
16628
+ "confirmPromptOpen",
16629
+ "confirmPromptClose",
16630
+ "clearConfirmOpen",
16631
+ "clearConfirmClose",
16632
+ "clearConfirmSetValue",
16633
+ "exitConfirmOpen",
16634
+ "exitConfirmClose",
16635
+ "slashConfirmOpen",
16636
+ "slashConfirmClose",
16637
+ "escConfirmOpen",
16638
+ "escConfirmClose",
16639
+ "sendModePickerOpen",
16640
+ "sendModePickerMove",
16641
+ "sendModePickerClose",
16642
+ "resetContextChip",
16643
+ "fleetSeed",
16644
+ "fleetSpawn",
16645
+ "fleetToolStart",
16646
+ "fleetToolEnd",
16647
+ "fleetStart",
16648
+ "fleetDelta",
16649
+ "fleetMessage",
16650
+ "fleetTool",
16651
+ "fleetUsage",
16652
+ "fleetDone",
16653
+ "fleetRemove",
16654
+ "fleetBudgetWarning",
16655
+ "fleetBudgetExtended",
16656
+ "fleetCtxPct",
16657
+ "fleetCost",
16658
+ "fleetConcurrency",
16659
+ "fleetBatch",
16660
+ "leaderIterStart",
16661
+ "leaderIterEnd",
16662
+ "leaderToolStart",
16663
+ "leaderToolEnd",
16664
+ "leaderCtxPct",
16665
+ "setFleetChat",
16666
+ "enhanceOpen",
16667
+ "enhanceClose",
16668
+ "enhanceBusy",
16669
+ "enhanceBusyDone",
16670
+ "enhanceResult",
16671
+ "enhanceCancel",
16672
+ "enhanceDismiss",
16673
+ "refineFailureOpen",
16674
+ "refineFailureClose",
16675
+ "continueConfirmOpen",
16676
+ "continueConfirmClose",
16677
+ "checkpointReceived",
16678
+ "rewindOverlayOpen",
16679
+ "rewindOverlayClose",
16680
+ "rewindOverlayMove",
16681
+ "setDeadline",
16682
+ "setLiveProvider",
16683
+ "setLiveModel",
16684
+ "setCapability",
16685
+ "setDesignKit",
16686
+ "setAnimationStyle",
16687
+ "setEffectiveMaxContext",
16688
+ "setStreamingText",
16689
+ "setToolStream",
16690
+ "toolStreamClear",
16691
+ "setThinkingWord",
16692
+ "setFleetVerbosity",
16693
+ "setAutonomyMode",
16694
+ "setSendMode",
16695
+ "setSteering",
16696
+ "setSteeringPending",
16697
+ "clearSteering",
16698
+ "setGoalText",
16699
+ "setGoalPanelGoal",
16700
+ "showGoal",
16701
+ "goalSummary",
16702
+ "goalRunInit",
16703
+ "goalRunPhaseUpdate",
16704
+ "goalRunRunningPhases",
16705
+ "goalRunElapsed",
16706
+ "goalRunTaskActive",
16707
+ "goalRunMonitorToggle",
16708
+ "goalRunReset",
16709
+ "sddBoardSnapshot",
16710
+ "toggleSddBoardMonitor",
16711
+ "sddBoardFocusNext",
16712
+ "sddBoardFocusPrev",
16713
+ "worktreeUpsert",
16714
+ "worktreeRemove",
16715
+ "toggleWorktreeMonitor",
16716
+ "collabBugFound",
16717
+ "collabPlanEmitted",
16718
+ "collabEvalComplete",
16719
+ "collabSessionDone",
16720
+ "collabSubagentSpawned",
16721
+ "debugStreamStats",
16722
+ "debugStreamStatsClear",
16723
+ "countdownTick",
16724
+ "countdownEnded",
16725
+ "coordinatorEvent",
16726
+ "toggleCoordinatorMonitor",
16727
+ "setEnhancedPrompt",
16728
+ "enhanceConfirmOpen",
16729
+ "enhanceConfirmClose",
16730
+ "setShowModelReasoning"
16731
+ ];
16732
+ var TEXT_BEARING_ENTRY_KINDS = /* @__PURE__ */ new Set([
16733
+ "user",
16734
+ "assistant",
16735
+ "thinking",
16736
+ "info",
16737
+ "warn",
16738
+ "error",
16739
+ "turn-summary"
16740
+ ]);
16741
+ var ALLOWED_ENTRY_KINDS = /* @__PURE__ */ new Set([
16742
+ ...TEXT_BEARING_ENTRY_KINDS,
16743
+ "tool",
16744
+ "banner",
16745
+ "divider"
16746
+ ]);
16747
+ var ALLOWED_SCROLL_DIRS = /* @__PURE__ */ new Set(["up", "down"]);
16748
+ var ALLOWED_AUTONOMY_MODES = /* @__PURE__ */ new Set([
16749
+ "off",
16750
+ "suggest",
16751
+ "auto",
16752
+ "eternal",
16753
+ "eternal-parallel"
16754
+ ]);
16755
+ var ALLOWED_SEND_MODES = /* @__PURE__ */ new Set(["queue", "steer", "btw", "direct"]);
16756
+ var ALLOWED_FLEET_CHAT_MODES = /* @__PURE__ */ new Set(["off", "concise", "full"]);
16757
+ var ALLOWED_COLLAB_VERDICTS = /* @__PURE__ */ new Set(["approve", "needs_revision", "reject"]);
16758
+ var ALLOWED_CAPABILITY_FIELDS = /* @__PURE__ */ new Set([
16759
+ "colorDepth",
16760
+ "mouseProtocol",
16761
+ "supportsTitle"
16762
+ ]);
16763
+ function validateAction(action) {
16764
+ const type = String(action.type);
16765
+ const typeAllowed = ALLOWED_ACTION_TYPES.includes(type);
16766
+ if (!typeAllowed) {
16767
+ return {
16768
+ valid: false,
16769
+ error: `action.type: "${type}" is not on the allow-list.`
16770
+ };
16771
+ }
16772
+ const normalized = normalizeActionType(type);
16773
+ if (!normalized) {
16774
+ return { valid: false, error: `action.type: "${type}" normalized to empty.` };
16775
+ }
16776
+ const payload = { ...action, type: normalized };
16777
+ const depth = measureDepth(payload, 0);
16778
+ if (depth > MAX_ACTION_DEPTH) {
16779
+ return {
16780
+ valid: false,
16781
+ error: `action: payload nesting depth ${depth} exceeds max ${MAX_ACTION_DEPTH}.`
16782
+ };
16783
+ }
16784
+ for (const [k, v] of Object.entries(payload)) {
16785
+ if (k === "actions") continue;
16786
+ if (typeof v === "string" && v.length > MAX_ACTION_STRING_FIELD) {
16787
+ return {
16788
+ valid: false,
16789
+ error: `action.${k}: string exceeds ${MAX_ACTION_STRING_FIELD.toLocaleString()} chars (got ${v.length}).`
16790
+ };
16791
+ }
16792
+ }
16793
+ switch (normalized) {
16794
+ // ── Buffer/input mutations ──────────────────────────────────────
16795
+ case "setBuffer": {
16796
+ const buf = String(action.buffer ?? "");
16797
+ if (buf.length > MAX_INPUT_BUFFER_CHARS) {
16798
+ return {
16799
+ valid: false,
16800
+ error: `setBuffer.buffer: exceeds ${MAX_INPUT_BUFFER_CHARS.toLocaleString()} chars (got ${buf.length}).`
16801
+ };
16802
+ }
16803
+ const cursor = Number(action.cursor);
16804
+ if (!Number.isInteger(cursor) || cursor < 0 || cursor > buf.length) {
16805
+ return {
16806
+ valid: false,
16807
+ error: `setBuffer.cursor: ${action.cursor} out of range [0, ${buf.length}].`
16808
+ };
16809
+ }
16810
+ return { valid: true, value: payload };
16811
+ }
16812
+ case "clearInput":
16813
+ return { valid: true, value: payload };
16814
+ // ── History mutations ───────────────────────────────────────────
16815
+ case "addEntry": {
16816
+ const entry = action.entry;
16817
+ if (!entry || typeof entry !== "object") {
16818
+ return { valid: false, error: "addEntry.entry: missing or non-object." };
16819
+ }
16820
+ const kind = String(entry.kind ?? "");
16821
+ if (!ALLOWED_ENTRY_KINDS.has(kind)) {
16822
+ return {
16823
+ valid: false,
16824
+ error: `addEntry.entry.kind: "${kind}" not on allow-list.`
16825
+ };
16826
+ }
16827
+ if (TEXT_BEARING_ENTRY_KINDS.has(kind)) {
16828
+ const text = entry.text;
16829
+ if (typeof text === "string" && text.length > MAX_ENTRY_TEXT_CHARS) {
16830
+ return {
16831
+ valid: false,
16832
+ error: `addEntry.entry.text: exceeds ${MAX_ENTRY_TEXT_CHARS.toLocaleString()} chars (got ${text.length}).`
16833
+ };
16834
+ }
16835
+ }
16836
+ return { valid: true, value: payload };
16837
+ }
16838
+ case "replaceEntry": {
16839
+ const id = Number(action.id);
16840
+ if (!Number.isInteger(id) || id < 0) {
16841
+ return { valid: false, error: `replaceEntry.id: ${action.id} is not a non-negative integer.` };
16842
+ }
16843
+ return { valid: true, value: payload };
16844
+ }
16845
+ case "replaceHistory": {
16846
+ const entries = action.entries;
16847
+ if (!Array.isArray(entries)) {
16848
+ return { valid: false, error: "replaceHistory.entries: not an array." };
16849
+ }
16850
+ if (entries.length > MAX_HISTORY_ENTRIES) {
16851
+ return {
16852
+ valid: false,
16853
+ error: `replaceHistory.entries: ${entries.length} exceeds max ${MAX_HISTORY_ENTRIES}.`
16854
+ };
16855
+ }
16856
+ return { valid: true, value: payload };
16857
+ }
16858
+ // ── Scroll ──────────────────────────────────────────────────────
16859
+ case "scrollBy": {
16860
+ const delta = Number(action.delta);
16861
+ if (!Number.isInteger(delta)) {
16862
+ return { valid: false, error: `scrollBy.delta: ${action.delta} is not an integer.` };
16863
+ }
16864
+ return { valid: true, value: payload };
16865
+ }
16866
+ case "scrollPage": {
16867
+ const dir = String(action.dir ?? "");
16868
+ if (!ALLOWED_SCROLL_DIRS.has(dir)) {
16869
+ return { valid: false, error: `scrollPage.dir: "${dir}" not on allow-list (up|down).` };
16870
+ }
16871
+ return { valid: true, value: payload };
16872
+ }
16873
+ case "setMeasuredLines": {
16874
+ const lines = Number(action.totalLines);
16875
+ if (!Number.isInteger(lines) || lines < 0) {
16876
+ return { valid: false, error: `setMeasuredLines.totalLines: ${action.totalLines} is not a non-negative integer.` };
16877
+ }
16878
+ return { valid: true, value: payload };
16879
+ }
16880
+ case "setViewportRows": {
16881
+ const rows = Number(action.rows);
16882
+ if (!Number.isInteger(rows) || rows < 0) {
16883
+ return { valid: false, error: `setViewportRows.rows: ${action.rows} is not a non-negative integer.` };
16884
+ }
16885
+ return { valid: true, value: payload };
16886
+ }
16887
+ // ── Picker ──────────────────────────────────────────────────────
16888
+ case "pickerMove":
16889
+ case "slashPickerMove":
16890
+ case "modelPickerMove":
16891
+ case "autonomyPickerMove":
16892
+ case "settingsPickerMove":
16893
+ case "statuslinePickerMove":
16894
+ case "pluginPickerMove":
16895
+ case "mcpPickerMove":
16896
+ case "toolsPickerMove":
16897
+ case "projectPickerMove":
16898
+ case "fKeyPickerMove":
16899
+ case "sessionsPanelMove":
16900
+ case "rewindOverlayMove":
16901
+ case "sendModePickerMove": {
16902
+ const delta = Number(action.delta);
16903
+ if (!Number.isInteger(delta) || delta < -1 || delta > 1) {
16904
+ return { valid: false, error: `${type}.delta: ${action.delta} is not -1, 0, or 1.` };
16905
+ }
16906
+ return { valid: true, value: payload };
16907
+ }
16908
+ case "pickerSetMatches":
16909
+ case "slashPickerSetMatches": {
16910
+ const matches = action.matches;
16911
+ if (!Array.isArray(matches)) {
16912
+ return { valid: false, error: `${type}.matches: not an array.` };
16913
+ }
16914
+ if (matches.length > MAX_PICKER_MATCHES) {
16915
+ return {
16916
+ valid: false,
16917
+ error: `${type}.matches: ${matches.length} exceeds max ${MAX_PICKER_MATCHES}.`
16918
+ };
16919
+ }
16920
+ return { valid: true, value: payload };
16921
+ }
16922
+ case "modelPickerSelect": {
16923
+ const idx = Number(action.index);
16924
+ if (!Number.isInteger(idx) || idx < 0) {
16925
+ return { valid: false, error: `modelPickerSelect.index: ${action.index} is not a non-negative integer.` };
16926
+ }
16927
+ return { valid: true, value: payload };
16928
+ }
16929
+ case "projectPickerSelect": {
16930
+ const idx = Number(action.selected);
16931
+ if (!Number.isInteger(idx) || idx < 0) {
16932
+ return { valid: false, error: `projectPickerSelect.selected: ${action.selected} is not a non-negative integer.` };
16933
+ }
16934
+ return { valid: true, value: payload };
16935
+ }
16936
+ case "projectPickerSetItems": {
16937
+ const items = action.items;
16938
+ if (!Array.isArray(items)) {
16939
+ return { valid: false, error: "projectPickerSetItems.items: not an array." };
16940
+ }
16941
+ if (items.length > MAX_PICKER_MATCHES) {
16942
+ return {
16943
+ valid: false,
16944
+ error: `projectPickerSetItems.items: ${items.length} exceeds max ${MAX_PICKER_MATCHES}.`
16945
+ };
16946
+ }
16947
+ return { valid: true, value: payload };
16948
+ }
16949
+ case "modelPickerSetProviders": {
16950
+ const providers = action.providers;
16951
+ if (!Array.isArray(providers)) {
16952
+ return { valid: false, error: "modelPickerSetProviders.providers: not an array." };
16953
+ }
16954
+ return { valid: true, value: payload };
16955
+ }
16956
+ // ── Settings ────────────────────────────────────────────────────
16957
+ case "settingsPick": {
16958
+ const field = String(action.field ?? "");
16959
+ if (field.length > 100) {
16960
+ return { valid: false, error: `settingsPick.field: length ${field.length} exceeds 100.` };
16961
+ }
16962
+ return { valid: true, value: payload };
16963
+ }
16964
+ // ── Fleet ───────────────────────────────────────────────────────
16965
+ case "fleetSeed": {
16966
+ const entries = action.entries;
16967
+ if (!Array.isArray(entries)) {
16968
+ return { valid: false, error: "fleetSeed.entries: not an array." };
16969
+ }
16970
+ if (entries.length > MAX_FLEET_ENTRIES) {
16971
+ return {
16972
+ valid: false,
16973
+ error: `fleetSeed.entries: ${entries.length} exceeds max ${MAX_FLEET_ENTRIES}.`
16974
+ };
16975
+ }
16976
+ return { valid: true, value: payload };
16977
+ }
16978
+ case "fleetBatch": {
16979
+ const actions = action.actions;
16980
+ if (!Array.isArray(actions)) {
16981
+ return { valid: false, error: "fleetBatch.actions: not an array." };
16982
+ }
16983
+ if (actions.length > MAX_BATCHED_ACTIONS) {
16984
+ return {
16985
+ valid: false,
16986
+ error: `fleetBatch.actions: ${actions.length} exceeds max ${MAX_BATCHED_ACTIONS}.`
16987
+ };
16988
+ }
16989
+ return { valid: true, value: payload };
16990
+ }
16991
+ case "fleetToolStart":
16992
+ case "fleetToolEnd":
16993
+ case "fleetTool": {
16994
+ const id = String(action.id ?? "");
16995
+ if (id.length === 0) {
16996
+ return { valid: false, error: `${type}.id: empty or missing.` };
16997
+ }
16998
+ return { valid: true, value: payload };
16999
+ }
17000
+ case "fleetSpawn":
17001
+ case "fleetStart":
17002
+ case "fleetDelta":
17003
+ case "fleetMessage":
17004
+ case "fleetUsage":
17005
+ case "fleetDone":
17006
+ case "fleetRemove":
17007
+ case "fleetBudgetWarning":
17008
+ case "fleetBudgetExtended":
17009
+ case "fleetCtxPct":
17010
+ case "fleetCost":
17011
+ case "fleetConcurrency":
17012
+ case "leaderIterStart":
17013
+ case "leaderIterEnd":
17014
+ case "leaderToolStart":
17015
+ case "leaderToolEnd":
17016
+ case "leaderCtxPct": {
17017
+ const id = String(action.id ?? "");
17018
+ if (id.length === 0) {
17019
+ return { valid: false, error: `${type}.id: empty or missing.` };
17020
+ }
17021
+ return { valid: true, value: payload };
17022
+ }
17023
+ case "setFleetChat": {
17024
+ const mode = String(action.mode ?? "");
17025
+ if (!ALLOWED_FLEET_CHAT_MODES.has(mode)) {
17026
+ return { valid: false, error: `setFleetChat.mode: "${mode}" not on allow-list.` };
17027
+ }
17028
+ return { valid: true, value: payload };
17029
+ }
17030
+ // ── State mutations ─────────────────────────────────────────────
17031
+ case "setAutonomyMode": {
17032
+ const mode = String(action.mode ?? "");
17033
+ if (!ALLOWED_AUTONOMY_MODES.has(mode)) {
17034
+ return { valid: false, error: `setAutonomyMode.mode: "${mode}" not on allow-list.` };
17035
+ }
17036
+ return { valid: true, value: payload };
17037
+ }
17038
+ case "setSendMode": {
17039
+ const mode = String(action.mode ?? "");
17040
+ if (!ALLOWED_SEND_MODES.has(mode)) {
17041
+ return { valid: false, error: `setSendMode.mode: "${mode}" not on allow-list.` };
17042
+ }
17043
+ return { valid: true, value: payload };
17044
+ }
17045
+ case "setLiveProvider":
17046
+ case "setLiveModel": {
17047
+ const value = String(action.value ?? "");
17048
+ if (value.length > MAX_HOST_STRING_FIELD) {
17049
+ return { valid: false, error: `${type}.value: exceeds ${MAX_HOST_STRING_FIELD} chars.` };
17050
+ }
17051
+ return { valid: true, value: payload };
17052
+ }
17053
+ case "setEffectiveMaxContext": {
17054
+ const ctx = Number(action.value);
17055
+ if (!Number.isInteger(ctx) || ctx < 0 || ctx > 1e7) {
17056
+ return { valid: false, error: `setEffectiveMaxContext.value: ${action.value} out of range [0, 10_000_000].` };
17057
+ }
17058
+ return { valid: true, value: payload };
17059
+ }
17060
+ case "setStreamingText": {
17061
+ const text = String(action.text ?? "");
17062
+ if (text.length > MAX_ENTRY_TEXT_CHARS) {
17063
+ return {
17064
+ valid: false,
17065
+ error: `setStreamingText.text: exceeds ${MAX_ENTRY_TEXT_CHARS.toLocaleString()} chars.`
17066
+ };
17067
+ }
17068
+ return { valid: true, value: payload };
17069
+ }
17070
+ case "setToolStream": {
17071
+ const text = String(action.text ?? "");
17072
+ if (text.length > MAX_TOOL_STREAM_RETAINED_CHARS) {
17073
+ return {
17074
+ valid: false,
17075
+ error: `setToolStream.text: exceeds ${MAX_TOOL_STREAM_RETAINED_CHARS.toLocaleString()} chars.`
17076
+ };
17077
+ }
17078
+ return { valid: true, value: payload };
17079
+ }
17080
+ case "setThinkingWord": {
17081
+ const word = String(action.word ?? "");
17082
+ if (word.length > 16) {
17083
+ return { valid: false, error: `setThinkingWord.word: "${word}" exceeds 16 chars.` };
17084
+ }
17085
+ return { valid: true, value: payload };
17086
+ }
17087
+ case "setAnimationStyle": {
17088
+ const style = String(action.style ?? "");
17089
+ if (style.length > 50) {
17090
+ return { valid: false, error: `setAnimationStyle.style: length ${style.length} exceeds 50.` };
17091
+ }
17092
+ return { valid: true, value: payload };
17093
+ }
17094
+ case "setCapability": {
17095
+ const cap = action.capability;
17096
+ if (!cap || typeof cap !== "object") {
17097
+ return { valid: false, error: "setCapability.capability: missing or non-object." };
17098
+ }
17099
+ for (const k of Object.keys(cap)) {
17100
+ if (!ALLOWED_CAPABILITY_FIELDS.has(k)) {
17101
+ return { valid: false, error: `setCapability.capability.${k}: unknown field.` };
17102
+ }
17103
+ }
17104
+ return { valid: true, value: payload };
17105
+ }
17106
+ // ── Confirm panels ──────────────────────────────────────────────
17107
+ case "clearConfirmOpen":
17108
+ case "exitConfirmOpen":
17109
+ case "slashConfirmOpen":
17110
+ case "escConfirmOpen":
17111
+ case "enhanceConfirmOpen": {
17112
+ const info = action.info;
17113
+ if (!info || typeof info !== "object") {
17114
+ return { valid: false, error: `${type}.info: missing or non-object.` };
17115
+ }
17116
+ return { valid: true, value: payload };
17117
+ }
17118
+ case "clearConfirmSetValue": {
17119
+ const value = String(action.value ?? "");
17120
+ if (value.length > 100) {
17121
+ return { valid: false, error: `clearConfirmSetValue.value: exceeds 100 chars.` };
17122
+ }
17123
+ return { valid: true, value: payload };
17124
+ }
17125
+ // ── Checkpoints ─────────────────────────────────────────────────
17126
+ case "checkpointReceived": {
17127
+ const cp = action.cp;
17128
+ if (!cp || typeof cp !== "object") {
17129
+ return { valid: false, error: "checkpointReceived.cp: missing or non-object." };
17130
+ }
17131
+ const promptIndex = Number(cp.promptIndex);
17132
+ if (!Number.isInteger(promptIndex) || promptIndex < 0) {
17133
+ return {
17134
+ valid: false,
17135
+ error: `checkpointReceived.cp.promptIndex: ${promptIndex} is not a non-negative integer.`
17136
+ };
17137
+ }
17138
+ return { valid: true, value: payload };
17139
+ }
17140
+ // ── Rewind ──────────────────────────────────────────────────────
17141
+ case "rewindOverlayOpen": {
17142
+ const checkpoints = action.checkpoints;
17143
+ if (!Array.isArray(checkpoints)) {
17144
+ return { valid: false, error: "rewindOverlayOpen.checkpoints: not an array." };
17145
+ }
17146
+ if (checkpoints.length > MAX_HISTORY_ENTRIES) {
17147
+ return {
17148
+ valid: false,
17149
+ error: `rewindOverlayOpen.checkpoints: ${checkpoints.length} exceeds max ${MAX_HISTORY_ENTRIES}.`
17150
+ };
17151
+ }
17152
+ return { valid: true, value: payload };
17153
+ }
17154
+ // ── Steering ────────────────────────────────────────────────────
17155
+ case "setSteering": {
17156
+ const text = String(action.text ?? "");
17157
+ if (text.length > MAX_INPUT_BUFFER_CHARS) {
17158
+ return {
17159
+ valid: false,
17160
+ error: `setSteering.text: exceeds ${MAX_INPUT_BUFFER_CHARS.toLocaleString()} chars.`
17161
+ };
17162
+ }
17163
+ return { valid: true, value: payload };
17164
+ }
17165
+ // ── Goal ────────────────────────────────────────────────────────
17166
+ case "goalRunInit": {
17167
+ const title = String(action.title ?? "");
17168
+ if (title.length > 500) {
17169
+ return { valid: false, error: `goalRunInit.title: exceeds 500 chars.` };
17170
+ }
17171
+ return { valid: true, value: payload };
17172
+ }
17173
+ case "goalRunPhaseUpdate": {
17174
+ const completed = Number(action.completedTasks);
17175
+ if (!Number.isInteger(completed) || completed < 0) {
17176
+ return { valid: false, error: `goalRunPhaseUpdate.completedTasks: ${completed} is not a non-negative integer.` };
17177
+ }
17178
+ const total = Number(action.totalTasks);
17179
+ if (!Number.isInteger(total) || total < 0) {
17180
+ return { valid: false, error: `goalRunPhaseUpdate.totalTasks: ${total} is not a non-negative integer.` };
17181
+ }
17182
+ return { valid: true, value: payload };
17183
+ }
17184
+ case "goalRunRunningPhases": {
17185
+ const phaseIds = action.phaseIds;
17186
+ if (!Array.isArray(phaseIds)) {
17187
+ return { valid: false, error: "goalRunRunningPhases.phaseIds: not an array." };
17188
+ }
17189
+ return { valid: true, value: payload };
17190
+ }
17191
+ case "goalRunElapsed": {
17192
+ const ms = Number(action.ms);
17193
+ if (!Number.isFinite(ms) || ms < 0) {
17194
+ return { valid: false, error: `goalRunElapsed.ms: ${ms} is not a non-negative number.` };
17195
+ }
17196
+ return { valid: true, value: payload };
17197
+ }
17198
+ case "goalRunTaskActive": {
17199
+ if (typeof action.active !== "boolean") {
17200
+ return { valid: false, error: "goalRunTaskActive.active: not a boolean." };
17201
+ }
17202
+ return { valid: true, value: payload };
17203
+ }
17204
+ // ── SDD board ───────────────────────────────────────────────────
17205
+ case "sddBoardSnapshot": {
17206
+ if (!action.snapshot || typeof action.snapshot !== "object") {
17207
+ return { valid: false, error: "sddBoardSnapshot.snapshot: missing or non-object." };
17208
+ }
17209
+ return { valid: true, value: payload };
17210
+ }
17211
+ // ── Worktree ────────────────────────────────────────────────────
17212
+ case "worktreeUpsert": {
17213
+ const handleId = String(action.handleId ?? "");
17214
+ if (handleId.length === 0) {
17215
+ return { valid: false, error: "worktreeUpsert.handleId: empty." };
17216
+ }
17217
+ return { valid: true, value: payload };
17218
+ }
17219
+ case "worktreeRemove": {
17220
+ const handleId = String(action.handleId ?? "");
17221
+ if (handleId.length === 0) {
17222
+ return { valid: false, error: "worktreeRemove.handleId: empty." };
17223
+ }
17224
+ return { valid: true, value: payload };
17225
+ }
17226
+ // ── Collaboration ───────────────────────────────────────────────
17227
+ case "collabBugFound": {
17228
+ const bugId = String(action.bugId ?? "");
17229
+ if (bugId.length === 0) {
17230
+ return { valid: false, error: "collabBugFound.bugId: empty." };
17231
+ }
17232
+ return { valid: true, value: payload };
17233
+ }
17234
+ case "collabSessionDone": {
17235
+ const verdict = String(action.verdict ?? "");
17236
+ if (!ALLOWED_COLLAB_VERDICTS.has(verdict)) {
17237
+ return { valid: false, error: `collabSessionDone.verdict: "${verdict}" not on allow-list.` };
17238
+ }
17239
+ return { valid: true, value: payload };
17240
+ }
17241
+ case "collabSubagentSpawned": {
17242
+ const role = String(action.role ?? "");
17243
+ if (role.length === 0) {
17244
+ return { valid: false, error: "collabSubagentSpawned.role: empty." };
17245
+ }
17246
+ return { valid: true, value: payload };
17247
+ }
17248
+ // ── Debug stream ────────────────────────────────────────────────
17249
+ case "debugStreamStats": {
17250
+ const chunkCount = Number(action.chunkCount);
17251
+ if (!Number.isInteger(chunkCount) || chunkCount < 0) {
17252
+ return { valid: false, error: `debugStreamStats.chunkCount: ${chunkCount} is not a non-negative integer.` };
17253
+ }
17254
+ const lastChunkSize = Number(action.lastChunkSize);
17255
+ if (!Number.isInteger(lastChunkSize) || lastChunkSize < 0) {
17256
+ return { valid: false, error: `debugStreamStats.lastChunkSize: ${lastChunkSize} is not a non-negative integer.` };
17257
+ }
17258
+ const totalBytes = Number(action.totalBytes);
17259
+ if (!Number.isInteger(totalBytes) || totalBytes < 0) {
17260
+ return { valid: false, error: `debugStreamStats.totalBytes: ${totalBytes} is not a non-negative integer.` };
17261
+ }
17262
+ return { valid: true, value: payload };
17263
+ }
17264
+ // ── Countdown ───────────────────────────────────────────────────
17265
+ case "countdownTick": {
17266
+ const remaining = Number(action.remainingSeconds);
17267
+ if (!Number.isFinite(remaining) || remaining < 0) {
17268
+ return { valid: false, error: `countdownTick.remainingSeconds: ${remaining} is not a non-negative number.` };
17269
+ }
17270
+ return { valid: true, value: payload };
17271
+ }
17272
+ // ── Coordinator ─────────────────────────────────────────────────
17273
+ case "coordinatorEvent": {
17274
+ if (!action.event || typeof action.event !== "object") {
17275
+ return { valid: false, error: "coordinatorEvent.event: missing or non-object." };
17276
+ }
17277
+ return { valid: true, value: payload };
17278
+ }
17279
+ // ── Sessions panel ──────────────────────────────────────────────
17280
+ case "sessionsPanelSet": {
17281
+ const sessions = action.sessions;
17282
+ if (!Array.isArray(sessions)) {
17283
+ return { valid: false, error: "sessionsPanelSet.sessions: not an array." };
17284
+ }
17285
+ if (sessions.length > 200) {
17286
+ return { valid: false, error: `sessionsPanelSet.sessions: ${sessions.length} exceeds max 200.` };
17287
+ }
17288
+ return { valid: true, value: payload };
17289
+ }
17290
+ case "sessionsPanelBusy": {
17291
+ if (typeof action.on !== "boolean") {
17292
+ return { valid: false, error: "sessionsPanelBusy.on: not a boolean." };
17293
+ }
17294
+ return { valid: true, value: payload };
17295
+ }
17296
+ case "sessionResumeConfirmSet": {
17297
+ const sessionId = String(action.sessionId ?? "");
17298
+ if (sessionId.length === 0) {
17299
+ return { valid: false, error: "sessionResumeConfirmSet.sessionId: empty." };
17300
+ }
17301
+ return { valid: true, value: payload };
17302
+ }
17303
+ // ── Simple state toggles and setters ────────────────────────────
17304
+ case "setShowModelReasoning": {
17305
+ if (typeof action.value !== "boolean") {
17306
+ return { valid: false, error: "setShowModelReasoning.value: not a boolean." };
17307
+ }
17308
+ return { valid: true, value: payload };
17309
+ }
17310
+ case "setEnhancedPrompt": {
17311
+ const text = String(action.text ?? "");
17312
+ if (text.length > MAX_ENTRY_TEXT_CHARS) {
17313
+ return {
17314
+ valid: false,
17315
+ error: `setEnhancedPrompt.text: exceeds ${MAX_ENTRY_TEXT_CHARS.toLocaleString()} chars.`
17316
+ };
17317
+ }
17318
+ return { valid: true, value: payload };
17319
+ }
17320
+ case "setDesignKit": {
17321
+ const name = String(action.name ?? "");
17322
+ if (name.length > 100) {
17323
+ return { valid: false, error: `setDesignKit.name: exceeds 100 chars.` };
17324
+ }
17325
+ return { valid: true, value: payload };
17326
+ }
17327
+ case "setGoalText":
17328
+ case "setGoalPanelGoal": {
17329
+ const text = String(action.text ?? "");
17330
+ if (text.length > 5e3) {
17331
+ return { valid: false, error: `${type}.text: exceeds 5000 chars.` };
17332
+ }
17333
+ return { valid: true, value: payload };
17334
+ }
17335
+ // ── Enhance / refine ───────────────────────────────────────────
17336
+ case "enhanceResult": {
17337
+ const result = action.result;
17338
+ if (!result || typeof result !== "object") {
17339
+ return { valid: false, error: "enhanceResult.result: missing or non-object." };
17340
+ }
17341
+ return { valid: true, value: payload };
17342
+ }
17343
+ case "refineFailureOpen": {
17344
+ const info = action.info;
17345
+ if (!info || typeof info !== "object") {
17346
+ return { valid: false, error: "refineFailureOpen.info: missing or non-object." };
17347
+ }
17348
+ return { valid: true, value: payload };
17349
+ }
17350
+ // ── Actions with no payload or trivial payload ──────────────────
17351
+ case "toggleHelp":
17352
+ case "toggleMonitor":
17353
+ case "toggleAgentsMonitor":
17354
+ case "toggleTodosMonitor":
17355
+ case "toggleQueuePanel":
17356
+ case "toggleProcessList":
17357
+ case "toggleCronMonitor":
17358
+ case "toggleAuditPanel":
17359
+ case "togglePlanPanel":
17360
+ case "closeAllPanels":
17361
+ case "toggleKanbanPanel":
17362
+ case "toggleGoalPanel":
17363
+ case "toggleGoalKanbanPanel":
17364
+ case "toggleContextPanel":
17365
+ case "toggleSessionsPanel":
17366
+ case "toggleSddBoardMonitor":
17367
+ case "toggleWorktreeMonitor":
17368
+ case "toggleCoordinatorMonitor":
17369
+ case "resetContextChip":
17370
+ case "clearConfirmClose":
17371
+ case "exitConfirmClose":
17372
+ case "slashConfirmClose":
17373
+ case "escConfirmClose":
17374
+ case "sendModePickerClose":
17375
+ case "enhanceClose":
17376
+ case "enhanceBusy":
17377
+ case "enhanceBusyDone":
17378
+ case "enhanceCancel":
17379
+ case "enhanceDismiss":
17380
+ case "enhanceConfirmClose":
17381
+ case "refineFailureClose":
17382
+ case "continueConfirmOpen":
17383
+ case "continueConfirmClose":
17384
+ case "rewindOverlayClose":
17385
+ case "countdownEnded":
17386
+ case "cancelSend":
17387
+ case "submit":
17388
+ case "afterSubmit":
17389
+ case "streamStart":
17390
+ case "streamToken":
17391
+ case "streamToolUse":
17392
+ case "streamToolResult":
17393
+ case "streamEnd":
17394
+ case "setMode":
17395
+ case "clearInput":
17396
+ case "clearHistory":
17397
+ case "toolStreamClear":
17398
+ case "debugStreamStatsClear":
17399
+ case "setSteeringPending":
17400
+ case "clearSteering":
17401
+ case "showGoal":
17402
+ case "goalSummary":
17403
+ case "goalRunMonitorToggle":
17404
+ case "goalRunReset":
17405
+ case "sddBoardFocusNext":
17406
+ case "sddBoardFocusPrev":
17407
+ case "compactHistory":
17408
+ case "scrollToBottom":
17409
+ case "scrollToTop":
17410
+ case "pickerOpen":
17411
+ case "pickerClose":
17412
+ case "slashPickerOpen":
17413
+ case "slashPickerClose":
17414
+ case "modelPickerOpen":
17415
+ case "modelPickerClose":
17416
+ case "autonomyPickerOpen":
17417
+ case "autonomyPickerClose":
17418
+ case "settingsPickerOpen":
17419
+ case "settingsPickerClose":
17420
+ case "statuslinePickerOpen":
17421
+ case "statuslinePickerClose":
17422
+ case "pluginPickerOpen":
17423
+ case "pluginPickerClose":
17424
+ case "mcpPickerOpen":
17425
+ case "mcpPickerClose":
17426
+ case "toolsPickerOpen":
17427
+ case "toolsPickerClose":
17428
+ case "projectPickerOpen":
17429
+ case "projectPickerClose":
17430
+ case "fKeyPickerOpen":
17431
+ case "fKeyPickerClose":
17432
+ case "confirmPromptOpen":
17433
+ case "confirmPromptClose":
17434
+ case "setDeadline":
17435
+ case "enhanceOpen":
17436
+ return { valid: true, value: payload };
17437
+ default:
17438
+ return {
17439
+ valid: false,
17440
+ error: `action.type: "${type}" has no type-specific validator \u2014 may be a missing case.`
17441
+ };
17442
+ }
17443
+ }
17444
+ function normalizeActionType(type) {
17445
+ const trimmed = String(type ?? "").trim();
17446
+ if (trimmed.length === 0) return null;
17447
+ return trimmed;
17448
+ }
17449
+ function measureDepth(value, depth) {
17450
+ if (depth > MAX_ACTION_DEPTH) return depth;
17451
+ if (value === null || typeof value !== "object") return depth;
17452
+ if (Array.isArray(value)) {
17453
+ let max2 = depth;
17454
+ for (const item of value.slice(0, 10)) {
17455
+ const d = measureDepth(item, depth + 1);
17456
+ if (d > max2) max2 = d;
17457
+ if (max2 > MAX_ACTION_DEPTH) return max2;
17458
+ }
17459
+ return max2;
17460
+ }
17461
+ let max = depth;
17462
+ for (const v of Object.values(value).slice(0, 10)) {
17463
+ const d = measureDepth(v, depth + 1);
17464
+ if (d > max) max = d;
17465
+ if (max > MAX_ACTION_DEPTH) return max;
17466
+ }
17467
+ return max;
17468
+ }
17469
+ function safeDispatch(action, dispatch) {
17470
+ const result = validateAction(action);
17471
+ if (!result.valid) {
17472
+ console.error(`[input-validation] REJECTED dispatch "${action.type}": ${result.error}`);
17473
+ return false;
17474
+ }
17475
+ dispatch(result.value);
17476
+ return true;
17477
+ }
17478
+
16518
17479
  // src/components/kanban-panel.tsx
16519
17480
  import {
16520
17481
  addTask,
@@ -19308,7 +20269,9 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
19308
20269
  const visibleCount = Math.min(entries.length, Math.max(1, Math.round(height / 3)));
19309
20270
  const estimatedPerEntry = Math.max(1, Math.round(height / visibleCount));
19310
20271
  for (const entry of entries) {
19311
- cache2.record(entry.id, estimatedPerEntry);
20272
+ if (cache2.getHeight(entry.id) === void 0) {
20273
+ cache2.record(entry.id, estimatedPerEntry);
20274
+ }
19312
20275
  }
19313
20276
  }
19314
20277
  const cacheTotal2 = cache2.totalHeight();
@@ -26110,6 +27073,7 @@ function App({
26110
27073
  provider,
26111
27074
  family,
26112
27075
  keyTail,
27076
+ profile,
26113
27077
  autonomyAgents,
26114
27078
  tokenSavingMode,
26115
27079
  toolCount,
@@ -26268,7 +27232,7 @@ function App({
26268
27232
  restoredEvents
26269
27233
  );
26270
27234
  const restoredCheckpoints = buildRestoredCheckpoints(restoredEvents);
26271
- const [state, dispatch] = useReducer(
27235
+ const [state, rawDispatch] = useReducer(
26272
27236
  reducer,
26273
27237
  createInitialState({
26274
27238
  banner,
@@ -26279,6 +27243,7 @@ function App({
26279
27243
  family,
26280
27244
  keyTail,
26281
27245
  sessionId: agent.ctx.session.id,
27246
+ profile,
26282
27247
  autonomyAgents,
26283
27248
  restoredEntries,
26284
27249
  restoredCheckpoints,
@@ -26287,6 +27252,12 @@ function App({
26287
27252
  initialFleetChat: fleetStreamController?.mode
26288
27253
  })
26289
27254
  );
27255
+ const dispatch = useCallback12(
27256
+ (action) => {
27257
+ safeDispatch(action, rawDispatch);
27258
+ },
27259
+ [rawDispatch]
27260
+ );
26290
27261
  const [focusedBoardId, setFocusedBoardId] = useState29(null);
26291
27262
  const boardFocusRef = useRef17(null);
26292
27263
  if (!boardFocusRef.current) {
@@ -26442,6 +27413,7 @@ function App({
26442
27413
  dispatch
26443
27414
  });
26444
27415
  const onMeasure = useCallback12((totalLines) => {
27416
+ if (totalLines === stateRef.current.totalLines) return;
26445
27417
  dispatch({ type: "setMeasuredLines", totalLines });
26446
27418
  }, []);
26447
27419
  const liveDirector = useCallback12(
@@ -28484,6 +29456,8 @@ Available chords:
28484
29456
  const [enhanceCountdown, setEnhanceCountdown] = useState29(null);
28485
29457
  const [enhanceStartedAt, setEnhanceStartedAt] = useState29(null);
28486
29458
  const [enhanceDurationMs, setEnhanceDurationMs] = useState29(null);
29459
+ const [refineProviderId, setRefineProviderId] = useState29(null);
29460
+ const [refineModel, setRefineModel] = useState29(null);
28487
29461
  const [nextStepsAutoSubmitCountdown, setNextStepsAutoSubmitCountdown] = useState29(
28488
29462
  null
28489
29463
  );
@@ -30108,6 +31082,8 @@ ${content}
30108
31082
  const attemptStartedAt = Date.now();
30109
31083
  setEnhanceStartedAt(attemptStartedAt);
30110
31084
  setEnhanceDurationMs(null);
31085
+ setRefineProviderId(provider2.id);
31086
+ setRefineModel(model2);
30111
31087
  enhanceAbortRef.current = ac;
30112
31088
  dispatch({ type: "enhanceBusy", on: true });
30113
31089
  let out = null;
@@ -30900,8 +31876,8 @@ ${content}
30900
31876
  original: enhanceOriginalRef.current,
30901
31877
  elapsedMs: enhanceStartedAt === null ? 0 : Math.max(0, Date.now() - enhanceStartedAt),
30902
31878
  pulseFrame: enhanceDots,
30903
- providerId: agent.ctx.provider?.id,
30904
- model: agent.ctx.model
31879
+ providerId: refineProviderId ?? agent.ctx.provider?.id,
31880
+ model: refineModel ?? agent.ctx.model
30905
31881
  }
30906
31882
  ) : null,
30907
31883
  state.enhance ? (() => {
@@ -30924,8 +31900,8 @@ ${content}
30924
31900
  enhanceLanguage: state.settingsPicker.enhanceLanguage,
30925
31901
  onDecision,
30926
31902
  onTick: (r) => setEnhanceCountdown(r > 0 ? r : null),
30927
- providerId: agent.ctx.provider?.id,
30928
- model: agent.ctx.model
31903
+ providerId: refineProviderId ?? agent.ctx.provider?.id,
31904
+ model: refineModel ?? agent.ctx.model
30929
31905
  }
30930
31906
  );
30931
31907
  })() : null,
@@ -31675,6 +32651,7 @@ async function runTui(opts) {
31675
32651
  provider: opts.provider,
31676
32652
  family: opts.family,
31677
32653
  keyTail: opts.keyTail,
32654
+ profile: opts.profile,
31678
32655
  autonomyAgents: opts.autonomyAgents,
31679
32656
  getPickableProviders: opts.getPickableProviders,
31680
32657
  switchProviderAndModel: opts.switchProviderAndModel,