msapling 2.3.6-beta.61 → 2.3.6-beta.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +419 -148
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -19262,6 +19262,105 @@ var init_src3 = __esm({
|
|
|
19262
19262
|
}
|
|
19263
19263
|
});
|
|
19264
19264
|
|
|
19265
|
+
// src/runtime/terminalScreen.ts
|
|
19266
|
+
function sanitizeTerminalText(value, preserveNewlines = true) {
|
|
19267
|
+
const text = String(value ?? "");
|
|
19268
|
+
const escape = String.fromCharCode(27);
|
|
19269
|
+
const bell = String.fromCharCode(7);
|
|
19270
|
+
const withoutEscapes = text.replace(new RegExp(`${escape}\\](?:[^${bell}${escape}]|${escape}(?!\\\\))*?(?:${bell}|${escape}\\\\)`, "g"), "").replace(new RegExp(`${escape}P(?:[^${escape}]|${escape}(?!\\\\))*?(?:${escape}\\\\)`, "g"), "").replace(new RegExp(`${escape}\\[[0-?]*[ -/]*[@-~]`, "g"), "").replace(new RegExp(`${escape}[()][0-2A-Z]`, "g"), "").replace(new RegExp(`${escape}.`, "g"), "");
|
|
19271
|
+
let safe = "";
|
|
19272
|
+
for (const character of withoutEscapes) {
|
|
19273
|
+
const code = character.codePointAt(0) ?? 0;
|
|
19274
|
+
const isNewline = code === 10;
|
|
19275
|
+
const isControl = code < 32 || code === 127;
|
|
19276
|
+
if (isControl && (!preserveNewlines || !isNewline)) continue;
|
|
19277
|
+
safe += character;
|
|
19278
|
+
}
|
|
19279
|
+
return safe;
|
|
19280
|
+
}
|
|
19281
|
+
function enterAlternateScreen(output = process.stdout, env = process.env) {
|
|
19282
|
+
if (alternateScreenActive || !output.isTTY || env.MSAPLING_NO_ALT_SCREEN === "1" || env.TERM === "dumb") return false;
|
|
19283
|
+
output.write(ENTER_ALTERNATE_SCREEN + (env.MSAPLING_NO_MOUSE_SCROLL === "1" ? "" : ENABLE_MOUSE_SCROLL));
|
|
19284
|
+
alternateScreenActive = true;
|
|
19285
|
+
return true;
|
|
19286
|
+
}
|
|
19287
|
+
function isSgrMouseReport(input) {
|
|
19288
|
+
const escape = String.fromCharCode(27);
|
|
19289
|
+
return new RegExp(`${escape}\\[<[0-9]+;[0-9]+;[0-9]+[mM]`).test(input);
|
|
19290
|
+
}
|
|
19291
|
+
function parseMouseWheel(input) {
|
|
19292
|
+
const escape = String.fromCharCode(27);
|
|
19293
|
+
const match = new RegExp(`${escape}\\[<([0-9]+);[0-9]+;[0-9]+[mM]`).exec(input);
|
|
19294
|
+
if (!match) return null;
|
|
19295
|
+
const button = Number(match[1]);
|
|
19296
|
+
if (button === 64) return "up";
|
|
19297
|
+
if (button === 65) return "down";
|
|
19298
|
+
return null;
|
|
19299
|
+
}
|
|
19300
|
+
function leaveAlternateScreen(output = process.stdout) {
|
|
19301
|
+
if (!alternateScreenActive) return false;
|
|
19302
|
+
output.write(LEAVE_ALTERNATE_SCREEN);
|
|
19303
|
+
alternateScreenActive = false;
|
|
19304
|
+
return true;
|
|
19305
|
+
}
|
|
19306
|
+
var ENTER_ALTERNATE_SCREEN, ENABLE_MOUSE_SCROLL, LEAVE_ALTERNATE_SCREEN, alternateScreenActive, MAX_PROTOCOL_BUFFER, TerminalInputDecoder;
|
|
19307
|
+
var init_terminalScreen = __esm({
|
|
19308
|
+
"src/runtime/terminalScreen.ts"() {
|
|
19309
|
+
"use strict";
|
|
19310
|
+
init_esm_shims();
|
|
19311
|
+
ENTER_ALTERNATE_SCREEN = "\x1B[?1049h\x1B[H";
|
|
19312
|
+
ENABLE_MOUSE_SCROLL = "\x1B[?1000h\x1B[?1006h";
|
|
19313
|
+
LEAVE_ALTERNATE_SCREEN = "\x1B[?1006l\x1B[?1000l\x1B[?1049l\x1B[?25h";
|
|
19314
|
+
alternateScreenActive = false;
|
|
19315
|
+
MAX_PROTOCOL_BUFFER = 64 * 1024;
|
|
19316
|
+
TerminalInputDecoder = class {
|
|
19317
|
+
pending = "";
|
|
19318
|
+
inBracketedPaste = false;
|
|
19319
|
+
feed(input) {
|
|
19320
|
+
const escape = String.fromCharCode(27);
|
|
19321
|
+
if (this.inBracketedPaste) {
|
|
19322
|
+
const candidate2 = this.pending + input;
|
|
19323
|
+
const endMarker = `${escape}[201~`;
|
|
19324
|
+
const end = candidate2.indexOf(endMarker);
|
|
19325
|
+
if (end < 0) {
|
|
19326
|
+
if (candidate2.length > MAX_PROTOCOL_BUFFER) this.reset();
|
|
19327
|
+
else this.pending = candidate2;
|
|
19328
|
+
return { protocol: true, text: "", mouseWheel: null };
|
|
19329
|
+
}
|
|
19330
|
+
const text = candidate2.slice(0, end);
|
|
19331
|
+
const remainder = candidate2.slice(end + endMarker.length);
|
|
19332
|
+
this.reset();
|
|
19333
|
+
return { protocol: true, text: text + remainder, mouseWheel: null };
|
|
19334
|
+
}
|
|
19335
|
+
const candidate = this.pending + input;
|
|
19336
|
+
this.pending = "";
|
|
19337
|
+
const pasteStart = `${escape}[200~`;
|
|
19338
|
+
if (candidate.startsWith(pasteStart)) {
|
|
19339
|
+
this.inBracketedPaste = true;
|
|
19340
|
+
const remainder = candidate.slice(pasteStart.length);
|
|
19341
|
+
return this.feed(remainder);
|
|
19342
|
+
}
|
|
19343
|
+
if (!candidate.startsWith(escape)) return { protocol: false, text: input, mouseWheel: null };
|
|
19344
|
+
const wheel = parseMouseWheel(candidate);
|
|
19345
|
+
if (wheel || isSgrMouseReport(candidate)) {
|
|
19346
|
+
return { protocol: true, text: "", mouseWheel: wheel };
|
|
19347
|
+
}
|
|
19348
|
+
const sgrPrefix = `${escape}[<`;
|
|
19349
|
+
const isPartialSgr = sgrPrefix.startsWith(candidate) || candidate.startsWith(sgrPrefix);
|
|
19350
|
+
if (isPartialSgr && candidate.length <= MAX_PROTOCOL_BUFFER) {
|
|
19351
|
+
this.pending = candidate;
|
|
19352
|
+
return { protocol: true, text: "", mouseWheel: null };
|
|
19353
|
+
}
|
|
19354
|
+
return { protocol: true, text: "", mouseWheel: null };
|
|
19355
|
+
}
|
|
19356
|
+
reset() {
|
|
19357
|
+
this.pending = "";
|
|
19358
|
+
this.inBracketedPaste = false;
|
|
19359
|
+
}
|
|
19360
|
+
};
|
|
19361
|
+
}
|
|
19362
|
+
});
|
|
19363
|
+
|
|
19265
19364
|
// src/runtime/errorPresentation.ts
|
|
19266
19365
|
function errorRecord(error) {
|
|
19267
19366
|
return error && typeof error === "object" ? error : {};
|
|
@@ -19385,19 +19484,20 @@ function renderCliError(error) {
|
|
|
19385
19484
|
tool: "Local tool guardrail",
|
|
19386
19485
|
cli: "Local CLI"
|
|
19387
19486
|
}[error.surface];
|
|
19388
|
-
return [
|
|
19487
|
+
return sanitizeTerminalText([
|
|
19389
19488
|
`[${error.code}] ${error.summary}`,
|
|
19390
19489
|
`Surface: ${surface}`,
|
|
19391
19490
|
`Why: ${error.explanation}`,
|
|
19392
19491
|
`Next: ${error.action}`,
|
|
19393
19492
|
...error.detail ? [`Detail: ${error.detail}`] : []
|
|
19394
|
-
].join("\n");
|
|
19493
|
+
].join("\n"));
|
|
19395
19494
|
}
|
|
19396
19495
|
var init_errorPresentation = __esm({
|
|
19397
19496
|
"src/runtime/errorPresentation.ts"() {
|
|
19398
19497
|
"use strict";
|
|
19399
19498
|
init_esm_shims();
|
|
19400
19499
|
init_src3();
|
|
19500
|
+
init_terminalScreen();
|
|
19401
19501
|
}
|
|
19402
19502
|
});
|
|
19403
19503
|
|
|
@@ -19851,7 +19951,6 @@ var init_toggles = __esm({
|
|
|
19851
19951
|
sessionToggles = /* @__PURE__ */ new Map([
|
|
19852
19952
|
["effort", "medium"],
|
|
19853
19953
|
// 'low' | 'medium' | 'high'
|
|
19854
|
-
["vimMode", false],
|
|
19855
19954
|
["fastMode", false],
|
|
19856
19955
|
["simpleMode", false],
|
|
19857
19956
|
["filterRegex", null]
|
|
@@ -19906,12 +20005,18 @@ var init_toggles = __esm({
|
|
|
19906
20005
|
context.addMessage("system", `effort set to: ${arg}`);
|
|
19907
20006
|
}
|
|
19908
20007
|
};
|
|
19909
|
-
vimCommand =
|
|
19910
|
-
"vim",
|
|
19911
|
-
"
|
|
19912
|
-
"
|
|
19913
|
-
|
|
19914
|
-
|
|
20008
|
+
vimCommand = {
|
|
20009
|
+
name: "vim",
|
|
20010
|
+
args: "[on|off]",
|
|
20011
|
+
description: "Show Vim editor-mode availability (not yet implemented)",
|
|
20012
|
+
category: "config",
|
|
20013
|
+
handler: (_args, context) => {
|
|
20014
|
+
context.addMessage(
|
|
20015
|
+
"system",
|
|
20016
|
+
"Vim input mode is not available yet. /vim does not change editor behavior; use the standard cursor and history keys shown by /shortcuts."
|
|
20017
|
+
);
|
|
20018
|
+
}
|
|
20019
|
+
};
|
|
19915
20020
|
fastCommand = makeToggle(
|
|
19916
20021
|
"fast",
|
|
19917
20022
|
"fastMode",
|
|
@@ -23665,7 +23770,7 @@ var init_version = __esm({
|
|
|
23665
23770
|
description: "Show version information for CLI and core packages",
|
|
23666
23771
|
category: "debug",
|
|
23667
23772
|
handler: async (_args, context) => {
|
|
23668
|
-
const cliVersion = true ? "2.3.6-beta.
|
|
23773
|
+
const cliVersion = true ? "2.3.6-beta.62" : "(dev)";
|
|
23669
23774
|
const coreVersion = true ? "2.3.6-beta.43" : "(dev)";
|
|
23670
23775
|
const runtime = process.version;
|
|
23671
23776
|
context.addMessage("system", "MSapling Version Info");
|
|
@@ -23939,7 +24044,7 @@ var init_shortcuts = __esm({
|
|
|
23939
24044
|
shortcutsCommand = {
|
|
23940
24045
|
name: "shortcuts",
|
|
23941
24046
|
aliases: ["sc"],
|
|
23942
|
-
description: "List
|
|
24047
|
+
description: "List keyboard controls and registered slash commands",
|
|
23943
24048
|
category: "debug",
|
|
23944
24049
|
handler: (args2, context) => {
|
|
23945
24050
|
const { commands: commands2 } = (init_commands(), __toCommonJS(commands_exports));
|
|
@@ -23975,7 +24080,19 @@ ${matching.length} command(s) found.`);
|
|
|
23975
24080
|
...CATEGORY_ORDER2.filter((c) => grouped[c]),
|
|
23976
24081
|
...Object.keys(grouped).filter((c) => !CATEGORY_ORDER2.includes(c)).sort()
|
|
23977
24082
|
];
|
|
23978
|
-
context.addMessage("system",
|
|
24083
|
+
context.addMessage("system", [
|
|
24084
|
+
"Keyboard Controls",
|
|
24085
|
+
" \u2191/\u2193 (empty prompt) Scroll transcript one row",
|
|
24086
|
+
" PageUp/PageDown Scroll transcript one page",
|
|
24087
|
+
" Ctrl+E Return to newest transcript row",
|
|
24088
|
+
" \u2190/\u2192 Move the prompt cursor",
|
|
24089
|
+
" Ctrl+A Move to start of prompt",
|
|
24090
|
+
" Ctrl+P/Ctrl+N Previous/next prompt history",
|
|
24091
|
+
" Shift+Enter Insert a newline",
|
|
24092
|
+
" Escape/Ctrl+C Cancel current operation",
|
|
24093
|
+
"",
|
|
24094
|
+
"Registered Slash Commands"
|
|
24095
|
+
].join("\n"));
|
|
23979
24096
|
context.addMessage("system", tableSep());
|
|
23980
24097
|
for (const cat of cats) {
|
|
23981
24098
|
const cmds = grouped[cat].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -29692,7 +29809,7 @@ import { render } from "ink";
|
|
|
29692
29809
|
|
|
29693
29810
|
// src/App.tsx
|
|
29694
29811
|
init_esm_shims();
|
|
29695
|
-
import { useState as useState5, useEffect as useEffect3, useCallback as useCallback2, useRef } from "react";
|
|
29812
|
+
import { useState as useState5, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
29696
29813
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
29697
29814
|
import { Box as Box7, Text as Text7, useApp, useInput as useInput4, useStdout } from "ink";
|
|
29698
29815
|
|
|
@@ -29702,11 +29819,11 @@ import { Box, Text } from "ink";
|
|
|
29702
29819
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
29703
29820
|
var Header = ({ compact: compact2 = false }) => compact2 ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
29704
29821
|
"\u25CF MSapling v",
|
|
29705
|
-
"2.3.6-beta.
|
|
29706
|
-
] }) : /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
29822
|
+
"2.3.6-beta.62"
|
|
29823
|
+
] }) : /* @__PURE__ */ jsxs(Box, { width: "100%", borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
29707
29824
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
29708
29825
|
"\u25CF MSapling CLI v",
|
|
29709
|
-
"2.3.6-beta.
|
|
29826
|
+
"2.3.6-beta.62"
|
|
29710
29827
|
] }),
|
|
29711
29828
|
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
|
|
29712
29829
|
] });
|
|
@@ -29714,6 +29831,7 @@ var Header = ({ compact: compact2 = false }) => compact2 ? /* @__PURE__ */ jsxs(
|
|
|
29714
29831
|
// src/components/Footer.tsx
|
|
29715
29832
|
init_esm_shims();
|
|
29716
29833
|
init_src3();
|
|
29834
|
+
init_terminalScreen();
|
|
29717
29835
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
29718
29836
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
29719
29837
|
var PRO_TIERS2 = /* @__PURE__ */ new Set(["pro", "monthly", "lifetime", "enterprise", "admin", "superadmin"]);
|
|
@@ -29759,18 +29877,21 @@ var Footer = ({ user, options, model, project, chatId, cwd, mode, lastCost, sess
|
|
|
29759
29877
|
const showCapMeter = user ? shouldShowCapMeter(user) : false;
|
|
29760
29878
|
const dailyPct = user && showCapMeter ? Math.min(100, Math.round(user.daily_tokens_used / user.daily_tokens_limit * 100)) : 0;
|
|
29761
29879
|
const standaloneSearchCost = getSessionStats().snapshot().standaloneSearch.estimatedCostUsd;
|
|
29762
|
-
|
|
29880
|
+
const safeModel = sanitizeTerminalText(model, false);
|
|
29881
|
+
const safeProject = sanitizeTerminalText(project, false);
|
|
29882
|
+
const safeChatId = chatId ? sanitizeTerminalText(chatId, false) : null;
|
|
29883
|
+
return /* @__PURE__ */ jsxs2(Box2, { width: "100%", borderStyle: "round", borderColor: "gray", paddingX: 1, marginTop: 1, flexDirection: "column", children: [
|
|
29763
29884
|
/* @__PURE__ */ jsxs2(Box2, { justifyContent: "space-between", children: [
|
|
29764
29885
|
/* @__PURE__ */ jsx2(Text2, { bold: true, children: "CLI telemetry" }),
|
|
29765
29886
|
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: formatAccountSummary(user, { billingProfile, isStale, usageError }) })
|
|
29766
29887
|
] }),
|
|
29767
29888
|
expanded && options.chat && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
29768
29889
|
"project: ",
|
|
29769
|
-
|
|
29890
|
+
safeProject,
|
|
29770
29891
|
" chat: ",
|
|
29771
|
-
|
|
29892
|
+
safeChatId ?? "none",
|
|
29772
29893
|
" model: ",
|
|
29773
|
-
|
|
29894
|
+
safeModel
|
|
29774
29895
|
] }),
|
|
29775
29896
|
options.location && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
29776
29897
|
"cwd: ",
|
|
@@ -29808,6 +29929,7 @@ function promptLabel(user) {
|
|
|
29808
29929
|
|
|
29809
29930
|
// src/components/ApprovalDialog.tsx
|
|
29810
29931
|
init_esm_shims();
|
|
29932
|
+
init_terminalScreen();
|
|
29811
29933
|
import { useState, useMemo } from "react";
|
|
29812
29934
|
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
29813
29935
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -29873,7 +29995,11 @@ var ApprovalDialog = ({
|
|
|
29873
29995
|
onResolve
|
|
29874
29996
|
}) => {
|
|
29875
29997
|
const [showFullDiff, setShowFullDiff] = useState(false);
|
|
29876
|
-
const
|
|
29998
|
+
const safeCommand = sanitizeTerminalText(command, false);
|
|
29999
|
+
const safeReason = sanitizeTerminalText(reason);
|
|
30000
|
+
const safePath = targetPath ? sanitizeTerminalText(targetPath, false) : void 0;
|
|
30001
|
+
const safeDiff = diff ? sanitizeTerminalText(diff) : void 0;
|
|
30002
|
+
const { hasDiff, diffText, title } = useMemo(() => extractDiffFromCommand(safeCommand, safeDiff), [safeCommand, safeDiff]);
|
|
29877
30003
|
const diffLines = useMemo(() => parseDiffLines(diffText), [diffText]);
|
|
29878
30004
|
useInput((input, key) => {
|
|
29879
30005
|
if (key.escape) {
|
|
@@ -29895,16 +30021,16 @@ var ApprovalDialog = ({
|
|
|
29895
30021
|
const isTruncated = !showFullDiff && diffLines.length > MAX_DIFF_COLLAPSED_LINES;
|
|
29896
30022
|
return /* @__PURE__ */ jsxs3(Box3, { borderStyle: "double", borderColor: "yellow", paddingX: 1, marginY: 1, flexDirection: "column", children: [
|
|
29897
30023
|
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "yellow", children: "SECURITY APPROVAL REQUIRED" }),
|
|
29898
|
-
/* @__PURE__ */ jsx3(Text3, { italic: true, dimColor: true, children:
|
|
30024
|
+
/* @__PURE__ */ jsx3(Text3, { italic: true, dimColor: true, children: safeReason }),
|
|
29899
30025
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, paddingX: 1, borderStyle: "round", borderColor: "gray", children: /* @__PURE__ */ jsxs3(Text3, { color: "white", children: [
|
|
29900
30026
|
"$ ",
|
|
29901
|
-
|
|
30027
|
+
safeCommand
|
|
29902
30028
|
] }) }),
|
|
29903
30029
|
hasDiff && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, children: [
|
|
29904
30030
|
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", children: [
|
|
29905
30031
|
/* @__PURE__ */ jsxs3(Text3, { bold: true, color: "cyan", children: [
|
|
29906
30032
|
"DIFF REVIEW ",
|
|
29907
|
-
|
|
30033
|
+
safePath || title ? `(${safePath || sanitizeTerminalText(title, false)})` : "",
|
|
29908
30034
|
":"
|
|
29909
30035
|
] }),
|
|
29910
30036
|
/* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
@@ -29955,6 +30081,7 @@ var ApprovalDialog = ({
|
|
|
29955
30081
|
|
|
29956
30082
|
// src/components/AskUserQuestion.tsx
|
|
29957
30083
|
init_esm_shims();
|
|
30084
|
+
init_terminalScreen();
|
|
29958
30085
|
import { useState as useState2 } from "react";
|
|
29959
30086
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
29960
30087
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -29989,7 +30116,7 @@ var AskUserQuestion = ({ question, options, multiSelect, onResolve }) => {
|
|
|
29989
30116
|
});
|
|
29990
30117
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
29991
30118
|
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "QUESTION FROM AGENT" }),
|
|
29992
|
-
/* @__PURE__ */ jsx4(Text4, { children: question }),
|
|
30119
|
+
/* @__PURE__ */ jsx4(Text4, { children: sanitizeTerminalText(question) }),
|
|
29993
30120
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: options.map((opt, i) => {
|
|
29994
30121
|
const isHighlighted = i === selectedIndex;
|
|
29995
30122
|
const isSelected = selectedIndices.has(i);
|
|
@@ -30000,9 +30127,9 @@ var AskUserQuestion = ({ question, options, multiSelect, onResolve }) => {
|
|
|
30000
30127
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
30001
30128
|
/* @__PURE__ */ jsxs4(Text4, { color: isHighlighted ? "blue" : "white", bold: isHighlighted, children: [
|
|
30002
30129
|
marker,
|
|
30003
|
-
opt.text
|
|
30130
|
+
sanitizeTerminalText(opt.text, false)
|
|
30004
30131
|
] }),
|
|
30005
|
-
isHighlighted && opt.preview && /* @__PURE__ */ jsx4(Box4, { marginLeft: 4, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: opt.preview }) })
|
|
30132
|
+
isHighlighted && opt.preview && /* @__PURE__ */ jsx4(Box4, { marginLeft: 4, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: sanitizeTerminalText(opt.preview) }) })
|
|
30006
30133
|
] }, i);
|
|
30007
30134
|
}) }),
|
|
30008
30135
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
@@ -30015,37 +30142,12 @@ var AskUserQuestion = ({ question, options, multiSelect, onResolve }) => {
|
|
|
30015
30142
|
|
|
30016
30143
|
// src/components/VirtualizedMessageList.tsx
|
|
30017
30144
|
init_esm_shims();
|
|
30145
|
+
init_terminalScreen();
|
|
30018
30146
|
import React3 from "react";
|
|
30019
30147
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
30148
|
+
import stringWidth from "string-width";
|
|
30149
|
+
import stripAnsi2 from "strip-ansi";
|
|
30020
30150
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
30021
|
-
function estimateLineCount(text, cols) {
|
|
30022
|
-
const effectiveCols = cols > 0 ? cols : 80;
|
|
30023
|
-
const physicalLines = text.split("\n");
|
|
30024
|
-
let total = 0;
|
|
30025
|
-
for (const line of physicalLines) {
|
|
30026
|
-
total += line.length === 0 ? 1 : Math.ceil(line.length / effectiveCols);
|
|
30027
|
-
}
|
|
30028
|
-
return total;
|
|
30029
|
-
}
|
|
30030
|
-
function computeViewport(messages, visibleLines, termColumns, offsetFromEnd = 0) {
|
|
30031
|
-
const cols = termColumns > 0 ? termColumns : 80;
|
|
30032
|
-
const budget = Math.max(visibleLines, 1);
|
|
30033
|
-
let linesUsed = 0;
|
|
30034
|
-
const endIdx = Math.max(0, messages.length - Math.max(0, Math.floor(offsetFromEnd)));
|
|
30035
|
-
let startIdx = endIdx;
|
|
30036
|
-
for (let i = endIdx - 1; i >= 0; i--) {
|
|
30037
|
-
const contentLines = estimateLineCount(messages[i].content, cols);
|
|
30038
|
-
const msgCost = contentLines + 2;
|
|
30039
|
-
if (linesUsed + msgCost > budget) break;
|
|
30040
|
-
linesUsed += msgCost;
|
|
30041
|
-
startIdx = i;
|
|
30042
|
-
}
|
|
30043
|
-
return {
|
|
30044
|
-
displayMessages: messages.slice(startIdx, endIdx),
|
|
30045
|
-
hiddenCount: startIdx,
|
|
30046
|
-
hiddenAfter: messages.length - endIdx
|
|
30047
|
-
};
|
|
30048
|
-
}
|
|
30049
30151
|
var ROLE_COLOR = {
|
|
30050
30152
|
user: "green",
|
|
30051
30153
|
assistant: "cyan",
|
|
@@ -30058,6 +30160,96 @@ var ROLE_LABEL = {
|
|
|
30058
30160
|
error: "Error: ",
|
|
30059
30161
|
system: ""
|
|
30060
30162
|
};
|
|
30163
|
+
function cleanTerminalText(value) {
|
|
30164
|
+
return sanitizeTerminalText(stripAnsi2(value)).replace(/\r\n?/g, "\n").replace(/\t/g, " ");
|
|
30165
|
+
}
|
|
30166
|
+
function graphemes(value) {
|
|
30167
|
+
if (typeof Intl.Segmenter === "function") {
|
|
30168
|
+
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
30169
|
+
return Array.from(segmenter.segment(value), (segment) => segment.segment);
|
|
30170
|
+
}
|
|
30171
|
+
return Array.from(value);
|
|
30172
|
+
}
|
|
30173
|
+
function wrapTerminalLine(value, columns) {
|
|
30174
|
+
const width = Math.max(1, Math.floor(columns));
|
|
30175
|
+
if (value.length === 0) return [""];
|
|
30176
|
+
const rows = [];
|
|
30177
|
+
let row3 = "";
|
|
30178
|
+
let rowWidth = 0;
|
|
30179
|
+
for (const grapheme of graphemes(value)) {
|
|
30180
|
+
const cellWidth = Math.max(0, stringWidth(grapheme));
|
|
30181
|
+
if (row3.length > 0 && rowWidth + cellWidth > width) {
|
|
30182
|
+
rows.push(row3);
|
|
30183
|
+
row3 = "";
|
|
30184
|
+
rowWidth = 0;
|
|
30185
|
+
}
|
|
30186
|
+
row3 += grapheme;
|
|
30187
|
+
rowWidth += cellWidth;
|
|
30188
|
+
}
|
|
30189
|
+
rows.push(row3);
|
|
30190
|
+
return rows;
|
|
30191
|
+
}
|
|
30192
|
+
function buildTranscriptRows(messages, termColumns, compact2 = false) {
|
|
30193
|
+
const columns = termColumns > 0 ? Math.floor(termColumns) : 80;
|
|
30194
|
+
const separator = "\u2500".repeat(Math.max(1, Math.min(columns, 60)));
|
|
30195
|
+
const rows = [];
|
|
30196
|
+
messages.forEach((message2, messageIndex) => {
|
|
30197
|
+
if (compact2 && messageIndex > 0) {
|
|
30198
|
+
rows.push({ messageIndex, role: message2.role, prefix: "", content: separator, separator: true });
|
|
30199
|
+
}
|
|
30200
|
+
const label = ROLE_LABEL[message2.role];
|
|
30201
|
+
const labelWidth = stringWidth(label);
|
|
30202
|
+
const contentWidth = Math.max(1, columns - labelWidth);
|
|
30203
|
+
const continuationPrefix = " ".repeat(labelWidth);
|
|
30204
|
+
let firstVisualRow = true;
|
|
30205
|
+
for (const physicalLine of cleanTerminalText(message2.content).split("\n")) {
|
|
30206
|
+
const wrapped = wrapTerminalLine(physicalLine, contentWidth);
|
|
30207
|
+
for (const content of wrapped) {
|
|
30208
|
+
rows.push({
|
|
30209
|
+
messageIndex,
|
|
30210
|
+
role: message2.role,
|
|
30211
|
+
prefix: firstVisualRow ? label : continuationPrefix,
|
|
30212
|
+
content
|
|
30213
|
+
});
|
|
30214
|
+
firstVisualRow = false;
|
|
30215
|
+
}
|
|
30216
|
+
}
|
|
30217
|
+
if (!compact2 && message2.role === "assistant") {
|
|
30218
|
+
rows.push({ messageIndex, role: message2.role, prefix: "", content: "", margin: true });
|
|
30219
|
+
}
|
|
30220
|
+
});
|
|
30221
|
+
return rows;
|
|
30222
|
+
}
|
|
30223
|
+
function uniqueMessageCount(rows) {
|
|
30224
|
+
return new Set(rows.map((row3) => row3.messageIndex)).size;
|
|
30225
|
+
}
|
|
30226
|
+
function computeViewport(messages, visibleLines, termColumns, offsetFromEnd = 0, compact2 = false) {
|
|
30227
|
+
const allRows = buildTranscriptRows(messages, termColumns, compact2);
|
|
30228
|
+
const totalRows = allRows.length;
|
|
30229
|
+
const budget = Math.max(1, Math.floor(visibleLines));
|
|
30230
|
+
const hiddenRowsAfter = Math.min(totalRows, Math.max(0, Math.floor(offsetFromEnd)));
|
|
30231
|
+
const end = totalRows - hiddenRowsAfter;
|
|
30232
|
+
let contentBudget = budget;
|
|
30233
|
+
let start = Math.max(0, end - contentBudget);
|
|
30234
|
+
if (start > 0 || hiddenRowsAfter > 0) {
|
|
30235
|
+
contentBudget = Math.max(0, budget - 1);
|
|
30236
|
+
start = Math.max(0, end - contentBudget);
|
|
30237
|
+
}
|
|
30238
|
+
const displayRows = allRows.slice(start, end);
|
|
30239
|
+
const visibleIndices = [...new Set(displayRows.map((row3) => row3.messageIndex))];
|
|
30240
|
+
const displayMessages = visibleIndices.map((index) => messages[index]);
|
|
30241
|
+
const beforeRows = allRows.slice(0, start);
|
|
30242
|
+
const afterRows = allRows.slice(end);
|
|
30243
|
+
return {
|
|
30244
|
+
displayMessages,
|
|
30245
|
+
displayRows,
|
|
30246
|
+
hiddenCount: uniqueMessageCount(beforeRows),
|
|
30247
|
+
hiddenAfter: uniqueMessageCount(afterRows),
|
|
30248
|
+
hiddenRowsBefore: start,
|
|
30249
|
+
hiddenRowsAfter,
|
|
30250
|
+
totalRows
|
|
30251
|
+
};
|
|
30252
|
+
}
|
|
30061
30253
|
var VirtualizedMessageList = ({
|
|
30062
30254
|
messages,
|
|
30063
30255
|
visibleLines,
|
|
@@ -30065,45 +30257,27 @@ var VirtualizedMessageList = ({
|
|
|
30065
30257
|
compact: compact2 = false,
|
|
30066
30258
|
offsetFromEnd = 0
|
|
30067
30259
|
}) => {
|
|
30068
|
-
const {
|
|
30069
|
-
() => computeViewport(messages, visibleLines, termColumns, offsetFromEnd),
|
|
30070
|
-
[messages, visibleLines, termColumns, offsetFromEnd]
|
|
30260
|
+
const { displayRows, hiddenRowsBefore, hiddenRowsAfter } = React3.useMemo(
|
|
30261
|
+
() => computeViewport(messages, visibleLines, termColumns, offsetFromEnd, compact2),
|
|
30262
|
+
[messages, visibleLines, termColumns, offsetFromEnd, compact2]
|
|
30071
30263
|
);
|
|
30072
|
-
|
|
30073
|
-
|
|
30074
|
-
(
|
|
30075
|
-
|
|
30076
|
-
|
|
30077
|
-
|
|
30078
|
-
flexDirection: "column",
|
|
30079
|
-
marginBottom: compact2 ? 0 : msg.role === "assistant" ? 1 : 0,
|
|
30080
|
-
children: [
|
|
30081
|
-
compact2 && i > 0 && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "\u2500".repeat(separatorWidth) }),
|
|
30082
|
-
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
30083
|
-
/* @__PURE__ */ jsx5(
|
|
30084
|
-
Text5,
|
|
30085
|
-
{
|
|
30086
|
-
color: ROLE_COLOR[msg.role],
|
|
30087
|
-
bold: msg.role !== "assistant",
|
|
30088
|
-
children: ROLE_LABEL[msg.role]
|
|
30089
|
-
}
|
|
30090
|
-
),
|
|
30091
|
-
/* @__PURE__ */ jsx5(Text5, { wrap: "wrap", children: msg.content })
|
|
30092
|
-
] })
|
|
30093
|
-
]
|
|
30094
|
-
},
|
|
30095
|
-
i
|
|
30096
|
-
))
|
|
30264
|
+
return /* @__PURE__ */ jsxs5(Box5, { width: "100%", flexDirection: "column", flexGrow: 1, children: [
|
|
30265
|
+
(hiddenRowsBefore > 0 || hiddenRowsAfter > 0) && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: `[\u2191 ${hiddenRowsBefore} rows \xB7 \u2193 ${hiddenRowsAfter} \xB7 PgUp/PgDn \xB7 Ctrl+E latest]` }),
|
|
30266
|
+
displayRows.map((row3, index) => row3.separator ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: row3.content }, `${row3.messageIndex}-${index}`) : row3.margin ? /* @__PURE__ */ jsx5(Text5, { children: " " }, `${row3.messageIndex}-${index}`) : /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate-end", children: [
|
|
30267
|
+
/* @__PURE__ */ jsx5(Text5, { color: ROLE_COLOR[row3.role], bold: row3.role !== "assistant", children: row3.prefix }),
|
|
30268
|
+
row3.content
|
|
30269
|
+
] }, `${row3.messageIndex}-${index}`))
|
|
30097
30270
|
] });
|
|
30098
30271
|
};
|
|
30099
30272
|
|
|
30100
30273
|
// src/App.tsx
|
|
30274
|
+
init_terminalScreen();
|
|
30101
30275
|
init_src();
|
|
30102
30276
|
init_src3();
|
|
30103
30277
|
|
|
30104
30278
|
// src/ui/TextInput.tsx
|
|
30105
30279
|
init_esm_shims();
|
|
30106
|
-
import { useState as useState3, useEffect } from "react";
|
|
30280
|
+
import React4, { useState as useState3, useEffect } from "react";
|
|
30107
30281
|
import { Box as Box6, Text as Text6, useInput as useInput3 } from "ink";
|
|
30108
30282
|
|
|
30109
30283
|
// src/state/commandHandler.ts
|
|
@@ -30690,7 +30864,42 @@ ${finalCmd}`;
|
|
|
30690
30864
|
}
|
|
30691
30865
|
|
|
30692
30866
|
// src/ui/TextInput.tsx
|
|
30867
|
+
init_terminalScreen();
|
|
30693
30868
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
30869
|
+
function sanitizePromptInput(value) {
|
|
30870
|
+
return sanitizeTerminalText(value);
|
|
30871
|
+
}
|
|
30872
|
+
function cursorBoundaries(value) {
|
|
30873
|
+
if (typeof Intl.Segmenter !== "function") {
|
|
30874
|
+
return Array.from({ length: value.length + 1 }, (_, index) => index);
|
|
30875
|
+
}
|
|
30876
|
+
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
30877
|
+
return [0, ...Array.from(segmenter.segment(value), (segment) => segment.index + segment.segment.length)];
|
|
30878
|
+
}
|
|
30879
|
+
function moveCursorLeft(value, cursor) {
|
|
30880
|
+
const boundaries = cursorBoundaries(value);
|
|
30881
|
+
return boundaries[Math.max(0, boundaries.findIndex((boundary) => boundary >= cursor) - 1)] ?? 0;
|
|
30882
|
+
}
|
|
30883
|
+
function moveCursorRight(value, cursor) {
|
|
30884
|
+
const boundaries = cursorBoundaries(value);
|
|
30885
|
+
return boundaries.find((boundary) => boundary > cursor) ?? value.length;
|
|
30886
|
+
}
|
|
30887
|
+
function moveCursorWordLeft(value, cursor) {
|
|
30888
|
+
const boundaries = cursorBoundaries(value);
|
|
30889
|
+
let index = boundaries.findIndex((boundary) => boundary >= cursor);
|
|
30890
|
+
if (index < 0) index = boundaries.length - 1;
|
|
30891
|
+
while (index > 0 && /\s/.test(value.slice(boundaries[index - 1], boundaries[index]))) index--;
|
|
30892
|
+
while (index > 0 && !/\s/.test(value.slice(boundaries[index - 1], boundaries[index]))) index--;
|
|
30893
|
+
return boundaries[index] ?? 0;
|
|
30894
|
+
}
|
|
30895
|
+
function moveCursorWordRight(value, cursor) {
|
|
30896
|
+
const boundaries = cursorBoundaries(value);
|
|
30897
|
+
let index = boundaries.findIndex((boundary) => boundary > cursor);
|
|
30898
|
+
if (index < 0) return value.length;
|
|
30899
|
+
while (index < boundaries.length - 1 && !/\s/.test(value.slice(boundaries[index], boundaries[index + 1]))) index++;
|
|
30900
|
+
while (index < boundaries.length - 1 && /\s/.test(value.slice(boundaries[index], boundaries[index + 1]))) index++;
|
|
30901
|
+
return boundaries[index] ?? value.length;
|
|
30902
|
+
}
|
|
30694
30903
|
var TextInput = ({
|
|
30695
30904
|
value,
|
|
30696
30905
|
onChange,
|
|
@@ -30702,11 +30911,24 @@ var TextInput = ({
|
|
|
30702
30911
|
transcriptNavigationActive = false
|
|
30703
30912
|
}) => {
|
|
30704
30913
|
const [history, setHistory] = useState3([]);
|
|
30914
|
+
const terminalInputDecoder = React4.useRef(new TerminalInputDecoder());
|
|
30705
30915
|
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
30916
|
+
const [cursor, setCursor] = useState3(value.length);
|
|
30706
30917
|
useEffect(() => {
|
|
30707
30918
|
storage.loadHistory().then((entries) => setHistory(filterSafeHistory(entries)));
|
|
30708
30919
|
}, [storage]);
|
|
30920
|
+
useEffect(() => {
|
|
30921
|
+
setCursor((current) => Math.min(current, value.length));
|
|
30922
|
+
}, [value]);
|
|
30709
30923
|
useInput3((input, key) => {
|
|
30924
|
+
const decoded = terminalInputDecoder.current.feed(input);
|
|
30925
|
+
if (decoded.protocol && key.escape) {
|
|
30926
|
+
terminalInputDecoder.current.reset();
|
|
30927
|
+
} else if (decoded.protocol) {
|
|
30928
|
+
if (!decoded.text) return;
|
|
30929
|
+
input = decoded.text;
|
|
30930
|
+
}
|
|
30931
|
+
const extendedKey = key;
|
|
30710
30932
|
if (key.ctrl && input === "c" || key.escape) {
|
|
30711
30933
|
onCancel?.();
|
|
30712
30934
|
return;
|
|
@@ -30714,39 +30936,70 @@ var TextInput = ({
|
|
|
30714
30936
|
if (disabled) return;
|
|
30715
30937
|
if (key.return) {
|
|
30716
30938
|
if (key.shift) {
|
|
30717
|
-
onChange(value + "\n");
|
|
30939
|
+
onChange(value.slice(0, cursor) + "\n" + value.slice(cursor));
|
|
30940
|
+
setCursor(cursor + 1);
|
|
30718
30941
|
} else {
|
|
30719
30942
|
onSubmit(value);
|
|
30720
30943
|
onChange("");
|
|
30944
|
+
setCursor(0);
|
|
30721
30945
|
setHistoryIndex(-1);
|
|
30722
30946
|
}
|
|
30723
|
-
} else if (key.backspace
|
|
30724
|
-
|
|
30947
|
+
} else if (key.backspace) {
|
|
30948
|
+
if (cursor > 0) {
|
|
30949
|
+
onChange(value.slice(0, cursor - 1) + value.slice(cursor));
|
|
30950
|
+
setCursor(cursor - 1);
|
|
30951
|
+
}
|
|
30952
|
+
} else if (key.delete) {
|
|
30953
|
+
if (cursor < value.length) onChange(value.slice(0, cursor) + value.slice(cursor + 1));
|
|
30954
|
+
} else if (extendedKey.home || key.ctrl && input === "a") {
|
|
30955
|
+
setCursor(0);
|
|
30956
|
+
} else if (extendedKey.end) {
|
|
30957
|
+
setCursor(value.length);
|
|
30958
|
+
} else if (key.leftArrow && key.ctrl) {
|
|
30959
|
+
setCursor((current) => moveCursorWordLeft(value, current));
|
|
30960
|
+
} else if (key.rightArrow && key.ctrl) {
|
|
30961
|
+
setCursor((current) => moveCursorWordRight(value, current));
|
|
30962
|
+
} else if (key.leftArrow) {
|
|
30963
|
+
setCursor((current) => moveCursorLeft(value, current));
|
|
30964
|
+
} else if (key.rightArrow) {
|
|
30965
|
+
setCursor((current) => moveCursorRight(value, current));
|
|
30725
30966
|
} else if (key.ctrl && input === "p" || key.upArrow && !transcriptNavigationActive) {
|
|
30726
30967
|
const nextIndex = historyIndex + 1;
|
|
30727
30968
|
if (nextIndex < history.length) {
|
|
30728
30969
|
setHistoryIndex(nextIndex);
|
|
30729
|
-
|
|
30970
|
+
const entry = history[history.length - 1 - nextIndex];
|
|
30971
|
+
const safeEntry = sanitizePromptInput(entry);
|
|
30972
|
+
onChange(safeEntry);
|
|
30973
|
+
setCursor(safeEntry.length);
|
|
30730
30974
|
}
|
|
30731
30975
|
} else if (key.ctrl && input === "n" || key.downArrow && !transcriptNavigationActive) {
|
|
30732
30976
|
const nextIndex = historyIndex - 1;
|
|
30733
30977
|
if (nextIndex >= 0) {
|
|
30734
30978
|
setHistoryIndex(nextIndex);
|
|
30735
|
-
|
|
30979
|
+
const entry = history[history.length - 1 - nextIndex];
|
|
30980
|
+
const safeEntry = sanitizePromptInput(entry);
|
|
30981
|
+
onChange(safeEntry);
|
|
30982
|
+
setCursor(safeEntry.length);
|
|
30736
30983
|
} else {
|
|
30737
30984
|
setHistoryIndex(-1);
|
|
30738
30985
|
onChange("");
|
|
30986
|
+
setCursor(0);
|
|
30739
30987
|
}
|
|
30740
30988
|
} else if ((key.upArrow || key.downArrow) && transcriptNavigationActive) {
|
|
30741
30989
|
return;
|
|
30742
30990
|
} else if (input && !key.ctrl && !key.meta) {
|
|
30743
|
-
|
|
30991
|
+
const safeInput = sanitizePromptInput(input);
|
|
30992
|
+
if (safeInput.length > 0) {
|
|
30993
|
+
onChange(value.slice(0, cursor) + safeInput + value.slice(cursor));
|
|
30994
|
+
setCursor(cursor + safeInput.length);
|
|
30995
|
+
}
|
|
30744
30996
|
}
|
|
30745
30997
|
});
|
|
30746
|
-
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
30998
|
+
return /* @__PURE__ */ jsxs6(Box6, { width: "100%", children: [
|
|
30747
30999
|
/* @__PURE__ */ jsx6(Text6, { bold: true, color: promptColor, children: "\u276F " }),
|
|
30748
|
-
/* @__PURE__ */ jsx6(Text6, { children: value }),
|
|
30749
|
-
!disabled && /* @__PURE__ */ jsx6(Text6, { backgroundColor: "white", color: "black", children: " " })
|
|
31000
|
+
/* @__PURE__ */ jsx6(Text6, { children: value.slice(0, cursor) }),
|
|
31001
|
+
!disabled && /* @__PURE__ */ jsx6(Text6, { backgroundColor: "white", color: "black", children: value[cursor] ?? " " }),
|
|
31002
|
+
/* @__PURE__ */ jsx6(Text6, { children: disabled ? value.slice(cursor) : value.slice(cursor + 1) })
|
|
30750
31003
|
] });
|
|
30751
31004
|
};
|
|
30752
31005
|
var PROMPT_COLOR_BY_MODE = {
|
|
@@ -30929,19 +31182,29 @@ init_errorPresentation();
|
|
|
30929
31182
|
|
|
30930
31183
|
// src/hooks/useTerminalResize.ts
|
|
30931
31184
|
init_esm_shims();
|
|
30932
|
-
import { useState as useState4, useEffect as useEffect2, useCallback } from "react";
|
|
30933
|
-
function
|
|
31185
|
+
import { useState as useState4, useEffect as useEffect2, useCallback, useRef } from "react";
|
|
31186
|
+
function normalizeTerminalDimensions(columns, rows) {
|
|
30934
31187
|
return {
|
|
30935
|
-
columns:
|
|
30936
|
-
rows:
|
|
31188
|
+
columns: Number.isFinite(columns) && columns > 0 ? Math.floor(columns) : 80,
|
|
31189
|
+
rows: Number.isFinite(rows) && rows > 0 ? Math.floor(rows) : 24
|
|
30937
31190
|
};
|
|
30938
31191
|
}
|
|
31192
|
+
function getCurrentDimensions() {
|
|
31193
|
+
return normalizeTerminalDimensions(process.stdout.columns ?? 80, process.stdout.rows ?? 24);
|
|
31194
|
+
}
|
|
30939
31195
|
function useTerminalResize() {
|
|
30940
31196
|
const [dimensions, setDimensions] = useState4(
|
|
30941
31197
|
getCurrentDimensions
|
|
30942
31198
|
);
|
|
31199
|
+
const resizeTimer = useRef(null);
|
|
31200
|
+
const resizeEpoch = useRef(0);
|
|
30943
31201
|
const handleResize = useCallback(() => {
|
|
30944
|
-
|
|
31202
|
+
const epoch = ++resizeEpoch.current;
|
|
31203
|
+
if (resizeTimer.current !== null) clearTimeout(resizeTimer.current);
|
|
31204
|
+
resizeTimer.current = setTimeout(() => {
|
|
31205
|
+
resizeTimer.current = null;
|
|
31206
|
+
if (epoch === resizeEpoch.current) setDimensions(getCurrentDimensions());
|
|
31207
|
+
}, 16);
|
|
30945
31208
|
}, []);
|
|
30946
31209
|
useEffect2(() => {
|
|
30947
31210
|
process.stdout.on("resize", handleResize);
|
|
@@ -30949,6 +31212,8 @@ function useTerminalResize() {
|
|
|
30949
31212
|
process.on("SIGWINCH", onSigwinch);
|
|
30950
31213
|
handleResize();
|
|
30951
31214
|
return () => {
|
|
31215
|
+
if (resizeTimer.current !== null) clearTimeout(resizeTimer.current);
|
|
31216
|
+
resizeTimer.current = null;
|
|
30952
31217
|
process.stdout.off("resize", handleResize);
|
|
30953
31218
|
process.off("SIGWINCH", onSigwinch);
|
|
30954
31219
|
};
|
|
@@ -31021,6 +31286,7 @@ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
31021
31286
|
var App = ({ compact: compact2 = false, continueSession: continueSession2 = false, executionMode: executionMode2 = "remote" }) => {
|
|
31022
31287
|
const [user, setUser] = useState5(null);
|
|
31023
31288
|
const [input, setInput] = useState5("");
|
|
31289
|
+
const terminalInputDecoder = useRef2(new TerminalInputDecoder());
|
|
31024
31290
|
const [history, setHistory] = useState5([]);
|
|
31025
31291
|
const [historyView, setHistoryView] = useState5(null);
|
|
31026
31292
|
const [historyOffset, setHistoryOffset] = useState5(0);
|
|
@@ -31046,20 +31312,20 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31046
31312
|
const [billingProfile, setBillingProfile] = useState5(executionMode2 === "local" ? "ollama" : "account-metered");
|
|
31047
31313
|
const [continuityProfile, setContinuityProfile] = useState5(executionMode2 === "local" ? "standalone-private" : "connected-mirrored");
|
|
31048
31314
|
const [bootstrapState, setBootstrapState] = useState5("loading");
|
|
31049
|
-
const submissionLockRef =
|
|
31315
|
+
const submissionLockRef = useRef2(false);
|
|
31050
31316
|
const { exit } = useApp();
|
|
31051
31317
|
const { stdout: termStdout } = useStdout();
|
|
31052
31318
|
const { columns: termResizeCols, rows: termResizeRows } = useTerminalResize();
|
|
31053
|
-
const storage =
|
|
31054
|
-
const client =
|
|
31319
|
+
const storage = useRef2(new StorageManager()).current;
|
|
31320
|
+
const client = useRef2(new MSaplingClient()).current;
|
|
31055
31321
|
const remoteEnvironment = describeRemoteEnvironment(client.getApiUrl());
|
|
31056
|
-
const modeContract =
|
|
31322
|
+
const modeContract = useRef2(new CliModeRuntime({
|
|
31057
31323
|
mode: executionMode2,
|
|
31058
31324
|
provider: process.env.MSAPLING_LOCAL_LLM_PROVIDER ?? "ollama"
|
|
31059
31325
|
})).current;
|
|
31060
|
-
const sessionRecovery =
|
|
31061
|
-
const checkpointTurns =
|
|
31062
|
-
const agentRef =
|
|
31326
|
+
const sessionRecovery = useRef2(new CliSessionRecovery()).current;
|
|
31327
|
+
const checkpointTurns = useRef2(/* @__PURE__ */ new Map()).current;
|
|
31328
|
+
const agentRef = useRef2(null);
|
|
31063
31329
|
const requestApproval = useCallback2((request) => {
|
|
31064
31330
|
agentRef.current?.fireLifecycleHook(
|
|
31065
31331
|
"notification",
|
|
@@ -31070,7 +31336,7 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31070
31336
|
setPendingApproval({ request, resolve: resolve31 });
|
|
31071
31337
|
});
|
|
31072
31338
|
}, []);
|
|
31073
|
-
const agent =
|
|
31339
|
+
const agent = useRef2(new Agent(client, process.cwd(), requestApproval, { executionMode: executionMode2, modeContract })).current;
|
|
31074
31340
|
agentRef.current = agent;
|
|
31075
31341
|
const applyStandaloneSyncState = (state) => {
|
|
31076
31342
|
const localChatId = "local-cli-chat";
|
|
@@ -31091,9 +31357,9 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31091
31357
|
setContinuityProfile(profile);
|
|
31092
31358
|
if (profile === "standalone-private") agent.configureStandaloneSync(null);
|
|
31093
31359
|
};
|
|
31094
|
-
const trustStore =
|
|
31095
|
-
const lastActivityRef =
|
|
31096
|
-
const pollingIntervalRef =
|
|
31360
|
+
const trustStore = useRef2(new TrustStore()).current;
|
|
31361
|
+
const lastActivityRef = useRef2(Date.now());
|
|
31362
|
+
const pollingIntervalRef = useRef2(null);
|
|
31097
31363
|
useEffect3(() => {
|
|
31098
31364
|
agent.setApprovalCallback(requestApproval);
|
|
31099
31365
|
}, [agent, requestApproval]);
|
|
@@ -31147,7 +31413,7 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31147
31413
|
setContextBudgetSnap(snapshotBudget(agent.getContextBudget()));
|
|
31148
31414
|
}, [agent]);
|
|
31149
31415
|
const getModel = useCallback2(() => activeModel, [activeModel]);
|
|
31150
|
-
const cliProjectRef =
|
|
31416
|
+
const cliProjectRef = useRef2(null);
|
|
31151
31417
|
const setProjectId = useCallback2((id) => {
|
|
31152
31418
|
if (cliProjectRef.current && id !== cliProjectRef.current) return;
|
|
31153
31419
|
setActiveProjectId(id);
|
|
@@ -31472,7 +31738,7 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31472
31738
|
return { journalEvents, checkpoints };
|
|
31473
31739
|
}
|
|
31474
31740
|
});
|
|
31475
|
-
const relayCommandRef =
|
|
31741
|
+
const relayCommandRef = useRef2(handleCommand);
|
|
31476
31742
|
relayCommandRef.current = handleCommand;
|
|
31477
31743
|
useEffect3(() => {
|
|
31478
31744
|
if (executionMode2 !== "remote" || process.env.MSAPLING_RELAY_ENABLED !== "1" || !activeProjectId) return;
|
|
@@ -31511,21 +31777,45 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31511
31777
|
const activityRows = pendingApproval ? 6 : pendingAskUser ? 10 : isRunning ? 2 : 0;
|
|
31512
31778
|
const visibleLines = Math.max(termHeight - (terminalLayout.fixedRows + footerRows + modeRows + activityRows), 1);
|
|
31513
31779
|
const displayedHistory = historyView ?? history;
|
|
31514
|
-
const historyPageStep = Math.max(1,
|
|
31515
|
-
const viewport = computeViewport(displayedHistory, visibleLines, termColumns, historyOffset);
|
|
31516
|
-
const
|
|
31780
|
+
const historyPageStep = Math.max(1, visibleLines - 1);
|
|
31781
|
+
const viewport = computeViewport(displayedHistory, visibleLines, termColumns, historyOffset, compactPresentation);
|
|
31782
|
+
const safeStatus = sanitizeTerminalText(status2, false);
|
|
31783
|
+
const safeProjectId = sanitizeTerminalText(activeProjectId || "none", false);
|
|
31784
|
+
const safeModel = sanitizeTerminalText(activeModel, false);
|
|
31785
|
+
const safeEnvironment = sanitizeTerminalText(remoteEnvironment.label, false);
|
|
31786
|
+
const canScrollOlder = viewport.hiddenRowsBefore > 0;
|
|
31517
31787
|
const canScrollNewer = historyOffset > 0;
|
|
31788
|
+
const previousTranscriptRowsRef = useRef2(viewport.totalRows);
|
|
31789
|
+
useEffect3(() => {
|
|
31790
|
+
const previousRows = previousTranscriptRowsRef.current;
|
|
31791
|
+
previousTranscriptRowsRef.current = viewport.totalRows;
|
|
31792
|
+
const rowDelta = viewport.totalRows - previousRows;
|
|
31793
|
+
if (historyOffset > 0 && rowDelta !== 0) {
|
|
31794
|
+
setHistoryOffset((current) => Math.min(
|
|
31795
|
+
Math.max(0, viewport.totalRows - 1),
|
|
31796
|
+
Math.max(0, current + rowDelta)
|
|
31797
|
+
));
|
|
31798
|
+
}
|
|
31799
|
+
}, [historyOffset, viewport.totalRows]);
|
|
31518
31800
|
const scrollTranscript = useCallback2((direction, page = false) => {
|
|
31519
31801
|
const amount = page ? historyPageStep : 1;
|
|
31520
31802
|
if (direction === "up") {
|
|
31521
|
-
setHistoryOffset((current) => Math.min(Math.max(0,
|
|
31803
|
+
setHistoryOffset((current) => Math.min(Math.max(0, viewport.totalRows - 1), current + amount));
|
|
31522
31804
|
} else {
|
|
31523
31805
|
setHistoryOffset((current) => Math.max(0, current - amount));
|
|
31524
31806
|
}
|
|
31525
|
-
}, [
|
|
31807
|
+
}, [historyPageStep, viewport.totalRows]);
|
|
31526
31808
|
useInput4((input2, key) => {
|
|
31527
31809
|
if (pendingApproval || pendingAskUser) return;
|
|
31528
|
-
|
|
31810
|
+
const decoded = terminalInputDecoder.current.feed(input2);
|
|
31811
|
+
if (decoded.protocol && !decoded.mouseWheel) return;
|
|
31812
|
+
if (isSgrMouseReport(input2) && !parseMouseWheel(input2)) return;
|
|
31813
|
+
const mouseWheel = decoded.mouseWheel ?? parseMouseWheel(input2);
|
|
31814
|
+
if (mouseWheel === "up") {
|
|
31815
|
+
scrollTranscript("up");
|
|
31816
|
+
} else if (mouseWheel === "down") {
|
|
31817
|
+
scrollTranscript("down");
|
|
31818
|
+
} else if (key.pageUp) {
|
|
31529
31819
|
scrollTranscript("up", true);
|
|
31530
31820
|
} else if (key.pageDown) {
|
|
31531
31821
|
scrollTranscript("down", true);
|
|
@@ -31538,9 +31828,9 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31538
31828
|
setHistoryView(null);
|
|
31539
31829
|
}
|
|
31540
31830
|
});
|
|
31541
|
-
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", padding: terminalLayout.outerPadding, children: [
|
|
31831
|
+
return /* @__PURE__ */ jsxs7(Box7, { width: termColumns, height: termHeight, flexDirection: "column", padding: terminalLayout.outerPadding, overflow: "hidden", children: [
|
|
31542
31832
|
/* @__PURE__ */ jsx7(Header, { compact: !terminalLayout.showFramedHeader }),
|
|
31543
|
-
/* @__PURE__ */ jsx7(Box7, {
|
|
31833
|
+
/* @__PURE__ */ jsx7(Box7, { width: "100%", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx7(
|
|
31544
31834
|
VirtualizedMessageList,
|
|
31545
31835
|
{
|
|
31546
31836
|
messages: displayedHistory,
|
|
@@ -31615,7 +31905,7 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31615
31905
|
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
31616
31906
|
/* @__PURE__ */ jsxs7(Text7, { color: executionMode2 === "local" ? "yellow" : "cyan", children: [
|
|
31617
31907
|
"Execution: ",
|
|
31618
|
-
executionMode2 === "local" ? "STANDALONE LOCAL" :
|
|
31908
|
+
executionMode2 === "local" ? "STANDALONE LOCAL" : safeEnvironment
|
|
31619
31909
|
] }),
|
|
31620
31910
|
/* @__PURE__ */ jsxs7(Text7, { color: billingProfile === "account-metered" ? "cyan" : "yellow", children: [
|
|
31621
31911
|
"Billing: ",
|
|
@@ -31628,15 +31918,15 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31628
31918
|
] }),
|
|
31629
31919
|
/* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
|
|
31630
31920
|
"Status: ",
|
|
31631
|
-
|
|
31921
|
+
safeStatus
|
|
31632
31922
|
] }),
|
|
31633
31923
|
/* @__PURE__ */ jsxs7(Text7, { color: "gray", children: [
|
|
31634
31924
|
"Project: ",
|
|
31635
|
-
|
|
31925
|
+
safeProjectId
|
|
31636
31926
|
] }),
|
|
31637
31927
|
/* @__PURE__ */ jsxs7(Text7, { color: "gray", children: [
|
|
31638
31928
|
"Model: ",
|
|
31639
|
-
|
|
31929
|
+
safeModel
|
|
31640
31930
|
] })
|
|
31641
31931
|
] }),
|
|
31642
31932
|
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", alignItems: "flex-end", children: [
|
|
@@ -31651,9 +31941,9 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31651
31941
|
contextBudgetSnap !== null && /* @__PURE__ */ jsx7(Text7, { color: contextBudgetColor(contextBudgetSnap.usedPct), children: formatContextBudgetLabel(contextBudgetSnap) })
|
|
31652
31942
|
] })
|
|
31653
31943
|
] }),
|
|
31654
|
-
terminalLayout.density === "condensed" && /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
31944
|
+
terminalLayout.density === "condensed" && /* @__PURE__ */ jsxs7(Box7, { width: "100%", flexDirection: "column", children: [
|
|
31655
31945
|
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate-end", color: executionMode2 === "local" ? "yellow" : "cyan", children: [
|
|
31656
|
-
executionMode2 === "local" ? "LOCAL" :
|
|
31946
|
+
executionMode2 === "local" ? "LOCAL" : safeEnvironment.replace("CONNECTED ", ""),
|
|
31657
31947
|
" \xB7 ",
|
|
31658
31948
|
mode,
|
|
31659
31949
|
" \xB7 ",
|
|
@@ -31662,17 +31952,17 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31662
31952
|
continuityProfile
|
|
31663
31953
|
] }),
|
|
31664
31954
|
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate-end", dimColor: true, children: [
|
|
31665
|
-
|
|
31955
|
+
safeModel,
|
|
31666
31956
|
contextBudgetSnap ? ` \xB7 ${formatContextBudgetLabel(contextBudgetSnap)}` : "",
|
|
31667
31957
|
lastCost > 0 ? ` \xB7 last $${lastCost.toFixed(4)}` : ""
|
|
31668
31958
|
] })
|
|
31669
31959
|
] }),
|
|
31670
31960
|
terminalLayout.density === "minimal" && /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate-end", dimColor: true, children: [
|
|
31671
|
-
executionMode2 === "local" ? "LOCAL" :
|
|
31961
|
+
executionMode2 === "local" ? "LOCAL" : safeEnvironment.replace("CONNECTED ", ""),
|
|
31672
31962
|
" \xB7 ",
|
|
31673
31963
|
mode,
|
|
31674
31964
|
" \xB7 ",
|
|
31675
|
-
|
|
31965
|
+
safeModel,
|
|
31676
31966
|
lastCost > 0 ? ` \xB7 $${lastCost.toFixed(4)}` : "",
|
|
31677
31967
|
contextBudgetSnap ? ` \xB7 ctx ${contextBudgetSnap.usedPct}%` : ""
|
|
31678
31968
|
] }),
|
|
@@ -31891,26 +32181,7 @@ function handleCliArgs(args2) {
|
|
|
31891
32181
|
// src/index.tsx
|
|
31892
32182
|
init_src3();
|
|
31893
32183
|
init_errorPresentation();
|
|
31894
|
-
|
|
31895
|
-
// src/runtime/terminalScreen.ts
|
|
31896
|
-
init_esm_shims();
|
|
31897
|
-
var ENTER_ALTERNATE_SCREEN = "\x1B[?1049h\x1B[H";
|
|
31898
|
-
var LEAVE_ALTERNATE_SCREEN = "\x1B[?1049l\x1B[?25h";
|
|
31899
|
-
var alternateScreenActive = false;
|
|
31900
|
-
function enterAlternateScreen(output = process.stdout, env = process.env) {
|
|
31901
|
-
if (alternateScreenActive || !output.isTTY || env.MSAPLING_NO_ALT_SCREEN === "1" || env.TERM === "dumb") return false;
|
|
31902
|
-
output.write(ENTER_ALTERNATE_SCREEN);
|
|
31903
|
-
alternateScreenActive = true;
|
|
31904
|
-
return true;
|
|
31905
|
-
}
|
|
31906
|
-
function leaveAlternateScreen(output = process.stdout) {
|
|
31907
|
-
if (!alternateScreenActive) return false;
|
|
31908
|
-
output.write(LEAVE_ALTERNATE_SCREEN);
|
|
31909
|
-
alternateScreenActive = false;
|
|
31910
|
-
return true;
|
|
31911
|
-
}
|
|
31912
|
-
|
|
31913
|
-
// src/index.tsx
|
|
32184
|
+
init_terminalScreen();
|
|
31914
32185
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
31915
32186
|
var index_default = App;
|
|
31916
32187
|
function restoreTerminalMode() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msapling",
|
|
3
|
-
"version": "2.3.6-beta.
|
|
3
|
+
"version": "2.3.6-beta.62",
|
|
4
4
|
"description": "Short-name distribution of the MSapling CLI.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "MSapling Team",
|
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
"proper-lockfile": "^4.1.2",
|
|
49
49
|
"react": "^18.3.1",
|
|
50
50
|
"shell-quote": "^1.8.1",
|
|
51
|
+
"string-width": "^5.1.2",
|
|
52
|
+
"strip-ansi": "^7.1.0",
|
|
51
53
|
"yaml": "^2.8.3"
|
|
52
54
|
},
|
|
53
55
|
"optionalDependencies": {
|