@wrongstack/tui 0.309.0 → 0.310.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/components/context-panel.d.ts +19 -0
- package/dist/hooks/use-active-theme.d.ts +2 -1
- package/dist/hooks/use-app-pipeline-builders.d.ts +99 -96
- package/dist/index.js +162 -35
- package/dist/run-tui-teardown.d.ts +62 -0
- package/dist/theme.d.ts +1 -2
- package/dist/tui-host-capabilities.d.ts +1 -1
- package/package.json +7 -7
|
@@ -14,10 +14,19 @@ export interface ContextPanelData {
|
|
|
14
14
|
* Surfaced in the panel so `/context` answers "how much of my spend
|
|
15
15
|
* is hitting the cache" without asking the user to chase the CLI
|
|
16
16
|
* `/context cache` subcommand.
|
|
17
|
+
*
|
|
18
|
+
* `savedUsd` is the gross read-discount USD figure computed by the
|
|
19
|
+
* counter (cache-read tokens × (input price − cache-read price)).
|
|
20
|
+
* `cacheWrite5m` / `cacheWrite1h` are present when the upstream exposed
|
|
21
|
+
* an Anthropic-style TTL split (Anthropic family, including MiniMax
|
|
22
|
+
* routed through the Anthropic Messages surface); OpenAI-family
|
|
23
|
+
* gateways emit only the aggregate and leave them undefined.
|
|
17
24
|
*/
|
|
18
25
|
cacheStats?: {
|
|
19
26
|
readTokens: number;
|
|
20
27
|
writeTokens: number;
|
|
28
|
+
cacheWrite5m?: number | undefined;
|
|
29
|
+
cacheWrite1h?: number | undefined;
|
|
21
30
|
hitRatio: number;
|
|
22
31
|
savedUsd: number;
|
|
23
32
|
} | undefined;
|
|
@@ -27,6 +36,16 @@ export interface ContextPanelData {
|
|
|
27
36
|
* exact extent of the cache, not just a percentage.
|
|
28
37
|
*/
|
|
29
38
|
cacheCoverageTokens?: number | undefined;
|
|
39
|
+
/** Session cache telemetry split by provider, including fallback/model switches. */
|
|
40
|
+
providerCacheStats?: Array<{
|
|
41
|
+
provider: string;
|
|
42
|
+
input: number;
|
|
43
|
+
cacheRead: number;
|
|
44
|
+
cacheWrite: number;
|
|
45
|
+
cacheWrite5m?: number | undefined;
|
|
46
|
+
cacheWrite1h?: number | undefined;
|
|
47
|
+
hitRatio: number;
|
|
48
|
+
}> | undefined;
|
|
30
49
|
/**
|
|
31
50
|
* Real, measured per-category token accounting for the live request. When
|
|
32
51
|
* present the Composition tab shows honest numbers; when absent (no request
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Theme } from '../theme.js';
|
|
1
2
|
/**
|
|
2
3
|
* Subscribes to the module-scoped active theme so a render reads the
|
|
3
4
|
* current `theme` snapshot. Used by the App shell to force a re-render
|
|
@@ -10,5 +11,5 @@
|
|
|
10
11
|
* but exposing it lets test code and stat panels introspect the active
|
|
11
12
|
* palette without re-implementing the listener.
|
|
12
13
|
*/
|
|
13
|
-
export declare function useActiveTheme():
|
|
14
|
+
export declare function useActiveTheme(): Theme;
|
|
14
15
|
//# sourceMappingURL=use-active-theme.d.ts.map
|
|
@@ -1,101 +1,104 @@
|
|
|
1
1
|
import type { AppProps } from '../app-props.js';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { AppExecutionPipelineArgs, KeyHandlerParams, RunBlocksParams, SubmitParams } from './use-app-execution-pipeline.js';
|
|
3
|
+
type K = KeyHandlerParams;
|
|
4
|
+
type R = RunBlocksParams;
|
|
5
|
+
type S = SubmitParams;
|
|
4
6
|
export declare function buildAppPipelineArgs(params: {
|
|
5
7
|
props: AppProps;
|
|
6
|
-
state:
|
|
7
|
-
dispatch:
|
|
8
|
-
historyScrollRef:
|
|
9
|
-
runInterruptLadder:
|
|
10
|
-
enhanceCancelledRef:
|
|
11
|
-
enhanceAbortRef:
|
|
12
|
-
enhanceOriginalRef:
|
|
13
|
-
enhanceEnabledRef:
|
|
14
|
-
inputGateRef:
|
|
15
|
-
lastEscAtRef:
|
|
16
|
-
dismissedEscAtRef:
|
|
17
|
-
streamingTextRef:
|
|
18
|
-
streamSegmentsRef:
|
|
19
|
-
pendingDeltaRef:
|
|
20
|
-
flushTimerRef:
|
|
21
|
-
sessionGenerationRef:
|
|
22
|
-
activeRunGenerationRef:
|
|
23
|
-
activeRunSettledRef:
|
|
24
|
-
assistantCommittedThisRunRef:
|
|
25
|
-
confirmExitRef:
|
|
26
|
-
chimeRef:
|
|
27
|
-
activeCtrlRef:
|
|
28
|
-
clearPendingConfirms:
|
|
29
|
-
liveDirector:
|
|
30
|
-
openProjectPicker:
|
|
31
|
-
loadLiveSessions:
|
|
32
|
-
openStatuslinePicker:
|
|
33
|
-
statuslineHiddenItems:
|
|
34
|
-
lastEnterAtRef:
|
|
35
|
-
draftRef:
|
|
36
|
-
setDraft:
|
|
37
|
-
clearDraft:
|
|
38
|
-
mouseMode:
|
|
39
|
-
nativeMouse:
|
|
40
|
-
termRows:
|
|
41
|
-
terminalColumns:
|
|
42
|
-
terminalRows:
|
|
43
|
-
mainColumnWidth:
|
|
44
|
-
overlayOpen:
|
|
45
|
-
effectiveSwarmOnSidebar:
|
|
46
|
-
sidebarTwinRowCount:
|
|
47
|
-
statusBarWrapRef:
|
|
48
|
-
belowStatusBarRef:
|
|
49
|
-
statusBarClickMapRef:
|
|
50
|
-
openModelPicker:
|
|
51
|
-
nextStepsAutoSubmitTimerRef:
|
|
52
|
-
nextStepsAutoSubmitSuggestionRef:
|
|
53
|
-
nextStepsAutoSubmitLabel:
|
|
54
|
-
setNextStepsAutoSubmitCountdown:
|
|
55
|
-
setNextStepsAutoSubmitLabel:
|
|
56
|
-
cancelNextStepsCountdown:
|
|
57
|
-
pasteClipboardText:
|
|
58
|
-
pasteClipboardImage:
|
|
59
|
-
onHistoryCopy:
|
|
60
|
-
tryPickerKey:
|
|
61
|
-
pasteAccumRef:
|
|
62
|
-
pasteFlushTimerRef:
|
|
63
|
-
commitPaste:
|
|
64
|
-
builderRef:
|
|
65
|
-
tokenPreviewsRef:
|
|
66
|
-
interruptsSyncRef:
|
|
67
|
-
stateRef:
|
|
68
|
-
runBlocksRef:
|
|
69
|
-
submitRef:
|
|
70
|
-
liveModel:
|
|
71
|
-
liveProvider:
|
|
72
|
-
activeMaxContext:
|
|
73
|
-
yoloLive:
|
|
74
|
-
autonomyLive:
|
|
75
|
-
liveModeLabel:
|
|
76
|
-
setMouseMode:
|
|
77
|
-
setNativeMouse:
|
|
78
|
-
setLiveModel:
|
|
79
|
-
setLiveProvider:
|
|
80
|
-
setActiveMaxContext:
|
|
81
|
-
setYoloLive:
|
|
82
|
-
setAutonomyLive:
|
|
83
|
-
setLiveModeLabel:
|
|
84
|
-
setLiveToolCount:
|
|
85
|
-
autoSubmitStreakRef:
|
|
86
|
-
autoSubmitCapWarnedRef:
|
|
87
|
-
autoSubmitLoopGuardRef:
|
|
88
|
-
runEternalLoopRef:
|
|
89
|
-
runParallelLoopRef:
|
|
90
|
-
midRunSendPickerRef:
|
|
91
|
-
openPromptPicker:
|
|
92
|
-
refreshGoalSummary:
|
|
93
|
-
exit:
|
|
94
|
-
setMemoryContextMonitor:
|
|
95
|
-
runSteerSequence:
|
|
96
|
-
setEnhanceStartedAt:
|
|
97
|
-
setEnhanceDurationMs:
|
|
98
|
-
setRefineProviderId:
|
|
99
|
-
setRefineModel:
|
|
8
|
+
state: K['state'];
|
|
9
|
+
dispatch: K['dispatch'];
|
|
10
|
+
historyScrollRef: K['historyScrollRef'];
|
|
11
|
+
runInterruptLadder: K['runInterruptLadder'];
|
|
12
|
+
enhanceCancelledRef: K['enhanceCancelledRef'];
|
|
13
|
+
enhanceAbortRef: K['enhanceAbortRef'];
|
|
14
|
+
enhanceOriginalRef: S['refs']['enhanceOriginal'];
|
|
15
|
+
enhanceEnabledRef: S['refs']['enhanceEnabled'];
|
|
16
|
+
inputGateRef: K['inputGateRef'];
|
|
17
|
+
lastEscAtRef: K['lastEscAtRef'];
|
|
18
|
+
dismissedEscAtRef: K['dismissedEscAtRef'];
|
|
19
|
+
streamingTextRef: K['streamingTextRef'];
|
|
20
|
+
streamSegmentsRef: R['refs']['streamSegments'];
|
|
21
|
+
pendingDeltaRef: R['refs']['pendingDelta'];
|
|
22
|
+
flushTimerRef: R['refs']['flushTimer'];
|
|
23
|
+
sessionGenerationRef: R['refs']['sessionGeneration'];
|
|
24
|
+
activeRunGenerationRef: R['refs']['activeRunGeneration'];
|
|
25
|
+
activeRunSettledRef: R['refs']['activeRunSettled'];
|
|
26
|
+
assistantCommittedThisRunRef: R['refs']['assistantCommitted'];
|
|
27
|
+
confirmExitRef: K['confirmExitRef'];
|
|
28
|
+
chimeRef: R['refs']['chime'];
|
|
29
|
+
activeCtrlRef: K['activeCtrlRef'];
|
|
30
|
+
clearPendingConfirms: K['clearPendingConfirms'];
|
|
31
|
+
liveDirector: K['liveDirector'];
|
|
32
|
+
openProjectPicker: K['openProjectPicker'];
|
|
33
|
+
loadLiveSessions: K['loadLiveSessions'];
|
|
34
|
+
openStatuslinePicker: K['openStatuslinePicker'];
|
|
35
|
+
statuslineHiddenItems: K['statuslineHiddenItems'];
|
|
36
|
+
lastEnterAtRef: K['lastEnterAtRef'];
|
|
37
|
+
draftRef: K['draftRef'];
|
|
38
|
+
setDraft: K['setDraft'];
|
|
39
|
+
clearDraft: S['actions']['clearDraft'];
|
|
40
|
+
mouseMode: K['mouseMode'];
|
|
41
|
+
nativeMouse: S['live']['nativeMouse'];
|
|
42
|
+
termRows: K['termRows'];
|
|
43
|
+
terminalColumns: K['terminalColumns'];
|
|
44
|
+
terminalRows: K['terminalRows'];
|
|
45
|
+
mainColumnWidth: K['mainColumnWidth'];
|
|
46
|
+
overlayOpen: K['overlayOpen'];
|
|
47
|
+
effectiveSwarmOnSidebar: K['effectiveSwarmOnSidebar'];
|
|
48
|
+
sidebarTwinRowCount: K['sidebarTwinRowCount'];
|
|
49
|
+
statusBarWrapRef: K['statusBarWrapRef'];
|
|
50
|
+
belowStatusBarRef: K['belowStatusBarRef'];
|
|
51
|
+
statusBarClickMapRef: K['statusBarClickMapRef'];
|
|
52
|
+
openModelPicker: K['openModelPicker'];
|
|
53
|
+
nextStepsAutoSubmitTimerRef: K['nextStepsAutoSubmitTimerRef'];
|
|
54
|
+
nextStepsAutoSubmitSuggestionRef: K['nextStepsAutoSubmitSuggestionRef'];
|
|
55
|
+
nextStepsAutoSubmitLabel: K['nextStepsAutoSubmitLabel'];
|
|
56
|
+
setNextStepsAutoSubmitCountdown: K['setNextStepsAutoSubmitCountdown'];
|
|
57
|
+
setNextStepsAutoSubmitLabel: K['setNextStepsAutoSubmitLabel'];
|
|
58
|
+
cancelNextStepsCountdown: K['cancelNextStepsCountdown'];
|
|
59
|
+
pasteClipboardText: K['pasteClipboardText'];
|
|
60
|
+
pasteClipboardImage: K['pasteClipboardImage'];
|
|
61
|
+
onHistoryCopy: K['onHistoryCopy'];
|
|
62
|
+
tryPickerKey: K['tryPickerKey'];
|
|
63
|
+
pasteAccumRef: K['pasteAccumRef'];
|
|
64
|
+
pasteFlushTimerRef: K['pasteFlushTimerRef'];
|
|
65
|
+
commitPaste: K['commitPaste'];
|
|
66
|
+
builderRef: S['refs']['builder'];
|
|
67
|
+
tokenPreviewsRef: S['refs']['tokenPreviews'];
|
|
68
|
+
interruptsSyncRef: R['refs']['interrupts'];
|
|
69
|
+
stateRef: R['refs']['state'];
|
|
70
|
+
runBlocksRef: AppExecutionPipelineArgs['runBlocksRef'];
|
|
71
|
+
submitRef: AppExecutionPipelineArgs['submitRef'];
|
|
72
|
+
liveModel: S['live']['model'];
|
|
73
|
+
liveProvider: S['live']['provider'];
|
|
74
|
+
activeMaxContext: S['live']['maxContext'];
|
|
75
|
+
yoloLive: S['live']['yolo'];
|
|
76
|
+
autonomyLive: S['live']['autonomy'];
|
|
77
|
+
liveModeLabel: S['live']['modeLabel'];
|
|
78
|
+
setMouseMode: S['live']['setMouseMode'];
|
|
79
|
+
setNativeMouse: S['live']['setNativeMouse'];
|
|
80
|
+
setLiveModel: S['live']['setModel'];
|
|
81
|
+
setLiveProvider: S['live']['setProvider'];
|
|
82
|
+
setActiveMaxContext: S['live']['setMaxContext'];
|
|
83
|
+
setYoloLive: S['live']['setYolo'];
|
|
84
|
+
setAutonomyLive: S['live']['setAutonomy'];
|
|
85
|
+
setLiveModeLabel: S['live']['setModeLabel'];
|
|
86
|
+
setLiveToolCount: S['live']['setToolCount'];
|
|
87
|
+
autoSubmitStreakRef: S['refs']['autoSubmitStreak'];
|
|
88
|
+
autoSubmitCapWarnedRef: S['refs']['autoSubmitCapWarned'];
|
|
89
|
+
autoSubmitLoopGuardRef: S['refs']['autoSubmitLoopGuard'];
|
|
90
|
+
runEternalLoopRef: S['refs']['eternalLoop'];
|
|
91
|
+
runParallelLoopRef: S['refs']['parallelLoop'];
|
|
92
|
+
midRunSendPickerRef: S['refs']['midRunSendPicker'];
|
|
93
|
+
openPromptPicker: S['actions']['openPromptPicker'];
|
|
94
|
+
refreshGoalSummary: S['actions']['refreshGoalSummary'];
|
|
95
|
+
exit: S['actions']['exit'];
|
|
96
|
+
setMemoryContextMonitor: S['actions']['setMemoryContextMonitor'];
|
|
97
|
+
runSteerSequence: S['actions']['runSteerSequence'];
|
|
98
|
+
setEnhanceStartedAt: S['actions']['setEnhanceStartedAt'];
|
|
99
|
+
setEnhanceDurationMs: S['actions']['setEnhanceDuration'];
|
|
100
|
+
setRefineProviderId: S['actions']['setRefineProvider'];
|
|
101
|
+
setRefineModel: S['actions']['setRefineModel'];
|
|
100
102
|
}): AppExecutionPipelineArgs;
|
|
103
|
+
export {};
|
|
101
104
|
//# sourceMappingURL=use-app-pipeline-builders.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1429,31 +1429,27 @@ function softColor(color) {
|
|
|
1429
1429
|
function getActiveTheme() {
|
|
1430
1430
|
return theme;
|
|
1431
1431
|
}
|
|
1432
|
+
function isThemeName(name) {
|
|
1433
|
+
return name in themePresets;
|
|
1434
|
+
}
|
|
1432
1435
|
function setActiveTheme(name) {
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (preset && name in themePresets) {
|
|
1436
|
-
applied = name;
|
|
1437
|
-
}
|
|
1438
|
-
if (!preset) {
|
|
1439
|
-
return applied;
|
|
1440
|
-
}
|
|
1441
|
-
const t = theme;
|
|
1442
|
-
const p = preset;
|
|
1443
|
-
for (const k of Object.keys(t)) {
|
|
1444
|
-
if (!(k in p)) delete t[k];
|
|
1436
|
+
if (name === void 0 || !isThemeName(name)) {
|
|
1437
|
+
return currentPresetName;
|
|
1445
1438
|
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1439
|
+
const preset = themePresets[name];
|
|
1440
|
+
const mutable = theme;
|
|
1441
|
+
for (const key of Object.keys(theme)) {
|
|
1442
|
+
if (!(key in preset)) delete mutable[key];
|
|
1448
1443
|
}
|
|
1449
|
-
|
|
1444
|
+
Object.assign(theme, preset);
|
|
1445
|
+
currentPresetName = name;
|
|
1450
1446
|
for (const cb of themeSubscribers) {
|
|
1451
1447
|
try {
|
|
1452
|
-
cb(
|
|
1448
|
+
cb(name);
|
|
1453
1449
|
} catch {
|
|
1454
1450
|
}
|
|
1455
1451
|
}
|
|
1456
|
-
return
|
|
1452
|
+
return name;
|
|
1457
1453
|
}
|
|
1458
1454
|
var themeSubscribers = /* @__PURE__ */ new Set();
|
|
1459
1455
|
function subscribeToTheme(cb) {
|
|
@@ -5443,6 +5439,7 @@ function MetricsSection({ data }) {
|
|
|
5443
5439
|
function CacheSection({ data }) {
|
|
5444
5440
|
const cs = data.cacheStats ?? { readTokens: 0, writeTokens: 0, hitRatio: 0, savedUsd: 0 };
|
|
5445
5441
|
const hasCache = cs.readTokens > 0 || cs.writeTokens > 0;
|
|
5442
|
+
const hasTtlSplit = cs.cacheWrite5m !== void 0 && cs.cacheWrite1h !== void 0;
|
|
5446
5443
|
const coverage = Math.max(0, data.cacheCoverageTokens ?? 0);
|
|
5447
5444
|
const max = data.ctxMaxTokens ?? 0;
|
|
5448
5445
|
const covBarLen = 30;
|
|
@@ -5459,8 +5456,58 @@ function CacheSection({ data }) {
|
|
|
5459
5456
|
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 read " }),
|
|
5460
5457
|
/* @__PURE__ */ jsx10(Text, { color: theme.textPrimary, children: cs.readTokens.toLocaleString("en-US") }),
|
|
5461
5458
|
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 write " }),
|
|
5462
|
-
/* @__PURE__ */ jsx10(Text, { color: theme.textSecondary, children: cs.writeTokens.toLocaleString("en-US") })
|
|
5459
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textSecondary, children: cs.writeTokens.toLocaleString("en-US") }),
|
|
5460
|
+
cs.savedUsd > 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
5461
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 saved " }),
|
|
5462
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.success, children: [
|
|
5463
|
+
"~$",
|
|
5464
|
+
cs.savedUsd.toFixed(2)
|
|
5465
|
+
] })
|
|
5466
|
+
] }) : null
|
|
5463
5467
|
] }),
|
|
5468
|
+
hasTtlSplit ? /* @__PURE__ */ jsxs9(Box, { children: [
|
|
5469
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: "Write TTL " }),
|
|
5470
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.textPrimary, children: [
|
|
5471
|
+
"5m ",
|
|
5472
|
+
(cs.cacheWrite5m ?? 0).toLocaleString("en-US")
|
|
5473
|
+
] }),
|
|
5474
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 " }),
|
|
5475
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.textSecondary, children: [
|
|
5476
|
+
"1h ",
|
|
5477
|
+
(cs.cacheWrite1h ?? 0).toLocaleString("en-US")
|
|
5478
|
+
] })
|
|
5479
|
+
] }) : null,
|
|
5480
|
+
(data.providerCacheStats?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs9(Box, { flexDirection: "column", children: [
|
|
5481
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: "Providers" }),
|
|
5482
|
+
data.providerCacheStats?.map((provider) => /* @__PURE__ */ jsxs9(Text, { children: [
|
|
5483
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.textPrimary, children: [
|
|
5484
|
+
" ",
|
|
5485
|
+
provider.provider
|
|
5486
|
+
] }),
|
|
5487
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 " }),
|
|
5488
|
+
/* @__PURE__ */ jsxs9(Text, { color: provider.cacheRead > 0 ? theme.success : theme.textMuted, children: [
|
|
5489
|
+
(provider.hitRatio * 100).toFixed(1),
|
|
5490
|
+
"%"
|
|
5491
|
+
] }),
|
|
5492
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 read " }),
|
|
5493
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textPrimary, children: provider.cacheRead.toLocaleString("en-US") }),
|
|
5494
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " \xB7 write " }),
|
|
5495
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textSecondary, children: provider.cacheWrite.toLocaleString("en-US") }),
|
|
5496
|
+
provider.cacheWrite5m !== void 0 && provider.cacheWrite1h !== void 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
5497
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: " (" }),
|
|
5498
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.textPrimary, children: [
|
|
5499
|
+
"5m ",
|
|
5500
|
+
provider.cacheWrite5m.toLocaleString("en-US")
|
|
5501
|
+
] }),
|
|
5502
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: ", " }),
|
|
5503
|
+
/* @__PURE__ */ jsxs9(Text, { color: theme.textSecondary, children: [
|
|
5504
|
+
"1h ",
|
|
5505
|
+
provider.cacheWrite1h.toLocaleString("en-US")
|
|
5506
|
+
] }),
|
|
5507
|
+
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: ")" })
|
|
5508
|
+
] }) : null
|
|
5509
|
+
] }, provider.provider))
|
|
5510
|
+
] }) : null,
|
|
5464
5511
|
coverage > 0 && max > 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
5465
5512
|
/* @__PURE__ */ jsxs9(Box, { marginTop: 1, children: [
|
|
5466
5513
|
/* @__PURE__ */ jsx10(Text, { color: theme.textMuted, children: "Coverage " }),
|
|
@@ -10320,6 +10367,7 @@ function AppStatusRegion({
|
|
|
10320
10367
|
})(),
|
|
10321
10368
|
cacheStats: cacheStats ?? { readTokens: 0, writeTokens: 0, hitRatio: 0, savedUsd: 0 },
|
|
10322
10369
|
cacheCoverageTokens: cacheCoverageTokens ?? 0,
|
|
10370
|
+
providerCacheStats: cacheStats?.providers ?? [],
|
|
10323
10371
|
fleetEntries: Object.values(state.fleet).map((e) => ({
|
|
10324
10372
|
name: e.name,
|
|
10325
10373
|
status: e.status,
|
|
@@ -20905,6 +20953,7 @@ function SidebarContent({
|
|
|
20905
20953
|
const cs = cacheStats ?? { readTokens: 0, writeTokens: 0, hitRatio: 0, savedUsd: 0 };
|
|
20906
20954
|
const hasCacheActivity = cs.readTokens > 0 || cs.writeTokens > 0;
|
|
20907
20955
|
const cacheHitPct = Math.round(cs.hitRatio * 100);
|
|
20956
|
+
const activeProviderCache = cs.providers?.find((entry) => entry.provider === provider);
|
|
20908
20957
|
const cacheCoveragePct = contextWindow && contextWindow.max > 0 ? Math.min(100, Math.round(cacheCoverageTokens / contextWindow.max * 100)) : 0;
|
|
20909
20958
|
const MAX_SIDEBAR_AGENTS = 12;
|
|
20910
20959
|
const allEntries = Object.values(entries);
|
|
@@ -21069,6 +21118,16 @@ function SidebarContent({
|
|
|
21069
21118
|
)
|
|
21070
21119
|
) })
|
|
21071
21120
|
] }),
|
|
21121
|
+
/* @__PURE__ */ jsx78(
|
|
21122
|
+
SidebarStatRow,
|
|
21123
|
+
{
|
|
21124
|
+
label: `${activeProviderCache?.provider ?? provider ?? "provider"} hit`,
|
|
21125
|
+
value: activeProviderCache ? `${(activeProviderCache.hitRatio * 100).toFixed(1)}%` : `${cacheHitPct}%`,
|
|
21126
|
+
color: theme.success,
|
|
21127
|
+
accent: theme.success,
|
|
21128
|
+
innerWidth: bodyWidth
|
|
21129
|
+
}
|
|
21130
|
+
),
|
|
21072
21131
|
/* @__PURE__ */ jsx78(
|
|
21073
21132
|
SidebarStatRow,
|
|
21074
21133
|
{
|
|
@@ -46258,6 +46317,50 @@ function createRunTuiClientRegistration(opts) {
|
|
|
46258
46317
|
return { register, unregister };
|
|
46259
46318
|
}
|
|
46260
46319
|
|
|
46320
|
+
// src/run-tui-teardown.ts
|
|
46321
|
+
var DEFAULT_CLOSE_BUDGET_MS = 1500;
|
|
46322
|
+
function createDurableTeardown(opts) {
|
|
46323
|
+
const closeBudgetMs = opts.closeBudgetMs ?? DEFAULT_CLOSE_BUDGET_MS;
|
|
46324
|
+
const salvageSync = () => {
|
|
46325
|
+
try {
|
|
46326
|
+
opts.getSession()?.flushSync?.();
|
|
46327
|
+
} catch {
|
|
46328
|
+
}
|
|
46329
|
+
};
|
|
46330
|
+
const awaitCloseBounded = async () => {
|
|
46331
|
+
await Promise.race([
|
|
46332
|
+
(async () => {
|
|
46333
|
+
try {
|
|
46334
|
+
await opts.getSession()?.close();
|
|
46335
|
+
} catch {
|
|
46336
|
+
}
|
|
46337
|
+
})(),
|
|
46338
|
+
new Promise((resolve) => {
|
|
46339
|
+
const t = setTimeout(resolve, closeBudgetMs);
|
|
46340
|
+
t.unref();
|
|
46341
|
+
})
|
|
46342
|
+
]);
|
|
46343
|
+
};
|
|
46344
|
+
const awaitDurableClose = async () => {
|
|
46345
|
+
salvageSync();
|
|
46346
|
+
try {
|
|
46347
|
+
opts.cleanup();
|
|
46348
|
+
} catch {
|
|
46349
|
+
}
|
|
46350
|
+
await awaitCloseBounded();
|
|
46351
|
+
salvageSync();
|
|
46352
|
+
};
|
|
46353
|
+
const shutdownViaSignal = async (exitCode) => {
|
|
46354
|
+
try {
|
|
46355
|
+
opts.killChildren?.();
|
|
46356
|
+
} catch {
|
|
46357
|
+
}
|
|
46358
|
+
await awaitDurableClose();
|
|
46359
|
+
opts.exit(exitCode);
|
|
46360
|
+
};
|
|
46361
|
+
return { shutdownViaSignal, awaitDurableClose, salvageSync };
|
|
46362
|
+
}
|
|
46363
|
+
|
|
46261
46364
|
// src/run-tui-title-controller.ts
|
|
46262
46365
|
import * as path11 from "node:path";
|
|
46263
46366
|
|
|
@@ -46512,6 +46615,24 @@ async function runTui(opts) {
|
|
|
46512
46615
|
unsilenceTerminal();
|
|
46513
46616
|
}
|
|
46514
46617
|
};
|
|
46618
|
+
let resolveRun;
|
|
46619
|
+
let runExitCode = 0;
|
|
46620
|
+
const finishRun = (code) => {
|
|
46621
|
+
detachListeners();
|
|
46622
|
+
if (!resolveRun) return;
|
|
46623
|
+
const resolve = resolveRun;
|
|
46624
|
+
resolveRun = void 0;
|
|
46625
|
+
resolve(code);
|
|
46626
|
+
};
|
|
46627
|
+
const durableTeardown = createDurableTeardown({
|
|
46628
|
+
getSession: () => opts.agent.ctx.session,
|
|
46629
|
+
killChildren: () => getProcessRegistry10().killAll({ force: true, preserveBackground: true }),
|
|
46630
|
+
cleanup,
|
|
46631
|
+
// Resolve the host instead of process.exit so CLI teardown (plugin
|
|
46632
|
+
// stop, Telegram lock.release, vector-memory close) still runs.
|
|
46633
|
+
// Rapid Ctrl+C and the hung-unmount timer still hard-exit.
|
|
46634
|
+
exit: (code) => finishRun(code)
|
|
46635
|
+
});
|
|
46515
46636
|
const RAPID_EXIT_WINDOW_MS = 2e3;
|
|
46516
46637
|
const RAPID_EXIT_THRESHOLD = 2;
|
|
46517
46638
|
let ctrlCPressTimestamps = [];
|
|
@@ -46522,21 +46643,20 @@ async function runTui(opts) {
|
|
|
46522
46643
|
getProcessRegistry10().killAll({ force: true, preserveBackground: true });
|
|
46523
46644
|
} catch {
|
|
46524
46645
|
}
|
|
46525
|
-
|
|
46526
|
-
opts.agent.ctx.session.flushSync?.();
|
|
46527
|
-
} catch {
|
|
46528
|
-
}
|
|
46646
|
+
durableTeardown.salvageSync();
|
|
46529
46647
|
cleanup();
|
|
46530
46648
|
process.exit(130);
|
|
46531
46649
|
};
|
|
46532
46650
|
const signals = ["SIGTERM", "SIGHUP", "SIGINT"];
|
|
46533
46651
|
const signalHandler = () => {
|
|
46652
|
+
runExitCode = 143;
|
|
46534
46653
|
inkInstance?.unmount();
|
|
46654
|
+
void durableTeardown.shutdownViaSignal(143);
|
|
46655
|
+
};
|
|
46656
|
+
const exitHandler = () => {
|
|
46657
|
+
durableTeardown.salvageSync();
|
|
46535
46658
|
cleanup();
|
|
46536
|
-
const sig = setTimeout(() => process.exit(143), 5e3);
|
|
46537
|
-
sig.unref();
|
|
46538
46659
|
};
|
|
46539
|
-
const exitHandler = () => cleanup();
|
|
46540
46660
|
const sigintHandler = () => {
|
|
46541
46661
|
const now = Date.now();
|
|
46542
46662
|
ctrlCPressTimestamps = ctrlCPressTimestamps.filter((t) => now - t < RAPID_EXIT_WINDOW_MS);
|
|
@@ -46546,10 +46666,9 @@ async function runTui(opts) {
|
|
|
46546
46666
|
forceExitViaRapidCtrlC();
|
|
46547
46667
|
return;
|
|
46548
46668
|
}
|
|
46669
|
+
runExitCode = 130;
|
|
46549
46670
|
inkInstance?.unmount();
|
|
46550
|
-
|
|
46551
|
-
const sig = setTimeout(() => process.exit(130), 5e3);
|
|
46552
|
-
sig.unref();
|
|
46671
|
+
void durableTeardown.shutdownViaSignal(130);
|
|
46553
46672
|
};
|
|
46554
46673
|
process.on("SIGINT", sigintHandler);
|
|
46555
46674
|
for (const s2 of ["SIGTERM", "SIGHUP", "SIGBREAK"]) {
|
|
@@ -46588,24 +46707,32 @@ async function runTui(opts) {
|
|
|
46588
46707
|
};
|
|
46589
46708
|
void tuiClientRegistration.register();
|
|
46590
46709
|
return new Promise((resolve) => {
|
|
46591
|
-
|
|
46710
|
+
resolveRun = resolve;
|
|
46592
46711
|
let hardExitTimer = null;
|
|
46593
46712
|
const onExit = (code) => {
|
|
46594
|
-
|
|
46713
|
+
runExitCode = code;
|
|
46595
46714
|
};
|
|
46596
46715
|
const settle = (code) => {
|
|
46597
46716
|
if (hardExitTimer) {
|
|
46598
46717
|
clearTimeout(hardExitTimer);
|
|
46599
46718
|
hardExitTimer = null;
|
|
46600
46719
|
}
|
|
46601
|
-
|
|
46602
|
-
|
|
46603
|
-
|
|
46720
|
+
void durableTeardown.awaitDurableClose().then(
|
|
46721
|
+
() => finishRun(code),
|
|
46722
|
+
() => finishRun(code)
|
|
46723
|
+
);
|
|
46604
46724
|
};
|
|
46605
46725
|
const requestExit = (code) => {
|
|
46606
46726
|
onExit(code);
|
|
46607
46727
|
inkInstance?.unmount();
|
|
46608
|
-
hardExitTimer = setTimeout(() =>
|
|
46728
|
+
hardExitTimer = setTimeout(() => {
|
|
46729
|
+
durableTeardown.salvageSync();
|
|
46730
|
+
try {
|
|
46731
|
+
getProcessRegistry10().killAll({ force: true, preserveBackground: true });
|
|
46732
|
+
} catch {
|
|
46733
|
+
}
|
|
46734
|
+
process.exit(code);
|
|
46735
|
+
}, 5e3);
|
|
46609
46736
|
hardExitTimer.unref();
|
|
46610
46737
|
};
|
|
46611
46738
|
opts.requestExit = requestExit;
|
|
@@ -46776,7 +46903,7 @@ async function runTui(opts) {
|
|
|
46776
46903
|
detachResize = () => stdout.off("resize", onResize2);
|
|
46777
46904
|
instance.waitUntilExit().then(() => {
|
|
46778
46905
|
detachResize?.();
|
|
46779
|
-
settle(
|
|
46906
|
+
settle(runExitCode);
|
|
46780
46907
|
}).catch(() => {
|
|
46781
46908
|
detachResize?.();
|
|
46782
46909
|
settle(1);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable teardown primitives for the TUI host.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from run-tui.ts so the kill-safety semantics are unit-testable
|
|
5
|
+
* without an Ink render loop.
|
|
6
|
+
*
|
|
7
|
+
* Why both a sync and an async step exist:
|
|
8
|
+
* - `flushSync()` drains the writer's in-memory buffer with blocking
|
|
9
|
+
* writes. That data survives ANY concurrent hard exit (the host's
|
|
10
|
+
* 500ms exit-grace timer, a second Ctrl+C, a supervisor SIGKILL racing
|
|
11
|
+
* us) because by the time it returns, the bytes are already handed to
|
|
12
|
+
* the OS.
|
|
13
|
+
* - `close()` additionally drains the async write chain, `datasync()`s
|
|
14
|
+
* the handle, and writes the `.summary.json` sidecar + `_index.jsonl`
|
|
15
|
+
* row. That work is async, cannot be forced synchronous, and therefore
|
|
16
|
+
* gets a bounded budget instead of being trusted to outlive the loop.
|
|
17
|
+
*
|
|
18
|
+
* Ordering contract of `shutdownViaSignal`:
|
|
19
|
+
* 1. killChildren — stop tool subprocesses from producing new events.
|
|
20
|
+
* 2. salvageSync — buffered events are durably on disk from here on.
|
|
21
|
+
* 3. cleanup — terminal restore; also kicks off close() (idempotent).
|
|
22
|
+
* 4. await close — bounded by closeBudgetMs; never hangs shutdown.
|
|
23
|
+
* 5. salvageSync — catch anything close() re-buffered while failing.
|
|
24
|
+
* 6. exit — caller-supplied exit function.
|
|
25
|
+
*/
|
|
26
|
+
/** Structural subset of SessionWriter the teardown needs. */
|
|
27
|
+
export interface TeardownSession {
|
|
28
|
+
/** Durable drain: buffer → disk → datasync → sidecar/index. Idempotent. */
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
/** Last-gasp synchronous drain of whatever is still in memory. */
|
|
31
|
+
flushSync?(): void;
|
|
32
|
+
}
|
|
33
|
+
export interface DurableTeardownOptions {
|
|
34
|
+
/** Reads the CURRENT writer so swaps (e.g. /resume) stay covered. */
|
|
35
|
+
getSession: () => TeardownSession | undefined;
|
|
36
|
+
/** Foreground child cleanup (process registry killAll). Best-effort. */
|
|
37
|
+
killChildren?: (() => void) | undefined;
|
|
38
|
+
/** Terminal restore + client unregister. Idempotent. */
|
|
39
|
+
cleanup: () => void;
|
|
40
|
+
/** Hard ceiling for awaiting close(). Default 1500ms. */
|
|
41
|
+
closeBudgetMs?: number;
|
|
42
|
+
/** Exit function — injectable so tests don't need process.exit. */
|
|
43
|
+
exit: (code: number) => void;
|
|
44
|
+
}
|
|
45
|
+
export interface DurableTeardown {
|
|
46
|
+
/**
|
|
47
|
+
* Signal-driven shutdown (SIGTERM/SIGHUP/Ctrl+C): full ordered sequence,
|
|
48
|
+
* ends by calling exit(). Safe to fire concurrently from several handlers
|
|
49
|
+
* — every step is idempotent and exit wins once.
|
|
50
|
+
*/
|
|
51
|
+
shutdownViaSignal(exitCode: number): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Awaited close WITHOUT exiting — used by the natural exit path (settle)
|
|
54
|
+
* so the host continues only after durability, and project-switch respawns
|
|
55
|
+
* keep working.
|
|
56
|
+
*/
|
|
57
|
+
awaitDurableClose(): Promise<void>;
|
|
58
|
+
/** Sync-only last-chance drain for 'exit' listeners / process.exit contexts. */
|
|
59
|
+
salvageSync(): void;
|
|
60
|
+
}
|
|
61
|
+
export declare function createDurableTeardown(opts: DurableTeardownOptions): DurableTeardown;
|
|
62
|
+
//# sourceMappingURL=run-tui-teardown.d.ts.map
|
package/dist/theme.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SyntaxPalette, SyntaxRole, Theme, ThemeName } from './theme-types.js';
|
|
1
|
+
import type { SyntaxPalette, SyntaxRole, Theme, ThemeListener, ThemeName } from './theme-types.js';
|
|
2
2
|
export { baseTheme, THEME_OPTIONS, themePickerOptions, themePresets } from './theme-presets.js';
|
|
3
3
|
export type { SyntaxPalette, SyntaxRole, Theme, ThemeName, ThemePickerOption, } from './theme-types.js';
|
|
4
4
|
export { catppuccin, detectSupportsBackground, mixHexColors, pastel, SYNTAX_TOKEN, } from './theme-utils.js';
|
|
@@ -30,7 +30,6 @@ export declare function resolveSyntaxPalette(palette?: Theme): SyntaxPalette;
|
|
|
30
30
|
export declare function softColor(color?: string): string | undefined;
|
|
31
31
|
export declare function getActiveTheme(): Theme;
|
|
32
32
|
export declare function setActiveTheme(name: string | undefined): ThemeName;
|
|
33
|
-
type ThemeListener = (name: ThemeName) => void;
|
|
34
33
|
export declare function subscribeToTheme(cb: ThemeListener): () => void;
|
|
35
34
|
export declare function getActiveThemeName(): ThemeName;
|
|
36
35
|
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -21,7 +21,7 @@ export interface RunBlocksCapabilities {
|
|
|
21
21
|
agent: Agent;
|
|
22
22
|
tokenCounter?: TokenCounter | undefined;
|
|
23
23
|
supportsVision?: (() => boolean | Promise<boolean>) | undefined;
|
|
24
|
-
visionAdapters
|
|
24
|
+
visionAdapters?: VisionAdapters | undefined;
|
|
25
25
|
onSDDOutput?: ((output: string) => Promise<string[]>) | undefined;
|
|
26
26
|
onSuggestionsParsed?: ((finalText: string) => void) | undefined;
|
|
27
27
|
predictNext?: ((input: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.310.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack terminal UI: Ink-based interactive renderer with history, pickers, and slash menus.",
|
|
6
6
|
"repository": {
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"ink": "7.1.1",
|
|
30
30
|
"react": "^19.2.8",
|
|
31
31
|
"string-width": "8.2.2",
|
|
32
|
-
"@wrongstack/
|
|
33
|
-
"@wrongstack/
|
|
34
|
-
"@wrongstack/
|
|
35
|
-
"@wrongstack/
|
|
36
|
-
"@wrongstack/
|
|
37
|
-
"@wrongstack/tools": "0.
|
|
32
|
+
"@wrongstack/core": "0.310.0",
|
|
33
|
+
"@wrongstack/kanban": "0.310.0",
|
|
34
|
+
"@wrongstack/runtime": "0.310.0",
|
|
35
|
+
"@wrongstack/sage": "0.310.0",
|
|
36
|
+
"@wrongstack/sdd": "0.310.0",
|
|
37
|
+
"@wrongstack/tools": "0.310.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@testing-library/dom": "^10.4.1",
|