@mtreeai/msapling-cli 2.3.6-beta.60 → 2.3.6-beta.61
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 +139 -82
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14450,6 +14450,14 @@ var init_Settings = __esm({
|
|
|
14450
14450
|
});
|
|
14451
14451
|
|
|
14452
14452
|
// ../core/src/agent/localModelPolicy.ts
|
|
14453
|
+
function buildDeterministicReadPlan(prompt4, availableTools) {
|
|
14454
|
+
if (MUTATING_INTENT.test(prompt4) || !LIST_DIRECTORY_INTENT.test(prompt4)) return null;
|
|
14455
|
+
if (!new Set(availableTools).has("list_directory")) return null;
|
|
14456
|
+
const absolute = (prompt4.match(QUOTED_WINDOWS_PATH)?.[1] ?? prompt4.match(WINDOWS_DRIVE_ROOT)?.[1] ?? prompt4.match(WINDOWS_ABSOLUTE_TOKEN)?.[1])?.trim();
|
|
14457
|
+
const drive = prompt4.match(WINDOWS_DRIVE_WORDS)?.[1] ?? prompt4.match(WINDOWS_DIRECTORY_THEN_DRIVE)?.[1];
|
|
14458
|
+
const path3 = absolute || (drive ? `${drive.toUpperCase()}:\\` : ".");
|
|
14459
|
+
return { tool: "list_directory", args: { path: path3 } };
|
|
14460
|
+
}
|
|
14453
14461
|
function buildReadToolRecovery(prompt4, response, availableTools) {
|
|
14454
14462
|
if (MUTATING_INTENT.test(prompt4)) return null;
|
|
14455
14463
|
const hasReadIntent = SAFE_READ_INTENT.test(prompt4) || SAFE_READ_VERB.test(prompt4);
|
|
@@ -14478,7 +14486,7 @@ function inferCapability(model) {
|
|
|
14478
14486
|
if (sizes.some((size) => size <= 7)) return "small";
|
|
14479
14487
|
return "unknown";
|
|
14480
14488
|
}
|
|
14481
|
-
var LOCAL_ACCESS_DENIAL, SAFE_READ_INTENT, SAFE_READ_VERB, PATH_LIKE_INTENT, MUTATING_INTENT, READ_RECOVERY_TOOLS, SAFE_TOOLS;
|
|
14489
|
+
var LOCAL_ACCESS_DENIAL, SAFE_READ_INTENT, SAFE_READ_VERB, PATH_LIKE_INTENT, MUTATING_INTENT, READ_RECOVERY_TOOLS, LIST_DIRECTORY_INTENT, QUOTED_WINDOWS_PATH, WINDOWS_DRIVE_ROOT, WINDOWS_ABSOLUTE_TOKEN, WINDOWS_DRIVE_WORDS, WINDOWS_DIRECTORY_THEN_DRIVE, SAFE_TOOLS;
|
|
14482
14490
|
var init_localModelPolicy = __esm({
|
|
14483
14491
|
"../core/src/agent/localModelPolicy.ts"() {
|
|
14484
14492
|
"use strict";
|
|
@@ -14489,6 +14497,12 @@ var init_localModelPolicy = __esm({
|
|
|
14489
14497
|
PATH_LIKE_INTENT = /(?:[A-Za-z]:[\\/]|\/{1,2}[A-Za-z0-9_.-]+\/|\.\.?[\\/])[A-Za-z0-9_.\\/ -]*/;
|
|
14490
14498
|
MUTATING_INTENT = /\b(?:create|overwrite|write|edit|modify|change|delete|remove|move|rename|execute|run|install|uninstall|commit|push|upload)\b/i;
|
|
14491
14499
|
READ_RECOVERY_TOOLS = ["read_file", "list_directory", "glob_files", "grep_search"];
|
|
14500
|
+
LIST_DIRECTORY_INTENT = /\b(?:list|show|display|enumerate|review|inspect|what(?:'s| is)? (?:in|inside))\b[^\n]{0,120}\b(?:files?|folders?|director(?:y|ies)|drive|workspace|project)\b/i;
|
|
14501
|
+
QUOTED_WINDOWS_PATH = /["']([A-Za-z]:[\\/][^"']*)["']/;
|
|
14502
|
+
WINDOWS_DRIVE_ROOT = /\b([A-Za-z]:[\\/])(?=\s|$|[.,;:)])/;
|
|
14503
|
+
WINDOWS_ABSOLUTE_TOKEN = /\b([A-Za-z]:[\\/][^\s,;]*)/;
|
|
14504
|
+
WINDOWS_DRIVE_WORDS = /\b([A-Za-z])\s+(?:drive|directory)\b/i;
|
|
14505
|
+
WINDOWS_DIRECTORY_THEN_DRIVE = /\b(?:drive|directory)\s+([A-Za-z])\b/i;
|
|
14492
14506
|
SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
14493
14507
|
"read_file",
|
|
14494
14508
|
"list_directory",
|
|
@@ -15028,6 +15042,33 @@ var init_Agent = __esm({
|
|
|
15028
15042
|
}
|
|
15029
15043
|
return this.executor.execute(toolName, args2, this.projectRoot);
|
|
15030
15044
|
}
|
|
15045
|
+
async executeDeterministicReadAdapter(chatId, turnId, plan) {
|
|
15046
|
+
const toolCallId = `client-read-${randomUUID6()}`;
|
|
15047
|
+
const request = {
|
|
15048
|
+
toolName: plan.tool,
|
|
15049
|
+
toolCallId,
|
|
15050
|
+
turnId,
|
|
15051
|
+
input: plan.args
|
|
15052
|
+
};
|
|
15053
|
+
await this.modeContract?.recordToolRequest(request);
|
|
15054
|
+
try {
|
|
15055
|
+
const result = await this.executeTurnTool(plan.tool, plan.args, false);
|
|
15056
|
+
await this.modeContract?.recordToolResult(request, result.content, !!result.isError);
|
|
15057
|
+
this.recordRemoteToolTelemetry(
|
|
15058
|
+
chatId,
|
|
15059
|
+
turnId,
|
|
15060
|
+
toolCallId,
|
|
15061
|
+
plan.tool,
|
|
15062
|
+
result.isError ? "failed" : "completed"
|
|
15063
|
+
);
|
|
15064
|
+
return result;
|
|
15065
|
+
} catch (error) {
|
|
15066
|
+
const content = SafetyGuard.redact(error instanceof Error ? error.message : String(error));
|
|
15067
|
+
await this.modeContract?.recordToolResult(request, content, true);
|
|
15068
|
+
this.recordRemoteToolTelemetry(chatId, turnId, toolCallId, plan.tool, "failed");
|
|
15069
|
+
throw error;
|
|
15070
|
+
}
|
|
15071
|
+
}
|
|
15031
15072
|
recordRemoteToolTelemetry(chatId, turnId, toolCallId, toolName, outcome) {
|
|
15032
15073
|
if (this.executionMode !== "remote") return;
|
|
15033
15074
|
if (this.toolTelemetryQueue.length >= TOOL_TELEMETRY_QUEUE_MAX) {
|
|
@@ -15277,7 +15318,37 @@ var init_Agent = __esm({
|
|
|
15277
15318
|
structuredToolResults = false;
|
|
15278
15319
|
}
|
|
15279
15320
|
}
|
|
15280
|
-
|
|
15321
|
+
let initialQueueItem = { prompt: prompt4, allowReadRecovery: true };
|
|
15322
|
+
if (!localTurn) {
|
|
15323
|
+
const initialToolNames = this.getTurnToolSchemas(false).map((tool) => String(tool.name));
|
|
15324
|
+
const deterministicPlan = buildDeterministicReadPlan(prompt4, initialToolNames);
|
|
15325
|
+
if (deterministicPlan) {
|
|
15326
|
+
const diagnostic = `[MSapling: running safe local ${deterministicPlan.tool} before the connected model.]
|
|
15327
|
+
`;
|
|
15328
|
+
await this.modeContract?.recordOutput(chatId, contractTurnId, diagnostic);
|
|
15329
|
+
onContent(diagnostic);
|
|
15330
|
+
const result = await this.executeDeterministicReadAdapter(
|
|
15331
|
+
chatId,
|
|
15332
|
+
contractTurnId,
|
|
15333
|
+
deterministicPlan
|
|
15334
|
+
);
|
|
15335
|
+
const evidence = boundToolResultForModel(result.content);
|
|
15336
|
+
initialQueueItem = {
|
|
15337
|
+
prompt: `A trusted MSapling client read-only adapter executed ${deterministicPlan.tool} with ${JSON.stringify(deterministicPlan.args)} for the original request below.
|
|
15338
|
+
|
|
15339
|
+
<client_tool_result error="${result.isError === true}">
|
|
15340
|
+
${evidence}
|
|
15341
|
+
</client_tool_result>
|
|
15342
|
+
|
|
15343
|
+
Original request: ${prompt4}
|
|
15344
|
+
|
|
15345
|
+
Answer directly from the tool result. Do not claim local access is unavailable, do not emit a patch or diff, and do not invent entries.`,
|
|
15346
|
+
allowedToolNames: [],
|
|
15347
|
+
allowReadRecovery: false
|
|
15348
|
+
};
|
|
15349
|
+
}
|
|
15350
|
+
}
|
|
15351
|
+
const queue = [initialQueueItem];
|
|
15281
15352
|
let rounds = 0;
|
|
15282
15353
|
let toolCallSeq = 0;
|
|
15283
15354
|
let streamUsage = null;
|
|
@@ -15450,16 +15521,44 @@ ${next.prompt}`
|
|
|
15450
15521
|
const recovery = !localTurn && allowReadRecovery && !remoteReadRecoveryUsed && !assistantResponse.includes("[MSapling: local model denied available file tools;") ? buildReadToolRecovery(prompt4, assistantResponse, turnTools.map((tool) => String(tool.name))) : null;
|
|
15451
15522
|
if (recovery) {
|
|
15452
15523
|
remoteReadRecoveryUsed = true;
|
|
15453
|
-
const
|
|
15524
|
+
const deterministicPlan = buildDeterministicReadPlan(prompt4, recovery.tools);
|
|
15525
|
+
if (deterministicPlan) {
|
|
15526
|
+
const diagnostic = `
|
|
15527
|
+
|
|
15528
|
+
[MSapling: connected model did not use the required read tool; running safe local ${deterministicPlan.tool}.]
|
|
15529
|
+
`;
|
|
15530
|
+
await this.modeContract?.recordOutput(chatId, contractTurnId, diagnostic);
|
|
15531
|
+
onContent(diagnostic);
|
|
15532
|
+
const result = await this.executeDeterministicReadAdapter(
|
|
15533
|
+
chatId,
|
|
15534
|
+
contractTurnId,
|
|
15535
|
+
deterministicPlan
|
|
15536
|
+
);
|
|
15537
|
+
const evidence = boundToolResultForModel(result.content);
|
|
15538
|
+
queue.push({
|
|
15539
|
+
prompt: `A trusted MSapling client read-only adapter executed ${deterministicPlan.tool} with ${JSON.stringify(deterministicPlan.args)} for the original request below.
|
|
15540
|
+
|
|
15541
|
+
<client_tool_result error="${result.isError === true}">
|
|
15542
|
+
${evidence}
|
|
15543
|
+
</client_tool_result>
|
|
15544
|
+
|
|
15545
|
+
Original request: ${prompt4}
|
|
15546
|
+
|
|
15547
|
+
Answer from the tool result. Do not claim local access is unavailable.`,
|
|
15548
|
+
allowedToolNames: []
|
|
15549
|
+
});
|
|
15550
|
+
} else {
|
|
15551
|
+
const diagnostic = `
|
|
15454
15552
|
|
|
15455
15553
|
[MSapling: connected model did not use required client file tools; retrying once with ${recovery.tools.join(", ")}.]
|
|
15456
15554
|
`;
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15555
|
+
await this.modeContract?.recordOutput(chatId, contractTurnId, diagnostic);
|
|
15556
|
+
onContent(diagnostic);
|
|
15557
|
+
queue.push({
|
|
15558
|
+
prompt: recovery.instruction,
|
|
15559
|
+
allowedToolNames: recovery.tools
|
|
15560
|
+
});
|
|
15561
|
+
}
|
|
15463
15562
|
}
|
|
15464
15563
|
continue;
|
|
15465
15564
|
}
|
|
@@ -23566,7 +23665,7 @@ var init_version = __esm({
|
|
|
23566
23665
|
description: "Show version information for CLI and core packages",
|
|
23567
23666
|
category: "debug",
|
|
23568
23667
|
handler: async (_args, context) => {
|
|
23569
|
-
const cliVersion = true ? "2.3.6-beta.
|
|
23668
|
+
const cliVersion = true ? "2.3.6-beta.61" : "(dev)";
|
|
23570
23669
|
const coreVersion = true ? "2.3.6-beta.43" : "(dev)";
|
|
23571
23670
|
const runtime = process.version;
|
|
23572
23671
|
context.addMessage("system", "MSapling Version Info");
|
|
@@ -29593,7 +29692,7 @@ import { render } from "ink";
|
|
|
29593
29692
|
|
|
29594
29693
|
// src/App.tsx
|
|
29595
29694
|
init_esm_shims();
|
|
29596
|
-
import { useState as useState5, useEffect as
|
|
29695
|
+
import { useState as useState5, useEffect as useEffect3, useCallback as useCallback2, useRef } from "react";
|
|
29597
29696
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
29598
29697
|
import { Box as Box7, Text as Text7, useApp, useInput as useInput4, useStdout } from "ink";
|
|
29599
29698
|
|
|
@@ -29603,11 +29702,11 @@ import { Box, Text } from "ink";
|
|
|
29603
29702
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
29604
29703
|
var Header = ({ compact: compact2 = false }) => compact2 ? /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
29605
29704
|
"\u25CF MSapling v",
|
|
29606
|
-
"2.3.6-beta.
|
|
29705
|
+
"2.3.6-beta.61"
|
|
29607
29706
|
] }) : /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
29608
29707
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
29609
29708
|
"\u25CF MSapling CLI v",
|
|
29610
|
-
"2.3.6-beta.
|
|
29709
|
+
"2.3.6-beta.61"
|
|
29611
29710
|
] }),
|
|
29612
29711
|
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
|
|
29613
29712
|
] });
|
|
@@ -29711,42 +29810,6 @@ function promptLabel(user) {
|
|
|
29711
29810
|
init_esm_shims();
|
|
29712
29811
|
import { useState, useMemo } from "react";
|
|
29713
29812
|
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
29714
|
-
|
|
29715
|
-
// src/hooks/useTerminalMouseScroll.ts
|
|
29716
|
-
init_esm_shims();
|
|
29717
|
-
import { useEffect, useRef } from "react";
|
|
29718
|
-
var ESC = String.fromCharCode(27);
|
|
29719
|
-
function isMouseReport(input) {
|
|
29720
|
-
return input.includes(`${ESC}[<`) && /\d+;\d+;\d+[mM]/.test(input);
|
|
29721
|
-
}
|
|
29722
|
-
function parseMouseScroll(input) {
|
|
29723
|
-
const directions = [];
|
|
29724
|
-
const pattern = new RegExp(`${ESC}\\[<(64|65);\\d+;\\d+[mM]`, "g");
|
|
29725
|
-
for (const match of input.matchAll(pattern)) {
|
|
29726
|
-
directions.push(match[1] === "64" ? "up" : "down");
|
|
29727
|
-
}
|
|
29728
|
-
return directions;
|
|
29729
|
-
}
|
|
29730
|
-
function useTerminalMouseScroll(onScroll) {
|
|
29731
|
-
const callback = useRef(onScroll);
|
|
29732
|
-
callback.current = onScroll;
|
|
29733
|
-
useEffect(() => {
|
|
29734
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
29735
|
-
const handleData = (chunk) => {
|
|
29736
|
-
for (const direction of parseMouseScroll(String(chunk))) {
|
|
29737
|
-
callback.current(direction);
|
|
29738
|
-
}
|
|
29739
|
-
};
|
|
29740
|
-
process.stdout.write("\x1B[?1000h\x1B[?1006h");
|
|
29741
|
-
process.stdin.on("data", handleData);
|
|
29742
|
-
return () => {
|
|
29743
|
-
process.stdin.off("data", handleData);
|
|
29744
|
-
process.stdout.write("\x1B[?1006l\x1B[?1000l");
|
|
29745
|
-
};
|
|
29746
|
-
}, []);
|
|
29747
|
-
}
|
|
29748
|
-
|
|
29749
|
-
// src/components/ApprovalDialog.tsx
|
|
29750
29813
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
29751
29814
|
function parseDiffLines(diffText) {
|
|
29752
29815
|
if (!diffText) return [];
|
|
@@ -29813,7 +29876,6 @@ var ApprovalDialog = ({
|
|
|
29813
29876
|
const { hasDiff, diffText, title } = useMemo(() => extractDiffFromCommand(command, diff), [command, diff]);
|
|
29814
29877
|
const diffLines = useMemo(() => parseDiffLines(diffText), [diffText]);
|
|
29815
29878
|
useInput((input, key) => {
|
|
29816
|
-
if (isMouseReport(input)) return;
|
|
29817
29879
|
if (key.escape) {
|
|
29818
29880
|
onResolve("no");
|
|
29819
29881
|
return;
|
|
@@ -29900,7 +29962,6 @@ var AskUserQuestion = ({ question, options, multiSelect, onResolve }) => {
|
|
|
29900
29962
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
29901
29963
|
const [selectedIndices, setSelectedIndices] = useState2(/* @__PURE__ */ new Set());
|
|
29902
29964
|
useInput2((input, key) => {
|
|
29903
|
-
if (isMouseReport(input)) return;
|
|
29904
29965
|
if (key.upArrow) {
|
|
29905
29966
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : options.length - 1);
|
|
29906
29967
|
} else if (key.downArrow) {
|
|
@@ -30010,7 +30071,7 @@ var VirtualizedMessageList = ({
|
|
|
30010
30071
|
);
|
|
30011
30072
|
const separatorWidth = termColumns > 0 ? Math.min(termColumns, 60) : 60;
|
|
30012
30073
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", flexGrow: 1, children: [
|
|
30013
|
-
(hiddenCount > 0 || hiddenAfter > 0) && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: `[\u2191 ${hiddenCount} older \xB7 \u2193 ${hiddenAfter} newer \xB7
|
|
30074
|
+
(hiddenCount > 0 || hiddenAfter > 0) && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: `[\u2191 ${hiddenCount} older \xB7 \u2193 ${hiddenAfter} newer \xB7 \u2191/\u2193 or PageUp/PageDown \xB7 Ctrl+E latest]` }),
|
|
30014
30075
|
displayMessages.map((msg, i) => /* @__PURE__ */ jsxs5(
|
|
30015
30076
|
Box5,
|
|
30016
30077
|
{
|
|
@@ -30042,7 +30103,7 @@ init_src3();
|
|
|
30042
30103
|
|
|
30043
30104
|
// src/ui/TextInput.tsx
|
|
30044
30105
|
init_esm_shims();
|
|
30045
|
-
import { useState as useState3, useEffect
|
|
30106
|
+
import { useState as useState3, useEffect } from "react";
|
|
30046
30107
|
import { Box as Box6, Text as Text6, useInput as useInput3 } from "ink";
|
|
30047
30108
|
|
|
30048
30109
|
// src/state/commandHandler.ts
|
|
@@ -30642,11 +30703,10 @@ var TextInput = ({
|
|
|
30642
30703
|
}) => {
|
|
30643
30704
|
const [history, setHistory] = useState3([]);
|
|
30644
30705
|
const [historyIndex, setHistoryIndex] = useState3(-1);
|
|
30645
|
-
|
|
30706
|
+
useEffect(() => {
|
|
30646
30707
|
storage.loadHistory().then((entries) => setHistory(filterSafeHistory(entries)));
|
|
30647
30708
|
}, [storage]);
|
|
30648
30709
|
useInput3((input, key) => {
|
|
30649
|
-
if (isMouseReport(input)) return;
|
|
30650
30710
|
if (key.ctrl && input === "c" || key.escape) {
|
|
30651
30711
|
onCancel?.();
|
|
30652
30712
|
return;
|
|
@@ -30869,7 +30929,7 @@ init_errorPresentation();
|
|
|
30869
30929
|
|
|
30870
30930
|
// src/hooks/useTerminalResize.ts
|
|
30871
30931
|
init_esm_shims();
|
|
30872
|
-
import { useState as useState4, useEffect as
|
|
30932
|
+
import { useState as useState4, useEffect as useEffect2, useCallback } from "react";
|
|
30873
30933
|
function getCurrentDimensions() {
|
|
30874
30934
|
return {
|
|
30875
30935
|
columns: process.stdout.columns ?? 80,
|
|
@@ -30883,7 +30943,7 @@ function useTerminalResize() {
|
|
|
30883
30943
|
const handleResize = useCallback(() => {
|
|
30884
30944
|
setDimensions(getCurrentDimensions());
|
|
30885
30945
|
}, []);
|
|
30886
|
-
|
|
30946
|
+
useEffect2(() => {
|
|
30887
30947
|
process.stdout.on("resize", handleResize);
|
|
30888
30948
|
const onSigwinch = () => handleResize();
|
|
30889
30949
|
process.on("SIGWINCH", onSigwinch);
|
|
@@ -30986,20 +31046,20 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
30986
31046
|
const [billingProfile, setBillingProfile] = useState5(executionMode2 === "local" ? "ollama" : "account-metered");
|
|
30987
31047
|
const [continuityProfile, setContinuityProfile] = useState5(executionMode2 === "local" ? "standalone-private" : "connected-mirrored");
|
|
30988
31048
|
const [bootstrapState, setBootstrapState] = useState5("loading");
|
|
30989
|
-
const submissionLockRef =
|
|
31049
|
+
const submissionLockRef = useRef(false);
|
|
30990
31050
|
const { exit } = useApp();
|
|
30991
31051
|
const { stdout: termStdout } = useStdout();
|
|
30992
31052
|
const { columns: termResizeCols, rows: termResizeRows } = useTerminalResize();
|
|
30993
|
-
const storage =
|
|
30994
|
-
const client =
|
|
31053
|
+
const storage = useRef(new StorageManager()).current;
|
|
31054
|
+
const client = useRef(new MSaplingClient()).current;
|
|
30995
31055
|
const remoteEnvironment = describeRemoteEnvironment(client.getApiUrl());
|
|
30996
|
-
const modeContract =
|
|
31056
|
+
const modeContract = useRef(new CliModeRuntime({
|
|
30997
31057
|
mode: executionMode2,
|
|
30998
31058
|
provider: process.env.MSAPLING_LOCAL_LLM_PROVIDER ?? "ollama"
|
|
30999
31059
|
})).current;
|
|
31000
|
-
const sessionRecovery =
|
|
31001
|
-
const checkpointTurns =
|
|
31002
|
-
const agentRef =
|
|
31060
|
+
const sessionRecovery = useRef(new CliSessionRecovery()).current;
|
|
31061
|
+
const checkpointTurns = useRef(/* @__PURE__ */ new Map()).current;
|
|
31062
|
+
const agentRef = useRef(null);
|
|
31003
31063
|
const requestApproval = useCallback2((request) => {
|
|
31004
31064
|
agentRef.current?.fireLifecycleHook(
|
|
31005
31065
|
"notification",
|
|
@@ -31010,7 +31070,7 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31010
31070
|
setPendingApproval({ request, resolve: resolve31 });
|
|
31011
31071
|
});
|
|
31012
31072
|
}, []);
|
|
31013
|
-
const agent =
|
|
31073
|
+
const agent = useRef(new Agent(client, process.cwd(), requestApproval, { executionMode: executionMode2, modeContract })).current;
|
|
31014
31074
|
agentRef.current = agent;
|
|
31015
31075
|
const applyStandaloneSyncState = (state) => {
|
|
31016
31076
|
const localChatId = "local-cli-chat";
|
|
@@ -31031,18 +31091,18 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31031
31091
|
setContinuityProfile(profile);
|
|
31032
31092
|
if (profile === "standalone-private") agent.configureStandaloneSync(null);
|
|
31033
31093
|
};
|
|
31034
|
-
const trustStore =
|
|
31035
|
-
const lastActivityRef =
|
|
31036
|
-
const pollingIntervalRef =
|
|
31037
|
-
|
|
31094
|
+
const trustStore = useRef(new TrustStore()).current;
|
|
31095
|
+
const lastActivityRef = useRef(Date.now());
|
|
31096
|
+
const pollingIntervalRef = useRef(null);
|
|
31097
|
+
useEffect3(() => {
|
|
31038
31098
|
agent.setApprovalCallback(requestApproval);
|
|
31039
31099
|
}, [agent, requestApproval]);
|
|
31040
|
-
|
|
31100
|
+
useEffect3(() => {
|
|
31041
31101
|
if (bypassExpiry === null) return;
|
|
31042
31102
|
const timer = setInterval(() => setPermissionNow(Date.now()), 1e3);
|
|
31043
31103
|
return () => clearInterval(timer);
|
|
31044
31104
|
}, [bypassExpiry]);
|
|
31045
|
-
|
|
31105
|
+
useEffect3(() => {
|
|
31046
31106
|
agent.setOnModeChange((m) => {
|
|
31047
31107
|
setModeState(m);
|
|
31048
31108
|
addMessage("system", `Mode changed to: ${m} (via plan-mode tool)`);
|
|
@@ -31071,7 +31131,7 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31071
31131
|
setModeState(m);
|
|
31072
31132
|
agent.setMode(m, source);
|
|
31073
31133
|
}, [agent]);
|
|
31074
|
-
|
|
31134
|
+
useEffect3(() => {
|
|
31075
31135
|
if (mode !== "bypassPermissions" || !isBypassExpired(bypassExpiry, permissionNow)) return;
|
|
31076
31136
|
setMode("default");
|
|
31077
31137
|
setBypassExpiry(null);
|
|
@@ -31087,7 +31147,7 @@ var App = ({ compact: compact2 = false, continueSession: continueSession2 = fals
|
|
|
31087
31147
|
setContextBudgetSnap(snapshotBudget(agent.getContextBudget()));
|
|
31088
31148
|
}, [agent]);
|
|
31089
31149
|
const getModel = useCallback2(() => activeModel, [activeModel]);
|
|
31090
|
-
const cliProjectRef =
|
|
31150
|
+
const cliProjectRef = useRef(null);
|
|
31091
31151
|
const setProjectId = useCallback2((id) => {
|
|
31092
31152
|
if (cliProjectRef.current && id !== cliProjectRef.current) return;
|
|
31093
31153
|
setActiveProjectId(id);
|
|
@@ -31173,7 +31233,7 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31173
31233
|
client.setToken("");
|
|
31174
31234
|
setStatus("Session expired - run /login");
|
|
31175
31235
|
}, [client, storage]);
|
|
31176
|
-
|
|
31236
|
+
useEffect3(() => {
|
|
31177
31237
|
agent.setAuthFailureHandler(handle401);
|
|
31178
31238
|
return () => agent.setAuthFailureHandler(null);
|
|
31179
31239
|
}, [agent, handle401]);
|
|
@@ -31194,7 +31254,7 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31194
31254
|
setStatus(classifyCliError(error, { executionMode: executionMode2 }).summary);
|
|
31195
31255
|
}
|
|
31196
31256
|
}, [client, activeChatId, setProjectId, handle401]);
|
|
31197
|
-
|
|
31257
|
+
useEffect3(() => {
|
|
31198
31258
|
(async () => {
|
|
31199
31259
|
try {
|
|
31200
31260
|
if (executionMode2 === "local") {
|
|
@@ -31306,14 +31366,14 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31306
31366
|
}
|
|
31307
31367
|
})();
|
|
31308
31368
|
}, []);
|
|
31309
|
-
|
|
31369
|
+
useEffect3(() => {
|
|
31310
31370
|
return () => {
|
|
31311
31371
|
void agent.flushPendingToolTelemetry();
|
|
31312
31372
|
void agent.flushPendingUsageTelemetry();
|
|
31313
31373
|
agent.fireLifecycleHook("session-end", { cwd: process.cwd() });
|
|
31314
31374
|
};
|
|
31315
31375
|
}, []);
|
|
31316
|
-
|
|
31376
|
+
useEffect3(() => {
|
|
31317
31377
|
if (!user) return;
|
|
31318
31378
|
createIdleAwarePoll(pollingIntervalRef, lastActivityRef, client, setUser, setUsageError);
|
|
31319
31379
|
return () => {
|
|
@@ -31412,9 +31472,9 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31412
31472
|
return { journalEvents, checkpoints };
|
|
31413
31473
|
}
|
|
31414
31474
|
});
|
|
31415
|
-
const relayCommandRef =
|
|
31475
|
+
const relayCommandRef = useRef(handleCommand);
|
|
31416
31476
|
relayCommandRef.current = handleCommand;
|
|
31417
|
-
|
|
31477
|
+
useEffect3(() => {
|
|
31418
31478
|
if (executionMode2 !== "remote" || process.env.MSAPLING_RELAY_ENABLED !== "1" || !activeProjectId) return;
|
|
31419
31479
|
let listener = null;
|
|
31420
31480
|
let cancelled = false;
|
|
@@ -31463,9 +31523,6 @@ ${renderCliError(classifyCliError(error, { executionMode: executionMode2 }))}`);
|
|
|
31463
31523
|
setHistoryOffset((current) => Math.max(0, current - amount));
|
|
31464
31524
|
}
|
|
31465
31525
|
}, [displayedHistory.length, historyPageStep]);
|
|
31466
|
-
useTerminalMouseScroll((direction) => {
|
|
31467
|
-
if (!pendingApproval && !pendingAskUser) scrollTranscript(direction);
|
|
31468
|
-
});
|
|
31469
31526
|
useInput4((input2, key) => {
|
|
31470
31527
|
if (pendingApproval || pendingAskUser) return;
|
|
31471
31528
|
if (key.pageUp) {
|
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.61",
|
|
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",
|