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