@wrongstack/tui 0.298.3 → 0.299.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-action-type.d.ts +18 -0
- package/dist/app-key-handler.d.ts +25 -0
- package/dist/app-settings-type.d.ts +2 -3
- package/dist/app-ui-state.d.ts +53 -1
- package/dist/brain-panel-model.d.ts +67 -0
- package/dist/components/history/entry.d.ts +15 -0
- package/dist/components/settings-picker-model.d.ts +1 -1
- package/dist/components/sidebar-content.d.ts +16 -0
- package/dist/history-entry.d.ts +39 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +348 -73
- package/dist/settings-contracts.d.ts +3 -1
- package/package.json +7 -7
|
@@ -940,6 +940,24 @@ export type Action = {
|
|
|
940
940
|
type: 'sidebarScroll';
|
|
941
941
|
delta: number;
|
|
942
942
|
viewportHeight?: number | undefined;
|
|
943
|
+
/**
|
|
944
|
+
* Rows occupied by routed twin panels (Todos / Plan / Kanban / …)
|
|
945
|
+
* mounted above `SidebarContent` inside `RightSidebar`. Subtracted
|
|
946
|
+
* from `viewportHeight` so the scroll clamp matches the actual
|
|
947
|
+
* viewport the user can scroll through. Defaults to 0 (no twins
|
|
948
|
+
* mounted) when omitted so existing call sites stay correct.
|
|
949
|
+
*/
|
|
950
|
+
sidebarTwinRowCount?: number | undefined;
|
|
951
|
+
/**
|
|
952
|
+
* Whether the swarm panel is on the sidebar using the effective
|
|
953
|
+
* source (picker draft when the picker is open, persisted
|
|
954
|
+
* `liveSettings` otherwise — see `app-view.tsx`). Drives the
|
|
955
|
+
* mission-queue reservation in `computeMaxSidebarScroll`; without
|
|
956
|
+
* this field the reducer only sees the picker draft and under-
|
|
957
|
+
* reserves the mission card when a config-only 'sidebar' swarm
|
|
958
|
+
* mode is persisted but the picker has never been opened.
|
|
959
|
+
*/
|
|
960
|
+
effectiveSwarmOnSidebar?: boolean | undefined;
|
|
943
961
|
}
|
|
944
962
|
/** Reset sidebar scroll offset to 0. */
|
|
945
963
|
| {
|
|
@@ -51,6 +51,31 @@ interface AppKeyHandlerOptions {
|
|
|
51
51
|
* scrollbar hit-tests use this instead of terminalColumns so the scrollbar
|
|
52
52
|
* track is correctly positioned to the left of the sidebar. */
|
|
53
53
|
mainColumnWidth: number;
|
|
54
|
+
/**
|
|
55
|
+
* Effective swarm-on-sidebar read: `panelPositions.fleet === 'sidebar'`
|
|
56
|
+
* OR the legacy `showAgentSwarmPanel === 'sidebar'` flag from
|
|
57
|
+
* `liveSettings`. The renderer at `app-view.tsx:897-899` reads
|
|
58
|
+
* ONLY the legacy `showAgentSwarmPanel` field (not the panel-
|
|
59
|
+
* position map) to decide whether to show the mission card; the
|
|
60
|
+
* scroll-clamp reservation must match that source or a config-only
|
|
61
|
+
* legacy 'sidebar' swarm mode (no recent picker open) will render
|
|
62
|
+
* the mission card but the clamp will under-reserve, hiding the
|
|
63
|
+
* bottom mission rows behind `RightSidebar`'s `overflowY="hidden"`
|
|
64
|
+
* viewport. The OR with `panelPositions.fleet` is directionally
|
|
65
|
+
* safe (over-reservation is harmless) and aligns with the field
|
|
66
|
+
* that gates whether the swarm twin is mounted. See
|
|
67
|
+
* {@link SidebarLayoutState.effectiveSwarmOnSidebar}. Threaded into
|
|
68
|
+
* `sidebarScroll` dispatches so the reducer's mission-queue
|
|
69
|
+
* reservation matches the actual render.
|
|
70
|
+
*/
|
|
71
|
+
effectiveSwarmOnSidebar: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Approximate row count for routed sidebar twin panels mounted above
|
|
74
|
+
* `SidebarContent`. Subtracted from `viewportHeight` by the reducer's
|
|
75
|
+
* scroll clamp so the user can't scroll past the end into blank space.
|
|
76
|
+
* See {@link SidebarLayoutState.sidebarTwinRowCount}.
|
|
77
|
+
*/
|
|
78
|
+
sidebarTwinRowCount: number;
|
|
54
79
|
statusBarWrapRef: MutableRefObject<DOMElement | null>;
|
|
55
80
|
belowStatusBarRef: MutableRefObject<DOMElement | null>;
|
|
56
81
|
liveStatuslineMode: string;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { FleetChatVerbosity, TokenSavingTier } from '@wrongstack/core/types';
|
|
2
|
-
import type { CacheTtl, ContextMode, ReasoningEffort, StatuslineMode } from './settings-contracts.js';
|
|
2
|
+
import type { AgentSwarmPanelMode, CacheTtl, ContextMode, ReasoningEffort, StatuslineMode } from './settings-contracts.js';
|
|
3
3
|
export type { PanelId, PanelPosition, PanelPositionMap } from './ui-contracts.js';
|
|
4
4
|
export { coercePanelPositionMap, DEFAULT_PANEL_POSITIONS, PANEL_IDS, } from './ui-contracts.js';
|
|
5
5
|
import type { PanelPositionMap } from './ui-contracts.js';
|
|
6
|
-
|
|
7
|
-
export type AgentSwarmPanelMode = 'bottom' | 'sidebar' | 'off';
|
|
6
|
+
export type { AgentSwarmPanelMode } from './settings-contracts.js';
|
|
8
7
|
/**
|
|
9
8
|
* Coerce a persisted showAgentSwarmPanel value (which may be a legacy boolean
|
|
10
9
|
* or the new tri-state string) into a valid AgentSwarmPanelMode.
|
package/dist/app-ui-state.d.ts
CHANGED
|
@@ -18,6 +18,25 @@ export interface SidebarLayoutState {
|
|
|
18
18
|
/** Width AppView must pass to nested routed sidebar panel frames. */
|
|
19
19
|
sidebarContentWidth: number;
|
|
20
20
|
mainColumnWidth: number;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the swarm panel (`AgentSwarmPanelMode === 'sidebar'`) is
|
|
23
|
+
* effective on the right sidebar using the dual source: picker draft
|
|
24
|
+
* when `state.settingsPicker.open`, persisted `liveSettings.panelPositions`
|
|
25
|
+
* otherwise. Mirrors the renderer-side read in `app-view.tsx` so the
|
|
26
|
+
* scroll-clamp reducer can reserve the mission-queue rows even when
|
|
27
|
+
* the persisted config never went through the picker UI.
|
|
28
|
+
*/
|
|
29
|
+
effectiveSwarmOnSidebar: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Approximate row count for routed sidebar twin panels mounted above
|
|
32
|
+
* `SidebarContent` inside `RightSidebar`. The reducer subtracts this
|
|
33
|
+
* from `viewportHeight` when computing the sidebar scroll clamp so the
|
|
34
|
+
* user can't scroll past the end into blank space when one or more
|
|
35
|
+
* routed twins are mounted. Each twin contributes a per-panel
|
|
36
|
+
* `ESTIMATED_HEIGHT` constant; over-estimation is safe (existing
|
|
37
|
+
* convention — see `SIDEBAR_MISSION_MAX_WRAP_LINES` docstring).
|
|
38
|
+
*/
|
|
39
|
+
sidebarTwinRowCount: number;
|
|
21
40
|
}
|
|
22
41
|
/**
|
|
23
42
|
* Resolve the TUI's right-sidebar layout once from the open-panel flags and
|
|
@@ -25,5 +44,38 @@ export interface SidebarLayoutState {
|
|
|
25
44
|
* this so a sidebar-routed panel narrows history consistently instead of
|
|
26
45
|
* being treated as a full-width overlay by one surface.
|
|
27
46
|
*/
|
|
28
|
-
export declare function resolveSidebarLayout(state: State, termCols: number, panelPositionsInput: Partial<Record<PanelId, 'bottom' | 'sidebar'>> | undefined, mailboxPanelOpen: boolean
|
|
47
|
+
export declare function resolveSidebarLayout(state: State, termCols: number, panelPositionsInput: Partial<Record<PanelId, 'bottom' | 'sidebar'>> | undefined, mailboxPanelOpen: boolean,
|
|
48
|
+
/**
|
|
49
|
+
* Open flags for each routable panel, used to compute the visible-twin
|
|
50
|
+
* row count for the scroll-clamp reservation. Panels not listed
|
|
51
|
+
* (or `undefined`) are treated as closed. Should mirror the same
|
|
52
|
+
* `sidebarPanelOpenFlags` map built in `app-view.tsx` so the
|
|
53
|
+
* dispatcher and the renderer agree on which twins are mounted.
|
|
54
|
+
*/
|
|
55
|
+
sidebarOpenFlags?: Partial<Record<PanelId, boolean>> | undefined,
|
|
56
|
+
/**
|
|
57
|
+
* Legacy `showAgentSwarmPanel === 'sidebar'` flag from the persisted
|
|
58
|
+
* `liveSettings` config — the same field the renderer at
|
|
59
|
+
* `app-view.tsx:897-899` reads (picker draft when open, persisted
|
|
60
|
+
* `liveSettings.showAgentSwarmPanel` when closed) to decide whether
|
|
61
|
+
* the mission card renders on the sidebar. The scroll-clamp
|
|
62
|
+
* reservation must match this source or a config-only 'sidebar'
|
|
63
|
+
* swarm mode (no recent picker open) renders the mission card but
|
|
64
|
+
* the clamp under-reserves, hiding the bottom mission rows behind
|
|
65
|
+
* `RightSidebar`'s `overflowY="hidden"` viewport. OR'd with
|
|
66
|
+
* `panelPositions.fleet === 'sidebar'` for safety (over-reservation
|
|
67
|
+
* is harmless). Defaults to `false` when omitted so existing call
|
|
68
|
+
* sites stay correct.
|
|
69
|
+
*/
|
|
70
|
+
legacySwarmOnSidebar?: boolean | undefined): SidebarLayoutState;
|
|
71
|
+
/**
|
|
72
|
+
* Conservative row-height estimate for any routed sidebar twin panel.
|
|
73
|
+
* Each twin renders a 1-row header + a 1-row separator + variable content +
|
|
74
|
+
* optional 1-row footer. 8 rows covers the natural height of the
|
|
75
|
+
* content-rich twins (Todos / Plan / Kanban / Goal / Sessions /
|
|
76
|
+
* Coordinator) without overshooting the simpler ones (Fleet / Worktree /
|
|
77
|
+
* etc.). Over-estimation is safe; the scroll-clamp subtracts this from
|
|
78
|
+
* `viewportHeight`.
|
|
79
|
+
*/
|
|
80
|
+
export declare const ESTIMATED_TWIN_HEIGHT = 8;
|
|
29
81
|
//# sourceMappingURL=app-ui-state.d.ts.map
|
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
* persist to the global config).
|
|
8
8
|
*/
|
|
9
9
|
import type { BrainRiskLevel } from './brain-contracts.js';
|
|
10
|
+
/** One selectable Council decision lens, as published by the host. */
|
|
11
|
+
export interface BrainPanelPersona {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
/** Seats using this lens get veto power unless the seat overrides it. */
|
|
16
|
+
defaultVeto?: boolean | undefined;
|
|
17
|
+
}
|
|
10
18
|
/** One configured pool entry / council voter, display-mapped. */
|
|
11
19
|
export interface BrainPanelVoter {
|
|
12
20
|
label: string;
|
|
@@ -43,8 +51,26 @@ export interface BrainPanelSettings {
|
|
|
43
51
|
usingSessionModel: boolean;
|
|
44
52
|
councilEnabled: boolean;
|
|
45
53
|
councilMinRisk: 'medium' | 'high' | 'critical';
|
|
54
|
+
/** Fraction of seats that must return a valid vote (undefined = default 0.5). */
|
|
55
|
+
councilQuorum?: number | undefined;
|
|
56
|
+
/** Fraction of cast weight the winner must exceed (undefined = default 0.5). */
|
|
57
|
+
councilApproval?: number | undefined;
|
|
58
|
+
/** Panel-diversity warning policy. A same-model panel agrees with itself. */
|
|
59
|
+
councilDistinctness: 'none' | 'model' | 'provider';
|
|
60
|
+
/** Per-seat completion timeout (undefined = inherit the decision timeout). */
|
|
61
|
+
councilPerCallTimeoutMs?: number | undefined;
|
|
62
|
+
/** Seats polled concurrently, 1..8 (undefined = default 3). */
|
|
63
|
+
councilMaxConcurrency?: number | undefined;
|
|
64
|
+
/** Output budget for the judge call (undefined = follows the seat budget). */
|
|
65
|
+
councilJudgeMaxTokens?: number | undefined;
|
|
46
66
|
/** Explicitly configured voters (empty = seats derive from the pool). */
|
|
47
67
|
voters: BrainPanelVoter[];
|
|
68
|
+
/**
|
|
69
|
+
* Selectable decision lenses, published by the host from the Council persona
|
|
70
|
+
* registry. Absent on hosts that predate the catalog — `personaCycle()` then
|
|
71
|
+
* falls back to the three lenses the panel used to hard-code.
|
|
72
|
+
*/
|
|
73
|
+
personaCatalog?: BrainPanelPersona[] | undefined;
|
|
48
74
|
/** Effective council seat labels (empty = council disabled). */
|
|
49
75
|
councilSeats: string[];
|
|
50
76
|
/**
|
|
@@ -110,6 +136,17 @@ export interface BrainPanelHost {
|
|
|
110
136
|
toggleVoterVeto(index: number): Promise<string | null>;
|
|
111
137
|
setJudge(providerId: string, model: string): Promise<string | null>;
|
|
112
138
|
clearJudge(): Promise<string | null>;
|
|
139
|
+
setCouncilQuorum(fraction: number): Promise<string | null>;
|
|
140
|
+
setCouncilApproval(fraction: number): Promise<string | null>;
|
|
141
|
+
setCouncilDistinctness(mode: 'none' | 'model' | 'provider'): Promise<string | null>;
|
|
142
|
+
/**
|
|
143
|
+
* The three positive-integer council knobs. `undefined` clears back to the
|
|
144
|
+
* default — unlike the LLM/cache ladders, `BrainCouncilPatch` accepts `null`
|
|
145
|
+
* for these, so a "default" rung is reachable here.
|
|
146
|
+
*/
|
|
147
|
+
setCouncilPerCallTimeout(ms: number | undefined): Promise<string | null>;
|
|
148
|
+
setCouncilMaxConcurrency(count: number | undefined): Promise<string | null>;
|
|
149
|
+
setCouncilJudgeMaxTokens(tokens: number | undefined): Promise<string | null>;
|
|
113
150
|
setLedgerEnabled(on: boolean): Promise<string | null>;
|
|
114
151
|
setAutoDeny(count: number | undefined): Promise<string | null>;
|
|
115
152
|
setTerminalPolicy(policy: BrainTerminalPolicyValue): Promise<string | null>;
|
|
@@ -157,6 +194,18 @@ export type BrainPanelRow = {
|
|
|
157
194
|
kind: 'voterAdd';
|
|
158
195
|
} | {
|
|
159
196
|
kind: 'judge';
|
|
197
|
+
} | {
|
|
198
|
+
kind: 'councilQuorum';
|
|
199
|
+
} | {
|
|
200
|
+
kind: 'councilApproval';
|
|
201
|
+
} | {
|
|
202
|
+
kind: 'councilDistinctness';
|
|
203
|
+
} | {
|
|
204
|
+
kind: 'councilTimeout';
|
|
205
|
+
} | {
|
|
206
|
+
kind: 'councilConcurrency';
|
|
207
|
+
} | {
|
|
208
|
+
kind: 'councilJudgeMaxTokens';
|
|
160
209
|
} | {
|
|
161
210
|
kind: 'ledgerToggle';
|
|
162
211
|
} | {
|
|
@@ -224,7 +273,25 @@ export declare const LLM_MAX_TOKENS_PRESETS: readonly number[];
|
|
|
224
273
|
export declare const LLM_MIN_CONFIDENCE_PRESETS: readonly number[];
|
|
225
274
|
export declare const CACHE_TTL_PRESETS: readonly number[];
|
|
226
275
|
export declare const CACHE_MAX_ENTRIES_PRESETS: readonly number[];
|
|
276
|
+
/**
|
|
277
|
+
* Council ladders. `undefined` is the "default" rung — `BrainCouncilPatch`
|
|
278
|
+
* accepts `null` for these three, unlike the LLM/cache knobs.
|
|
279
|
+
*/
|
|
280
|
+
export declare const COUNCIL_FRACTION_PRESETS: readonly number[];
|
|
281
|
+
export declare const COUNCIL_DISTINCTNESS_PRESETS: ReadonlyArray<'none' | 'model' | 'provider'>;
|
|
282
|
+
export declare const COUNCIL_TIMEOUT_PRESETS: ReadonlyArray<number | undefined>;
|
|
283
|
+
export declare const COUNCIL_CONCURRENCY_PRESETS: ReadonlyArray<number | undefined>;
|
|
284
|
+
export declare const COUNCIL_JUDGE_MAX_TOKENS_PRESETS: ReadonlyArray<number | undefined>;
|
|
285
|
+
/**
|
|
286
|
+
* Fallback lens cycle for hosts that publish no `personaCatalog`. Prefer
|
|
287
|
+
* {@link personaCycle}, which uses the host's catalog when it is available —
|
|
288
|
+
* the registry ships six lenses, not these three.
|
|
289
|
+
*/
|
|
227
290
|
export declare const PERSONA_CYCLE: readonly ['executor', 'skeptic', 'auditor'];
|
|
291
|
+
/** Lens ids the panel may cycle through for the given settings snapshot. */
|
|
292
|
+
export declare function personaCycle(settings: BrainPanelSettings): readonly string[];
|
|
293
|
+
/** Human-readable lens name for a persona id, falling back to the id itself. */
|
|
294
|
+
export declare function personaLabel(settings: BrainPanelSettings, id: string | undefined): string;
|
|
228
295
|
/** Cycle helper: step through a preset ladder from the current value. */
|
|
229
296
|
export declare function cyclePreset<T>(presets: ReadonlyArray<T>, current: T, delta: number): T;
|
|
230
297
|
//# sourceMappingURL=brain-panel-model.d.ts.map
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { TodoItem } from '@wrongstack/core/agent';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import type { HistoryEntry } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* One-line summary of how a council resolved.
|
|
6
|
+
*
|
|
7
|
+
* `distinctTargetCount` is on the headline on purpose: a panel where several
|
|
8
|
+
* seats resolved to the SAME model produces a perfectly normal-looking verdict
|
|
9
|
+
* while adding cost without adding independence, and that is invisible unless
|
|
10
|
+
* the count is shown next to the seat count.
|
|
11
|
+
*/
|
|
12
|
+
export declare function councilHeadline(council: NonNullable<Extract<HistoryEntry, {
|
|
13
|
+
kind: 'brain';
|
|
14
|
+
}>['council']>): string;
|
|
15
|
+
/** One seat's line under the council headline. */
|
|
16
|
+
export declare function councilSeatLine(seat: NonNullable<Extract<HistoryEntry, {
|
|
17
|
+
kind: 'brain';
|
|
18
|
+
}>['council']>['seats'][number]): string;
|
|
4
19
|
export declare const Entry: React.MemoExoticComponent<({ entry, termWidth, termHeight, setSuggestions, autonomyMode, multiDiffSummaryThreshold, todos, showModelReasoning, showSageMemoryInject, }: {
|
|
5
20
|
entry: HistoryEntry;
|
|
6
21
|
termWidth: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SettingsPickerPatch } from '../settings-contracts.js';
|
|
1
|
+
import type { SettingsPickerPatch } from '../settings-contracts.js';
|
|
2
2
|
/** Selectable presets for the auto-proceed delay, so the field is fully
|
|
3
3
|
* keyboard-cyclable (←/→) instead of needing typed numeric input. */
|
|
4
4
|
export declare const DELAY_PRESETS_MS: number[];
|
|
@@ -43,5 +43,21 @@ export interface SidebarContentProps {
|
|
|
43
43
|
/** The current session ID — used to highlight the active session row. */
|
|
44
44
|
currentSessionId?: string | undefined;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Normalized "is this session row the current session?" predicate used by
|
|
48
|
+
* both the `SidebarContent` SESSIONS card (live + resume rows) and the
|
|
49
|
+
* `SessionsPanelSidebar` (sidebar twin). The runtime `currentSessionId`
|
|
50
|
+
* is the authoritative source — when defined, the row whose id matches
|
|
51
|
+
* is the current row. When undefined (e.g. before the host registers a
|
|
52
|
+
* session), the per-row `isCurrent` flag is the fallback (carried over
|
|
53
|
+
* from the resume-picker domain for the case where the picker marks
|
|
54
|
+
* the current session as non-resumable but the host hasn't published
|
|
55
|
+
* the runtime id yet). A row without an id can never be the current
|
|
56
|
+
* row, regardless of what its fallback flag says. The two SESSIONS
|
|
57
|
+
* rows used to disagree on which key to read (live used strict id
|
|
58
|
+
* compare, resume used `rs.isCurrent` first); this helper is the
|
|
59
|
+
* single source of truth.
|
|
60
|
+
*/
|
|
61
|
+
export declare function isCurrentSession(rowId: string | undefined, currentSessionId: string | undefined, fallbackIsCurrent?: boolean | undefined): boolean;
|
|
46
62
|
export declare function SidebarContent({ contextWindow, entries, fleetCounts, provider, model, width, scrollOffset, focused, todos, showSwarmSection, liveSessions, resumeSessions, currentSessionId, }: SidebarContentProps): React.ReactElement;
|
|
47
63
|
//# sourceMappingURL=sidebar-content.d.ts.map
|
package/dist/history-entry.d.ts
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
/** Render-neutral conversation entry contracts retained by TUI state. */
|
|
2
|
+
/** One seat's observable vote. No hidden chain-of-thought is retained. */
|
|
3
|
+
export interface BrainCouncilSeatTrace {
|
|
4
|
+
seatId: string;
|
|
5
|
+
persona: string;
|
|
6
|
+
status: 'valid' | 'invalid' | 'failed' | 'cancelled';
|
|
7
|
+
/** The option the seat voted for, when the question was option-bearing. */
|
|
8
|
+
optionId?: string | undefined;
|
|
9
|
+
model?: string | undefined;
|
|
10
|
+
veto?: boolean | undefined;
|
|
11
|
+
durationMs?: number | undefined;
|
|
12
|
+
error?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Panel summary attached to a council-tier Brain entry.
|
|
16
|
+
*
|
|
17
|
+
* The council is by far the most expensive tier — N provider calls per
|
|
18
|
+
* decision — and used to be entirely invisible: the votes were emitted onto
|
|
19
|
+
* the bus but no surface consumed them, so a slow, costly decision looked
|
|
20
|
+
* identical to a free policy one.
|
|
21
|
+
*/
|
|
22
|
+
export interface BrainCouncilTrace {
|
|
23
|
+
resolution: string;
|
|
24
|
+
configuredSeatCount: number;
|
|
25
|
+
validVoteCount: number;
|
|
26
|
+
/** Distinct provider/model targets that served the valid votes. */
|
|
27
|
+
distinctTargetCount: number;
|
|
28
|
+
judgeUsed: boolean;
|
|
29
|
+
totalTokens?: number | undefined;
|
|
30
|
+
durationMs?: number | undefined;
|
|
31
|
+
/** Structural warnings — most importantly a CORRELATED (non-diverse) panel. */
|
|
32
|
+
warnings?: string[] | undefined;
|
|
33
|
+
seats: BrainCouncilSeatTrace[];
|
|
34
|
+
}
|
|
2
35
|
export interface AutonomyAgentStatus {
|
|
3
36
|
/** Short display name (e.g. "Brain", "Shadow", "Kanban", "Mailbox", "Memory"). */
|
|
4
37
|
name: string;
|
|
@@ -185,6 +218,12 @@ export type HistoryEntry = {
|
|
|
185
218
|
rationale?: string | undefined;
|
|
186
219
|
outcome?: string | undefined;
|
|
187
220
|
interventionKind?: string | undefined;
|
|
221
|
+
/**
|
|
222
|
+
* How the multi-LLM council reached this verdict, when a council decided
|
|
223
|
+
* it. Present only for council-tier decisions; the single-LLM and policy
|
|
224
|
+
* tiers leave it undefined.
|
|
225
|
+
*/
|
|
226
|
+
council?: BrainCouncilTrace | undefined;
|
|
188
227
|
} | {
|
|
189
228
|
id: number;
|
|
190
229
|
kind: 'banner';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { Settings } from './app.js';
|
|
2
2
|
export { buildGoalPreamble } from './app.js';
|
|
3
3
|
export type { AuthCatalogRow, AuthFlowIo, AuthFlowResult, AuthKeyRow, AuthLocalPresetRow, AuthOAuthKind, AuthPanelHost, AuthProviderRow, } from './auth-panel-model.js';
|
|
4
|
-
export type { BrainDenyIsTerminal, BrainHeuristicKey, BrainPanelHeuristics, BrainPanelHost, BrainPanelSettings, BrainPanelVoter, BrainTerminalPolicyValue, BrainTraceContent, } from './brain-panel-model.js';
|
|
4
|
+
export type { BrainDenyIsTerminal, BrainHeuristicKey, BrainPanelHeuristics, BrainPanelHost, BrainPanelPersona, BrainPanelSettings, BrainPanelVoter, BrainTerminalPolicyValue, BrainTraceContent, } from './brain-panel-model.js';
|
|
5
5
|
export { replaySessionMessages } from './components/history/replay.js';
|
|
6
6
|
export type { PluginPickerItem } from './components/plugin-picker.js';
|
|
7
7
|
export type { ParsedNextStep, ParseNextStepsResult } from './components/suggestions.js';
|
package/dist/index.js
CHANGED
|
@@ -3827,6 +3827,14 @@ function brainPanelRows(settings) {
|
|
|
3827
3827
|
rows.push({ kind: "councilMinRisk" });
|
|
3828
3828
|
for (let i = 0; i < voters.length; i += 1) rows.push({ kind: "voter", index: i });
|
|
3829
3829
|
rows.push({ kind: "voterAdd" }, { kind: "judge" });
|
|
3830
|
+
rows.push(
|
|
3831
|
+
{ kind: "councilQuorum" },
|
|
3832
|
+
{ kind: "councilApproval" },
|
|
3833
|
+
{ kind: "councilDistinctness" },
|
|
3834
|
+
{ kind: "councilTimeout" },
|
|
3835
|
+
{ kind: "councilConcurrency" },
|
|
3836
|
+
{ kind: "councilJudgeMaxTokens" }
|
|
3837
|
+
);
|
|
3830
3838
|
}
|
|
3831
3839
|
rows.push({ kind: "ledgerToggle" });
|
|
3832
3840
|
if (settings.ledgerEnabled) rows.push({ kind: "autoDeny" });
|
|
@@ -3876,6 +3884,39 @@ var CACHE_TTL_PRESETS = [
|
|
|
3876
3884
|
36e5
|
|
3877
3885
|
];
|
|
3878
3886
|
var CACHE_MAX_ENTRIES_PRESETS = [50, 100, 200, 500, 1e3];
|
|
3887
|
+
var COUNCIL_FRACTION_PRESETS = [0.25, 0.5, 0.6, 0.67, 0.75, 1];
|
|
3888
|
+
var COUNCIL_DISTINCTNESS_PRESETS = [
|
|
3889
|
+
"none",
|
|
3890
|
+
"model",
|
|
3891
|
+
"provider"
|
|
3892
|
+
];
|
|
3893
|
+
var COUNCIL_TIMEOUT_PRESETS = [
|
|
3894
|
+
void 0,
|
|
3895
|
+
1e4,
|
|
3896
|
+
15e3,
|
|
3897
|
+
3e4,
|
|
3898
|
+
6e4
|
|
3899
|
+
];
|
|
3900
|
+
var COUNCIL_CONCURRENCY_PRESETS = [
|
|
3901
|
+
void 0,
|
|
3902
|
+
1,
|
|
3903
|
+
2,
|
|
3904
|
+
3,
|
|
3905
|
+
4,
|
|
3906
|
+
6,
|
|
3907
|
+
8
|
|
3908
|
+
];
|
|
3909
|
+
var COUNCIL_JUDGE_MAX_TOKENS_PRESETS = [
|
|
3910
|
+
void 0,
|
|
3911
|
+
300,
|
|
3912
|
+
500,
|
|
3913
|
+
700,
|
|
3914
|
+
1200
|
|
3915
|
+
];
|
|
3916
|
+
function personaLabel(settings, id) {
|
|
3917
|
+
if (!id) return "voter";
|
|
3918
|
+
return settings.personaCatalog?.find((persona) => persona.id === id)?.name ?? id;
|
|
3919
|
+
}
|
|
3879
3920
|
function cyclePreset(presets, current, delta) {
|
|
3880
3921
|
const idx = presets.indexOf(current);
|
|
3881
3922
|
const from = idx >= 0 ? idx : 0;
|
|
@@ -7257,6 +7298,50 @@ function useBrainPanel(opts) {
|
|
|
7257
7298
|
runBrainMutation(() => host.setCouncilMinRisk(next));
|
|
7258
7299
|
return;
|
|
7259
7300
|
}
|
|
7301
|
+
case "councilQuorum":
|
|
7302
|
+
runBrainMutation(
|
|
7303
|
+
() => host.setCouncilQuorum(
|
|
7304
|
+
cyclePreset(COUNCIL_FRACTION_PRESETS, settings.councilQuorum ?? 0.5, delta)
|
|
7305
|
+
)
|
|
7306
|
+
);
|
|
7307
|
+
return;
|
|
7308
|
+
case "councilApproval":
|
|
7309
|
+
runBrainMutation(
|
|
7310
|
+
() => host.setCouncilApproval(
|
|
7311
|
+
cyclePreset(COUNCIL_FRACTION_PRESETS, settings.councilApproval ?? 0.5, delta)
|
|
7312
|
+
)
|
|
7313
|
+
);
|
|
7314
|
+
return;
|
|
7315
|
+
case "councilDistinctness": {
|
|
7316
|
+
const next = cycleEnum(
|
|
7317
|
+
COUNCIL_DISTINCTNESS_PRESETS,
|
|
7318
|
+
settings.councilDistinctness,
|
|
7319
|
+
delta
|
|
7320
|
+
);
|
|
7321
|
+
runBrainMutation(() => host.setCouncilDistinctness(next));
|
|
7322
|
+
return;
|
|
7323
|
+
}
|
|
7324
|
+
case "councilTimeout":
|
|
7325
|
+
runBrainMutation(
|
|
7326
|
+
() => host.setCouncilPerCallTimeout(
|
|
7327
|
+
cyclePreset(COUNCIL_TIMEOUT_PRESETS, settings.councilPerCallTimeoutMs, delta)
|
|
7328
|
+
)
|
|
7329
|
+
);
|
|
7330
|
+
return;
|
|
7331
|
+
case "councilConcurrency":
|
|
7332
|
+
runBrainMutation(
|
|
7333
|
+
() => host.setCouncilMaxConcurrency(
|
|
7334
|
+
cyclePreset(COUNCIL_CONCURRENCY_PRESETS, settings.councilMaxConcurrency, delta)
|
|
7335
|
+
)
|
|
7336
|
+
);
|
|
7337
|
+
return;
|
|
7338
|
+
case "councilJudgeMaxTokens":
|
|
7339
|
+
runBrainMutation(
|
|
7340
|
+
() => host.setCouncilJudgeMaxTokens(
|
|
7341
|
+
cyclePreset(COUNCIL_JUDGE_MAX_TOKENS_PRESETS, settings.councilJudgeMaxTokens, delta)
|
|
7342
|
+
)
|
|
7343
|
+
);
|
|
7344
|
+
return;
|
|
7260
7345
|
case "ledgerToggle":
|
|
7261
7346
|
runBrainMutation(() => host.setLedgerEnabled(!settings.ledgerEnabled));
|
|
7262
7347
|
return;
|
|
@@ -14626,7 +14711,8 @@ function reduceSettingsValues(state, action) {
|
|
|
14626
14711
|
}
|
|
14627
14712
|
|
|
14628
14713
|
// src/reducers/workspace-panels.ts
|
|
14629
|
-
|
|
14714
|
+
var SIDEBAR_MISSION_MAX_WRAP_LINES = 10;
|
|
14715
|
+
function computeMaxSidebarScroll(state, viewportHeight = 20, effectiveSwarmOnSidebar) {
|
|
14630
14716
|
let contentHeight = 0;
|
|
14631
14717
|
contentHeight += 4;
|
|
14632
14718
|
contentHeight += 3;
|
|
@@ -14644,9 +14730,9 @@ function computeMaxSidebarScroll(state, viewportHeight = 20) {
|
|
|
14644
14730
|
if (runningSubagents.length > agentCap) contentHeight += 1;
|
|
14645
14731
|
contentHeight += 1;
|
|
14646
14732
|
}
|
|
14647
|
-
const
|
|
14648
|
-
if (
|
|
14649
|
-
contentHeight += 1 + SIDEBAR_MISSION_ROWS + 1 + 1;
|
|
14733
|
+
const swarmOnSidebar = effectiveSwarmOnSidebar ?? state.settingsPicker.showAgentSwarmPanel === "sidebar";
|
|
14734
|
+
if (swarmOnSidebar) {
|
|
14735
|
+
contentHeight += 1 + SIDEBAR_MISSION_ROWS * SIDEBAR_MISSION_MAX_WRAP_LINES + 1 + 1;
|
|
14650
14736
|
}
|
|
14651
14737
|
const liveSessionCount = state.sessionsPanel.sessions.length;
|
|
14652
14738
|
const resumeSessionCount = state.resumePicker.sessions.length;
|
|
@@ -14742,9 +14828,11 @@ function reduceWorkspacePanels(state, action) {
|
|
|
14742
14828
|
case "toggleSidebarFocus":
|
|
14743
14829
|
return state.sidebarFocused ? { ...state, sidebarFocused: false, sidebarScrollOffset: 0 } : { ...state, sidebarFocused: true };
|
|
14744
14830
|
case "sidebarScroll": {
|
|
14831
|
+
const adjustedViewportHeight = (action.viewportHeight ?? 20) - (action.sidebarTwinRowCount ?? 0);
|
|
14745
14832
|
const maxScroll = computeMaxSidebarScroll(
|
|
14746
14833
|
state,
|
|
14747
|
-
|
|
14834
|
+
Math.max(1, adjustedViewportHeight),
|
|
14835
|
+
action.effectiveSwarmOnSidebar
|
|
14748
14836
|
);
|
|
14749
14837
|
return {
|
|
14750
14838
|
...state,
|
|
@@ -19161,7 +19249,7 @@ import { useEffect as useEffect41 } from "react";
|
|
|
19161
19249
|
var MONITOR_INTERVENTION_GRACE_MS = 5e3;
|
|
19162
19250
|
function useBrainEvents(events, dispatch, getSessionId) {
|
|
19163
19251
|
useEffect41(() => {
|
|
19164
|
-
const
|
|
19252
|
+
const isCurrentSession2 = (sessionId) => {
|
|
19165
19253
|
const current = getSessionId?.();
|
|
19166
19254
|
return !sessionId || !current || sessionId === current;
|
|
19167
19255
|
};
|
|
@@ -19176,8 +19264,21 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19176
19264
|
return decision.reason;
|
|
19177
19265
|
}
|
|
19178
19266
|
};
|
|
19267
|
+
const councilTraces = /* @__PURE__ */ new Map();
|
|
19268
|
+
const councilVotes = /* @__PURE__ */ new Map();
|
|
19269
|
+
const COUNCIL_TRACE_MAX = 100;
|
|
19270
|
+
const capCouncilMap = (map) => {
|
|
19271
|
+
while (map.size > COUNCIL_TRACE_MAX) {
|
|
19272
|
+
const oldest = map.keys().next().value;
|
|
19273
|
+
if (oldest === void 0) break;
|
|
19274
|
+
map.delete(oldest);
|
|
19275
|
+
}
|
|
19276
|
+
};
|
|
19179
19277
|
const addBrainEntry = (status, payload) => {
|
|
19180
19278
|
const p = payload;
|
|
19279
|
+
const council = councilTraces.get(p.request.id);
|
|
19280
|
+
councilTraces.delete(p.request.id);
|
|
19281
|
+
councilVotes.delete(p.request.id);
|
|
19181
19282
|
const decision = decisionSummary(p.decision);
|
|
19182
19283
|
dispatch({ type: "brainStatus", state: status, source: p.request.source, risk: p.request.risk, summary: decision });
|
|
19183
19284
|
if (status === "ask_human") {
|
|
@@ -19194,7 +19295,7 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19194
19295
|
dispatch({ type: "brainPromptClear" });
|
|
19195
19296
|
}
|
|
19196
19297
|
const rationale = p.decision.type === "deny" ? void 0 : p.decision.rationale;
|
|
19197
|
-
dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale } });
|
|
19298
|
+
dispatch({ type: "addEntry", entry: { kind: "brain", status, source: p.request.source, risk: p.request.risk, question: p.request.question, decision, rationale, ...council ? { council } : {} } });
|
|
19198
19299
|
};
|
|
19199
19300
|
const pendingMonitorAnswers = /* @__PURE__ */ new Map();
|
|
19200
19301
|
const SHOWN_MONITOR_ANSWERS_MAX = 500;
|
|
@@ -19207,11 +19308,11 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19207
19308
|
}
|
|
19208
19309
|
};
|
|
19209
19310
|
const offRequested = events.on("brain.decision_requested", ({ sessionId, request }) => {
|
|
19210
|
-
if (!
|
|
19311
|
+
if (!isCurrentSession2(sessionId)) return;
|
|
19211
19312
|
dispatch({ type: "brainStatus", state: "deciding", source: request.source, risk: request.risk, summary: requestSummary(request) });
|
|
19212
19313
|
});
|
|
19213
19314
|
const offAnswered = events.on("brain.decision_answered", (payload) => {
|
|
19214
|
-
if (!
|
|
19315
|
+
if (!isCurrentSession2(payload.sessionId)) return;
|
|
19215
19316
|
if (!payload.request.id.startsWith("brainmon-")) {
|
|
19216
19317
|
addBrainEntry("answered", payload);
|
|
19217
19318
|
return;
|
|
@@ -19220,7 +19321,7 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19220
19321
|
if (previous) clearTimeout(previous);
|
|
19221
19322
|
const timer = setTimeout(() => {
|
|
19222
19323
|
pendingMonitorAnswers.delete(payload.request.id);
|
|
19223
|
-
if (
|
|
19324
|
+
if (isCurrentSession2(payload.sessionId)) {
|
|
19224
19325
|
rememberShownAnswer(payload.request.id);
|
|
19225
19326
|
addBrainEntry("answered", payload);
|
|
19226
19327
|
}
|
|
@@ -19229,13 +19330,52 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19229
19330
|
pendingMonitorAnswers.set(payload.request.id, timer);
|
|
19230
19331
|
});
|
|
19231
19332
|
const offAskHuman = events.on("brain.decision_ask_human", (payload) => {
|
|
19232
|
-
if (
|
|
19333
|
+
if (isCurrentSession2(payload.sessionId)) addBrainEntry("ask_human", payload);
|
|
19233
19334
|
});
|
|
19234
19335
|
const offDenied = events.on("brain.decision_denied", (payload) => {
|
|
19235
|
-
if (
|
|
19336
|
+
if (isCurrentSession2(payload.sessionId)) addBrainEntry("denied", payload);
|
|
19337
|
+
});
|
|
19338
|
+
const offCouncilVote = events.on("brain.council_vote", (payload) => {
|
|
19339
|
+
if (!isCurrentSession2(payload.sessionId)) return;
|
|
19340
|
+
const seats = councilVotes.get(payload.requestId) ?? [];
|
|
19341
|
+
seats.push({
|
|
19342
|
+
seatId: payload.seatId,
|
|
19343
|
+
persona: payload.persona,
|
|
19344
|
+
status: payload.status,
|
|
19345
|
+
optionId: payload.optionId,
|
|
19346
|
+
model: payload.model,
|
|
19347
|
+
veto: payload.veto,
|
|
19348
|
+
durationMs: payload.durationMs,
|
|
19349
|
+
error: payload.error
|
|
19350
|
+
});
|
|
19351
|
+
councilVotes.set(payload.requestId, seats);
|
|
19352
|
+
capCouncilMap(councilVotes);
|
|
19353
|
+
dispatch({
|
|
19354
|
+
type: "brainStatus",
|
|
19355
|
+
state: "deciding",
|
|
19356
|
+
source: "council",
|
|
19357
|
+
risk: "high",
|
|
19358
|
+
summary: `council \xB7 ${seats.length} seat${seats.length === 1 ? "" : "s"} voted`
|
|
19359
|
+
});
|
|
19360
|
+
});
|
|
19361
|
+
const offCouncilResolved = events.on("brain.council_resolved", (payload) => {
|
|
19362
|
+
if (!isCurrentSession2(payload.sessionId)) return;
|
|
19363
|
+
councilTraces.set(payload.requestId, {
|
|
19364
|
+
resolution: payload.resolution,
|
|
19365
|
+
configuredSeatCount: payload.configuredSeatCount,
|
|
19366
|
+
validVoteCount: payload.validVoteCount,
|
|
19367
|
+
distinctTargetCount: payload.distinctTargetCount,
|
|
19368
|
+
judgeUsed: payload.judgeUsed,
|
|
19369
|
+
totalTokens: payload.usage?.totalTokens,
|
|
19370
|
+
durationMs: payload.usage?.durationMs,
|
|
19371
|
+
...payload.warnings?.length ? { warnings: [...payload.warnings] } : {},
|
|
19372
|
+
seats: councilVotes.get(payload.requestId) ?? []
|
|
19373
|
+
});
|
|
19374
|
+
capCouncilMap(councilTraces);
|
|
19375
|
+
councilVotes.delete(payload.requestId);
|
|
19236
19376
|
});
|
|
19237
19377
|
const offIntervention = events.on("brain.intervention", (payload) => {
|
|
19238
|
-
if (!
|
|
19378
|
+
if (!isCurrentSession2(payload.sessionId)) return;
|
|
19239
19379
|
if (shownMonitorAnswers.has(payload.request.id)) return;
|
|
19240
19380
|
const pending = pendingMonitorAnswers.get(payload.request.id);
|
|
19241
19381
|
if (pending) {
|
|
@@ -19265,9 +19405,13 @@ function useBrainEvents(events, dispatch, getSessionId) {
|
|
|
19265
19405
|
offAnswered();
|
|
19266
19406
|
offAskHuman();
|
|
19267
19407
|
offDenied();
|
|
19408
|
+
offCouncilVote();
|
|
19409
|
+
offCouncilResolved();
|
|
19268
19410
|
offIntervention();
|
|
19269
19411
|
for (const timer of pendingMonitorAnswers.values()) clearTimeout(timer);
|
|
19270
19412
|
pendingMonitorAnswers.clear();
|
|
19413
|
+
councilTraces.clear();
|
|
19414
|
+
councilVotes.clear();
|
|
19271
19415
|
};
|
|
19272
19416
|
}, [events, dispatch, getSessionId]);
|
|
19273
19417
|
}
|
|
@@ -19324,13 +19468,13 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19324
19468
|
);
|
|
19325
19469
|
useEffect42(() => {
|
|
19326
19470
|
const seen = /* @__PURE__ */ new Set();
|
|
19327
|
-
const
|
|
19471
|
+
const isCurrentSession2 = (sessionId) => {
|
|
19328
19472
|
const current = getSessionId?.();
|
|
19329
19473
|
return !sessionId || !current || sessionId === current;
|
|
19330
19474
|
};
|
|
19331
19475
|
const mode = () => getChatMode?.() ?? "full";
|
|
19332
19476
|
const offSpawned = events.on("subagent.spawned", (e) => {
|
|
19333
|
-
if (!
|
|
19477
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19334
19478
|
if (sessionGenerationRef) gate.track(e.subagentId);
|
|
19335
19479
|
seen.add(e.subagentId);
|
|
19336
19480
|
const l = lbl(e.subagentId, e.name);
|
|
@@ -19358,7 +19502,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19358
19502
|
}
|
|
19359
19503
|
});
|
|
19360
19504
|
const offStarted = events.on("subagent.task_started", (e) => {
|
|
19361
|
-
if (!
|
|
19505
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19362
19506
|
if (!gate.isLive(e.subagentId)) return;
|
|
19363
19507
|
seen.add(e.subagentId);
|
|
19364
19508
|
const l = lbl(e.subagentId);
|
|
@@ -19378,7 +19522,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19378
19522
|
}
|
|
19379
19523
|
});
|
|
19380
19524
|
const offCompleted = events.on("subagent.task_completed", (e) => {
|
|
19381
|
-
if (!
|
|
19525
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19382
19526
|
if (!gate.isLive(e.subagentId)) return;
|
|
19383
19527
|
seen.add(e.subagentId);
|
|
19384
19528
|
const l = lbl(e.subagentId);
|
|
@@ -19412,7 +19556,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19412
19556
|
}
|
|
19413
19557
|
});
|
|
19414
19558
|
const offRemoved = events.on("subagent.removed", (e) => {
|
|
19415
|
-
if (!
|
|
19559
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19416
19560
|
seen.delete(e.subagentId);
|
|
19417
19561
|
labelsRef.current.delete(e.subagentId);
|
|
19418
19562
|
ctxDispatchRef.current.delete(e.subagentId);
|
|
@@ -19425,7 +19569,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19425
19569
|
dispatch({ type: "fleetRemove", id: e.subagentId });
|
|
19426
19570
|
});
|
|
19427
19571
|
const offBudgetWarning = events.on("subagent.budget_warning", (e) => {
|
|
19428
|
-
if (!
|
|
19572
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19429
19573
|
if (!gate.isLive(e.subagentId)) return;
|
|
19430
19574
|
seen.add(e.subagentId);
|
|
19431
19575
|
const l = lbl(e.subagentId);
|
|
@@ -19453,7 +19597,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19453
19597
|
}
|
|
19454
19598
|
});
|
|
19455
19599
|
const offBudgetExtended = events.on("subagent.budget_extended", (e) => {
|
|
19456
|
-
if (!
|
|
19600
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19457
19601
|
if (!gate.isLive(e.subagentId)) return;
|
|
19458
19602
|
seen.add(e.subagentId);
|
|
19459
19603
|
const l = lbl(e.subagentId);
|
|
@@ -19477,7 +19621,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19477
19621
|
}
|
|
19478
19622
|
});
|
|
19479
19623
|
const offIterationSummary = events.on("subagent.iteration_summary", (e) => {
|
|
19480
|
-
if (!
|
|
19624
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19481
19625
|
if (!gate.isLive(e.subagentId)) return;
|
|
19482
19626
|
seen.add(e.subagentId);
|
|
19483
19627
|
if (mode() !== "full") return;
|
|
@@ -19497,7 +19641,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19497
19641
|
});
|
|
19498
19642
|
});
|
|
19499
19643
|
const offCtxPct = events.on("subagent.ctx_pct", (e) => {
|
|
19500
|
-
if (!
|
|
19644
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19501
19645
|
if (!gate.isLive(e.subagentId)) return;
|
|
19502
19646
|
seen.add(e.subagentId);
|
|
19503
19647
|
const emit = () => {
|
|
@@ -19538,13 +19682,13 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19538
19682
|
});
|
|
19539
19683
|
const offConcurrencyChanged = events.on("concurrency.changed", (e) => {
|
|
19540
19684
|
const { n, sessionId } = e;
|
|
19541
|
-
if (!
|
|
19685
|
+
if (!isCurrentSession2(sessionId)) return;
|
|
19542
19686
|
if (typeof n === "number" && n > 0) {
|
|
19543
19687
|
dispatch({ type: "fleetConcurrency", n });
|
|
19544
19688
|
}
|
|
19545
19689
|
});
|
|
19546
19690
|
const offLeaderCtxPct = events.on("ctx.pct", (e) => {
|
|
19547
|
-
if (!
|
|
19691
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19548
19692
|
latestLeaderCtxPctRef.current = e;
|
|
19549
19693
|
const emit = () => {
|
|
19550
19694
|
const latest = latestLeaderCtxPctRef.current ?? e;
|
|
@@ -19581,7 +19725,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19581
19725
|
emit();
|
|
19582
19726
|
});
|
|
19583
19727
|
const offLeaderMaxContext = events.on("ctx.max_context", (e) => {
|
|
19584
|
-
if (!
|
|
19728
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19585
19729
|
if (e.maxContext > 0) setActiveMaxContext(e.maxContext);
|
|
19586
19730
|
});
|
|
19587
19731
|
const offCompactionFired = events.on("compaction.fired", (e) => {
|
|
@@ -19589,7 +19733,7 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
19589
19733
|
if (entry) dispatch({ type: "addEntry", entry });
|
|
19590
19734
|
});
|
|
19591
19735
|
const offTool = events.on("subagent.tool_executed", (e) => {
|
|
19592
|
-
if (!
|
|
19736
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19593
19737
|
if (!gate.isLive(e.subagentId)) return;
|
|
19594
19738
|
dispatch({
|
|
19595
19739
|
type: "fleetTool",
|
|
@@ -19648,12 +19792,12 @@ function useTuiEventBridge({
|
|
|
19648
19792
|
}
|
|
19649
19793
|
function useSessionEvents(events, dispatch, onClearHistory, getSessionId) {
|
|
19650
19794
|
useEffect43(() => {
|
|
19651
|
-
const
|
|
19795
|
+
const isCurrentSession2 = (sessionId) => {
|
|
19652
19796
|
const current = getSessionId?.();
|
|
19653
19797
|
return !sessionId || !current || sessionId === current;
|
|
19654
19798
|
};
|
|
19655
19799
|
const offCheckpoint = events.on("checkpoint.written", (e) => {
|
|
19656
|
-
if (!
|
|
19800
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19657
19801
|
dispatch({
|
|
19658
19802
|
type: "checkpointReceived",
|
|
19659
19803
|
cp: {
|
|
@@ -19665,7 +19809,7 @@ function useSessionEvents(events, dispatch, onClearHistory, getSessionId) {
|
|
|
19665
19809
|
});
|
|
19666
19810
|
});
|
|
19667
19811
|
const offRewound = events.on("session.rewound", (e) => {
|
|
19668
|
-
if (!
|
|
19812
|
+
if (!isCurrentSession2(e.sessionId)) return;
|
|
19669
19813
|
dispatch({ type: "sessionRewound", toPromptIndex: e.toPromptIndex });
|
|
19670
19814
|
dispatch({ type: "clearHistory" });
|
|
19671
19815
|
dispatch({ type: "resetContextChip" });
|
|
@@ -19680,13 +19824,13 @@ function useSessionEvents(events, dispatch, onClearHistory, getSessionId) {
|
|
|
19680
19824
|
function useGoalEvents(subscribeGoal, dispatch, stateRef, getSessionId) {
|
|
19681
19825
|
useEffect43(() => {
|
|
19682
19826
|
if (!subscribeGoal) return;
|
|
19683
|
-
const
|
|
19827
|
+
const isCurrentSession2 = (sessionId) => {
|
|
19684
19828
|
const current = getSessionId?.();
|
|
19685
19829
|
return !sessionId || !current || sessionId === current;
|
|
19686
19830
|
};
|
|
19687
19831
|
const handler = (event, payload) => {
|
|
19688
19832
|
const sessionId = payload && typeof payload === "object" && "sessionId" in payload ? payload.sessionId : void 0;
|
|
19689
|
-
if (!
|
|
19833
|
+
if (!isCurrentSession2(sessionId)) return;
|
|
19690
19834
|
switch (event) {
|
|
19691
19835
|
case "phase.started": {
|
|
19692
19836
|
const p = payload;
|
|
@@ -21216,19 +21360,31 @@ function mergeStatuslineHiddenItems(hookHidden, reducerHidden) {
|
|
|
21216
21360
|
function isPickerOverlayOpen(state) {
|
|
21217
21361
|
return state.modelPicker.open || state.autonomyPicker.open || state.modePicker.open || state.designPicker.open || state.resumePicker.open || state.promptPicker.open || state.settingsPicker.open || state.slashPicker.open || state.statuslinePicker.open || state.pluginPicker.open || state.mcpPicker.open || state.toolsPicker.open || state.brainPanel.open || state.helpPanel.open || state.shadowPanel.open || state.fKeyPicker.open || state.authPanel.open || state.picker.open;
|
|
21218
21362
|
}
|
|
21219
|
-
function resolveSidebarLayout(state, termCols, panelPositionsInput, mailboxPanelOpen) {
|
|
21363
|
+
function resolveSidebarLayout(state, termCols, panelPositionsInput, mailboxPanelOpen, sidebarOpenFlags, legacySwarmOnSidebar) {
|
|
21220
21364
|
const panelPositions = coercePanelPositionMap(panelPositionsInput);
|
|
21221
21365
|
const routedToSidebar = (id) => panelPositions[id] === "sidebar";
|
|
21222
21366
|
const overlayOpen = isPickerOverlayOpen(state) || state.coordinator.monitorOpen && !routedToSidebar("coordinator") || state.auditPanelOpen || state.connectionsPanelOpen && !routedToSidebar("connections") || state.helpOpen || state.agentsMonitorOpen && !routedToSidebar("agents") || state.monitorOpen && !routedToSidebar("fleet") || state.contextPanelOpen || state.processListOpen && !routedToSidebar("processList") || state.todosMonitorOpen && !routedToSidebar("todos") || state.worktreeMonitorOpen && !routedToSidebar("worktree") || state.planPanelOpen && !routedToSidebar("plan") || state.kanbanPanelOpen && !routedToSidebar("kanban") || state.queuePanelOpen && !routedToSidebar("queue") || state.goalPanelOpen && !routedToSidebar("goal") || state.sessionsPanelOpen && !routedToSidebar("sessions") || state.projectPicker.open && !routedToSidebar("projectPicker") || state.goalKanbanPanelOpen || state.cronMonitorOpen || state.rewindOverlay != null || state.shellCommandWarning != null || state.confirmQueue.length > 0 || state.clearConfirm != null || state.exitConfirm != null || state.slashConfirm != null || state.escConfirm != null || state.sendModePicker != null || state.enhance != null || state.enhanceBusy || state.refineCountdown != null || state.refineFailure != null || state.continueConfirm != null || state.brainPrompt != null || mailboxPanelOpen || (state.goalRun?.monitorOpen ?? false) && !routedToSidebar("coordinator") || (state.sddBoard?.monitorOpen ?? false);
|
|
21223
21367
|
const sidebarWidth = overlayOpen ? 0 : computeSidebarWidth(termCols);
|
|
21368
|
+
const effectiveSwarmOnSidebar = panelPositions.fleet === "sidebar" || (legacySwarmOnSidebar ?? false);
|
|
21369
|
+
let sidebarTwinRowCount = 0;
|
|
21370
|
+
if (sidebarOpenFlags) {
|
|
21371
|
+
for (const id of PANEL_IDS) {
|
|
21372
|
+
if (routedToSidebar(id) && sidebarOpenFlags[id]) {
|
|
21373
|
+
sidebarTwinRowCount += ESTIMATED_TWIN_HEIGHT;
|
|
21374
|
+
}
|
|
21375
|
+
}
|
|
21376
|
+
}
|
|
21224
21377
|
return {
|
|
21225
21378
|
panelPositions,
|
|
21226
21379
|
overlayOpen,
|
|
21227
21380
|
sidebarWidth,
|
|
21228
21381
|
sidebarContentWidth: computeSidebarContentWidth(sidebarWidth),
|
|
21229
|
-
mainColumnWidth: termCols - sidebarWidth
|
|
21382
|
+
mainColumnWidth: termCols - sidebarWidth,
|
|
21383
|
+
effectiveSwarmOnSidebar,
|
|
21384
|
+
sidebarTwinRowCount
|
|
21230
21385
|
};
|
|
21231
21386
|
}
|
|
21387
|
+
var ESTIMATED_TWIN_HEIGHT = 8;
|
|
21232
21388
|
|
|
21233
21389
|
// src/app-view.tsx
|
|
21234
21390
|
import { expectDefined as expectDefined5 } from "@wrongstack/core/utils";
|
|
@@ -26595,10 +26751,11 @@ function rowText(row, s2) {
|
|
|
26595
26751
|
return { label: " risk floor", value: s2.councilMinRisk, dim: "council convenes at/above this risk" };
|
|
26596
26752
|
case "voter": {
|
|
26597
26753
|
const v = s2.voters[row.index];
|
|
26754
|
+
const lens = personaLabel(s2, v?.persona);
|
|
26598
26755
|
return {
|
|
26599
26756
|
label: ` ${row.index + 1}.`,
|
|
26600
26757
|
value: v?.label ?? "",
|
|
26601
|
-
dim: `${
|
|
26758
|
+
dim: `${lens}${v?.veto ? " \xB7 VETO" : ""}${v?.weight ? ` \xB7 w=${v.weight}` : ""} (p persona \xB7 v veto \xB7 d remove)`
|
|
26602
26759
|
};
|
|
26603
26760
|
}
|
|
26604
26761
|
case "voterAdd":
|
|
@@ -26611,6 +26768,42 @@ function rowText(row, s2) {
|
|
|
26611
26768
|
dim: "Enter = pick \xB7 d = auto"
|
|
26612
26769
|
};
|
|
26613
26770
|
}
|
|
26771
|
+
case "councilQuorum":
|
|
26772
|
+
return {
|
|
26773
|
+
label: " quorum",
|
|
26774
|
+
value: String(s2.councilQuorum ?? 0.5),
|
|
26775
|
+
dim: "fraction of seats that must return a valid vote"
|
|
26776
|
+
};
|
|
26777
|
+
case "councilApproval":
|
|
26778
|
+
return {
|
|
26779
|
+
label: " approval",
|
|
26780
|
+
value: String(s2.councilApproval ?? 0.5),
|
|
26781
|
+
dim: "winning weight must exceed this fraction, else the judge decides"
|
|
26782
|
+
};
|
|
26783
|
+
case "councilDistinctness":
|
|
26784
|
+
return {
|
|
26785
|
+
label: " distinctness",
|
|
26786
|
+
value: s2.councilDistinctness,
|
|
26787
|
+
dim: s2.councilDistinctness === "none" ? "off \u2014 a same-model panel agrees with itself and is never reported" : `warn when seats do not use distinct ${s2.councilDistinctness}s`
|
|
26788
|
+
};
|
|
26789
|
+
case "councilTimeout":
|
|
26790
|
+
return {
|
|
26791
|
+
label: " seat timeout",
|
|
26792
|
+
value: s2.councilPerCallTimeoutMs === void 0 ? "default" : `${s2.councilPerCallTimeoutMs}ms`,
|
|
26793
|
+
dim: "per-seat completion budget (default = the decision timeout)"
|
|
26794
|
+
};
|
|
26795
|
+
case "councilConcurrency":
|
|
26796
|
+
return {
|
|
26797
|
+
label: " concurrency",
|
|
26798
|
+
value: s2.councilMaxConcurrency === void 0 ? "default (3)" : String(s2.councilMaxConcurrency),
|
|
26799
|
+
dim: "seats polled at once, 1..8 \u2014 higher is faster and burstier"
|
|
26800
|
+
};
|
|
26801
|
+
case "councilJudgeMaxTokens":
|
|
26802
|
+
return {
|
|
26803
|
+
label: " judge tokens",
|
|
26804
|
+
value: s2.councilJudgeMaxTokens === void 0 ? "default" : String(s2.councilJudgeMaxTokens),
|
|
26805
|
+
dim: "output budget for the tie-breaker call"
|
|
26806
|
+
};
|
|
26614
26807
|
case "ledgerToggle":
|
|
26615
26808
|
return {
|
|
26616
26809
|
label: "Ledger",
|
|
@@ -32853,7 +33046,8 @@ function parseInline(text) {
|
|
|
32853
33046
|
let urlEnd = i + 8;
|
|
32854
33047
|
while (urlEnd < text.length) {
|
|
32855
33048
|
const c = text[urlEnd];
|
|
32856
|
-
|
|
33049
|
+
const urlChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._~:/?#@!" + String.fromCharCode(36) + String.fromCharCode(38) + "+,;=-%[]()'*";
|
|
33050
|
+
if (c !== void 0 && urlChars.includes(c)) {
|
|
32857
33051
|
urlEnd++;
|
|
32858
33052
|
} else {
|
|
32859
33053
|
break;
|
|
@@ -33475,6 +33669,22 @@ function brainStatusStyle(status) {
|
|
|
33475
33669
|
return { icon: "\xD7", color: "red" };
|
|
33476
33670
|
}
|
|
33477
33671
|
}
|
|
33672
|
+
function councilHeadline(council) {
|
|
33673
|
+
const parts = [
|
|
33674
|
+
`\u21B3 Council: ${council.resolution}`,
|
|
33675
|
+
`${council.validVoteCount}/${council.configuredSeatCount} seats`,
|
|
33676
|
+
`${council.distinctTargetCount} distinct target${council.distinctTargetCount === 1 ? "" : "s"}`
|
|
33677
|
+
];
|
|
33678
|
+
if (council.judgeUsed) parts.push("judge used");
|
|
33679
|
+
if (council.durationMs !== void 0) parts.push(`${Math.round(council.durationMs / 100) / 10}s`);
|
|
33680
|
+
if (council.totalTokens) parts.push(`${council.totalTokens} tok`);
|
|
33681
|
+
return parts.join(" \xB7 ");
|
|
33682
|
+
}
|
|
33683
|
+
function councilSeatLine(seat) {
|
|
33684
|
+
const verdict = seat.status === "valid" ? seat.optionId ?? "stance" : seat.error ?? seat.status;
|
|
33685
|
+
const suffix = [seat.model, seat.veto ? "veto" : void 0].filter(Boolean).join(", ");
|
|
33686
|
+
return ` ${seat.status === "valid" ? "\u2022" : "\xD7"} ${seat.persona} \u2192 ${verdict}${suffix ? ` (${suffix})` : ""}`;
|
|
33687
|
+
}
|
|
33478
33688
|
function memoryLifecycleStyle(action) {
|
|
33479
33689
|
if (action === "entered" || action === "recovered") return { icon: "\u21B3", color: "green" };
|
|
33480
33690
|
if (action === "exited") return { icon: "\u21B2", color: "red" };
|
|
@@ -34039,7 +34249,12 @@ var Entry = React8.memo(function Entry2({
|
|
|
34039
34249
|
entry.outcome ? /* @__PURE__ */ jsx71(Box, { paddingLeft: indentWidth, marginTop: 1, children: /* @__PURE__ */ jsxs68(Text, { children: [
|
|
34040
34250
|
/* @__PURE__ */ jsx71(Text, { bold: true, color: statusStyle.color, children: "\u2713 Outcome: " }),
|
|
34041
34251
|
/* @__PURE__ */ jsx71(Text, { color: theme.textPrimary, children: entry.outcome })
|
|
34042
|
-
] }) }) : null
|
|
34252
|
+
] }) }) : null,
|
|
34253
|
+
entry.council ? /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", paddingLeft: indentWidth, marginTop: 1, children: [
|
|
34254
|
+
/* @__PURE__ */ jsx71(Text, { dimColor: true, children: councilHeadline(entry.council) }),
|
|
34255
|
+
entry.council.seats.map((seat) => /* @__PURE__ */ jsx71(Text, { dimColor: true, children: councilSeatLine(seat) }, seat.seatId)),
|
|
34256
|
+
(entry.council.warnings ?? []).map((warning) => /* @__PURE__ */ jsx71(Text, { color: theme.warn, children: ` \u26A0 ${warning}` }, warning))
|
|
34257
|
+
] }) : null
|
|
34043
34258
|
]
|
|
34044
34259
|
}
|
|
34045
34260
|
);
|
|
@@ -34943,8 +35158,10 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
34943
35158
|
Box,
|
|
34944
35159
|
{
|
|
34945
35160
|
flexDirection: "column",
|
|
34946
|
-
|
|
35161
|
+
width: termWidth,
|
|
35162
|
+
flexShrink: 0,
|
|
34947
35163
|
height: vp,
|
|
35164
|
+
overflowX: "hidden",
|
|
34948
35165
|
overflowY: "hidden",
|
|
34949
35166
|
justifyContent: scrolled ? "flex-start" : "flex-end",
|
|
34950
35167
|
children: /* @__PURE__ */ jsxs71(Box, { flexDirection: "column", flexShrink: 0, marginTop: scrolled && clip2 > 0 ? -clip2 : 0, children: [
|
|
@@ -35021,6 +35238,13 @@ function trunc2(s2, max) {
|
|
|
35021
35238
|
if (s2.length <= max) return s2;
|
|
35022
35239
|
return `${s2.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
35023
35240
|
}
|
|
35241
|
+
function isCurrentSession(rowId, currentSessionId, fallbackIsCurrent) {
|
|
35242
|
+
if (rowId === void 0) return false;
|
|
35243
|
+
if (currentSessionId !== void 0) {
|
|
35244
|
+
return rowId === currentSessionId;
|
|
35245
|
+
}
|
|
35246
|
+
return fallbackIsCurrent === true;
|
|
35247
|
+
}
|
|
35024
35248
|
function statusGlyph(entry) {
|
|
35025
35249
|
switch (entry.status) {
|
|
35026
35250
|
case "running":
|
|
@@ -35055,8 +35279,7 @@ function liveSessionColor(status) {
|
|
|
35055
35279
|
if (status === "active" || status === "running") return theme.success;
|
|
35056
35280
|
if (status === "idle") return theme.accent;
|
|
35057
35281
|
if (status === "error" || status === "stale") return theme.error;
|
|
35058
|
-
|
|
35059
|
-
return theme.textMuted;
|
|
35282
|
+
return theme.warn;
|
|
35060
35283
|
}
|
|
35061
35284
|
function outcomeBadge(outcome) {
|
|
35062
35285
|
switch (outcome) {
|
|
@@ -35120,7 +35343,7 @@ function Card({
|
|
|
35120
35343
|
}
|
|
35121
35344
|
);
|
|
35122
35345
|
}
|
|
35123
|
-
function buildMissionRows(todos, maxRows
|
|
35346
|
+
function buildMissionRows(todos, maxRows) {
|
|
35124
35347
|
const list = todos ?? [];
|
|
35125
35348
|
const total = list.length;
|
|
35126
35349
|
const done = list.filter((t) => t.status === "completed").length;
|
|
@@ -35131,10 +35354,7 @@ function buildMissionRows(todos, maxRows, textWidth) {
|
|
|
35131
35354
|
const rows = shown.map((t) => ({
|
|
35132
35355
|
id: t.id,
|
|
35133
35356
|
status: t.status,
|
|
35134
|
-
label:
|
|
35135
|
-
t.status === "in_progress" && t.activeForm ? t.activeForm : t.content,
|
|
35136
|
-
textWidth
|
|
35137
|
-
)
|
|
35357
|
+
label: t.status === "in_progress" && t.activeForm ? t.activeForm : t.content
|
|
35138
35358
|
}));
|
|
35139
35359
|
return { rows, overflow: ordered.length - shown.length, done, total };
|
|
35140
35360
|
}
|
|
@@ -35172,7 +35392,7 @@ function SidebarContent({
|
|
|
35172
35392
|
];
|
|
35173
35393
|
const hiddenAgentCount = runningSubagents.length - agentCap;
|
|
35174
35394
|
const running = fleetCounts?.running ?? runningSubagents.length;
|
|
35175
|
-
const mission = showSwarmSection ? buildMissionRows(todos, SIDEBAR_MISSION_ROWS
|
|
35395
|
+
const mission = showSwarmSection ? buildMissionRows(todos, SIDEBAR_MISSION_ROWS) : { rows: [], overflow: 0, done: 0, total: 0 };
|
|
35176
35396
|
return /* @__PURE__ */ jsxs72(
|
|
35177
35397
|
Box,
|
|
35178
35398
|
{
|
|
@@ -35308,29 +35528,29 @@ function SidebarContent({
|
|
|
35308
35528
|
),
|
|
35309
35529
|
mission.rows.map((m) => {
|
|
35310
35530
|
if (m.status === "completed") {
|
|
35311
|
-
return /* @__PURE__ */ jsxs72(Box, { children: [
|
|
35531
|
+
return /* @__PURE__ */ jsxs72(Box, { width: innerWidth, flexDirection: "row", children: [
|
|
35312
35532
|
/* @__PURE__ */ jsxs72(Text, { color: theme.success, children: [
|
|
35313
35533
|
glyphs.success,
|
|
35314
35534
|
" "
|
|
35315
35535
|
] }),
|
|
35316
|
-
/* @__PURE__ */ jsx75(Text, { color: theme.textMuted, dimColor: true, strikethrough: true,
|
|
35536
|
+
/* @__PURE__ */ jsx75(Text, { color: theme.textMuted, dimColor: true, strikethrough: true, children: m.label })
|
|
35317
35537
|
] }, m.id);
|
|
35318
35538
|
}
|
|
35319
35539
|
if (m.status === "in_progress") {
|
|
35320
|
-
return /* @__PURE__ */ jsxs72(Box, { children: [
|
|
35540
|
+
return /* @__PURE__ */ jsxs72(Box, { width: innerWidth, flexDirection: "row", children: [
|
|
35321
35541
|
/* @__PURE__ */ jsxs72(Text, { color: theme.accent, children: [
|
|
35322
35542
|
glyphs.running,
|
|
35323
35543
|
" "
|
|
35324
35544
|
] }),
|
|
35325
|
-
/* @__PURE__ */ jsx75(Text, { color: theme.textPrimary, bold: true,
|
|
35545
|
+
/* @__PURE__ */ jsx75(Text, { color: theme.textPrimary, bold: true, children: m.label })
|
|
35326
35546
|
] }, m.id);
|
|
35327
35547
|
}
|
|
35328
|
-
return /* @__PURE__ */ jsxs72(Box, { children: [
|
|
35548
|
+
return /* @__PURE__ */ jsxs72(Box, { width: innerWidth, flexDirection: "row", children: [
|
|
35329
35549
|
/* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, children: [
|
|
35330
35550
|
glyphs.pending,
|
|
35331
35551
|
" "
|
|
35332
35552
|
] }),
|
|
35333
|
-
/* @__PURE__ */ jsx75(Text, { color: theme.textSecondary,
|
|
35553
|
+
/* @__PURE__ */ jsx75(Text, { color: theme.textSecondary, children: m.label })
|
|
35334
35554
|
] }, m.id);
|
|
35335
35555
|
}),
|
|
35336
35556
|
mission.overflow > 0 ? /* @__PURE__ */ jsxs72(Text, { color: theme.textMuted, dimColor: true, children: [
|
|
@@ -35353,7 +35573,10 @@ function SidebarContent({
|
|
|
35353
35573
|
}
|
|
35354
35574
|
),
|
|
35355
35575
|
liveSessions && liveSessions.length > 0 ? /* @__PURE__ */ jsx75(Box, { flexDirection: "column", children: liveSessions.slice(0, 3).map((s2) => {
|
|
35356
|
-
const isCurrent =
|
|
35576
|
+
const isCurrent = isCurrentSession(
|
|
35577
|
+
s2.sessionId,
|
|
35578
|
+
currentSessionId
|
|
35579
|
+
);
|
|
35357
35580
|
const icon = isCurrent ? "\u25CF" : liveSessionIcon(s2.status);
|
|
35358
35581
|
const color = liveSessionColor(s2.status);
|
|
35359
35582
|
const name = trunc2(s2.projectName, innerWidth - 6);
|
|
@@ -35381,6 +35604,11 @@ function SidebarContent({
|
|
|
35381
35604
|
flexDirection: "column",
|
|
35382
35605
|
marginTop: liveSessions && liveSessions.length > 0 ? 1 : 0,
|
|
35383
35606
|
children: resumeSessions.slice(0, 3).map((rs) => {
|
|
35607
|
+
const isCurrent = isCurrentSession(
|
|
35608
|
+
rs.id,
|
|
35609
|
+
currentSessionId,
|
|
35610
|
+
rs.isCurrent
|
|
35611
|
+
);
|
|
35384
35612
|
const badge = outcomeBadge(rs.outcome);
|
|
35385
35613
|
const title = trunc2(
|
|
35386
35614
|
rs.title || rs.lastUserMessage || rs.id,
|
|
@@ -35395,9 +35623,9 @@ function SidebarContent({
|
|
|
35395
35623
|
/* @__PURE__ */ jsx75(
|
|
35396
35624
|
Text,
|
|
35397
35625
|
{
|
|
35398
|
-
color:
|
|
35626
|
+
color: isCurrent ? theme.accent : theme.textSecondary,
|
|
35399
35627
|
wrap: "truncate",
|
|
35400
|
-
|
|
35628
|
+
bold: isCurrent,
|
|
35401
35629
|
children: title
|
|
35402
35630
|
}
|
|
35403
35631
|
),
|
|
@@ -35888,7 +36116,7 @@ function PlanPanelSidebar({
|
|
|
35888
36116
|
ordered.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "no plan items" }) : ordered.map((item) => {
|
|
35889
36117
|
const icon = item.status === "done" ? glyphs.success : item.status === "in_progress" ? "\u25D0" : "\u25CB";
|
|
35890
36118
|
const color = item.status === "done" ? theme.success : item.status === "in_progress" ? theme.warn : theme.textMuted;
|
|
35891
|
-
return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36119
|
+
return /* @__PURE__ */ jsxs74(Box, { width: inner, flexDirection: "row", children: [
|
|
35892
36120
|
/* @__PURE__ */ jsx77(Text, { color, children: icon }),
|
|
35893
36121
|
/* @__PURE__ */ jsxs74(
|
|
35894
36122
|
Text,
|
|
@@ -35897,7 +36125,7 @@ function PlanPanelSidebar({
|
|
|
35897
36125
|
...item.status === "done" ? { dimColor: true, strikethrough: true } : {},
|
|
35898
36126
|
children: [
|
|
35899
36127
|
" ",
|
|
35900
|
-
|
|
36128
|
+
item.title
|
|
35901
36129
|
]
|
|
35902
36130
|
}
|
|
35903
36131
|
)
|
|
@@ -35935,7 +36163,7 @@ function TodosPanelSidebar({ todos, width }) {
|
|
|
35935
36163
|
const icon = t.status === "completed" ? glyphs.success : t.status === "in_progress" ? "\u25CF" : "\u25CB";
|
|
35936
36164
|
const color = t.status === "completed" ? theme.success : t.status === "in_progress" ? theme.accent : theme.textMuted;
|
|
35937
36165
|
const label = t.status === "in_progress" && t.activeForm ? t.activeForm : t.content;
|
|
35938
|
-
return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36166
|
+
return /* @__PURE__ */ jsxs74(Box, { width: inner, flexDirection: "row", children: [
|
|
35939
36167
|
/* @__PURE__ */ jsx77(Text, { color, children: icon }),
|
|
35940
36168
|
/* @__PURE__ */ jsxs74(
|
|
35941
36169
|
Text,
|
|
@@ -35944,7 +36172,7 @@ function TodosPanelSidebar({ todos, width }) {
|
|
|
35944
36172
|
...t.status === "completed" ? { dimColor: true, strikethrough: true } : {},
|
|
35945
36173
|
children: [
|
|
35946
36174
|
" ",
|
|
35947
|
-
|
|
36175
|
+
label
|
|
35948
36176
|
]
|
|
35949
36177
|
}
|
|
35950
36178
|
)
|
|
@@ -35965,7 +36193,7 @@ function QueuePanelSidebar({ items, width }) {
|
|
|
35965
36193
|
kicker: "queued prompts",
|
|
35966
36194
|
right: /* @__PURE__ */ jsx77(Text, { color: items.length > 0 ? theme.warn : theme.textMuted, bold: true, children: items.length }),
|
|
35967
36195
|
footer: "F7 details",
|
|
35968
|
-
children: /* @__PURE__ */ jsx77(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: items.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "queue is empty" }) : items.slice(0, 10).map((item, i) => /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36196
|
+
children: /* @__PURE__ */ jsx77(SidebarPanelCard, { innerWidth: inner, marginBottom: 0, children: items.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "queue is empty" }) : items.slice(0, 10).map((item, i) => /* @__PURE__ */ jsxs74(Box, { width: inner, flexDirection: "row", children: [
|
|
35969
36197
|
/* @__PURE__ */ jsxs74(Text, { color: theme.textMuted, children: [
|
|
35970
36198
|
i + 1,
|
|
35971
36199
|
"."
|
|
@@ -35974,10 +36202,9 @@ function QueuePanelSidebar({ items, width }) {
|
|
|
35974
36202
|
Text,
|
|
35975
36203
|
{
|
|
35976
36204
|
color: theme.textPrimary,
|
|
35977
|
-
wrap: "truncate",
|
|
35978
36205
|
children: [
|
|
35979
36206
|
" ",
|
|
35980
|
-
|
|
36207
|
+
item.displayText
|
|
35981
36208
|
]
|
|
35982
36209
|
}
|
|
35983
36210
|
)
|
|
@@ -36085,7 +36312,7 @@ function GoalPanelSidebar({
|
|
|
36085
36312
|
),
|
|
36086
36313
|
deliverables.slice(0, 6).map((d, i) => {
|
|
36087
36314
|
const done = /^\[[x✓]\]|✅|\(done\)/i.test(d);
|
|
36088
|
-
return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36315
|
+
return /* @__PURE__ */ jsxs74(Box, { width: inner, flexDirection: "row", children: [
|
|
36089
36316
|
/* @__PURE__ */ jsx77(Text, { color: done ? theme.success : theme.textMuted, children: done ? glyphs.success : glyphs.pending }),
|
|
36090
36317
|
/* @__PURE__ */ jsxs74(
|
|
36091
36318
|
Text,
|
|
@@ -36094,7 +36321,7 @@ function GoalPanelSidebar({
|
|
|
36094
36321
|
...done ? { dimColor: true, strikethrough: true } : {},
|
|
36095
36322
|
children: [
|
|
36096
36323
|
" ",
|
|
36097
|
-
|
|
36324
|
+
d.replace(/^\[[ x✓]\]\s*/, "")
|
|
36098
36325
|
]
|
|
36099
36326
|
}
|
|
36100
36327
|
)
|
|
@@ -36138,7 +36365,10 @@ function SessionsPanelSidebar({
|
|
|
36138
36365
|
}
|
|
36139
36366
|
),
|
|
36140
36367
|
live.map((s2) => {
|
|
36141
|
-
const isCurrent =
|
|
36368
|
+
const isCurrent = isCurrentSession(
|
|
36369
|
+
s2.sessionId,
|
|
36370
|
+
currentSessionId
|
|
36371
|
+
);
|
|
36142
36372
|
const icon = isCurrent ? "\u25CF" : liveSessionGlyph(s2.status);
|
|
36143
36373
|
const color = liveSessionColor2(s2.status);
|
|
36144
36374
|
return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
@@ -36171,13 +36401,18 @@ function SessionsPanelSidebar({
|
|
|
36171
36401
|
const rel = fmtRelative2(rs.lastActivityAt ?? rs.endedAt);
|
|
36172
36402
|
const outcomeGlyph = rs.outcome === "completed" ? glyphs.success : rs.outcome === "error" ? glyphs.failure : rs.outcome === "timeout" ? "\u23F1" : "\u2298";
|
|
36173
36403
|
const outcomeColor = rs.outcome === "completed" ? theme.success : rs.outcome === "error" ? theme.error : rs.outcome === "timeout" ? theme.warn : theme.textMuted;
|
|
36404
|
+
const isCurrent = isCurrentSession(
|
|
36405
|
+
rs.id,
|
|
36406
|
+
currentSessionId,
|
|
36407
|
+
rs.isCurrent
|
|
36408
|
+
);
|
|
36174
36409
|
return /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36175
36410
|
/* @__PURE__ */ jsx77(Text, { color: outcomeColor, children: outcomeGlyph }),
|
|
36176
36411
|
/* @__PURE__ */ jsxs74(
|
|
36177
36412
|
Text,
|
|
36178
36413
|
{
|
|
36179
|
-
color:
|
|
36180
|
-
bold:
|
|
36414
|
+
color: isCurrent ? theme.accent : theme.textSecondary,
|
|
36415
|
+
bold: isCurrent,
|
|
36181
36416
|
wrap: "truncate",
|
|
36182
36417
|
children: [
|
|
36183
36418
|
" ",
|
|
@@ -36295,11 +36530,11 @@ function KanbanPanelSidebar({
|
|
|
36295
36530
|
innerWidth: inner
|
|
36296
36531
|
}
|
|
36297
36532
|
),
|
|
36298
|
-
activeCardTitles.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "no active cards" }) : activeCardTitles.slice(0, 6).map((title, i) => /* @__PURE__ */ jsxs74(Box, { flexDirection: "row", children: [
|
|
36533
|
+
activeCardTitles.length === 0 ? /* @__PURE__ */ jsx77(Text, { color: theme.textMuted, children: "no active cards" }) : activeCardTitles.slice(0, 6).map((title, i) => /* @__PURE__ */ jsxs74(Box, { width: inner, flexDirection: "row", children: [
|
|
36299
36534
|
/* @__PURE__ */ jsx77(Text, { color: theme.warn, children: "\u25CF" }),
|
|
36300
|
-
/* @__PURE__ */ jsxs74(Text, { color: theme.textPrimary,
|
|
36535
|
+
/* @__PURE__ */ jsxs74(Text, { color: theme.textPrimary, children: [
|
|
36301
36536
|
" ",
|
|
36302
|
-
|
|
36537
|
+
title
|
|
36303
36538
|
] })
|
|
36304
36539
|
] }, i))
|
|
36305
36540
|
] })
|
|
@@ -39164,6 +39399,8 @@ function createAppKeyHandler(options) {
|
|
|
39164
39399
|
terminalColumns,
|
|
39165
39400
|
terminalRows,
|
|
39166
39401
|
mainColumnWidth,
|
|
39402
|
+
effectiveSwarmOnSidebar,
|
|
39403
|
+
sidebarTwinRowCount,
|
|
39167
39404
|
statusBarWrapRef,
|
|
39168
39405
|
belowStatusBarRef,
|
|
39169
39406
|
liveStatuslineMode,
|
|
@@ -39366,11 +39603,23 @@ function createAppKeyHandler(options) {
|
|
|
39366
39603
|
if (state.sidebarFocused && !overlayOpen) {
|
|
39367
39604
|
const sidebarViewportHeight = termRows - 2;
|
|
39368
39605
|
if (key.upArrow) {
|
|
39369
|
-
dispatch({
|
|
39606
|
+
dispatch({
|
|
39607
|
+
type: "sidebarScroll",
|
|
39608
|
+
delta: -1,
|
|
39609
|
+
viewportHeight: sidebarViewportHeight,
|
|
39610
|
+
sidebarTwinRowCount,
|
|
39611
|
+
effectiveSwarmOnSidebar
|
|
39612
|
+
});
|
|
39370
39613
|
return;
|
|
39371
39614
|
}
|
|
39372
39615
|
if (key.downArrow) {
|
|
39373
|
-
dispatch({
|
|
39616
|
+
dispatch({
|
|
39617
|
+
type: "sidebarScroll",
|
|
39618
|
+
delta: 1,
|
|
39619
|
+
viewportHeight: sidebarViewportHeight,
|
|
39620
|
+
sidebarTwinRowCount,
|
|
39621
|
+
effectiveSwarmOnSidebar
|
|
39622
|
+
});
|
|
39374
39623
|
return;
|
|
39375
39624
|
}
|
|
39376
39625
|
if (key.escape) {
|
|
@@ -39419,7 +39668,9 @@ function createAppKeyHandler(options) {
|
|
|
39419
39668
|
dispatch({
|
|
39420
39669
|
type: "sidebarScroll",
|
|
39421
39670
|
delta: key.mouse.wheel > 0 ? -1 : 1,
|
|
39422
|
-
viewportHeight: termRows - 2
|
|
39671
|
+
viewportHeight: termRows - 2,
|
|
39672
|
+
sidebarTwinRowCount,
|
|
39673
|
+
effectiveSwarmOnSidebar
|
|
39423
39674
|
});
|
|
39424
39675
|
return;
|
|
39425
39676
|
}
|
|
@@ -39864,11 +40115,33 @@ function App(props) {
|
|
|
39864
40115
|
} = useLiveSettingsState({ getSettings, titleController, chime, confirmExit });
|
|
39865
40116
|
const mailbox = useMailboxViewModel(events);
|
|
39866
40117
|
const { setMailboxPanelOpen } = mailbox;
|
|
40118
|
+
const sidebarOpenFlags = {
|
|
40119
|
+
projectPicker: state.projectPicker.open,
|
|
40120
|
+
fleet: state.monitorOpen,
|
|
40121
|
+
agents: state.agentsMonitorOpen && (liveSettings?.showAgentSwarmPanel ?? "bottom") !== "off",
|
|
40122
|
+
worktree: state.worktreeMonitorOpen,
|
|
40123
|
+
plan: state.planPanelOpen,
|
|
40124
|
+
todos: state.todosMonitorOpen,
|
|
40125
|
+
queue: state.queuePanelOpen,
|
|
40126
|
+
processList: state.processListOpen,
|
|
40127
|
+
goal: state.goalPanelOpen,
|
|
40128
|
+
sessions: state.sessionsPanelOpen,
|
|
40129
|
+
coordinator: state.coordinator.monitorOpen || (state.goalRun?.monitorOpen ?? false),
|
|
40130
|
+
kanban: state.kanbanPanelOpen,
|
|
40131
|
+
connections: state.connectionsPanelOpen
|
|
40132
|
+
};
|
|
39867
40133
|
const sidebarLayout = resolveSidebarLayout(
|
|
39868
40134
|
state,
|
|
39869
40135
|
stdout?.columns ?? 80,
|
|
39870
40136
|
liveSettings?.panelPositions,
|
|
39871
|
-
mailbox.mailboxPanelOpen
|
|
40137
|
+
mailbox.mailboxPanelOpen,
|
|
40138
|
+
sidebarOpenFlags,
|
|
40139
|
+
// Legacy `showAgentSwarmPanel === 'sidebar'` source from the
|
|
40140
|
+
// persisted config. Mirrors the renderer's read at
|
|
40141
|
+
// `app-view.tsx:897-899` so the scroll-clamp reservation matches
|
|
40142
|
+
// the actual source the renderer uses to decide whether to
|
|
40143
|
+
// render the mission card on the sidebar.
|
|
40144
|
+
(liveSettings?.showAgentSwarmPanel ?? "bottom") === "sidebar"
|
|
39872
40145
|
);
|
|
39873
40146
|
useEffect70(() => {
|
|
39874
40147
|
titleController?.setModel(liveModel);
|
|
@@ -40343,6 +40616,8 @@ function App(props) {
|
|
|
40343
40616
|
terminalColumns: stdout?.columns ?? 80,
|
|
40344
40617
|
terminalRows: stdout?.rows ?? 24,
|
|
40345
40618
|
mainColumnWidth: sidebarLayout.mainColumnWidth,
|
|
40619
|
+
effectiveSwarmOnSidebar: sidebarLayout.effectiveSwarmOnSidebar,
|
|
40620
|
+
sidebarTwinRowCount: sidebarLayout.sidebarTwinRowCount,
|
|
40346
40621
|
statusBarWrapRef,
|
|
40347
40622
|
belowStatusBarRef,
|
|
40348
40623
|
liveStatuslineMode,
|
|
@@ -12,6 +12,8 @@ export type TokenSavingTierTui = 'auto' | 'off' | 'minimal' | 'light' | 'medium'
|
|
|
12
12
|
export type FleetChatVerbosityTui = 'off' | 'full';
|
|
13
13
|
export type ConfigScope = 'global' | 'project';
|
|
14
14
|
export type AnimationStyleChoice = 'rainbow' | 'wave' | 'pulse' | 'dots' | 'breathe' | 'cycle';
|
|
15
|
+
/** Where to render the agent swarm panel: lower region, sidebar, or hidden. */
|
|
16
|
+
export type AgentSwarmPanelMode = 'bottom' | 'sidebar' | 'off';
|
|
15
17
|
export type SettingsPickerPatch = Partial<{
|
|
16
18
|
mode: SettingsMode;
|
|
17
19
|
delayMs: number;
|
|
@@ -54,7 +56,7 @@ export type SettingsPickerPatch = Partial<{
|
|
|
54
56
|
breakerEnabled: boolean;
|
|
55
57
|
breakerAutoKillResetMs: number;
|
|
56
58
|
showModelReasoning: boolean;
|
|
57
|
-
showAgentSwarmPanel:
|
|
59
|
+
showAgentSwarmPanel: AgentSwarmPanelMode;
|
|
58
60
|
/**
|
|
59
61
|
* Per-panel position map (one entry per F-key panel id). Each value is
|
|
60
62
|
* 'bottom' (F-key behavior) or 'sidebar' (right-sidebar twin). Callers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.299.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack terminal UI: Ink-based interactive renderer with history, pickers, and slash menus.",
|
|
6
6
|
"repository": {
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"ink": "7.1.1",
|
|
30
30
|
"react": "^19.2.8",
|
|
31
|
-
"@wrongstack/
|
|
32
|
-
"@wrongstack/
|
|
33
|
-
"@wrongstack/
|
|
34
|
-
"@wrongstack/
|
|
35
|
-
"@wrongstack/sdd": "0.
|
|
36
|
-
"@wrongstack/
|
|
31
|
+
"@wrongstack/runtime": "0.299.0",
|
|
32
|
+
"@wrongstack/kanban": "0.299.0",
|
|
33
|
+
"@wrongstack/core": "0.299.0",
|
|
34
|
+
"@wrongstack/sage": "0.299.0",
|
|
35
|
+
"@wrongstack/sdd": "0.299.0",
|
|
36
|
+
"@wrongstack/tools": "0.299.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@testing-library/dom": "^10.4.1",
|