@letrquan/book 0.2.0 → 0.4.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3771 -40
- package/README.md +135 -1311
- package/dist/additional-roots-VAWRQ625.js +32 -0
- package/dist/{app-MOXXWEOY.js → app-J7BVPSUH.js} +9648 -5509
- package/dist/app-J7BVPSUH.js.map +1 -0
- package/dist/chunk-2AAOF5B5.js +28 -0
- package/dist/chunk-2AAOF5B5.js.map +1 -0
- package/dist/chunk-32WBCUAN.js +660 -0
- package/dist/chunk-32WBCUAN.js.map +1 -0
- package/dist/chunk-4DKHLZRI.js +120 -0
- package/dist/chunk-4DKHLZRI.js.map +1 -0
- package/dist/{chunk-CAGOB2N4.js → chunk-62EEAUID.js} +6 -4
- package/dist/chunk-62EEAUID.js.map +1 -0
- package/dist/chunk-AHC7OU75.js +1124 -0
- package/dist/chunk-AHC7OU75.js.map +1 -0
- package/dist/{chunk-E75IPST5.js → chunk-AJZWLKLQ.js} +73 -70
- package/dist/chunk-AJZWLKLQ.js.map +1 -0
- package/dist/chunk-B5FC3MYZ.js +395 -0
- package/dist/chunk-B5FC3MYZ.js.map +1 -0
- package/dist/{chunk-KWHQ2XXL.js → chunk-DNFQTSMJ.js} +55 -13
- package/dist/chunk-DNFQTSMJ.js.map +1 -0
- package/dist/{chunk-J7MIZ5CA.js → chunk-E5WLQSKA.js} +719 -89
- package/dist/chunk-E5WLQSKA.js.map +1 -0
- package/dist/chunk-ECLC4CIJ.js +1181 -0
- package/dist/chunk-ECLC4CIJ.js.map +1 -0
- package/dist/chunk-EEX6QNXV.js +127 -0
- package/dist/chunk-EEX6QNXV.js.map +1 -0
- package/dist/chunk-EFXVSQ5J.js +931 -0
- package/dist/chunk-EFXVSQ5J.js.map +1 -0
- package/dist/{chunk-V4BOYR52.js → chunk-ENLB7NYV.js} +1304 -326
- package/dist/chunk-ENLB7NYV.js.map +1 -0
- package/dist/chunk-FPR7SKIE.js +6926 -0
- package/dist/chunk-FPR7SKIE.js.map +1 -0
- package/dist/{chunk-DGMQEI6Y.js → chunk-HFB74CLM.js} +30 -9
- package/dist/chunk-HFB74CLM.js.map +1 -0
- package/dist/{chunk-5RDRAO4B.js → chunk-HOZXKOE3.js} +37 -1
- package/dist/chunk-HOZXKOE3.js.map +1 -0
- package/dist/chunk-IDYWN37T.js +36 -0
- package/dist/chunk-IDYWN37T.js.map +1 -0
- package/dist/chunk-J4F2QLM2.js +273 -0
- package/dist/chunk-J4F2QLM2.js.map +1 -0
- package/dist/chunk-JGF5HLSI.js +1065 -0
- package/dist/chunk-JGF5HLSI.js.map +1 -0
- package/dist/{chunk-XIFFTATU.js → chunk-KDNWMKXV.js} +7166 -4237
- package/dist/chunk-KDNWMKXV.js.map +1 -0
- package/dist/chunk-KXAYUIKP.js +90 -0
- package/dist/chunk-KXAYUIKP.js.map +1 -0
- package/dist/{chunk-3U5IBM24.js → chunk-MEOB2DZA.js} +12 -2
- package/dist/chunk-MEOB2DZA.js.map +1 -0
- package/dist/{chunk-WKBO5R4O.js → chunk-MV5PQNIA.js} +2 -2
- package/dist/chunk-MV5PQNIA.js.map +1 -0
- package/dist/chunk-N2G4Q7ME.js +2672 -0
- package/dist/chunk-N2G4Q7ME.js.map +1 -0
- package/dist/chunk-OJBMDM5H.js +299 -0
- package/dist/chunk-OJBMDM5H.js.map +1 -0
- package/dist/{chunk-URLQAXTR.js → chunk-PTDC7ZUP.js} +2 -2
- package/dist/chunk-PTDC7ZUP.js.map +1 -0
- package/dist/{chunk-574C6MQR.js → chunk-REASC2QG.js} +173 -64
- package/dist/chunk-REASC2QG.js.map +1 -0
- package/dist/{chunk-7N4J557C.js → chunk-RT5SATF7.js} +1 -1
- package/dist/chunk-RT5SATF7.js.map +1 -0
- package/dist/chunk-SBTU5BEC.js +114 -0
- package/dist/chunk-SBTU5BEC.js.map +1 -0
- package/dist/{chunk-5KLVH3PY.js → chunk-SWPDKLNM.js} +5 -3
- package/dist/chunk-SWPDKLNM.js.map +1 -0
- package/dist/chunk-UCFJ43OS.js +520 -0
- package/dist/chunk-UCFJ43OS.js.map +1 -0
- package/dist/{chunk-VZQXX3WW.js → chunk-W7SLYS3M.js} +80 -16
- package/dist/chunk-W7SLYS3M.js.map +1 -0
- package/dist/{chunk-ANSJPYGI.js → chunk-WV3O5PGX.js} +3 -3
- package/dist/chunk-WV3O5PGX.js.map +1 -0
- package/dist/chunk-XHAO3K7I.js +18 -0
- package/dist/chunk-XHAO3K7I.js.map +1 -0
- package/dist/chunk-XJRJVXJR.js +1050 -0
- package/dist/chunk-XJRJVXJR.js.map +1 -0
- package/dist/chunk-YIL6HTJX.js +663 -0
- package/dist/chunk-YIL6HTJX.js.map +1 -0
- package/dist/{chunk-24AXE6SP.js → chunk-ZPSZZUWF.js} +1 -1
- package/dist/chunk-ZPSZZUWF.js.map +1 -0
- package/dist/{command-approvals-6Y57VCWZ.js → command-approvals-ZRY66LCW.js} +7 -5
- package/dist/context-C3RAP6K5.js +41 -0
- package/dist/{hook-approvals-CTUFKEJT.js → hook-approvals-DPQD5H65.js} +6 -5
- package/dist/index.js +947 -203
- package/dist/index.js.map +1 -1
- package/dist/{interactive-assets-CCAAWVKH.js → interactive-assets-73AQO5WP.js} +18 -9
- package/dist/interactive-assets-73AQO5WP.js.map +1 -0
- package/dist/job-runner.js +166 -111
- package/dist/job-runner.js.map +1 -1
- package/dist/job-supervisor.d.ts +2 -0
- package/dist/job-supervisor.js +121 -0
- package/dist/job-supervisor.js.map +1 -0
- package/dist/loader-DQNPDKOX.js +27 -0
- package/dist/{mcp-approvals-WNPH65BK.js → mcp-approvals-27LJYADQ.js} +6 -5
- package/dist/{mcp-config-YIJIES2C.js → mcp-config-GXSODNCM.js} +4 -3
- package/dist/memory-store-I6Z54VUN.js +51 -0
- package/dist/{model-window-store-YFVNXCIP.js → model-window-store-6VKXXTPJ.js} +9 -4
- package/dist/openai-compatible-IPUNBJ53.js +16 -0
- package/dist/permission-approvals-Q5IMFEZI.js +15 -0
- package/dist/permissions-7Y35X6HZ.js +62 -0
- package/dist/provider-approvals-5AGH3RVT.js +76 -0
- package/dist/sandbox-N2RY72GN.js +42 -0
- package/dist/{scrollback-LUKLIBVI.js → scrollback-GD76GNM4.js} +44 -26
- package/dist/scrollback-GD76GNM4.js.map +1 -0
- package/dist/sdk.d.ts +2739 -2069
- package/dist/sdk.js +77 -42
- package/dist/sdk.js.map +1 -1
- package/dist/settings-loader-KDBH45AQ.js +43 -0
- package/dist/settings-loader-KDBH45AQ.js.map +1 -0
- package/dist/{settings-removed-JWWPT4WA.js → settings-removed-3ATWJEF3.js} +2 -2
- package/dist/settings-removed-3ATWJEF3.js.map +1 -0
- package/dist/shell-selection-Z5WORZU4.js +31 -0
- package/dist/shell-selection-Z5WORZU4.js.map +1 -0
- package/package.json +25 -24
- package/dist/app-MOXXWEOY.js.map +0 -1
- package/dist/chunk-24AXE6SP.js.map +0 -1
- package/dist/chunk-3U5IBM24.js.map +0 -1
- package/dist/chunk-574C6MQR.js.map +0 -1
- package/dist/chunk-5GDZ22YP.js +0 -449
- package/dist/chunk-5GDZ22YP.js.map +0 -1
- package/dist/chunk-5KLVH3PY.js.map +0 -1
- package/dist/chunk-5RDRAO4B.js.map +0 -1
- package/dist/chunk-7N4J557C.js.map +0 -1
- package/dist/chunk-A7JLBK2Y.js +0 -3506
- package/dist/chunk-A7JLBK2Y.js.map +0 -1
- package/dist/chunk-ANSJPYGI.js.map +0 -1
- package/dist/chunk-BTZZUCLI.js +0 -264
- package/dist/chunk-BTZZUCLI.js.map +0 -1
- package/dist/chunk-C7D4NJ2D.js +0 -217
- package/dist/chunk-C7D4NJ2D.js.map +0 -1
- package/dist/chunk-CAGOB2N4.js.map +0 -1
- package/dist/chunk-DGMQEI6Y.js.map +0 -1
- package/dist/chunk-E75IPST5.js.map +0 -1
- package/dist/chunk-EYGD6X2T.js +0 -180
- package/dist/chunk-EYGD6X2T.js.map +0 -1
- package/dist/chunk-GTVB4HEM.js +0 -765
- package/dist/chunk-GTVB4HEM.js.map +0 -1
- package/dist/chunk-J7MIZ5CA.js.map +0 -1
- package/dist/chunk-KWHQ2XXL.js.map +0 -1
- package/dist/chunk-L6LK2QIQ.js +0 -657
- package/dist/chunk-L6LK2QIQ.js.map +0 -1
- package/dist/chunk-MAQXCUR4.js +0 -1007
- package/dist/chunk-MAQXCUR4.js.map +0 -1
- package/dist/chunk-S4XL7HOM.js +0 -402
- package/dist/chunk-S4XL7HOM.js.map +0 -1
- package/dist/chunk-URLQAXTR.js.map +0 -1
- package/dist/chunk-V4BOYR52.js.map +0 -1
- package/dist/chunk-VZQXX3WW.js.map +0 -1
- package/dist/chunk-WKBO5R4O.js.map +0 -1
- package/dist/chunk-XIFFTATU.js.map +0 -1
- package/dist/context-ZC5IFEAX.js +0 -25
- package/dist/interactive-assets-CCAAWVKH.js.map +0 -1
- package/dist/loader-4IDS2RIE.js +0 -15
- package/dist/openai-compatible-RHZUBHV6.js +0 -10
- package/dist/permission-approvals-76PVREFD.js +0 -14
- package/dist/permissions-CHCKTFQQ.js +0 -28
- package/dist/sandbox-CNVAQDA7.js +0 -23
- package/dist/scrollback-LUKLIBVI.js.map +0 -1
- package/dist/settings-loader-M2QP5TX2.js +0 -21
- package/dist/shell-selection-V6QAYXPX.js +0 -17
- package/patches/ink+6.8.0.patch +0 -13
- package/scripts/apply-ink-patch.mjs +0 -29
- package/scripts/ink-patch.mjs +0 -59
- package/scripts/verify-ink-patch.mjs +0 -11
- /package/dist/{command-approvals-6Y57VCWZ.js.map → additional-roots-VAWRQ625.js.map} +0 -0
- /package/dist/{context-ZC5IFEAX.js.map → command-approvals-ZRY66LCW.js.map} +0 -0
- /package/dist/{hook-approvals-CTUFKEJT.js.map → context-C3RAP6K5.js.map} +0 -0
- /package/dist/{loader-4IDS2RIE.js.map → hook-approvals-DPQD5H65.js.map} +0 -0
- /package/dist/{mcp-approvals-WNPH65BK.js.map → loader-DQNPDKOX.js.map} +0 -0
- /package/dist/{mcp-config-YIJIES2C.js.map → mcp-approvals-27LJYADQ.js.map} +0 -0
- /package/dist/{model-window-store-YFVNXCIP.js.map → mcp-config-GXSODNCM.js.map} +0 -0
- /package/dist/{openai-compatible-RHZUBHV6.js.map → memory-store-I6Z54VUN.js.map} +0 -0
- /package/dist/{permission-approvals-76PVREFD.js.map → model-window-store-6VKXXTPJ.js.map} +0 -0
- /package/dist/{permissions-CHCKTFQQ.js.map → openai-compatible-IPUNBJ53.js.map} +0 -0
- /package/dist/{sandbox-CNVAQDA7.js.map → permission-approvals-Q5IMFEZI.js.map} +0 -0
- /package/dist/{settings-loader-M2QP5TX2.js.map → permissions-7Y35X6HZ.js.map} +0 -0
- /package/dist/{settings-removed-JWWPT4WA.js.map → provider-approvals-5AGH3RVT.js.map} +0 -0
- /package/dist/{shell-selection-V6QAYXPX.js.map → sandbox-N2RY72GN.js.map} +0 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
import {
|
|
2
|
+
reachesUncPath
|
|
3
|
+
} from "./chunk-EEX6QNXV.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveBookHome
|
|
6
|
+
} from "./chunk-ZPSZZUWF.js";
|
|
7
|
+
|
|
8
|
+
// src/tools/aliases.ts
|
|
9
|
+
var TOOL_ALIASES = {
|
|
10
|
+
read_file: "Read",
|
|
11
|
+
write_file: "Write",
|
|
12
|
+
edit_file: "Edit",
|
|
13
|
+
multi_edit: "MultiEdit",
|
|
14
|
+
apply_patch: "ApplyPatch",
|
|
15
|
+
glob: "Glob",
|
|
16
|
+
glob_files: "Glob",
|
|
17
|
+
grep: "Grep",
|
|
18
|
+
bash: "Bash",
|
|
19
|
+
// Legacy snake_case git tool names — backward compatible.
|
|
20
|
+
git_status: "GitStatus",
|
|
21
|
+
git_diff: "GitDiff",
|
|
22
|
+
git_log: "GitLog",
|
|
23
|
+
git_commit: "GitCommit",
|
|
24
|
+
git_branch: "GitBranch"
|
|
25
|
+
};
|
|
26
|
+
function canonicalToolName(name) {
|
|
27
|
+
return TOOL_ALIASES[name] ?? name;
|
|
28
|
+
}
|
|
29
|
+
var PROVIDER_TOOL_PREFIXES = [
|
|
30
|
+
"parent:",
|
|
31
|
+
"default:",
|
|
32
|
+
"tool:",
|
|
33
|
+
"parent.",
|
|
34
|
+
"default.",
|
|
35
|
+
"tool.",
|
|
36
|
+
"functions."
|
|
37
|
+
];
|
|
38
|
+
function unwrapProviderPrefix(name) {
|
|
39
|
+
const prefix = PROVIDER_TOOL_PREFIXES.find((candidate) => name.startsWith(candidate));
|
|
40
|
+
return prefix ? name.slice(prefix.length) : name;
|
|
41
|
+
}
|
|
42
|
+
function displayToolName(name) {
|
|
43
|
+
return canonicalToolName(unwrapProviderPrefix(name));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/tools/primary-arg.ts
|
|
47
|
+
function getPrimaryArg(args) {
|
|
48
|
+
if (typeof args.command === "string") return args.command.split("\n")[0];
|
|
49
|
+
if (typeof args.shell_id === "string") return args.shell_id;
|
|
50
|
+
if (typeof args.shellId === "string") return args.shellId;
|
|
51
|
+
if (typeof args.taskId === "string") return args.taskId;
|
|
52
|
+
if (typeof args.task_id === "string") return args.task_id;
|
|
53
|
+
if (typeof args.filePath === "string") return args.filePath;
|
|
54
|
+
if (typeof args.file_path === "string") return args.file_path;
|
|
55
|
+
if (typeof args.patch === "string") {
|
|
56
|
+
const match = args.patch.match(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/m);
|
|
57
|
+
if (match) return match[1].trim();
|
|
58
|
+
}
|
|
59
|
+
if (typeof args.notebook_path === "string") return args.notebook_path;
|
|
60
|
+
if (typeof args.pattern === "string") return args.pattern;
|
|
61
|
+
if (typeof args.path === "string") return args.path;
|
|
62
|
+
if (typeof args.agent === "string") return args.agent;
|
|
63
|
+
if (typeof args.skill === "string") return args.skill;
|
|
64
|
+
if (typeof args.message === "string") return args.message;
|
|
65
|
+
if (typeof args.url === "string") return args.url;
|
|
66
|
+
if (typeof args.query === "string") return args.query;
|
|
67
|
+
if (typeof args.subject === "string") return args.subject;
|
|
68
|
+
if (typeof args.old_string === "string") return args.old_string.slice(0, 60);
|
|
69
|
+
const keys = Object.keys(args);
|
|
70
|
+
if (keys.length > 0) {
|
|
71
|
+
const v = args[keys[0]];
|
|
72
|
+
return typeof v === "string" ? v : "";
|
|
73
|
+
}
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/tools/result.ts
|
|
78
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
79
|
+
import { dirname, join } from "path";
|
|
80
|
+
|
|
81
|
+
// src/tools/tool-capabilities.ts
|
|
82
|
+
var FILE_MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
83
|
+
"ApplyPatch",
|
|
84
|
+
"Write",
|
|
85
|
+
"Edit",
|
|
86
|
+
"MultiEdit",
|
|
87
|
+
"NotebookEdit"
|
|
88
|
+
]);
|
|
89
|
+
function isFileMutatingTool(canonicalName) {
|
|
90
|
+
return FILE_MUTATING_TOOLS.has(canonicalName);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/tools/result.ts
|
|
94
|
+
var TOOL_RESULT_MAX_BYTES = 50 * 1024;
|
|
95
|
+
var READ_EMPTY_FILE_NOTICE = "[Empty file: 0 lines.]";
|
|
96
|
+
function toolOutputDirectory() {
|
|
97
|
+
return join(resolveBookHome(), "tool-output");
|
|
98
|
+
}
|
|
99
|
+
function presentationFor(content, override) {
|
|
100
|
+
return {
|
|
101
|
+
kind: override?.kind ?? "text",
|
|
102
|
+
summary: override?.summary ?? content.split("\n")[0]?.trim() ?? "",
|
|
103
|
+
details: override?.details ?? content,
|
|
104
|
+
metadata: override?.metadata,
|
|
105
|
+
target: override?.target
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function toolSuccess(content, options = {}) {
|
|
109
|
+
return {
|
|
110
|
+
version: 2,
|
|
111
|
+
toolCallId: options.toolCallId ?? "",
|
|
112
|
+
status: "success",
|
|
113
|
+
content,
|
|
114
|
+
data: options.data,
|
|
115
|
+
presentation: options.presentation ? presentationFor(content, options.presentation) : void 0,
|
|
116
|
+
artifacts: options.artifacts,
|
|
117
|
+
pagination: options.pagination
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function toolFailure(message, options = {}) {
|
|
121
|
+
const error = {
|
|
122
|
+
code: options.code ?? "tool_error",
|
|
123
|
+
message,
|
|
124
|
+
retryable: options.retryable ?? false,
|
|
125
|
+
remediation: options.remediation,
|
|
126
|
+
details: options.details
|
|
127
|
+
};
|
|
128
|
+
const content = options.content ?? "";
|
|
129
|
+
return {
|
|
130
|
+
version: 2,
|
|
131
|
+
toolCallId: options.toolCallId ?? "",
|
|
132
|
+
status: options.status ?? "error",
|
|
133
|
+
content,
|
|
134
|
+
data: options.data,
|
|
135
|
+
structuredError: error,
|
|
136
|
+
presentation: options.presentation ? presentationFor(message, {
|
|
137
|
+
summary: message.split("\n")[0]?.trim(),
|
|
138
|
+
details: message,
|
|
139
|
+
...options.presentation
|
|
140
|
+
}) : void 0,
|
|
141
|
+
artifacts: options.artifacts,
|
|
142
|
+
pagination: options.pagination
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function toolResultSucceeded(result) {
|
|
146
|
+
return result.status === "success";
|
|
147
|
+
}
|
|
148
|
+
function toolResultErrorMessage(result) {
|
|
149
|
+
return result.structuredError?.message;
|
|
150
|
+
}
|
|
151
|
+
function rawToolResultModelContent(result) {
|
|
152
|
+
const content = result.content;
|
|
153
|
+
if (toolResultSucceeded(result)) {
|
|
154
|
+
return content.trim().length === 0 ? "(no output)" : content;
|
|
155
|
+
}
|
|
156
|
+
const remediation = result.structuredError?.remediation;
|
|
157
|
+
const fix = remediation ? `
|
|
158
|
+
Fix: ${remediation}` : "";
|
|
159
|
+
const detail = content ? `
|
|
160
|
+
${content}` : "";
|
|
161
|
+
return `ERROR [${result.structuredError?.code ?? result.status}]: ${toolResultErrorMessage(result) ?? "tool failed"}${fix}${detail}`;
|
|
162
|
+
}
|
|
163
|
+
function toolResultModelContent(result) {
|
|
164
|
+
if (result.maskedPlaceholder !== void 0) return result.maskedPlaceholder;
|
|
165
|
+
const raw = rawToolResultModelContent(result);
|
|
166
|
+
if (Buffer.byteLength(raw) <= TOOL_RESULT_MAX_BYTES) return raw;
|
|
167
|
+
if (!toolResultSucceeded(result)) {
|
|
168
|
+
const prefix = `ERROR [${result.structuredError?.code ?? result.status}]: `;
|
|
169
|
+
const fix = result.structuredError?.remediation ? `
|
|
170
|
+
Fix: ${result.structuredError.remediation}` : "";
|
|
171
|
+
const budget = Math.max(
|
|
172
|
+
1,
|
|
173
|
+
TOOL_RESULT_MAX_BYTES - Buffer.byteLength(prefix) - Buffer.byteLength(fix)
|
|
174
|
+
);
|
|
175
|
+
return `${prefix}${headTailPreview(failureText(result), result.artifacts?.outputPath, budget)}${fix}`;
|
|
176
|
+
}
|
|
177
|
+
return clippedOutputPreview(raw, result.artifacts?.outputPath, TOOL_RESULT_MAX_BYTES);
|
|
178
|
+
}
|
|
179
|
+
function utf8Prefix(text, maxBytes) {
|
|
180
|
+
if (maxBytes <= 0) return "";
|
|
181
|
+
const bytes = Buffer.from(text);
|
|
182
|
+
if (bytes.byteLength <= maxBytes) return text;
|
|
183
|
+
return bytes.subarray(0, maxBytes).toString("utf8").replace(/\uFFFD$/u, "");
|
|
184
|
+
}
|
|
185
|
+
function utf8Suffix(text, maxBytes) {
|
|
186
|
+
if (maxBytes <= 0) return "";
|
|
187
|
+
const bytes = Buffer.from(text);
|
|
188
|
+
if (bytes.byteLength <= maxBytes) return text;
|
|
189
|
+
let start = bytes.byteLength - maxBytes;
|
|
190
|
+
while (start < bytes.byteLength && (bytes[start] & 192) === 128) start++;
|
|
191
|
+
return bytes.subarray(start).toString("utf8");
|
|
192
|
+
}
|
|
193
|
+
var FAILURE_HEAD_MAX_BYTES = 8 * 1024;
|
|
194
|
+
function failureText(result) {
|
|
195
|
+
const message = toolResultErrorMessage(result) ?? "tool failed";
|
|
196
|
+
return result.content ? `${message}
|
|
197
|
+
${result.content}` : message;
|
|
198
|
+
}
|
|
199
|
+
function headTailPreview(text, outputPath, maxBytes) {
|
|
200
|
+
const totalBytes = Buffer.byteLength(text);
|
|
201
|
+
const headWindow = Math.min(FAILURE_HEAD_MAX_BYTES, Math.floor(maxBytes * 0.2));
|
|
202
|
+
const window = utf8Prefix(text, headWindow);
|
|
203
|
+
if (Buffer.byteLength(window) >= totalBytes) return text;
|
|
204
|
+
const lastBreak = window.lastIndexOf("\n");
|
|
205
|
+
const head = lastBreak >= 0 ? window.slice(0, lastBreak + 1) : window;
|
|
206
|
+
const headShown = head.trimEnd();
|
|
207
|
+
const headBytes = Buffer.byteLength(headShown);
|
|
208
|
+
const omittedNotice = (omitted) => outputPath ? `[... ${omitted} bytes omitted. Full output: ${outputPath}]` : `[... ${omitted} bytes omitted. Full output unavailable.]`;
|
|
209
|
+
const reserve = Buffer.byteLength(omittedNotice(totalBytes)) + 2;
|
|
210
|
+
const tailRoom = maxBytes - headBytes - reserve;
|
|
211
|
+
if (tailRoom <= 0) return [headShown, omittedNotice(totalBytes - headBytes)].join("\n");
|
|
212
|
+
const tailWindow = utf8Suffix(text, tailRoom);
|
|
213
|
+
const breakAt = tailWindow.indexOf("\n");
|
|
214
|
+
const tail = breakAt >= 0 ? tailWindow.slice(breakAt + 1) : tailWindow;
|
|
215
|
+
const notice = omittedNotice(totalBytes - headBytes - Buffer.byteLength(tail));
|
|
216
|
+
return [headShown, notice, tail].join("\n");
|
|
217
|
+
}
|
|
218
|
+
function clippedOutputPreview(content, outputPath, maxBytes) {
|
|
219
|
+
const notice = outputPath ? `
|
|
220
|
+
|
|
221
|
+
[Output truncated at ${maxBytes} bytes. Full output: ${outputPath}]` : `
|
|
222
|
+
|
|
223
|
+
[Output truncated at ${maxBytes} bytes. Full output unavailable.]`;
|
|
224
|
+
const previewBudget = Math.max(0, maxBytes - Buffer.byteLength(notice));
|
|
225
|
+
return `${utf8Prefix(content, previewBudget).trimEnd()}${notice}`;
|
|
226
|
+
}
|
|
227
|
+
async function boundToolResultOutput(input, _workspaceRoot, maxBytes = TOOL_RESULT_MAX_BYTES, artifactRoot) {
|
|
228
|
+
const result = normalizeToolResult(input);
|
|
229
|
+
const modelContent = rawToolResultModelContent(result);
|
|
230
|
+
const modelContentBytes = Buffer.byteLength(modelContent);
|
|
231
|
+
const contentBytes = Buffer.byteLength(result.content);
|
|
232
|
+
const details = result.presentation?.details;
|
|
233
|
+
const detailsBytes = details === void 0 ? 0 : Buffer.byteLength(details);
|
|
234
|
+
if (modelContentBytes <= maxBytes && detailsBytes <= maxBytes) return result;
|
|
235
|
+
let outputPath = result.artifacts?.outputPath;
|
|
236
|
+
if (!outputPath) {
|
|
237
|
+
const outputFile = join(artifactRoot ?? toolOutputDirectory(), `${crypto.randomUUID()}.txt`);
|
|
238
|
+
try {
|
|
239
|
+
await mkdir(dirname(outputFile), { recursive: true });
|
|
240
|
+
await writeFile(
|
|
241
|
+
outputFile,
|
|
242
|
+
detailsBytes > modelContentBytes && details ? details : modelContent,
|
|
243
|
+
"utf8"
|
|
244
|
+
);
|
|
245
|
+
outputPath = outputFile.replace(/\\/g, "/");
|
|
246
|
+
} catch {
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const modelOverflow = modelContentBytes > maxBytes;
|
|
250
|
+
const content = toolResultSucceeded(result) ? contentBytes > maxBytes ? clippedOutputPreview(result.content, outputPath, maxBytes) : result.content : modelOverflow ? "" : result.content;
|
|
251
|
+
const errorPrefix = `ERROR [${result.structuredError?.code ?? result.status}]: `;
|
|
252
|
+
const fixReserve = result.structuredError?.remediation ? Buffer.byteLength(`
|
|
253
|
+
Fix: ${result.structuredError.remediation}`) : 0;
|
|
254
|
+
const errorBudget = Math.max(1, maxBytes - Buffer.byteLength(errorPrefix) - fixReserve);
|
|
255
|
+
const structuredError = result.structuredError ? {
|
|
256
|
+
...result.structuredError,
|
|
257
|
+
// The message and the output are clipped as one text, so a failure
|
|
258
|
+
// keeps both ends: the error line and any framing at the top, and the
|
|
259
|
+
// verdict at the bottom. The room the `Fix:` line needs is reserved
|
|
260
|
+
// above, so the remediation is never what gets clipped.
|
|
261
|
+
message: modelOverflow ? headTailPreview(failureText(result), outputPath, errorBudget) : result.structuredError.message
|
|
262
|
+
} : result.structuredError;
|
|
263
|
+
const clippedDetails = details ? detailsBytes > maxBytes ? (
|
|
264
|
+
// The transcript row reads the same way the model does: a failure's
|
|
265
|
+
// head and tail, not one end of it — the same reason as above.
|
|
266
|
+
toolResultSucceeded(result) ? clippedOutputPreview(details, outputPath, maxBytes) : headTailPreview(details, outputPath, maxBytes)
|
|
267
|
+
) : details : toolResultSucceeded(result) ? content : structuredError?.message;
|
|
268
|
+
return {
|
|
269
|
+
...result,
|
|
270
|
+
content,
|
|
271
|
+
structuredError,
|
|
272
|
+
presentation: result.presentation ? { ...result.presentation, details: clippedDetails } : result.presentation,
|
|
273
|
+
artifacts: outputPath ? { ...result.artifacts, outputPath } : result.artifacts,
|
|
274
|
+
pagination: {
|
|
275
|
+
...result.pagination,
|
|
276
|
+
truncated: true,
|
|
277
|
+
omittedBytes: Math.max(
|
|
278
|
+
result.pagination?.omittedBytes ?? 0,
|
|
279
|
+
Math.max(modelContentBytes, contentBytes, detailsBytes) - maxBytes
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function replaceToolResult(result, patch) {
|
|
285
|
+
const status = patch.status ?? result.status;
|
|
286
|
+
const content = patch.content ?? result.content;
|
|
287
|
+
return {
|
|
288
|
+
...result,
|
|
289
|
+
status,
|
|
290
|
+
content,
|
|
291
|
+
// New content replaces what the model read: a placeholder standing in for
|
|
292
|
+
// the previous text would hide the rewrite (a PostToolUse hook's
|
|
293
|
+
// `modifiedOutput`, the plan-approval note) behind the line the tool wrote.
|
|
294
|
+
...patch.content !== void 0 ? { maskedPlaceholder: void 0 } : {},
|
|
295
|
+
structuredError: patch.error ?? (status === "success" ? void 0 : result.structuredError),
|
|
296
|
+
presentation: result.presentation || patch.presentation ? presentationFor(content, {
|
|
297
|
+
...result.presentation,
|
|
298
|
+
...patch.presentation
|
|
299
|
+
}) : void 0
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function normalizeToolResult(result) {
|
|
303
|
+
const legacy = result;
|
|
304
|
+
const legacySuccess = legacy.success;
|
|
305
|
+
const legacyError = typeof legacy.error === "string" ? legacy.error : void 0;
|
|
306
|
+
const status = result.status ? result.status : legacySuccess ? "success" : legacyError?.startsWith("SKIPPED") ? "blocked" : legacyError?.startsWith("CANCELLED") ? "cancelled" : legacyError?.startsWith("Tool timeout") ? "timed_out" : "error";
|
|
307
|
+
const content = result.content ?? legacy.output ?? "";
|
|
308
|
+
const error = status === "success" ? void 0 : {
|
|
309
|
+
...result.structuredError ?? {},
|
|
310
|
+
code: result.structuredError?.code ?? (status === "blocked" ? "blocked" : status),
|
|
311
|
+
message: legacyError ?? result.structuredError?.message ?? "Tool failed",
|
|
312
|
+
retryable: result.structuredError?.retryable ?? status === "timed_out"
|
|
313
|
+
};
|
|
314
|
+
const artifacts = result.artifacts ?? (legacy.fileMutation || legacy.fileMutations || legacy.fileObservations || legacy.eventRef || legacy.outputPath ? {
|
|
315
|
+
fileMutation: legacy.fileMutation,
|
|
316
|
+
fileMutations: legacy.fileMutations,
|
|
317
|
+
fileObservations: legacy.fileObservations,
|
|
318
|
+
eventRef: legacy.eventRef,
|
|
319
|
+
outputPath: legacy.outputPath
|
|
320
|
+
} : void 0);
|
|
321
|
+
const metrics = result.metrics ?? (legacy.durationMs !== void 0 || legacy.retryAttempt !== void 0 ? { durationMs: legacy.durationMs, retryAttempt: legacy.retryAttempt } : void 0);
|
|
322
|
+
return {
|
|
323
|
+
version: 2,
|
|
324
|
+
toolCallId: result.toolCallId,
|
|
325
|
+
status,
|
|
326
|
+
content,
|
|
327
|
+
// Masking's placeholder survives a resume, or a restored compaction's tail
|
|
328
|
+
// would come back at full size.
|
|
329
|
+
..."maskedPlaceholder" in result && result.maskedPlaceholder !== void 0 ? { maskedPlaceholder: result.maskedPlaceholder } : {},
|
|
330
|
+
data: result.data,
|
|
331
|
+
structuredError: error,
|
|
332
|
+
presentation: result.presentation,
|
|
333
|
+
artifacts,
|
|
334
|
+
metrics,
|
|
335
|
+
pagination: result.pagination
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function nonEmptyLines(content) {
|
|
339
|
+
return content.split("\n").filter((line) => line.trim()).length;
|
|
340
|
+
}
|
|
341
|
+
function readLineMetadata(start, count) {
|
|
342
|
+
const first = Math.max(1, Math.floor(start));
|
|
343
|
+
const lines = Math.max(0, Math.floor(count));
|
|
344
|
+
if (lines <= 0) return ["empty"];
|
|
345
|
+
const size = lines === 1 ? "1 line" : `${lines} lines`;
|
|
346
|
+
return first > 1 ? [size, `${first}-${first + lines - 1}`] : [size];
|
|
347
|
+
}
|
|
348
|
+
function readResultMetadata(args, content) {
|
|
349
|
+
if (args.outline === true) {
|
|
350
|
+
const entries = content.split("\n").filter((line) => /^\d+: /.test(line)).length;
|
|
351
|
+
return ["outline", entries === 1 ? "1 entry" : `${entries} entries`];
|
|
352
|
+
}
|
|
353
|
+
let body = content === READ_EMPTY_FILE_NOTICE ? "" : content.replace(/\n\[Lines? \d[^\n]*\]$/, "");
|
|
354
|
+
if (body === content) body = body.replace(/(?:^|\n)\d+: $/, "");
|
|
355
|
+
const lineCount = body ? body.split("\n").length : 0;
|
|
356
|
+
const offset = Number(args.offset ?? 0);
|
|
357
|
+
const start = Number.isFinite(offset) && offset > 0 ? Math.floor(offset) : 1;
|
|
358
|
+
return readLineMetadata(start, lineCount);
|
|
359
|
+
}
|
|
360
|
+
function grepResultMetadata(args, content) {
|
|
361
|
+
const noun = args.output_mode === "files_with_matches" ? "file" : "match";
|
|
362
|
+
if (/^No matches found$/i.test(content.trim()))
|
|
363
|
+
return `0 ${noun === "file" ? "files" : "matches"}`;
|
|
364
|
+
const lines = content.split("\n");
|
|
365
|
+
let count;
|
|
366
|
+
if (noun === "file") count = lines.filter((line) => line.trim()).length;
|
|
367
|
+
else if (args.output_mode === "count") {
|
|
368
|
+
count = lines.reduce((total, line) => total + (Number(/:(\d+)\s*$/.exec(line)?.[1]) || 0), 0);
|
|
369
|
+
} else count = lines.filter((line) => /:\d+:/.test(line)).length || nonEmptyLines(content);
|
|
370
|
+
return `${count} ${count === 1 ? noun : noun === "file" ? "files" : "matches"}`;
|
|
371
|
+
}
|
|
372
|
+
function enrichToolResultPresentation(input, toolName, args) {
|
|
373
|
+
const result = normalizeToolResult(input);
|
|
374
|
+
const name = canonicalToolName(toolName);
|
|
375
|
+
const content = result.content;
|
|
376
|
+
const explicitPresentation = result.presentation;
|
|
377
|
+
const target = explicitPresentation?.target ?? (getPrimaryArg(args) || void 0);
|
|
378
|
+
const metadata = explicitPresentation?.metadata ? [...explicitPresentation.metadata] : [];
|
|
379
|
+
const inferKind = explicitPresentation?.kind === void 0;
|
|
380
|
+
const inferSummary = explicitPresentation?.summary === void 0;
|
|
381
|
+
const inferMetadata = explicitPresentation?.metadata === void 0;
|
|
382
|
+
let kind = explicitPresentation?.kind ?? "text";
|
|
383
|
+
let summary = explicitPresentation?.summary ?? content.split("\n")[0]?.trim() ?? "";
|
|
384
|
+
if (isFileMutatingTool(name)) {
|
|
385
|
+
if (inferKind) {
|
|
386
|
+
kind = result.artifacts?.fileMutation ? "file" : /^@@/m.test(content) ? "diff" : "file";
|
|
387
|
+
}
|
|
388
|
+
const mutation = result.artifacts?.fileMutation ?? result.artifacts?.fileMutations?.[0];
|
|
389
|
+
if (mutation) {
|
|
390
|
+
if (inferMetadata) {
|
|
391
|
+
if (mutation.addedLines) metadata.push(`+${mutation.addedLines}`);
|
|
392
|
+
if (mutation.removedLines) metadata.push(`-${mutation.removedLines}`);
|
|
393
|
+
if (!mutation.addedLines && !mutation.removedLines) metadata.push("no changes");
|
|
394
|
+
}
|
|
395
|
+
if (inferSummary) {
|
|
396
|
+
summary = `${mutation.kind === "create" ? "Created" : mutation.kind === "delete" ? "Deleted" : "Updated"} ${mutation.filePath}`;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} else if (name === "Read") {
|
|
400
|
+
if (inferKind) kind = "file";
|
|
401
|
+
if (inferMetadata && result.status === "success")
|
|
402
|
+
metadata.push(...readResultMetadata(args, content));
|
|
403
|
+
if (inferSummary) summary = target ? `Read ${target}` : summary;
|
|
404
|
+
} else if (name === "Glob") {
|
|
405
|
+
if (inferKind) kind = "search";
|
|
406
|
+
const count = /^(?:No files found|No matches found)$/i.test(content.trim()) ? 0 : nonEmptyLines(content.replace(/\n\.\.\. \(truncated[\s\S]*$/, ""));
|
|
407
|
+
if (inferMetadata) metadata.push(`${count} ${count === 1 ? "file" : "files"}`);
|
|
408
|
+
if (inferSummary) summary = `Found ${count} ${count === 1 ? "file" : "files"}`;
|
|
409
|
+
} else if (name === "Grep") {
|
|
410
|
+
if (inferKind) kind = "search";
|
|
411
|
+
if (result.status === "success") {
|
|
412
|
+
const label = grepResultMetadata(args, content);
|
|
413
|
+
if (inferMetadata) metadata.push(label);
|
|
414
|
+
if (inferSummary) summary = `Found ${label}`;
|
|
415
|
+
}
|
|
416
|
+
} else if (name === "Bash" || name === "BashOutput" || name === "KillShell") {
|
|
417
|
+
if (inferKind) kind = "command";
|
|
418
|
+
if (inferSummary) summary = target ? `${name}: ${target}` : summary;
|
|
419
|
+
} else if (name === "GitDiff") {
|
|
420
|
+
if (inferKind) kind = "diff";
|
|
421
|
+
} else if (name.startsWith("Web") || name === "ToolSearch" || name.startsWith("SessionHistory")) {
|
|
422
|
+
if (inferKind) kind = name === "ToolSearch" ? "search" : "markdown";
|
|
423
|
+
} else if (name.startsWith("Task") || name === "TodoWrite") {
|
|
424
|
+
if (inferKind) kind = "task";
|
|
425
|
+
} else if (name.startsWith("Agent") || name.startsWith("Evidence")) {
|
|
426
|
+
if (inferKind) kind = "agent";
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
...result,
|
|
430
|
+
presentation: {
|
|
431
|
+
kind,
|
|
432
|
+
summary,
|
|
433
|
+
details: explicitPresentation?.details ?? content,
|
|
434
|
+
metadata,
|
|
435
|
+
target: explicitPresentation?.target ?? result.artifacts?.fileMutation?.filePath ?? target
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/tools/path-utils.ts
|
|
441
|
+
import { existsSync, lstatSync, realpathSync } from "fs";
|
|
442
|
+
import { basename, dirname as dirname2, isAbsolute, join as join2, relative, resolve, sep } from "path";
|
|
443
|
+
var REAL_PATH_COMPARISON = { relative, isAbsolute, sep };
|
|
444
|
+
function isOutside(root, candidate, path = REAL_PATH_COMPARISON) {
|
|
445
|
+
const rel = path.relative(root, candidate);
|
|
446
|
+
return rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel);
|
|
447
|
+
}
|
|
448
|
+
function nearestExistingPath(inputPath) {
|
|
449
|
+
let candidate = inputPath;
|
|
450
|
+
while (!existsSync(candidate)) {
|
|
451
|
+
const parent = dirname2(candidate);
|
|
452
|
+
if (parent === candidate) return null;
|
|
453
|
+
candidate = parent;
|
|
454
|
+
}
|
|
455
|
+
return candidate;
|
|
456
|
+
}
|
|
457
|
+
function resolveWorkspacePath(workspaceRoot, inputPath) {
|
|
458
|
+
const lexicalRoot = resolve(workspaceRoot);
|
|
459
|
+
const filePath = resolve(isAbsolute(inputPath) ? inputPath : resolve(lexicalRoot, inputPath));
|
|
460
|
+
const canonicalRoot = canonicalizePath(lexicalRoot);
|
|
461
|
+
const canonicalPath = canonicalizePath(filePath);
|
|
462
|
+
if (isOutside(canonicalRoot, canonicalPath)) return null;
|
|
463
|
+
const asWrittenInside = !isOutside(lexicalRoot, filePath);
|
|
464
|
+
const rel = asWrittenInside ? relative(lexicalRoot, filePath) : relative(canonicalRoot, canonicalPath);
|
|
465
|
+
return { filePath, canonicalPath, relativePath: rel.replace(/\\/g, "/") };
|
|
466
|
+
}
|
|
467
|
+
function resolveReadablePathDetail(context, inputPath) {
|
|
468
|
+
const wsMatch = resolveWorkspacePath(context.workspaceRoot, inputPath);
|
|
469
|
+
if (wsMatch) {
|
|
470
|
+
return { path: { ...wsMatch, root: context.workspaceRoot, inWorkspace: true } };
|
|
471
|
+
}
|
|
472
|
+
if (!isAbsolute(inputPath)) return { reason: "unreachable" };
|
|
473
|
+
for (const root of [...context.readOnlyRoots ?? [], ...context.additionalRoots ?? []]) {
|
|
474
|
+
const match = resolveWorkspacePath(root, inputPath);
|
|
475
|
+
if (match) return { path: { ...match, root, inWorkspace: false } };
|
|
476
|
+
}
|
|
477
|
+
const memory = context.memorySearchRoot ? resolveMemorySearchPath(context.memorySearchRoot, inputPath) : null;
|
|
478
|
+
return memory ? { path: memory } : { reason: "unreachable" };
|
|
479
|
+
}
|
|
480
|
+
function resolveMemorySearchPath(memoryRoot, inputPath) {
|
|
481
|
+
const match = resolveWorkspacePath(memoryRoot, inputPath);
|
|
482
|
+
if (!match) return null;
|
|
483
|
+
const fromRoot = relative(canonicalizePath(resolve(memoryRoot)), match.canonicalPath);
|
|
484
|
+
const segments = [...match.relativePath.split("/"), ...fromRoot.split(sep)];
|
|
485
|
+
if (segments.some((segment) => segment.startsWith(".") && segment !== "." && segment !== "..")) {
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
return { ...match, root: memoryRoot, inWorkspace: false };
|
|
489
|
+
}
|
|
490
|
+
function resolveMentionReadablePath(roots, absolutePath) {
|
|
491
|
+
if (reachesUncPath(absolutePath)) return { reason: "unc" };
|
|
492
|
+
return resolveReadablePathDetail(
|
|
493
|
+
{ workspaceRoot: roots.workspaceRoot, additionalRoots: roots.additionalRoots },
|
|
494
|
+
absolutePath
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
function resolveReadablePath(context, inputPath) {
|
|
498
|
+
const detail = resolveReadablePathDetail(context, inputPath);
|
|
499
|
+
return "path" in detail ? detail.path : null;
|
|
500
|
+
}
|
|
501
|
+
function resolveMutationPath(context, inputPath) {
|
|
502
|
+
const memory = context.memoryWrite ? resolveMemoryWritePath(context.workspaceRoot, context.memoryWrite.root, inputPath) : null;
|
|
503
|
+
if (memory) return memory;
|
|
504
|
+
const inWorkspace = resolveWorkspacePath(context.workspaceRoot, inputPath);
|
|
505
|
+
if (inWorkspace) return { ...inWorkspace, root: context.workspaceRoot, inWorkspace: true };
|
|
506
|
+
if (!isAbsolute(inputPath)) return null;
|
|
507
|
+
for (const root of context.additionalRoots ?? []) {
|
|
508
|
+
const match = resolveWorkspacePath(root, inputPath);
|
|
509
|
+
if (!match) continue;
|
|
510
|
+
const rel = relative(resolve(context.workspaceRoot), match.filePath);
|
|
511
|
+
return { ...match, relativePath: rel.replace(/\\/g, "/"), root, inWorkspace: false };
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
function hasLinkBelow(root, filePath) {
|
|
516
|
+
let current = root;
|
|
517
|
+
for (const segment of relative(root, filePath).split(sep)) {
|
|
518
|
+
current = join2(current, segment);
|
|
519
|
+
try {
|
|
520
|
+
if (lstatSync(current).isSymbolicLink()) return true;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
const code = error.code;
|
|
523
|
+
if (code === "ENOENT" || code === "ENOTDIR") return false;
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
function resolveMemoryWritePath(workspaceRoot, memoryRoot, inputPath) {
|
|
530
|
+
if (!isAbsolute(inputPath)) return null;
|
|
531
|
+
const filePath = resolve(inputPath);
|
|
532
|
+
if (!basename(filePath).toLowerCase().endsWith(".md")) return null;
|
|
533
|
+
const lexicalRoot = resolve(memoryRoot);
|
|
534
|
+
const canonicalRoot = canonicalizePath(lexicalRoot);
|
|
535
|
+
const canonicalPath = canonicalizePath(filePath);
|
|
536
|
+
if (canonicalPath === canonicalRoot || isOutside(canonicalRoot, canonicalPath)) return null;
|
|
537
|
+
const writtenRoot = [lexicalRoot, canonicalRoot].find((root) => !isOutside(root, filePath));
|
|
538
|
+
if (!writtenRoot) return null;
|
|
539
|
+
const below = relative(writtenRoot, filePath).split(sep);
|
|
540
|
+
if (below.some((segment) => segment.startsWith("."))) return null;
|
|
541
|
+
if (relative(canonicalRoot, canonicalPath).split(sep).some((s) => s.startsWith(".")))
|
|
542
|
+
return null;
|
|
543
|
+
if (hasLinkBelow(writtenRoot, filePath)) return null;
|
|
544
|
+
const rel = relative(resolve(workspaceRoot), filePath);
|
|
545
|
+
return {
|
|
546
|
+
filePath,
|
|
547
|
+
canonicalPath,
|
|
548
|
+
relativePath: rel.replace(/\\/g, "/"),
|
|
549
|
+
root: memoryRoot,
|
|
550
|
+
inWorkspace: false,
|
|
551
|
+
memory: true
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function mutationDisplayPath(resolved) {
|
|
555
|
+
if (!resolved.memory) return resolved.relativePath;
|
|
556
|
+
return memoryDisplayName(resolved.root, resolved.canonicalPath);
|
|
557
|
+
}
|
|
558
|
+
function memoryDisplayName(memoryRoot, canonicalPath) {
|
|
559
|
+
const below = relative(canonicalizePath(resolve(memoryRoot)), canonicalPath);
|
|
560
|
+
return `memory/${below.split(sep).join("/")}`;
|
|
561
|
+
}
|
|
562
|
+
function memoryReadDisplayPath(roots, resolved) {
|
|
563
|
+
const memoryRoot = roots.memorySearchRoot ?? roots.memoryWrite?.root;
|
|
564
|
+
if (!memoryRoot) return void 0;
|
|
565
|
+
const canonicalRoot = canonicalizePath(resolve(memoryRoot));
|
|
566
|
+
if (resolved.canonicalPath === canonicalRoot || isOutside(canonicalRoot, resolved.canonicalPath)) {
|
|
567
|
+
return void 0;
|
|
568
|
+
}
|
|
569
|
+
return memoryDisplayName(memoryRoot, resolved.canonicalPath);
|
|
570
|
+
}
|
|
571
|
+
function messagePathFor(resolved) {
|
|
572
|
+
return resolved.memory ? resolved.filePath : resolved.relativePath;
|
|
573
|
+
}
|
|
574
|
+
function pathOutsideWorkspaceResult(inputPath) {
|
|
575
|
+
return toolFailure(`Path outside workspace and additionalDirectories: ${inputPath}`, {
|
|
576
|
+
code: "path_outside_workspace",
|
|
577
|
+
remediation: "Add its directory to additionalDirectories, or start Book in a directory that contains it. No permission rule and no permission mode can change which roots a read may cross."
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
function realWorkspaceRoot(root) {
|
|
581
|
+
try {
|
|
582
|
+
return realpathSync.native(root);
|
|
583
|
+
} catch {
|
|
584
|
+
return resolve(root);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function canonicalizePath(inputPath) {
|
|
588
|
+
const absolute = resolve(inputPath);
|
|
589
|
+
const existing = nearestExistingPath(absolute);
|
|
590
|
+
if (!existing) return absolute;
|
|
591
|
+
try {
|
|
592
|
+
return resolve(realpathSync.native(existing), relative(existing, absolute));
|
|
593
|
+
} catch {
|
|
594
|
+
return absolute;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function isUnderRoot(canonicalPath, root) {
|
|
598
|
+
return !isOutside(canonicalizePath(root), canonicalPath);
|
|
599
|
+
}
|
|
600
|
+
function comparablePath(value, platform = process.platform) {
|
|
601
|
+
if (platform !== "win32") return value;
|
|
602
|
+
return value.replaceAll("\\", "/").toLowerCase();
|
|
603
|
+
}
|
|
604
|
+
function hasBookLocalSettingsShape(canonicalPath, options) {
|
|
605
|
+
const parts = canonicalPath.toLowerCase().split(/[\\/]/);
|
|
606
|
+
if (parts[parts.length - 1] === ".book") return options.directory === true;
|
|
607
|
+
return parts[parts.length - 2] === ".book" && parts[parts.length - 1] === "settings.local.json";
|
|
608
|
+
}
|
|
609
|
+
function isBookLocalSettingsPath(path, root, options = {}) {
|
|
610
|
+
if (!hasBookLocalSettingsShape(path, options)) return false;
|
|
611
|
+
const target = canonicalizePath(path).toLowerCase();
|
|
612
|
+
const bookDir = join2(canonicalizePath(root), ".book").toLowerCase();
|
|
613
|
+
return target === join2(bookDir, "settings.local.json") || options.directory === true && target === bookDir;
|
|
614
|
+
}
|
|
615
|
+
function isBookLocalSettingsUnderRoots(path, roots, options = {}) {
|
|
616
|
+
if (!hasBookLocalSettingsShape(path, options)) return false;
|
|
617
|
+
return [
|
|
618
|
+
roots.workspaceRoot,
|
|
619
|
+
...roots.readOnlyRoots ?? [],
|
|
620
|
+
...roots.additionalRoots ?? []
|
|
621
|
+
].some((root) => isBookLocalSettingsPath(path, root, options));
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export {
|
|
625
|
+
TOOL_ALIASES,
|
|
626
|
+
canonicalToolName,
|
|
627
|
+
unwrapProviderPrefix,
|
|
628
|
+
displayToolName,
|
|
629
|
+
getPrimaryArg,
|
|
630
|
+
isFileMutatingTool,
|
|
631
|
+
TOOL_RESULT_MAX_BYTES,
|
|
632
|
+
READ_EMPTY_FILE_NOTICE,
|
|
633
|
+
toolSuccess,
|
|
634
|
+
toolFailure,
|
|
635
|
+
toolResultSucceeded,
|
|
636
|
+
toolResultErrorMessage,
|
|
637
|
+
toolResultModelContent,
|
|
638
|
+
utf8Prefix,
|
|
639
|
+
boundToolResultOutput,
|
|
640
|
+
replaceToolResult,
|
|
641
|
+
normalizeToolResult,
|
|
642
|
+
readLineMetadata,
|
|
643
|
+
readResultMetadata,
|
|
644
|
+
grepResultMetadata,
|
|
645
|
+
enrichToolResultPresentation,
|
|
646
|
+
isOutside,
|
|
647
|
+
resolveWorkspacePath,
|
|
648
|
+
resolveReadablePathDetail,
|
|
649
|
+
resolveMentionReadablePath,
|
|
650
|
+
resolveReadablePath,
|
|
651
|
+
resolveMutationPath,
|
|
652
|
+
mutationDisplayPath,
|
|
653
|
+
memoryReadDisplayPath,
|
|
654
|
+
messagePathFor,
|
|
655
|
+
pathOutsideWorkspaceResult,
|
|
656
|
+
realWorkspaceRoot,
|
|
657
|
+
canonicalizePath,
|
|
658
|
+
isUnderRoot,
|
|
659
|
+
comparablePath,
|
|
660
|
+
isBookLocalSettingsPath,
|
|
661
|
+
isBookLocalSettingsUnderRoots
|
|
662
|
+
};
|
|
663
|
+
//# sourceMappingURL=chunk-YIL6HTJX.js.map
|