@cryer/star-cli 0.3.10 → 0.3.11
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/{chunk-MNVCCOI2.js → chunk-63CGUF3F.js} +209 -11
- package/dist/chunk-63CGUF3F.js.map +1 -0
- package/dist/{chunk-PDFC7QVW.js → chunk-GYXF6NPC.js} +28 -6
- package/dist/chunk-GYXF6NPC.js.map +1 -0
- package/dist/{chunk-A5PXPWHB.js → chunk-LSYGHLRU.js} +13 -1
- package/dist/chunk-LSYGHLRU.js.map +1 -0
- package/dist/{chunk-IJGUW4PM.js → chunk-N4MIQSNZ.js} +2 -2
- package/dist/chunk-N4MIQSNZ.js.map +1 -0
- package/dist/{chunk-URC7JXKX.js → chunk-Q5FJN4LN.js} +7 -3
- package/dist/{chunk-URC7JXKX.js.map → chunk-Q5FJN4LN.js.map} +1 -1
- package/dist/{loop-TW2FHL7J.js → loop-AY4PXRVP.js} +5 -5
- package/dist/main.js +7 -8
- package/dist/main.js.map +1 -1
- package/dist/{repl-GBVIW5QR.js → repl-YBNTJOSB.js} +287 -51
- package/dist/repl-YBNTJOSB.js.map +1 -0
- package/dist/{tools-7EBGCYYE.js → tools-BH55BVIS.js} +3 -3
- package/package.json +25 -16
- package/dist/chunk-A5PXPWHB.js.map +0 -1
- package/dist/chunk-IJGUW4PM.js.map +0 -1
- package/dist/chunk-MNVCCOI2.js.map +0 -1
- package/dist/chunk-PDFC7QVW.js.map +0 -1
- package/dist/repl-GBVIW5QR.js.map +0 -1
- /package/dist/{loop-TW2FHL7J.js.map → loop-AY4PXRVP.js.map} +0 -0
- /package/dist/{tools-7EBGCYYE.js.map → tools-BH55BVIS.js.map} +0 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
buildDisplayMessages,
|
|
7
7
|
clearSessions,
|
|
8
8
|
computeCostUsd,
|
|
9
|
+
deleteSession,
|
|
9
10
|
estimateCost,
|
|
10
11
|
folderIcon,
|
|
11
12
|
formatByteCount,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
previewLines,
|
|
20
21
|
relativeTime,
|
|
21
22
|
renderMarkdown,
|
|
23
|
+
resolveIconMode,
|
|
22
24
|
resolveMentions,
|
|
23
25
|
resolveSessionId,
|
|
24
26
|
sessionPreview,
|
|
@@ -28,7 +30,7 @@ import {
|
|
|
28
30
|
thinkingIcon,
|
|
29
31
|
toTerminalSafe,
|
|
30
32
|
toolIcon
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-GYXF6NPC.js";
|
|
32
34
|
import {
|
|
33
35
|
AgentLoop,
|
|
34
36
|
WORKING_DIFF_MAX_LINES,
|
|
@@ -45,14 +47,14 @@ import {
|
|
|
45
47
|
isDangerousCommand,
|
|
46
48
|
isGitRepo,
|
|
47
49
|
summarizeMessages
|
|
48
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-63CGUF3F.js";
|
|
49
51
|
import {
|
|
50
52
|
contextWindowTokens,
|
|
51
53
|
coreMessageText,
|
|
52
54
|
diffTreeNames,
|
|
53
55
|
reconcileStarMessages,
|
|
54
56
|
toCoreMessages
|
|
55
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-N4MIQSNZ.js";
|
|
56
58
|
import {
|
|
57
59
|
createModel,
|
|
58
60
|
reasoningEffortMetadata
|
|
@@ -66,7 +68,7 @@ import {
|
|
|
66
68
|
formatTaskFinished,
|
|
67
69
|
formatTaskList,
|
|
68
70
|
formatTaskStarted
|
|
69
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-Q5FJN4LN.js";
|
|
70
72
|
import {
|
|
71
73
|
MAX_IMAGE_DIMENSION,
|
|
72
74
|
SKIP_DIRS,
|
|
@@ -95,7 +97,7 @@ import {
|
|
|
95
97
|
starHome,
|
|
96
98
|
upsertEnvContent,
|
|
97
99
|
userMemoryPath
|
|
98
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-LSYGHLRU.js";
|
|
99
101
|
|
|
100
102
|
// src/cli/repl.tsx
|
|
101
103
|
import { Box as Box13, Text as Text14, render, useApp } from "ink";
|
|
@@ -662,7 +664,7 @@ async function compactSession(opts) {
|
|
|
662
664
|
return {
|
|
663
665
|
message: `Compacted context: ${messages.length} -> ${next.length} messages (~${formatTokens(beforeTokens)} -> ~${formatTokens(afterTokens)} estimated tokens).`,
|
|
664
666
|
compacted: true,
|
|
665
|
-
messages:
|
|
667
|
+
messages: next
|
|
666
668
|
};
|
|
667
669
|
}
|
|
668
670
|
async function applyCompactionSummary(original, compacted, config, model, temperature, signal) {
|
|
@@ -2261,7 +2263,7 @@ function filterCommands(input, commands) {
|
|
|
2261
2263
|
const fuzzy = commands.filter(
|
|
2262
2264
|
(cmd) => !cmd.name.toLowerCase().startsWith(prefix) && isSubsequence(prefix, cmd.name.toLowerCase())
|
|
2263
2265
|
).sort(byName);
|
|
2264
|
-
return [...prefixed, ...fuzzy]
|
|
2266
|
+
return [...prefixed, ...fuzzy];
|
|
2265
2267
|
}
|
|
2266
2268
|
function didYouMeanSuffix(names) {
|
|
2267
2269
|
if (names.length === 0) return "";
|
|
@@ -2281,7 +2283,7 @@ function filterArgHints(input, commands) {
|
|
|
2281
2283
|
const candidates = typeof source === "function" ? source(argPrefix) : source;
|
|
2282
2284
|
const prefix = argPrefix.toLowerCase();
|
|
2283
2285
|
const stem = input.slice(0, input.length - argPrefix.length);
|
|
2284
|
-
return candidates.filter((candidate) => candidate.toLowerCase().startsWith(prefix)).
|
|
2286
|
+
return candidates.filter((candidate) => candidate.toLowerCase().startsWith(prefix)).map((value) => ({ value, replacement: `${stem}${value}` }));
|
|
2285
2287
|
}
|
|
2286
2288
|
|
|
2287
2289
|
// src/cli/commands/undo.ts
|
|
@@ -2607,14 +2609,38 @@ import { Box, Text } from "ink";
|
|
|
2607
2609
|
import { useRef as useRef2, useState } from "react";
|
|
2608
2610
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2609
2611
|
var SELECT_PROMPT_MAX_VISIBLE = 9;
|
|
2610
|
-
function SelectPrompt({ title, options, onSelect, onCancel }) {
|
|
2612
|
+
function SelectPrompt({ title, options, onSelect, onCancel, onDelete }) {
|
|
2611
2613
|
const [index, setIndex] = useState(0);
|
|
2612
2614
|
const indexRef = useRef2(0);
|
|
2615
|
+
const [confirming, setConfirming] = useState(null);
|
|
2616
|
+
const confirmingRef = useRef2(null);
|
|
2617
|
+
const deletingRef = useRef2(false);
|
|
2618
|
+
const setConfirm = (option) => {
|
|
2619
|
+
confirmingRef.current = option;
|
|
2620
|
+
setConfirming(option);
|
|
2621
|
+
};
|
|
2613
2622
|
const move = (delta) => {
|
|
2614
2623
|
indexRef.current = Math.max(0, Math.min(indexRef.current + delta, options.length - 1));
|
|
2615
2624
|
setIndex(indexRef.current);
|
|
2616
2625
|
};
|
|
2617
2626
|
useInput((input, key) => {
|
|
2627
|
+
const pending = confirmingRef.current;
|
|
2628
|
+
if (pending) {
|
|
2629
|
+
if (input === "y" || input === "Y") {
|
|
2630
|
+
setConfirm(null);
|
|
2631
|
+
if (onDelete && !deletingRef.current) {
|
|
2632
|
+
deletingRef.current = true;
|
|
2633
|
+
void onDelete(pending.value).catch(() => options).then((next) => {
|
|
2634
|
+
deletingRef.current = false;
|
|
2635
|
+
indexRef.current = Math.min(indexRef.current, Math.max(0, next.length - 1));
|
|
2636
|
+
setIndex(indexRef.current);
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
} else if (input === "n" || input === "N" || key.escape) {
|
|
2640
|
+
setConfirm(null);
|
|
2641
|
+
}
|
|
2642
|
+
return;
|
|
2643
|
+
}
|
|
2618
2644
|
if (key.escape) {
|
|
2619
2645
|
onCancel();
|
|
2620
2646
|
return;
|
|
@@ -2624,6 +2650,11 @@ function SelectPrompt({ title, options, onSelect, onCancel }) {
|
|
|
2624
2650
|
if (option) onSelect(option.value);
|
|
2625
2651
|
return;
|
|
2626
2652
|
}
|
|
2653
|
+
if (onDelete && key.ctrl && input === "x") {
|
|
2654
|
+
const option = options[indexRef.current];
|
|
2655
|
+
if (option) setConfirm(option);
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2627
2658
|
if (key.downArrow || input === "j") {
|
|
2628
2659
|
move(1);
|
|
2629
2660
|
} else if (key.upArrow || input === "k") {
|
|
@@ -2665,7 +2696,15 @@ function SelectPrompt({ title, options, onSelect, onCancel }) {
|
|
|
2665
2696
|
below,
|
|
2666
2697
|
" more below"
|
|
2667
2698
|
] }),
|
|
2668
|
-
/* @__PURE__ */
|
|
2699
|
+
confirming ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
2700
|
+
"Delete ",
|
|
2701
|
+
confirming.label,
|
|
2702
|
+
"? [y] yes [n] no"
|
|
2703
|
+
] }) : /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2704
|
+
"[\u2191/\u2193 or j/k] move [Enter] select",
|
|
2705
|
+
onDelete ? " [Ctrl+X] delete" : "",
|
|
2706
|
+
" [Esc] cancel"
|
|
2707
|
+
] })
|
|
2669
2708
|
] });
|
|
2670
2709
|
}
|
|
2671
2710
|
|
|
@@ -2966,7 +3005,7 @@ var InputBox = memo(function InputBox2({
|
|
|
2966
3005
|
if (suggestions.length > 0) {
|
|
2967
3006
|
const cmd = suggestions[activeIndex];
|
|
2968
3007
|
if (!cmd) return;
|
|
2969
|
-
const text = `/${cmd.name}
|
|
3008
|
+
const text = `/${cmd.name}`;
|
|
2970
3009
|
edit(text, text.length);
|
|
2971
3010
|
return;
|
|
2972
3011
|
}
|
|
@@ -3095,7 +3134,11 @@ ${currentValue.slice(currentCursor)}`,
|
|
|
3095
3134
|
);
|
|
3096
3135
|
return;
|
|
3097
3136
|
}
|
|
3098
|
-
|
|
3137
|
+
let text = expandPastes(currentValue).trim();
|
|
3138
|
+
if (suggestions.length > 0 && text.startsWith("/") && text.length > 1) {
|
|
3139
|
+
const cmd = suggestions[activeIndex];
|
|
3140
|
+
if (cmd) text = `/${cmd.name}`;
|
|
3141
|
+
}
|
|
3099
3142
|
if (text.length > 0) {
|
|
3100
3143
|
if (!text.startsWith("/")) setHistory((prev) => [...prev, text]);
|
|
3101
3144
|
onSubmit(text);
|
|
@@ -3219,18 +3262,47 @@ ${value.slice(cursor)}`, cursor + 1);
|
|
|
3219
3262
|
const cursorChar = at === "\n" || at === void 0 || at === PASTE_DELIM ? " " : at;
|
|
3220
3263
|
const tail = (at === "\n" ? "\n" : "") + stylePasteTokens(after);
|
|
3221
3264
|
const styled = search ? `\x1B[36m(reverse-search) \x1B[39m'${search.query}': ${search.match === null ? "\x1B[2mno match\x1B[22m\x1B[7m \x1B[27m" : `${history[search.match]}\x1B[7m \x1B[27m`}` : `\x1B[36m\u276F \x1B[39m${stylePasteTokens(before)}\x1B[7m${cursorChar}\x1B[27m${tail}`;
|
|
3265
|
+
const menuStart = Math.min(
|
|
3266
|
+
Math.max(0, activeIndex - Math.floor(MAX_SUGGESTIONS / 2)),
|
|
3267
|
+
Math.max(0, suggestionCount - MAX_SUGGESTIONS)
|
|
3268
|
+
);
|
|
3269
|
+
const menuEnd = Math.min(suggestionCount, menuStart + MAX_SUGGESTIONS);
|
|
3222
3270
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
3223
3271
|
/* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsx2(Text2, { children: styled }) }),
|
|
3224
|
-
suggestions.length > 0 && /* @__PURE__ */
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
] },
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3272
|
+
suggestions.length > 0 && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingLeft: 2, children: [
|
|
3273
|
+
menuStart > 0 && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
3274
|
+
"\u2026 ",
|
|
3275
|
+
menuStart,
|
|
3276
|
+
" more above"
|
|
3277
|
+
] }),
|
|
3278
|
+
suggestions.slice(menuStart, menuEnd).map((cmd, index) => {
|
|
3279
|
+
const label = cmd.usage ?? `/${cmd.name}`;
|
|
3280
|
+
return menuStart + index === activeIndex ? /* @__PURE__ */ jsx2(Text2, { bold: true, inverse: true, children: `${label} - ${cmd.description}` }, cmd.name) : /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
3281
|
+
/* @__PURE__ */ jsx2(Text2, { color: "cyan", children: label }),
|
|
3282
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: ` - ${cmd.description}` })
|
|
3283
|
+
] }, cmd.name);
|
|
3284
|
+
}),
|
|
3285
|
+
menuEnd < suggestions.length && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
3286
|
+
"\u2026 ",
|
|
3287
|
+
suggestions.length - menuEnd,
|
|
3288
|
+
" more below"
|
|
3289
|
+
] })
|
|
3290
|
+
] }),
|
|
3291
|
+
argHints.length > 0 && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingLeft: 2, children: [
|
|
3292
|
+
menuStart > 0 && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
3293
|
+
"\u2026 ",
|
|
3294
|
+
menuStart,
|
|
3295
|
+
" more above"
|
|
3296
|
+
] }),
|
|
3297
|
+
argHints.slice(menuStart, menuEnd).map(
|
|
3298
|
+
(hint, index) => menuStart + index === activeIndex ? /* @__PURE__ */ jsx2(Text2, { bold: true, inverse: true, children: hint.value }, hint.value) : /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: hint.value }, hint.value)
|
|
3299
|
+
),
|
|
3300
|
+
menuEnd < argHints.length && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
3301
|
+
"\u2026 ",
|
|
3302
|
+
argHints.length - menuEnd,
|
|
3303
|
+
" more below"
|
|
3304
|
+
] })
|
|
3305
|
+
] }),
|
|
3234
3306
|
showPathSuggestions && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", paddingLeft: 2, children: pathSuggestions.map(
|
|
3235
3307
|
(sugg, index) => index === activeIndex ? /* @__PURE__ */ jsx2(Text2, { bold: true, inverse: true, children: `@${sugg.path}` }, sugg.path) : /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
3236
3308
|
/* @__PURE__ */ jsx2(Text2, { color: "cyan", children: `@${sugg.path}` }),
|
|
@@ -3600,10 +3672,11 @@ var MessageList = memo2(function MessageList2({ messages }) {
|
|
|
3600
3672
|
] }) }, message.id);
|
|
3601
3673
|
}
|
|
3602
3674
|
if (message.role === "user") {
|
|
3675
|
+
const color = message.steer ? "magenta" : "cyan";
|
|
3603
3676
|
return /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", marginBottom, children: [
|
|
3604
3677
|
/* @__PURE__ */ jsxs7(Box6, { children: [
|
|
3605
|
-
/* @__PURE__ */ jsx7(Text7, { bold: true, color: "
|
|
3606
|
-
/* @__PURE__ */ jsxs7(Text7, { color
|
|
3678
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, color, children: message.steer ? "\xBB " : "\u276F " }),
|
|
3679
|
+
/* @__PURE__ */ jsxs7(Text7, { color, children: [
|
|
3607
3680
|
message.text,
|
|
3608
3681
|
message.interrupted && interruptedMarker(message.text)
|
|
3609
3682
|
] })
|
|
@@ -3815,6 +3888,14 @@ function truncateTail(text, max) {
|
|
|
3815
3888
|
if (flat.length <= max) return flat;
|
|
3816
3889
|
return `\u2026${flat.slice(flat.length - max)}`;
|
|
3817
3890
|
}
|
|
3891
|
+
function roughReasoningTokens(text) {
|
|
3892
|
+
let weight = 0;
|
|
3893
|
+
for (let i = 0; i < text.length; i++) {
|
|
3894
|
+
const code = text.charCodeAt(i);
|
|
3895
|
+
weight += code >= 12288 && code <= 12543 || code >= 13312 && code <= 19903 || code >= 19968 && code <= 40959 || code >= 63744 && code <= 64255 || code >= 65280 && code <= 65519 ? 4 : 1;
|
|
3896
|
+
}
|
|
3897
|
+
return Math.ceil(weight / 4);
|
|
3898
|
+
}
|
|
3818
3899
|
var ThinkingIndicator = memo5(function ThinkingIndicator2({
|
|
3819
3900
|
reasoning,
|
|
3820
3901
|
frame,
|
|
@@ -3827,13 +3908,17 @@ var ThinkingIndicator = memo5(function ThinkingIndicator2({
|
|
|
3827
3908
|
const spinner = SPINNER_FRAMES[(frame ?? tick) % SPINNER_FRAMES.length];
|
|
3828
3909
|
const label = activity ?? `${thinkingIcon} star is thinking\u2026`;
|
|
3829
3910
|
const elapsedSec = startedAt === void 0 ? void 0 : Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
|
|
3830
|
-
const
|
|
3911
|
+
const stats = [];
|
|
3912
|
+
if (elapsedSec !== void 0 && elapsedSec >= 3) stats.push(formatElapsedSeconds(elapsedSec));
|
|
3913
|
+
const thoughtTokens = reasoning ? roughReasoningTokens(reasoning) : 0;
|
|
3914
|
+
if (thoughtTokens > 0) stats.push(`~${formatTokens(thoughtTokens)} thought`);
|
|
3915
|
+
const status = stats.length > 0 ? ` (${stats.join(" \xB7 ")})` : "";
|
|
3831
3916
|
return /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", children: [
|
|
3832
3917
|
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
3833
3918
|
spinner,
|
|
3834
3919
|
" ",
|
|
3835
3920
|
label,
|
|
3836
|
-
|
|
3921
|
+
status
|
|
3837
3922
|
] }),
|
|
3838
3923
|
tail !== "" && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
3839
3924
|
" ",
|
|
@@ -3990,6 +4075,12 @@ var PromptQueue = class {
|
|
|
3990
4075
|
this.items.push({ id: this.nextId++, ...prompt });
|
|
3991
4076
|
return this.items.length;
|
|
3992
4077
|
}
|
|
4078
|
+
// Jump the queue: steering prompts the running turn never delivered are
|
|
4079
|
+
// recovered here when the turn ends, and they were submitted before the
|
|
4080
|
+
// already-queued entries.
|
|
4081
|
+
enqueueFront(prompt) {
|
|
4082
|
+
this.items.unshift({ id: this.nextId++, ...prompt });
|
|
4083
|
+
}
|
|
3993
4084
|
dequeue() {
|
|
3994
4085
|
return this.items.shift();
|
|
3995
4086
|
}
|
|
@@ -4035,9 +4126,56 @@ async function executeShellBang(raw, cwd, signal) {
|
|
|
4035
4126
|
};
|
|
4036
4127
|
}
|
|
4037
4128
|
|
|
4129
|
+
// src/cli/terminal-title.ts
|
|
4130
|
+
import path14 from "path";
|
|
4131
|
+
var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4132
|
+
var TITLE_INTERVAL_MS = 120;
|
|
4133
|
+
var CONTROL_CHARS = /[\x00-\x1f\x7f]/g;
|
|
4134
|
+
function setTerminalTitle(title, deps = {}) {
|
|
4135
|
+
const isTTY = deps.isTTY ?? Boolean(process.stdout.isTTY);
|
|
4136
|
+
if (!isTTY) return;
|
|
4137
|
+
const write = deps.write ?? ((text) => process.stdout.write(text));
|
|
4138
|
+
write(`\x1B]0;${title.replace(CONTROL_CHARS, "")}\x07`);
|
|
4139
|
+
}
|
|
4140
|
+
var TerminalTitle = class _TerminalTitle {
|
|
4141
|
+
constructor(base, deps) {
|
|
4142
|
+
this.base = base;
|
|
4143
|
+
this.deps = deps;
|
|
4144
|
+
}
|
|
4145
|
+
base;
|
|
4146
|
+
deps;
|
|
4147
|
+
timer = null;
|
|
4148
|
+
frame = 0;
|
|
4149
|
+
static forCwd(cwd, deps = {}) {
|
|
4150
|
+
return new _TerminalTitle(`star-cli \u2014 ${path14.basename(cwd) || cwd}`, deps);
|
|
4151
|
+
}
|
|
4152
|
+
start() {
|
|
4153
|
+
if (this.timer) return;
|
|
4154
|
+
this.render(SPINNER_FRAMES2[this.frame] ?? "\u280B");
|
|
4155
|
+
this.timer = setInterval(() => {
|
|
4156
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES2.length;
|
|
4157
|
+
this.render(SPINNER_FRAMES2[this.frame] ?? "\u280B");
|
|
4158
|
+
}, TITLE_INTERVAL_MS);
|
|
4159
|
+
this.timer.unref();
|
|
4160
|
+
}
|
|
4161
|
+
// "done" leaves a bell glyph in the title until the next turn starts;
|
|
4162
|
+
// "idle" (interrupt, unmount) restores the bare title.
|
|
4163
|
+
stop(kind = "done") {
|
|
4164
|
+
if (this.timer) {
|
|
4165
|
+
clearInterval(this.timer);
|
|
4166
|
+
this.timer = null;
|
|
4167
|
+
}
|
|
4168
|
+
this.frame = 0;
|
|
4169
|
+
this.render(kind === "done" ? resolveIconMode(this.deps.env) === "emoji" ? "\u{1F514}" : "!" : "");
|
|
4170
|
+
}
|
|
4171
|
+
render(prefix) {
|
|
4172
|
+
setTerminalTitle(prefix ? `${prefix} ${this.base}` : this.base, this.deps);
|
|
4173
|
+
}
|
|
4174
|
+
};
|
|
4175
|
+
|
|
4038
4176
|
// src/cli/update-check.ts
|
|
4039
4177
|
import { mkdir, readFile as readFile4, rename, writeFile } from "fs/promises";
|
|
4040
|
-
import
|
|
4178
|
+
import path15 from "path";
|
|
4041
4179
|
var REGISTRY_URL2 = "https://registry.npmjs.org/@cryer%2fstar-cli/latest";
|
|
4042
4180
|
var TIMEOUT_MS = 5e3;
|
|
4043
4181
|
var THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -4045,7 +4183,7 @@ async function defaultFetcher2(url) {
|
|
|
4045
4183
|
return fetch(url, { signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
4046
4184
|
}
|
|
4047
4185
|
function defaultStatePath() {
|
|
4048
|
-
return
|
|
4186
|
+
return path15.join(starHome(), "update-check.json");
|
|
4049
4187
|
}
|
|
4050
4188
|
async function readState(statePath) {
|
|
4051
4189
|
try {
|
|
@@ -4060,7 +4198,7 @@ async function readState(statePath) {
|
|
|
4060
4198
|
}
|
|
4061
4199
|
async function writeState(statePath, state) {
|
|
4062
4200
|
try {
|
|
4063
|
-
await mkdir(
|
|
4201
|
+
await mkdir(path15.dirname(statePath), { recursive: true });
|
|
4064
4202
|
const tmp = `${statePath}.tmp-${process.pid}`;
|
|
4065
4203
|
await writeFile(tmp, JSON.stringify(state), "utf8");
|
|
4066
4204
|
await rename(tmp, statePath);
|
|
@@ -4131,7 +4269,7 @@ var BUSY_BLOCKED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
4131
4269
|
function formatUsage(usage) {
|
|
4132
4270
|
return `API usage this session: ${usage.requests} requests, ${formatTokens(usage.promptTokens)} prompt + ${formatTokens(usage.completionTokens)} completion = ${formatTokens(usage.totalTokens)} tokens`;
|
|
4133
4271
|
}
|
|
4134
|
-
var SESSION_PICKER_CAP =
|
|
4272
|
+
var SESSION_PICKER_CAP = 100;
|
|
4135
4273
|
var SESSION_PREVIEW_MAX = 60;
|
|
4136
4274
|
var MAX_VISIBLE_QUEUED = 5;
|
|
4137
4275
|
var REASONING_EFFORT_LEVELS = ["minimal", "low", "medium", "high", "max"];
|
|
@@ -4186,6 +4324,7 @@ function Repl({
|
|
|
4186
4324
|
const planApprovalRef = useRef6(false);
|
|
4187
4325
|
const pendingRewindRef = useRef6(null);
|
|
4188
4326
|
const pickerRef = useRef6(null);
|
|
4327
|
+
const titleRef = useRef6(null);
|
|
4189
4328
|
const pendingConnectRef = useRef6(null);
|
|
4190
4329
|
const modelNameRef = useRef6(model);
|
|
4191
4330
|
const sessionStoreRef = useRef6(sessionStore);
|
|
@@ -4213,11 +4352,11 @@ function Repl({
|
|
|
4213
4352
|
null
|
|
4214
4353
|
);
|
|
4215
4354
|
const pushMessage = useCallback(
|
|
4216
|
-
(role, text, note, tight, interrupted, diff) => {
|
|
4355
|
+
(role, text, note, tight, interrupted, diff, steer) => {
|
|
4217
4356
|
setMessages((prev) => {
|
|
4218
4357
|
const next = [
|
|
4219
4358
|
...prev,
|
|
4220
|
-
{ id: nextIdRef.current++, role, text, note, tight, interrupted, diff }
|
|
4359
|
+
{ id: nextIdRef.current++, role, text, note, tight, interrupted, diff, steer }
|
|
4221
4360
|
];
|
|
4222
4361
|
messagesRef.current = next;
|
|
4223
4362
|
return next;
|
|
@@ -4268,10 +4407,10 @@ function Repl({
|
|
|
4268
4407
|
setPendingConnectState(p);
|
|
4269
4408
|
}, []);
|
|
4270
4409
|
const showPicker = useCallback(
|
|
4271
|
-
(title, options) => {
|
|
4410
|
+
(title, options, onDelete) => {
|
|
4272
4411
|
if (pickerRef.current) return Promise.resolve(null);
|
|
4273
4412
|
return new Promise((resolve) => {
|
|
4274
|
-
setPicker({ title, options, resolve });
|
|
4413
|
+
setPicker({ title, options, resolve, onDelete });
|
|
4275
4414
|
});
|
|
4276
4415
|
},
|
|
4277
4416
|
[setPicker]
|
|
@@ -4398,6 +4537,7 @@ function Repl({
|
|
|
4398
4537
|
tickerStopRef.current?.();
|
|
4399
4538
|
abortRef.current?.abort();
|
|
4400
4539
|
pendingRef.current?.resolve(false);
|
|
4540
|
+
titleRef.current?.stop("idle");
|
|
4401
4541
|
};
|
|
4402
4542
|
}, [attachConfirmHandler]);
|
|
4403
4543
|
useEffect4(() => {
|
|
@@ -4664,7 +4804,7 @@ function Repl({
|
|
|
4664
4804
|
setTodoSession(store.id);
|
|
4665
4805
|
setTodos(await loadTodos(cwd, store.id));
|
|
4666
4806
|
hydrateSnapshots(await loadSessionSnapshots(store.dir));
|
|
4667
|
-
const display = buildDisplayMessages(
|
|
4807
|
+
const display = buildDisplayMessages(resumed.messages);
|
|
4668
4808
|
nextIdRef.current = display.length;
|
|
4669
4809
|
applyMessages(display);
|
|
4670
4810
|
usageRef.current = resumed.meta.usage ? { ...resumed.meta.usage } : emptyUsage();
|
|
@@ -4674,6 +4814,10 @@ function Repl({
|
|
|
4674
4814
|
},
|
|
4675
4815
|
[applyMessages, cwd, stopBackgroundWork]
|
|
4676
4816
|
);
|
|
4817
|
+
const terminalTitle = useCallback(() => {
|
|
4818
|
+
titleRef.current ??= TerminalTitle.forCwd(cwd);
|
|
4819
|
+
return titleRef.current;
|
|
4820
|
+
}, [cwd]);
|
|
4677
4821
|
const runStream = useCallback(
|
|
4678
4822
|
async (input, extraImages = []) => {
|
|
4679
4823
|
const resolved = await resolveMentions(input, cwd);
|
|
@@ -4700,6 +4844,7 @@ function Repl({
|
|
|
4700
4844
|
setThoughtSummary(null);
|
|
4701
4845
|
setStreamingText("");
|
|
4702
4846
|
setIsStreaming(true);
|
|
4847
|
+
terminalTitle().start();
|
|
4703
4848
|
flushedRef.current = { streamed: "", reasoning: "" };
|
|
4704
4849
|
const commitStreamed = (tight) => {
|
|
4705
4850
|
const uncommitted = streamedRef.current.slice(lastCommittedLenRef.current);
|
|
@@ -4859,6 +5004,7 @@ function Repl({
|
|
|
4859
5004
|
lastCommittedLenRef.current = 0;
|
|
4860
5005
|
setStreamingText(null);
|
|
4861
5006
|
const interrupted = controller.signal.aborted;
|
|
5007
|
+
terminalTitle().stop(interrupted ? "idle" : "done");
|
|
4862
5008
|
notifyBell({
|
|
4863
5009
|
enabled: config.notifyBell,
|
|
4864
5010
|
thresholdSec: config.notifyBellThresholdSec,
|
|
@@ -4901,6 +5047,14 @@ function Repl({
|
|
|
4901
5047
|
`Session budget exceeded: $${formatDollars(cost ?? 0)} of $${formatDollars(budget ?? 0)} (sessionBudgetUsd). New prompts are blocked \u2014 raise sessionBudgetUsd in the config or start a /new session.`
|
|
4902
5048
|
);
|
|
4903
5049
|
}
|
|
5050
|
+
const backend2 = backendRef.current;
|
|
5051
|
+
if (backend2 instanceof AgentLoop) {
|
|
5052
|
+
const undelivered = backend2.takeUndeliveredSteers();
|
|
5053
|
+
for (const text of [...undelivered].reverse()) {
|
|
5054
|
+
queueRef.current.enqueueFront({ text, images: [] });
|
|
5055
|
+
}
|
|
5056
|
+
if (undelivered.length > 0) setQueueItems(queueRef.current.list());
|
|
5057
|
+
}
|
|
4904
5058
|
const nextPrompt = queueRef.current.dequeue();
|
|
4905
5059
|
if (nextPrompt) {
|
|
4906
5060
|
if (status === "exceeded") {
|
|
@@ -4924,7 +5078,8 @@ function Repl({
|
|
|
4924
5078
|
setPlanApproval,
|
|
4925
5079
|
cwd,
|
|
4926
5080
|
config,
|
|
4927
|
-
sessionCostUsd
|
|
5081
|
+
sessionCostUsd,
|
|
5082
|
+
terminalTitle
|
|
4928
5083
|
]
|
|
4929
5084
|
);
|
|
4930
5085
|
useEffect4(() => {
|
|
@@ -5072,11 +5227,41 @@ ${lines.join("\n")}`;
|
|
|
5072
5227
|
};
|
|
5073
5228
|
})
|
|
5074
5229
|
);
|
|
5230
|
+
const deleted = [];
|
|
5231
|
+
const onDelete = async (id) => {
|
|
5232
|
+
const picker2 = pickerRef.current;
|
|
5233
|
+
const option = (picker2?.options ?? options).find((o) => o.value === id);
|
|
5234
|
+
try {
|
|
5235
|
+
await deleteSession(id);
|
|
5236
|
+
} catch (error) {
|
|
5237
|
+
pushMessage(
|
|
5238
|
+
"system",
|
|
5239
|
+
`Failed to delete session ${shortSessionId(id)}: ${error instanceof Error ? error.message : String(error)}`
|
|
5240
|
+
);
|
|
5241
|
+
return picker2?.options ?? options;
|
|
5242
|
+
}
|
|
5243
|
+
deleted.push(option?.label ?? shortSessionId(id));
|
|
5244
|
+
const remaining = (picker2?.options ?? options).filter((o) => o.value !== id);
|
|
5245
|
+
if (picker2) {
|
|
5246
|
+
if (remaining.length === 0) {
|
|
5247
|
+
handlePickerCancel();
|
|
5248
|
+
} else {
|
|
5249
|
+
setPicker({ ...picker2, options: remaining });
|
|
5250
|
+
}
|
|
5251
|
+
}
|
|
5252
|
+
return remaining;
|
|
5253
|
+
};
|
|
5075
5254
|
const picked = await showPicker(
|
|
5076
5255
|
all ? "Resume a session (all directories)" : "Resume a session",
|
|
5077
|
-
options
|
|
5256
|
+
options,
|
|
5257
|
+
onDelete
|
|
5078
5258
|
);
|
|
5079
|
-
if (!picked)
|
|
5259
|
+
if (!picked) {
|
|
5260
|
+
if (deleted.length > 0) {
|
|
5261
|
+
return `Deleted ${deleted.length} session(s): ${deleted.join(", ")}.`;
|
|
5262
|
+
}
|
|
5263
|
+
return "Session unchanged \u2014 picker cancelled.";
|
|
5264
|
+
}
|
|
5080
5265
|
return resume(picked);
|
|
5081
5266
|
},
|
|
5082
5267
|
forkSession: async () => {
|
|
@@ -5293,7 +5478,7 @@ ${plan.affected.length} file change(s) will be reverted, ${messageCount} message
|
|
|
5293
5478
|
if (result.messageIndex !== null && current instanceof AgentLoop) {
|
|
5294
5479
|
retracted = await current.retractFromIndex(result.messageIndex);
|
|
5295
5480
|
if (retracted > 0) {
|
|
5296
|
-
const display = buildDisplayMessages([...current.
|
|
5481
|
+
const display = buildDisplayMessages([...current.getStarMessages()]);
|
|
5297
5482
|
nextIdRef.current = display.length;
|
|
5298
5483
|
redrawMessages(display);
|
|
5299
5484
|
}
|
|
@@ -5390,6 +5575,8 @@ ${plan.affected.length} file change(s) will be reverted, ${messageCount} message
|
|
|
5390
5575
|
setPendingRewind,
|
|
5391
5576
|
setPendingConnect,
|
|
5392
5577
|
showPicker,
|
|
5578
|
+
handlePickerCancel,
|
|
5579
|
+
setPicker,
|
|
5393
5580
|
stopBackgroundWork
|
|
5394
5581
|
]);
|
|
5395
5582
|
const runShellBang = useCallback(
|
|
@@ -5479,13 +5666,55 @@ ${plan.affected.length} file change(s) will be reverted, ${messageCount} message
|
|
|
5479
5666
|
const images = pendingImagesRef.current.map((staged) => staged.image);
|
|
5480
5667
|
if (images.length > 0) clearPendingImages();
|
|
5481
5668
|
if (abortRef.current || busyCommandRef.current) {
|
|
5669
|
+
const backend2 = backendRef.current;
|
|
5670
|
+
if (abortRef.current && images.length === 0 && backend2 instanceof AgentLoop) {
|
|
5671
|
+
void (async () => {
|
|
5672
|
+
const picked = await showPicker("Turn is running \u2014 how should this be sent?", [
|
|
5673
|
+
{
|
|
5674
|
+
value: "steer",
|
|
5675
|
+
label: "insert into the running turn",
|
|
5676
|
+
description: "delivered to the model at the next step boundary"
|
|
5677
|
+
},
|
|
5678
|
+
{
|
|
5679
|
+
value: "queue",
|
|
5680
|
+
label: "queue for after the turn",
|
|
5681
|
+
description: "sent as a new prompt once the current turn finishes"
|
|
5682
|
+
}
|
|
5683
|
+
]);
|
|
5684
|
+
if (picked === "steer") {
|
|
5685
|
+
backend2.injectUserMessage(text);
|
|
5686
|
+
pushMessage(
|
|
5687
|
+
"user",
|
|
5688
|
+
text,
|
|
5689
|
+
"steering the running turn \u2014 the model sees it at the next step",
|
|
5690
|
+
void 0,
|
|
5691
|
+
void 0,
|
|
5692
|
+
void 0,
|
|
5693
|
+
true
|
|
5694
|
+
);
|
|
5695
|
+
return;
|
|
5696
|
+
}
|
|
5697
|
+
queueRef.current.enqueue({ text, images });
|
|
5698
|
+
setQueueItems(queueRef.current.list());
|
|
5699
|
+
})();
|
|
5700
|
+
return;
|
|
5701
|
+
}
|
|
5482
5702
|
queueRef.current.enqueue({ text, images });
|
|
5483
5703
|
setQueueItems(queueRef.current.list());
|
|
5484
5704
|
return;
|
|
5485
5705
|
}
|
|
5486
5706
|
void runStream(text, images);
|
|
5487
5707
|
},
|
|
5488
|
-
[
|
|
5708
|
+
[
|
|
5709
|
+
registry,
|
|
5710
|
+
pushMessage,
|
|
5711
|
+
runStream,
|
|
5712
|
+
runShellBang,
|
|
5713
|
+
config,
|
|
5714
|
+
clearPendingImages,
|
|
5715
|
+
sessionCostUsd,
|
|
5716
|
+
showPicker
|
|
5717
|
+
]
|
|
5489
5718
|
);
|
|
5490
5719
|
const commandHints = useMemo(
|
|
5491
5720
|
() => registry.list().map((cmd) => ({
|
|
@@ -5497,15 +5726,21 @@ ${plan.affected.length} file change(s) will be reverted, ${messageCount} message
|
|
|
5497
5726
|
[registry]
|
|
5498
5727
|
);
|
|
5499
5728
|
useEffect4(() => {
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5729
|
+
const refresh = () => {
|
|
5730
|
+
setGitBranch(getGitSummaryCached(cwd)?.branch ?? null);
|
|
5731
|
+
const current = backendRef.current;
|
|
5732
|
+
if (current instanceof AgentLoop) {
|
|
5733
|
+
const window_ = contextWindowTokens(config, modelNameRef.current);
|
|
5734
|
+
const pct = current.estimateContextTokens() / window_ * 100;
|
|
5735
|
+
setContextPercent(pct < 10 ? Math.round(pct * 10) / 10 : Math.round(pct));
|
|
5736
|
+
} else {
|
|
5737
|
+
setContextPercent(null);
|
|
5738
|
+
}
|
|
5739
|
+
};
|
|
5740
|
+
refresh();
|
|
5741
|
+
if (!isStreaming) return;
|
|
5742
|
+
const timer = setInterval(refresh, 2e3);
|
|
5743
|
+
return () => clearInterval(timer);
|
|
5509
5744
|
}, [cwd, config, isStreaming, epoch, modelName]);
|
|
5510
5745
|
const sessionCost = sessionCostUsd();
|
|
5511
5746
|
return /* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", children: [
|
|
@@ -5545,7 +5780,8 @@ ${plan.affected.length} file change(s) will be reverted, ${messageCount} message
|
|
|
5545
5780
|
title: picker.title,
|
|
5546
5781
|
options: picker.options,
|
|
5547
5782
|
onSelect: handlePickerSelect,
|
|
5548
|
-
onCancel: handlePickerCancel
|
|
5783
|
+
onCancel: handlePickerCancel,
|
|
5784
|
+
onDelete: picker.onDelete
|
|
5549
5785
|
}
|
|
5550
5786
|
),
|
|
5551
5787
|
pendingConnect && /* @__PURE__ */ jsx11(
|
|
@@ -5634,4 +5870,4 @@ export {
|
|
|
5634
5870
|
Repl,
|
|
5635
5871
|
renderRepl
|
|
5636
5872
|
};
|
|
5637
|
-
//# sourceMappingURL=repl-
|
|
5873
|
+
//# sourceMappingURL=repl-YBNTJOSB.js.map
|