@wrongstack/tui 0.236.0 → 0.255.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/index.d.ts +51 -3
- package/dist/index.js +265 -39
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -338,8 +338,8 @@ interface RunTuiOptions {
|
|
|
338
338
|
* visible bar without a round-trip. The initial value is loaded from
|
|
339
339
|
* the config file before App mounts.
|
|
340
340
|
*/
|
|
341
|
-
statuslineHiddenItems: Array<'todos' | 'plan' | 'fleet' | 'git' | 'elapsed' | 'context' | 'cost'>;
|
|
342
|
-
setStatuslineHiddenItems: (items: Array<'todos' | 'plan' | 'fleet' | 'git' | 'elapsed' | 'context' | 'cost'>) => void;
|
|
341
|
+
statuslineHiddenItems: Array<'todos' | 'plan' | 'tasks' | 'fleet' | 'git' | 'elapsed' | 'context' | 'cost'>;
|
|
342
|
+
setStatuslineHiddenItems: (items: Array<'todos' | 'plan' | 'tasks' | 'fleet' | 'git' | 'elapsed' | 'context' | 'cost'>) => void;
|
|
343
343
|
/**
|
|
344
344
|
* Controller for the agents monitor overlay. App installs a dispatch-backed
|
|
345
345
|
* setter on mount so the `/agents on|off` slash command can toggle the
|
|
@@ -417,6 +417,12 @@ interface RunTuiOptions {
|
|
|
417
417
|
* Used by the TUI to display and auto-submit next steps in 'auto' mode.
|
|
418
418
|
*/
|
|
419
419
|
getSuggestions?: (() => string[]) | undefined;
|
|
420
|
+
/**
|
|
421
|
+
* Write parsed next steps into the shared suggestion store.
|
|
422
|
+
* Called by the Entry component after parsing each assistant message
|
|
423
|
+
* so /next 1 and the auto-submit countdown can access them.
|
|
424
|
+
*/
|
|
425
|
+
setSuggestions?: ((steps: string[]) => void) | undefined;
|
|
420
426
|
/**
|
|
421
427
|
* Messages restored from a previous session. When provided (non-empty),
|
|
422
428
|
* the TUI renders the prior conversation as history entries so a resumed
|
|
@@ -531,4 +537,46 @@ declare function parseInline(text: string): InlineToken[];
|
|
|
531
537
|
*/
|
|
532
538
|
declare function replaySessionEvents(events: SessionEvent[], startId: number): HistoryEntry[];
|
|
533
539
|
|
|
534
|
-
|
|
540
|
+
/**
|
|
541
|
+
* Unified next-steps suggestion parser.
|
|
542
|
+
*
|
|
543
|
+
* Three code paths feed into the suggestion store:
|
|
544
|
+
* 1. TUI rendering — entry.tsx parses "💡 Next steps" from assistant output
|
|
545
|
+
* 2. REPL store — repl.ts parses "💡 Next steps" from final agent output
|
|
546
|
+
* 3. /suggest output — suggest.ts parses LLM-generated numbered lists
|
|
547
|
+
*
|
|
548
|
+
* Heading mode (`requireHeading = true`):
|
|
549
|
+
* strict=true — only 💡 emoji heading (TUI rendering)
|
|
550
|
+
* strict=false — 💡, ##, plain "Next steps" headings (REPL store)
|
|
551
|
+
*
|
|
552
|
+
* Raw mode (`requireHeading = false`):
|
|
553
|
+
* Parses numbered/bullet items from anywhere in text (subagent /suggest output).
|
|
554
|
+
*/
|
|
555
|
+
interface ParsedNextStep {
|
|
556
|
+
index: number;
|
|
557
|
+
text: string;
|
|
558
|
+
}
|
|
559
|
+
interface ParseNextStepsResult {
|
|
560
|
+
/** Matched steps with their original index and stripped text. */
|
|
561
|
+
steps: ParsedNextStep[];
|
|
562
|
+
/** Flat string array — what gets stored in the suggestion store. */
|
|
563
|
+
texts: string[];
|
|
564
|
+
/**
|
|
565
|
+
* Content with the entire "💡 Next steps" block removed.
|
|
566
|
+
* Used by entry.tsx to strip suggestions from the rendered message body.
|
|
567
|
+
*/
|
|
568
|
+
stripped: string;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Parse "💡 Next steps" blocks from assistant output (or raw numbered lines).
|
|
572
|
+
*
|
|
573
|
+
* @param content — raw assistant message text or subagent output
|
|
574
|
+
* @param strict — when true, only the 💡 emoji heading is accepted (TUI rendering).
|
|
575
|
+
* when false, also accepts ## / plain "Next steps" headings (REPL store).
|
|
576
|
+
* @param requireHeading — when true, a heading must precede the item list.
|
|
577
|
+
* when false, numbered/bullet items are parsed from anywhere in text
|
|
578
|
+
* (used by /suggest subagent output which has no heading).
|
|
579
|
+
*/
|
|
580
|
+
declare function parseNextSteps(content: string, strict?: boolean, requireHeading?: boolean): ParseNextStepsResult;
|
|
581
|
+
|
|
582
|
+
export { type ParseNextStepsResult, type ParsedNextStep, type RunTuiOptions, type Settings, parseInline, parseNextSteps, replaySessionEvents, runTui };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { writeErr, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1,
|
|
1
|
+
import { writeErr, resolveProjectDir, wstackGlobalRoot, GlobalMailbox, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, expectDefined as expectDefined$1, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
|
|
2
2
|
export { buildGoalPreamble } from '@wrongstack/core';
|
|
3
3
|
import { Box as Box$1, useInput, useStdin, useStdout, Text as Text$1, render, useApp, measureElement, Static } from 'ink';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
4
5
|
import * as path4 from 'path';
|
|
5
6
|
import React5, { forwardRef, useState, useEffect, useMemo, memo, useRef, useCallback, useReducer, useLayoutEffect } from 'react';
|
|
6
7
|
import * as fs2 from 'fs/promises';
|
|
@@ -86,6 +87,27 @@ var Box = forwardRef(function Box2({ borderColor, backgroundColor, ...rest }, re
|
|
|
86
87
|
}
|
|
87
88
|
);
|
|
88
89
|
});
|
|
90
|
+
function useTokenCounterRefresh(tokenCounter, events) {
|
|
91
|
+
const [data, setData] = useState(
|
|
92
|
+
() => tokenCounter ? {
|
|
93
|
+
usage: tokenCounter.total(),
|
|
94
|
+
cost: tokenCounter.estimateCost(),
|
|
95
|
+
cacheStats: tokenCounter.cacheStats()
|
|
96
|
+
} : void 0
|
|
97
|
+
);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (!tokenCounter || !events) return;
|
|
100
|
+
const off = events.on("token.accounted", () => {
|
|
101
|
+
setData({
|
|
102
|
+
usage: tokenCounter.total(),
|
|
103
|
+
cost: tokenCounter.estimateCost(),
|
|
104
|
+
cacheStats: tokenCounter.cacheStats()
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
return off;
|
|
108
|
+
}, [tokenCounter, events]);
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
89
111
|
var MODE_ICONS = {
|
|
90
112
|
teach: "\u{1F9D1}\u200D\u{1F3EB}",
|
|
91
113
|
brief: "\u26A1",
|
|
@@ -131,6 +153,7 @@ function StatusBar({
|
|
|
131
153
|
processCount,
|
|
132
154
|
context,
|
|
133
155
|
hiddenItems,
|
|
156
|
+
events,
|
|
134
157
|
eternalStage,
|
|
135
158
|
goalSummary,
|
|
136
159
|
indexState,
|
|
@@ -155,9 +178,10 @@ function StatusBar({
|
|
|
155
178
|
const isCompact = termWidth < COMPACT_THRESHOLD;
|
|
156
179
|
const isComfortable = termWidth >= COMFORTABLE_THRESHOLD;
|
|
157
180
|
const hiddenSet = new Set(hiddenItems);
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const
|
|
181
|
+
const tokenData = useTokenCounterRefresh(tokenCounter, events);
|
|
182
|
+
const usage = tokenData?.usage;
|
|
183
|
+
const cost = tokenData?.cost;
|
|
184
|
+
const cache2 = tokenData?.cacheStats;
|
|
161
185
|
const [elapsedMs, setElapsedMs] = useState(startedAt ? Date.now() - startedAt : 0);
|
|
162
186
|
useEffect(() => {
|
|
163
187
|
if (startedAt == null) return;
|
|
@@ -295,6 +319,9 @@ function StatusBar({
|
|
|
295
319
|
"/",
|
|
296
320
|
indexState.totalFiles
|
|
297
321
|
] })
|
|
322
|
+
] }) : indexState?.circuit?.state === "open" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
323
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
324
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2699 index paused (/reindex)" })
|
|
298
325
|
] }) : null
|
|
299
326
|
] })
|
|
300
327
|
) }),
|
|
@@ -552,7 +579,22 @@ function StatusBar({
|
|
|
552
579
|
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
553
580
|
"\u{1F465} ",
|
|
554
581
|
mailbox.onlineAgents,
|
|
555
|
-
"
|
|
582
|
+
" agent",
|
|
583
|
+
mailbox.onlineAgents === 1 ? "" : "s",
|
|
584
|
+
mailbox.onlineClients.tui + mailbox.onlineClients.webui + mailbox.onlineClients.repl > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
585
|
+
mailbox.onlineClients.tui > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
586
|
+
" \xB7 \u{1F5A5} TUI",
|
|
587
|
+
mailbox.onlineClients.tui > 1 ? `\xD7${mailbox.onlineClients.tui}` : ""
|
|
588
|
+
] }) : null,
|
|
589
|
+
mailbox.onlineClients.webui > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
590
|
+
" \xB7 \u{1F310} WebUI",
|
|
591
|
+
mailbox.onlineClients.webui > 1 ? `\xD7${mailbox.onlineClients.webui}` : ""
|
|
592
|
+
] }) : null,
|
|
593
|
+
mailbox.onlineClients.repl > 0 ? /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
594
|
+
" \xB7 \u2328 REPL",
|
|
595
|
+
mailbox.onlineClients.repl > 1 ? `\xD7${mailbox.onlineClients.repl}` : ""
|
|
596
|
+
] }) : null
|
|
597
|
+
] }) : null
|
|
556
598
|
] }),
|
|
557
599
|
mailbox.lastSubject ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
558
600
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
@@ -3756,19 +3798,107 @@ function Banner({
|
|
|
3756
3798
|
] })
|
|
3757
3799
|
] });
|
|
3758
3800
|
}
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3801
|
+
|
|
3802
|
+
// src/components/suggestions.ts
|
|
3803
|
+
var STRICT_HEADING_RE = /💡\s*Next steps?\s*\n+/i;
|
|
3804
|
+
var PERMISSIVE_HEADING_PATTERNS = [
|
|
3805
|
+
{ re: /💡\s*Next steps?\s*\n+/i, label: "emoji" },
|
|
3806
|
+
{ re: /##?\s*Next steps?\s*\n+/i, label: "markdown" },
|
|
3807
|
+
{ re: /\n{1,2}Next steps?\s*\n+/i, label: "plain" }
|
|
3808
|
+
];
|
|
3809
|
+
var ITEM_RE = /^(?:(\d+)[.)]\s*|[-*•]\s*)(.+)$/;
|
|
3810
|
+
var MAX_STEPS = 6;
|
|
3811
|
+
function parseNextSteps(content, strict = false, requireHeading = true) {
|
|
3812
|
+
if (requireHeading) {
|
|
3813
|
+
return parseWithHeading(content, strict);
|
|
3814
|
+
}
|
|
3815
|
+
return parseRawNumbered(content);
|
|
3816
|
+
}
|
|
3817
|
+
function parseRawNumbered(content) {
|
|
3818
|
+
const lines = content.split("\n");
|
|
3764
3819
|
const steps = [];
|
|
3765
|
-
const
|
|
3766
|
-
for (const
|
|
3767
|
-
const
|
|
3768
|
-
if (
|
|
3820
|
+
const seenNumbers = /* @__PURE__ */ new Set();
|
|
3821
|
+
for (const rawLine of lines) {
|
|
3822
|
+
const line = rawLine.trim();
|
|
3823
|
+
if (!line) continue;
|
|
3824
|
+
const m = ITEM_RE.exec(line);
|
|
3825
|
+
if (!m) continue;
|
|
3826
|
+
const numPart = m[1];
|
|
3827
|
+
let text = m[2].trim();
|
|
3828
|
+
let index;
|
|
3829
|
+
if (numPart !== void 0) {
|
|
3830
|
+
index = Number.parseInt(numPart, 10);
|
|
3831
|
+
} else {
|
|
3832
|
+
index = steps.length + 1;
|
|
3833
|
+
}
|
|
3834
|
+
if (seenNumbers.has(index)) continue;
|
|
3835
|
+
if (text.length < 3) continue;
|
|
3836
|
+
seenNumbers.add(index);
|
|
3837
|
+
steps.push({ index, text });
|
|
3838
|
+
if (steps.length >= MAX_STEPS) break;
|
|
3839
|
+
}
|
|
3840
|
+
return { steps, texts: steps.map((s2) => s2.text), stripped: content };
|
|
3841
|
+
}
|
|
3842
|
+
function parseWithHeading(content, strict) {
|
|
3843
|
+
const headingRe = strict ? STRICT_HEADING_RE : buildPermissiveHeadingRe();
|
|
3844
|
+
const headingMatch = headingRe.exec(content);
|
|
3845
|
+
if (!headingMatch) {
|
|
3846
|
+
return { steps: [], texts: [], stripped: content };
|
|
3847
|
+
}
|
|
3848
|
+
const headingEnd = headingMatch.index + headingMatch[0].length;
|
|
3849
|
+
const afterHeading = content.slice(headingEnd);
|
|
3850
|
+
const lines = afterHeading.split("\n");
|
|
3851
|
+
const steps = [];
|
|
3852
|
+
const seenNumbers = /* @__PURE__ */ new Set();
|
|
3853
|
+
for (const rawLine of lines) {
|
|
3854
|
+
const line = rawLine.trim();
|
|
3855
|
+
if (!line) continue;
|
|
3856
|
+
const m = ITEM_RE.exec(line);
|
|
3857
|
+
if (!m) break;
|
|
3858
|
+
const numPart = m[1];
|
|
3859
|
+
let text = m[2].trim();
|
|
3860
|
+
let index;
|
|
3861
|
+
if (numPart !== void 0) {
|
|
3862
|
+
index = Number.parseInt(numPart, 10);
|
|
3863
|
+
} else {
|
|
3864
|
+
index = steps.length + 1;
|
|
3865
|
+
}
|
|
3866
|
+
if (seenNumbers.has(index)) continue;
|
|
3867
|
+
if (text.length < 3) continue;
|
|
3868
|
+
seenNumbers.add(index);
|
|
3869
|
+
steps.push({ index, text });
|
|
3870
|
+
if (steps.length >= MAX_STEPS) break;
|
|
3871
|
+
}
|
|
3872
|
+
if (steps.length === 0) {
|
|
3873
|
+
return { steps: [], texts: [], stripped: content };
|
|
3874
|
+
}
|
|
3875
|
+
const texts = steps.map((s2) => s2.text);
|
|
3876
|
+
const blockStart = headingMatch.index;
|
|
3877
|
+
const blockEnd = headingEnd + findBlockEnd(afterHeading, steps.length);
|
|
3878
|
+
const stripped = (content.slice(0, blockStart) + content.slice(blockStart + blockEnd)).replace(/\n{3,}/g, "\n\n").trim();
|
|
3879
|
+
return { steps, texts, stripped };
|
|
3880
|
+
}
|
|
3881
|
+
function buildPermissiveHeadingRe() {
|
|
3882
|
+
const variants = PERMISSIVE_HEADING_PATTERNS.map(({ re }) => `(?:${re.source})`).join("|");
|
|
3883
|
+
return new RegExp(variants, "i");
|
|
3884
|
+
}
|
|
3885
|
+
function findBlockEnd(afterHeading, stepCount) {
|
|
3886
|
+
const lines = afterHeading.split("\n");
|
|
3887
|
+
let consumed = 0;
|
|
3888
|
+
let found = 0;
|
|
3889
|
+
for (const rawLine of lines) {
|
|
3890
|
+
const line = rawLine.trim();
|
|
3891
|
+
if (!line) {
|
|
3892
|
+
consumed += rawLine.length + 1;
|
|
3893
|
+
continue;
|
|
3894
|
+
}
|
|
3895
|
+
const m = ITEM_RE.exec(line);
|
|
3896
|
+
if (!m) break;
|
|
3897
|
+
consumed += rawLine.length + 1;
|
|
3898
|
+
found++;
|
|
3899
|
+
if (found >= stepCount) break;
|
|
3769
3900
|
}
|
|
3770
|
-
|
|
3771
|
-
return { steps: steps.slice(0, 6), stripped };
|
|
3901
|
+
return consumed;
|
|
3772
3902
|
}
|
|
3773
3903
|
function brainStatusStyle(status) {
|
|
3774
3904
|
switch (status) {
|
|
@@ -3798,12 +3928,19 @@ function brainRiskColor(risk) {
|
|
|
3798
3928
|
}
|
|
3799
3929
|
var Entry = React5.memo(function Entry2({
|
|
3800
3930
|
entry,
|
|
3801
|
-
termWidth
|
|
3931
|
+
termWidth,
|
|
3932
|
+
setSuggestions
|
|
3802
3933
|
}) {
|
|
3803
3934
|
const nextSteps = useMemo(() => {
|
|
3804
3935
|
if (entry.kind !== "assistant") return { steps: [], stripped: "" };
|
|
3805
|
-
return parseNextSteps(entry.text);
|
|
3936
|
+
return parseNextSteps(entry.text, true);
|
|
3806
3937
|
}, [entry.kind, entry.text]);
|
|
3938
|
+
useEffect(() => {
|
|
3939
|
+
if (!setSuggestions) return;
|
|
3940
|
+
const text = entry.text ?? "";
|
|
3941
|
+
const { texts } = parseNextSteps(text, true);
|
|
3942
|
+
if (texts.length > 0) setSuggestions(texts);
|
|
3943
|
+
}, [entry.kind, entry.text, setSuggestions]);
|
|
3807
3944
|
switch (entry.kind) {
|
|
3808
3945
|
case "user":
|
|
3809
3946
|
return /* @__PURE__ */ jsx(
|
|
@@ -4044,7 +4181,7 @@ var Entry = React5.memo(function Entry2({
|
|
|
4044
4181
|
}
|
|
4045
4182
|
}
|
|
4046
4183
|
});
|
|
4047
|
-
function History({ entries, generation, streamingText, toolStream }) {
|
|
4184
|
+
function History({ entries, generation, streamingText, toolStream, setSuggestions }) {
|
|
4048
4185
|
const { stdout } = useStdout();
|
|
4049
4186
|
const [termSize, setTermSize] = useState({
|
|
4050
4187
|
columns: stdout?.columns ?? 80,
|
|
@@ -4062,7 +4199,7 @@ function History({ entries, generation, streamingText, toolStream }) {
|
|
|
4062
4199
|
const termWidth = termSize.columns;
|
|
4063
4200
|
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
4064
4201
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4065
|
-
/* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth }) }, entry.id) }, generation ?? 0),
|
|
4202
|
+
/* @__PURE__ */ jsx(Static, { items: entries, children: (entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions }) }, entry.id) }, generation ?? 0),
|
|
4066
4203
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1, children: tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null })
|
|
4067
4204
|
] });
|
|
4068
4205
|
}
|
|
@@ -4111,7 +4248,8 @@ function ScrollableHistory({
|
|
|
4111
4248
|
viewportRows,
|
|
4112
4249
|
totalLines,
|
|
4113
4250
|
onMeasure,
|
|
4114
|
-
maxWidth
|
|
4251
|
+
maxWidth,
|
|
4252
|
+
setSuggestions
|
|
4115
4253
|
}) {
|
|
4116
4254
|
const { stdout } = useStdout();
|
|
4117
4255
|
const rawWidth = stdout?.columns ?? 80;
|
|
@@ -4150,7 +4288,7 @@ function ScrollableHistory({
|
|
|
4150
4288
|
flexShrink: 0,
|
|
4151
4289
|
children: [
|
|
4152
4290
|
hiddenCount > 0 ? /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: ` \u2191 ${hiddenCount} earlier ${hiddenCount === 1 ? "entry" : "entries"} (scroll lives in this session; full log on disk)` }) }) : null,
|
|
4153
|
-
shown.map((entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, flexShrink: 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth }) }, entry.id)),
|
|
4291
|
+
shown.map((entry) => /* @__PURE__ */ jsx(Box, { marginBottom: entry.kind === "turn-summary" ? 1 : 0, flexShrink: 0, children: /* @__PURE__ */ jsx(Entry, { entry, termWidth, setSuggestions }) }, entry.id)),
|
|
4154
4292
|
tail ? /* @__PURE__ */ jsx(AssistantTail, { text: tail, termWidth }) : null,
|
|
4155
4293
|
toolTail && toolStream ? /* @__PURE__ */ jsx(
|
|
4156
4294
|
ToolStreamBox,
|
|
@@ -4209,6 +4347,15 @@ function startHeapWatchdog(opts = {}) {
|
|
|
4209
4347
|
}).catch(() => void 0);
|
|
4210
4348
|
};
|
|
4211
4349
|
const tick = () => {
|
|
4350
|
+
let userTimings = 0;
|
|
4351
|
+
try {
|
|
4352
|
+
userTimings = performance.getEntriesByType("mark").length + performance.getEntriesByType("measure").length;
|
|
4353
|
+
if (userTimings > 0) {
|
|
4354
|
+
performance.clearMarks();
|
|
4355
|
+
performance.clearMeasures();
|
|
4356
|
+
}
|
|
4357
|
+
} catch {
|
|
4358
|
+
}
|
|
4212
4359
|
const s2 = takeHeapSample();
|
|
4213
4360
|
if (s2.load >= criticalAt && criticalArmed) {
|
|
4214
4361
|
criticalArmed = false;
|
|
@@ -4237,7 +4384,7 @@ function startHeapWatchdog(opts = {}) {
|
|
|
4237
4384
|
extras = opts.collectStats?.() ?? {};
|
|
4238
4385
|
} catch {
|
|
4239
4386
|
}
|
|
4240
|
-
append(JSON.stringify({ pid: process.pid, ...s2, ...extras }));
|
|
4387
|
+
append(JSON.stringify({ pid: process.pid, ...s2, userTimings, ...extras }));
|
|
4241
4388
|
}
|
|
4242
4389
|
};
|
|
4243
4390
|
const timer = setInterval(tick, sampleEveryMs);
|
|
@@ -5396,7 +5543,7 @@ var MODE_DESC = {
|
|
|
5396
5543
|
suggest: "Shows next-step suggestions after each turn",
|
|
5397
5544
|
auto: "Self-driving \u2014 agent continues automatically"
|
|
5398
5545
|
};
|
|
5399
|
-
var SETTINGS_FIELD_COUNT =
|
|
5546
|
+
var SETTINGS_FIELD_COUNT = 25;
|
|
5400
5547
|
var CONFIG_SCOPES = ["global", "project"];
|
|
5401
5548
|
function SettingsPicker({
|
|
5402
5549
|
field,
|
|
@@ -6832,6 +6979,7 @@ function useSessionEvents(events, dispatch, onClearHistory) {
|
|
|
6832
6979
|
const offRewound = events.on("session.rewound", () => {
|
|
6833
6980
|
dispatch({ type: "sessionRewound", toPromptIndex: 0 });
|
|
6834
6981
|
dispatch({ type: "clearHistory" });
|
|
6982
|
+
dispatch({ type: "resetContextChip" });
|
|
6835
6983
|
onClearHistory?.(dispatch);
|
|
6836
6984
|
});
|
|
6837
6985
|
return () => {
|
|
@@ -7756,20 +7904,20 @@ function reducer(state, action) {
|
|
|
7756
7904
|
const enext = (ebase + action.delta + ENHANCE_DELAY_PRESETS.length) % ENHANCE_DELAY_PRESETS.length;
|
|
7757
7905
|
return { ...state, settingsPicker: { ...sp, enhanceDelayMs: expectDefined$1(ENHANCE_DELAY_PRESETS[enext]), hint: void 0 } };
|
|
7758
7906
|
}
|
|
7759
|
-
if (f ===
|
|
7760
|
-
if (f ===
|
|
7761
|
-
const i = CONFIG_SCOPES.indexOf(sp.configScope);
|
|
7762
|
-
const base = i < 0 ? 0 : i;
|
|
7763
|
-
const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
|
|
7764
|
-
return { ...state, settingsPicker: { ...sp, configScope: expectDefined$1(CONFIG_SCOPES[next]), hint: void 0 } };
|
|
7765
|
-
}
|
|
7766
|
-
if (f === 22) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
|
|
7767
|
-
if (f === 23) {
|
|
7907
|
+
if (f === 21) return { ...state, settingsPicker: { ...sp, enhanceEnabled: !sp.enhanceEnabled, hint: void 0 } };
|
|
7908
|
+
if (f === 22) {
|
|
7768
7909
|
const i = ENHANCE_LANGUAGES.indexOf(sp.enhanceLanguage);
|
|
7769
7910
|
const base = i < 0 ? 0 : i;
|
|
7770
7911
|
const next = (base + action.delta + ENHANCE_LANGUAGES.length) % ENHANCE_LANGUAGES.length;
|
|
7771
7912
|
return { ...state, settingsPicker: { ...sp, enhanceLanguage: expectDefined$1(ENHANCE_LANGUAGES[next]), hint: void 0 } };
|
|
7772
7913
|
}
|
|
7914
|
+
if (f === 23) return { ...state, settingsPicker: { ...sp, debugStream: !sp.debugStream, hint: void 0 } };
|
|
7915
|
+
if (f === 24) {
|
|
7916
|
+
const i = CONFIG_SCOPES.indexOf(sp.configScope);
|
|
7917
|
+
const base = i < 0 ? 0 : i;
|
|
7918
|
+
const next = (base + action.delta + CONFIG_SCOPES.length) % CONFIG_SCOPES.length;
|
|
7919
|
+
return { ...state, settingsPicker: { ...sp, configScope: expectDefined$1(CONFIG_SCOPES[next]), hint: void 0 } };
|
|
7920
|
+
}
|
|
7773
7921
|
return state;
|
|
7774
7922
|
}
|
|
7775
7923
|
case "settingsHint":
|
|
@@ -8610,6 +8758,7 @@ function App({
|
|
|
8610
8758
|
predictNext,
|
|
8611
8759
|
onSuggestionsParsed,
|
|
8612
8760
|
getSuggestions,
|
|
8761
|
+
setSuggestions,
|
|
8613
8762
|
switchAutonomy,
|
|
8614
8763
|
effectiveMaxContext,
|
|
8615
8764
|
onExit,
|
|
@@ -9048,7 +9197,8 @@ function App({
|
|
|
9048
9197
|
}, [getLiveSessions]);
|
|
9049
9198
|
const [mailboxStatus, setMailboxStatus] = useState({
|
|
9050
9199
|
unread: 0,
|
|
9051
|
-
onlineAgents: 0
|
|
9200
|
+
onlineAgents: 0,
|
|
9201
|
+
onlineClients: { tui: 0, webui: 0, repl: 0 }
|
|
9052
9202
|
});
|
|
9053
9203
|
useEffect(() => {
|
|
9054
9204
|
const seenAgents = /* @__PURE__ */ new Set();
|
|
@@ -9074,11 +9224,25 @@ function App({
|
|
|
9074
9224
|
if (p?.agentId) seenAgents.add(p.agentId);
|
|
9075
9225
|
setMailboxStatus((prev) => ({ ...prev, onlineAgents: seenAgents.size }));
|
|
9076
9226
|
});
|
|
9227
|
+
const unsub5 = events.onPattern("mailbox.sync_clients", (_e, payload) => {
|
|
9228
|
+
const p = payload;
|
|
9229
|
+
if (p) {
|
|
9230
|
+
setMailboxStatus((prev) => ({
|
|
9231
|
+
...prev,
|
|
9232
|
+
onlineClients: {
|
|
9233
|
+
tui: p.tui ?? 0,
|
|
9234
|
+
webui: p.webui ?? 0,
|
|
9235
|
+
repl: p.repl ?? 0
|
|
9236
|
+
}
|
|
9237
|
+
}));
|
|
9238
|
+
}
|
|
9239
|
+
});
|
|
9077
9240
|
return () => {
|
|
9078
9241
|
unsub1();
|
|
9079
9242
|
unsub2();
|
|
9080
9243
|
unsub3();
|
|
9081
9244
|
unsub4();
|
|
9245
|
+
unsub5();
|
|
9082
9246
|
};
|
|
9083
9247
|
}, [events]);
|
|
9084
9248
|
const [mailboxPanelOpen, setMailboxPanelOpen] = useState(false);
|
|
@@ -10639,14 +10803,14 @@ function App({
|
|
|
10639
10803
|
return;
|
|
10640
10804
|
}
|
|
10641
10805
|
if (item.kind === "project") {
|
|
10642
|
-
onProjectSelect?.(item.key, item.kind);
|
|
10806
|
+
await onProjectSelect?.(item.key, item.kind);
|
|
10643
10807
|
dispatch({ type: "projectPickerClose" });
|
|
10644
10808
|
requestExit?.(42);
|
|
10645
10809
|
return;
|
|
10646
10810
|
}
|
|
10647
10811
|
dispatch({ type: "projectPickerClose" });
|
|
10648
10812
|
if (item.key === "new-session") {
|
|
10649
|
-
onProjectSelect?.(item.key, item.kind);
|
|
10813
|
+
await onProjectSelect?.(item.key, item.kind);
|
|
10650
10814
|
requestExit?.(42);
|
|
10651
10815
|
} else if (item.key === "prev-sessions") {
|
|
10652
10816
|
void submit("/resume");
|
|
@@ -11887,7 +12051,8 @@ User message:
|
|
|
11887
12051
|
scrollOffset: state.scrollOffset,
|
|
11888
12052
|
viewportRows: state.viewportRows,
|
|
11889
12053
|
totalLines: state.totalLines,
|
|
11890
|
-
onMeasure: (totalLines) => dispatch({ type: "setMeasuredLines", totalLines })
|
|
12054
|
+
onMeasure: (totalLines) => dispatch({ type: "setMeasuredLines", totalLines }),
|
|
12055
|
+
setSuggestions
|
|
11891
12056
|
}
|
|
11892
12057
|
) : /* @__PURE__ */ jsx(
|
|
11893
12058
|
History,
|
|
@@ -11895,7 +12060,8 @@ User message:
|
|
|
11895
12060
|
entries: state.entries,
|
|
11896
12061
|
generation: state.historyGen,
|
|
11897
12062
|
streamingText: state.streamingText,
|
|
11898
|
-
toolStream: state.toolStream
|
|
12063
|
+
toolStream: state.toolStream,
|
|
12064
|
+
setSuggestions
|
|
11899
12065
|
}
|
|
11900
12066
|
),
|
|
11901
12067
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexShrink: 0, ref: bottomRegionRef, children: [
|
|
@@ -12146,6 +12312,7 @@ User message:
|
|
|
12146
12312
|
subagentCount: Object.keys(state.fleet).length,
|
|
12147
12313
|
processCount: getProcessRegistry().activeCount,
|
|
12148
12314
|
hiddenItems,
|
|
12315
|
+
events,
|
|
12149
12316
|
eternalStage: state.eternalStage,
|
|
12150
12317
|
goalSummary: state.goalSummary,
|
|
12151
12318
|
indexState,
|
|
@@ -12421,6 +12588,7 @@ async function runTui(opts) {
|
|
|
12421
12588
|
const cleanup = () => {
|
|
12422
12589
|
if (cleaned) return;
|
|
12423
12590
|
cleaned = true;
|
|
12591
|
+
unregisterTuiClient();
|
|
12424
12592
|
unsilenceTerminal();
|
|
12425
12593
|
try {
|
|
12426
12594
|
stopTitle();
|
|
@@ -12447,6 +12615,64 @@ async function runTui(opts) {
|
|
|
12447
12615
|
}
|
|
12448
12616
|
process.off("exit", exitHandler);
|
|
12449
12617
|
};
|
|
12618
|
+
let clientHeartbeatTimer = null;
|
|
12619
|
+
let clientSyncTimer = null;
|
|
12620
|
+
const CLIENT_HEARTBEAT_MS = 15e3;
|
|
12621
|
+
const CLIENT_SYNC_MS = 3e4;
|
|
12622
|
+
const registerTuiClient = async () => {
|
|
12623
|
+
if (!opts.projectRoot) return null;
|
|
12624
|
+
try {
|
|
12625
|
+
const projectDir = resolveProjectDir(opts.projectRoot, wstackGlobalRoot());
|
|
12626
|
+
const mailbox = new GlobalMailbox(projectDir, opts.events);
|
|
12627
|
+
const clientId = `tui@${randomUUID().slice(0, 8)}`;
|
|
12628
|
+
await mailbox.registerClient({
|
|
12629
|
+
clientId,
|
|
12630
|
+
sessionId: opts.projectRoot,
|
|
12631
|
+
name: `TUI [${path4.basename(opts.projectRoot)}]`,
|
|
12632
|
+
source: "tui",
|
|
12633
|
+
pid: process.pid
|
|
12634
|
+
});
|
|
12635
|
+
clientHeartbeatTimer = setInterval(() => {
|
|
12636
|
+
mailbox.clientHeartbeat({ clientId }).catch(() => {
|
|
12637
|
+
});
|
|
12638
|
+
}, CLIENT_HEARTBEAT_MS);
|
|
12639
|
+
clientHeartbeatTimer.unref();
|
|
12640
|
+
const syncClients = async () => {
|
|
12641
|
+
try {
|
|
12642
|
+
const statuses = await mailbox.getClientStatuses();
|
|
12643
|
+
const counts = { tui: 0, webui: 0, repl: 0 };
|
|
12644
|
+
for (const s2 of statuses) {
|
|
12645
|
+
if (s2.online && s2.source in counts) {
|
|
12646
|
+
counts[s2.source]++;
|
|
12647
|
+
}
|
|
12648
|
+
}
|
|
12649
|
+
opts.events.emitCustom("mailbox.sync_clients", counts);
|
|
12650
|
+
} catch {
|
|
12651
|
+
}
|
|
12652
|
+
};
|
|
12653
|
+
setTimeout(() => {
|
|
12654
|
+
void syncClients();
|
|
12655
|
+
}, 5e3);
|
|
12656
|
+
clientSyncTimer = setInterval(() => {
|
|
12657
|
+
void syncClients();
|
|
12658
|
+
}, CLIENT_SYNC_MS);
|
|
12659
|
+
clientSyncTimer.unref();
|
|
12660
|
+
return clientId;
|
|
12661
|
+
} catch {
|
|
12662
|
+
return null;
|
|
12663
|
+
}
|
|
12664
|
+
};
|
|
12665
|
+
const unregisterTuiClient = () => {
|
|
12666
|
+
if (clientHeartbeatTimer) {
|
|
12667
|
+
clearInterval(clientHeartbeatTimer);
|
|
12668
|
+
clientHeartbeatTimer = null;
|
|
12669
|
+
}
|
|
12670
|
+
if (clientSyncTimer) {
|
|
12671
|
+
clearInterval(clientSyncTimer);
|
|
12672
|
+
clientSyncTimer = null;
|
|
12673
|
+
}
|
|
12674
|
+
};
|
|
12675
|
+
registerTuiClient();
|
|
12450
12676
|
return new Promise((resolve) => {
|
|
12451
12677
|
let exitCode = 0;
|
|
12452
12678
|
let hardExitTimer = null;
|
|
@@ -12751,6 +12977,6 @@ function eventToEntry(ev, pendingTools, completedTools) {
|
|
|
12751
12977
|
}
|
|
12752
12978
|
}
|
|
12753
12979
|
|
|
12754
|
-
export { parseInline, replaySessionEvents, runTui };
|
|
12980
|
+
export { parseInline, parseNextSteps, replaySessionEvents, runTui };
|
|
12755
12981
|
//# sourceMappingURL=index.js.map
|
|
12756
12982
|
//# sourceMappingURL=index.js.map
|