@x-code-cli/core 0.1.7 → 0.1.8
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/agent/file-ingest.d.ts +62 -0
- package/dist/agent/file-ingest.d.ts.map +1 -0
- package/dist/agent/file-ingest.js +390 -0
- package/dist/agent/file-ingest.js.map +1 -0
- package/dist/agent/light-compact.d.ts +13 -0
- package/dist/agent/light-compact.d.ts.map +1 -0
- package/dist/agent/light-compact.js +106 -0
- package/dist/agent/light-compact.js.map +1 -0
- package/dist/agent/loop-guard.d.ts +50 -0
- package/dist/agent/loop-guard.d.ts.map +1 -0
- package/dist/agent/loop-guard.js +107 -0
- package/dist/agent/loop-guard.js.map +1 -0
- package/dist/agent/loop-state.d.ts +11 -0
- package/dist/agent/loop-state.d.ts.map +1 -1
- package/dist/agent/loop-state.js +2 -0
- package/dist/agent/loop-state.js.map +1 -1
- package/dist/agent/loop.d.ts +2 -2
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +65 -8
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/messages.d.ts +5 -2
- package/dist/agent/messages.d.ts.map +1 -1
- package/dist/agent/messages.js.map +1 -1
- package/dist/agent/provider-compat.d.ts +7 -0
- package/dist/agent/provider-compat.d.ts.map +1 -1
- package/dist/agent/provider-compat.js +122 -0
- package/dist/agent/provider-compat.js.map +1 -1
- package/dist/agent/system-prompt.js +3 -3
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/agent/tool-execution.d.ts.map +1 -1
- package/dist/agent/tool-execution.js +68 -26
- package/dist/agent/tool-execution.js.map +1 -1
- package/dist/agent/tool-result-sanitize.d.ts +8 -0
- package/dist/agent/tool-result-sanitize.d.ts.map +1 -0
- package/dist/agent/tool-result-sanitize.js +77 -0
- package/dist/agent/tool-result-sanitize.js.map +1 -0
- package/dist/agent/vision-fallback.d.ts +22 -0
- package/dist/agent/vision-fallback.d.ts.map +1 -0
- package/dist/agent/vision-fallback.js +127 -0
- package/dist/agent/vision-fallback.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/cache-control.d.ts +29 -0
- package/dist/providers/cache-control.d.ts.map +1 -0
- package/dist/providers/cache-control.js +93 -0
- package/dist/providers/cache-control.js.map +1 -0
- package/dist/providers/capabilities.d.ts +15 -0
- package/dist/providers/capabilities.d.ts.map +1 -0
- package/dist/providers/capabilities.js +38 -0
- package/dist/providers/capabilities.js.map +1 -0
- package/dist/tools/index.d.ts +31 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -10
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read-file.d.ts +29 -1
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +103 -10
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/shell-provider.d.ts +13 -0
- package/dist/tools/shell-provider.d.ts.map +1 -0
- package/dist/tools/shell-provider.js +74 -0
- package/dist/tools/shell-provider.js.map +1 -0
- package/dist/tools/shell-utils.d.ts +1 -7
- package/dist/tools/shell-utils.d.ts.map +1 -1
- package/dist/tools/shell-utils.js +0 -17
- package/dist/tools/shell-utils.js.map +1 -1
- package/dist/tools/truncate.d.ts +36 -0
- package/dist/tools/truncate.d.ts.map +1 -0
- package/dist/tools/truncate.js +118 -0
- package/dist/tools/truncate.js.map +1 -0
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/shell-error.d.ts +12 -0
- package/dist/utils/shell-error.d.ts.map +1 -0
- package/dist/utils/shell-error.js +73 -0
- package/dist/utils/shell-error.js.map +1 -0
- package/package.json +21 -12
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ProviderCapabilities {
|
|
2
|
+
/** Provider can receive inline image parts (base64 or URL) in user messages. */
|
|
3
|
+
image: boolean;
|
|
4
|
+
/** Provider can receive inline PDF file parts. */
|
|
5
|
+
pdf: boolean;
|
|
6
|
+
/** Provider has a dedicated /files upload endpoint (file_id references). */
|
|
7
|
+
filesApi: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Extract `provider` from a `provider:model` id. Returns `unknown` if the
|
|
10
|
+
* separator is missing (defensive — shouldn't happen with resolved ids). */
|
|
11
|
+
export declare function providerOf(modelId: string): string;
|
|
12
|
+
/** Look up capabilities for a model id. Unknown providers default to text-only
|
|
13
|
+
* — safer than assuming vision support. */
|
|
14
|
+
export declare function capabilitiesOf(modelId: string): ProviderCapabilities;
|
|
15
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/providers/capabilities.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,oBAAoB;IACnC,gFAAgF;IAChF,KAAK,EAAE,OAAO,CAAA;IACd,kDAAkD;IAClD,GAAG,EAAE,OAAO,CAAA;IACZ,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAA;CAClB;AAiBD;6EAC6E;AAC7E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;4CAC4C;AAC5C,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAEpE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @x-code-cli/core — Provider multi-modal capability table
|
|
2
|
+
//
|
|
3
|
+
// Declares whether each provider's API can natively accept image / pdf
|
|
4
|
+
// content parts in user messages and tool results. Used by the file-ingest
|
|
5
|
+
// pipeline (to decide inline-vs-OCR) and provider-compat (to strip binary
|
|
6
|
+
// parts before sending to providers that would reject them).
|
|
7
|
+
//
|
|
8
|
+
// Provider-level, not model-level. Some providers (alibaba, zhipu) have
|
|
9
|
+
// separate vision-only model ids — users who pick a text-only Qwen/GLM
|
|
10
|
+
// variant and paste an image will still get API errors. That's a deliberate
|
|
11
|
+
// simplification: model-level capability tracking would require per-id
|
|
12
|
+
// tables that go stale quickly.
|
|
13
|
+
const CAPS = {
|
|
14
|
+
anthropic: { image: true, pdf: true, filesApi: true },
|
|
15
|
+
openai: { image: true, pdf: true, filesApi: true },
|
|
16
|
+
google: { image: true, pdf: true, filesApi: true },
|
|
17
|
+
xai: { image: true, pdf: true, filesApi: true },
|
|
18
|
+
moonshotai: { image: true, pdf: true, filesApi: true },
|
|
19
|
+
alibaba: { image: true, pdf: true, filesApi: true },
|
|
20
|
+
zhipu: { image: true, pdf: true, filesApi: true },
|
|
21
|
+
deepseek: { image: false, pdf: false, filesApi: false },
|
|
22
|
+
// Custom OpenAI-compatible endpoints are conservative-by-default —
|
|
23
|
+
// users who know their endpoint supports vision can override via env
|
|
24
|
+
// (X_CODE_CUSTOM_SUPPORTS_IMAGE=1) if we ever add that.
|
|
25
|
+
custom: { image: false, pdf: false, filesApi: false },
|
|
26
|
+
};
|
|
27
|
+
/** Extract `provider` from a `provider:model` id. Returns `unknown` if the
|
|
28
|
+
* separator is missing (defensive — shouldn't happen with resolved ids). */
|
|
29
|
+
export function providerOf(modelId) {
|
|
30
|
+
const idx = modelId.indexOf(':');
|
|
31
|
+
return idx > 0 ? modelId.slice(0, idx) : 'unknown';
|
|
32
|
+
}
|
|
33
|
+
/** Look up capabilities for a model id. Unknown providers default to text-only
|
|
34
|
+
* — safer than assuming vision support. */
|
|
35
|
+
export function capabilitiesOf(modelId) {
|
|
36
|
+
return CAPS[providerOf(modelId)] ?? { image: false, pdf: false, filesApi: false };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/providers/capabilities.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,uEAAuE;AACvE,2EAA2E;AAC3E,0EAA0E;AAC1E,6DAA6D;AAC7D,EAAE;AACF,wEAAwE;AACxE,uEAAuE;AACvE,4EAA4E;AAC5E,uEAAuE;AACvE,gCAAgC;AAWhC,MAAM,IAAI,GAAyC;IACjD,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACrD,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACtD,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACnD,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjD,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE;IACvD,mEAAmE;IACnE,qEAAqE;IACrE,wDAAwD;IACxD,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE;CACtD,CAAA;AAED;6EAC6E;AAC7E,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACpD,CAAC;AAED;4CAC4C;AAC5C,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;AACnF,CAAC"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -14,7 +14,35 @@ export declare const toolRegistry: {
|
|
|
14
14
|
filePath: string;
|
|
15
15
|
offset?: number | undefined;
|
|
16
16
|
limit?: number | undefined;
|
|
17
|
-
}, string
|
|
17
|
+
}, string | {
|
|
18
|
+
type: string;
|
|
19
|
+
value: ({
|
|
20
|
+
type: string;
|
|
21
|
+
text: string;
|
|
22
|
+
data?: undefined;
|
|
23
|
+
mediaType?: undefined;
|
|
24
|
+
} | {
|
|
25
|
+
type: string;
|
|
26
|
+
data: string;
|
|
27
|
+
mediaType: string;
|
|
28
|
+
text?: undefined;
|
|
29
|
+
})[];
|
|
30
|
+
} | {
|
|
31
|
+
type: string;
|
|
32
|
+
value: ({
|
|
33
|
+
type: string;
|
|
34
|
+
text: string;
|
|
35
|
+
data?: undefined;
|
|
36
|
+
mediaType?: undefined;
|
|
37
|
+
filename?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
type: string;
|
|
40
|
+
data: string;
|
|
41
|
+
mediaType: string;
|
|
42
|
+
filename: string;
|
|
43
|
+
text?: undefined;
|
|
44
|
+
})[];
|
|
45
|
+
}>;
|
|
18
46
|
writeFile: import("ai").Tool<{
|
|
19
47
|
filePath: string;
|
|
20
48
|
content: string;
|
|
@@ -66,8 +94,6 @@ export declare const toolRegistry: {
|
|
|
66
94
|
}, string>;
|
|
67
95
|
};
|
|
68
96
|
export { readFile, writeFile, edit, shell, glob, grep, listDir, webSearch, webFetch, askUser, saveKnowledge, };
|
|
69
|
-
|
|
70
|
-
export
|
|
71
|
-
/** Truncate tool result, keeping head and tail */
|
|
72
|
-
export declare function truncateToolResult(result: string): string;
|
|
97
|
+
export { MAX_TOOL_RESULT_LINES, MAX_TOOL_RESULT_BYTES, MAX_AGGREGATE_TOOL_RESULT_BYTES, truncateToolResult, } from './truncate.js';
|
|
98
|
+
export type { TruncateOptions } from './truncate.js';
|
|
73
99
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYxB,CAAA;AAED,OAAO,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,SAAS,EACT,QAAQ,EACR,OAAO,EACP,aAAa,GACd,CAAA;AAED,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,+BAA+B,EAC/B,kBAAkB,GACnB,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/tools/index.js
CHANGED
|
@@ -24,14 +24,5 @@ export const toolRegistry = {
|
|
|
24
24
|
saveKnowledge,
|
|
25
25
|
};
|
|
26
26
|
export { readFile, writeFile, edit, shell, glob, grep, listDir, webSearch, webFetch, askUser, saveKnowledge, };
|
|
27
|
-
|
|
28
|
-
export const MAX_TOOL_RESULT_CHARS = 30000;
|
|
29
|
-
/** Truncate tool result, keeping head and tail */
|
|
30
|
-
export function truncateToolResult(result) {
|
|
31
|
-
if (result.length <= MAX_TOOL_RESULT_CHARS)
|
|
32
|
-
return result;
|
|
33
|
-
const half = Math.floor(MAX_TOOL_RESULT_CHARS / 2);
|
|
34
|
-
const truncatedChars = result.length - MAX_TOOL_RESULT_CHARS;
|
|
35
|
-
return result.slice(0, half) + `\n\n... [truncated ${truncatedChars} characters] ...\n\n` + result.slice(-half);
|
|
36
|
-
}
|
|
27
|
+
export { MAX_TOOL_RESULT_LINES, MAX_TOOL_RESULT_BYTES, MAX_AGGREGATE_TOOL_RESULT_BYTES, truncateToolResult, } from './truncate.js';
|
|
37
28
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,QAAQ;IACR,SAAS;IACT,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,SAAS;IACT,QAAQ;IACR,OAAO;IACP,aAAa;CACd,CAAA;AAED,OAAO,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,SAAS,EACT,QAAQ,EACR,OAAO,EACP,aAAa,GACd,CAAA;AAED,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,QAAQ;IACR,SAAS;IACT,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,SAAS;IACT,QAAQ;IACR,OAAO;IACP,aAAa;CACd,CAAA;AAED,OAAO,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,SAAS,EACT,QAAQ,EACR,OAAO,EACP,aAAa,GACd,CAAA;AAED,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,+BAA+B,EAC/B,kBAAkB,GACnB,MAAM,eAAe,CAAA"}
|
|
@@ -2,5 +2,33 @@ export declare const readFile: import("ai").Tool<{
|
|
|
2
2
|
filePath: string;
|
|
3
3
|
offset?: number | undefined;
|
|
4
4
|
limit?: number | undefined;
|
|
5
|
-
}, string
|
|
5
|
+
}, string | {
|
|
6
|
+
type: string;
|
|
7
|
+
value: ({
|
|
8
|
+
type: string;
|
|
9
|
+
text: string;
|
|
10
|
+
data?: undefined;
|
|
11
|
+
mediaType?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
type: string;
|
|
14
|
+
data: string;
|
|
15
|
+
mediaType: string;
|
|
16
|
+
text?: undefined;
|
|
17
|
+
})[];
|
|
18
|
+
} | {
|
|
19
|
+
type: string;
|
|
20
|
+
value: ({
|
|
21
|
+
type: string;
|
|
22
|
+
text: string;
|
|
23
|
+
data?: undefined;
|
|
24
|
+
mediaType?: undefined;
|
|
25
|
+
filename?: undefined;
|
|
26
|
+
} | {
|
|
27
|
+
type: string;
|
|
28
|
+
data: string;
|
|
29
|
+
mediaType: string;
|
|
30
|
+
filename: string;
|
|
31
|
+
text?: undefined;
|
|
32
|
+
})[];
|
|
33
|
+
}>;
|
|
6
34
|
//# sourceMappingURL=read-file.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-file.d.ts","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read-file.d.ts","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"AAoEA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6DnB,CAAA"}
|
package/dist/tools/read-file.js
CHANGED
|
@@ -1,25 +1,118 @@
|
|
|
1
1
|
// @x-code-cli/core — readFile tool
|
|
2
|
+
//
|
|
3
|
+
// Text files are returned as numbered-line strings (the format agents have
|
|
4
|
+
// been trained against). Binary files (images, PDFs) are returned as an
|
|
5
|
+
// AI-SDK `content` tool result so providers that accept inline media
|
|
6
|
+
// receive proper `image-data` / `file-data` parts instead of a base64 blob
|
|
7
|
+
// stuffed inside a text string.
|
|
8
|
+
//
|
|
9
|
+
// The tool itself does NOT branch on provider capability — that would
|
|
10
|
+
// couple the tool layer to the currently-active model. Instead, every
|
|
11
|
+
// binary result goes out as content parts and the provider-compat layer
|
|
12
|
+
// strips them (falling back to OCR'd text) before they reach a provider
|
|
13
|
+
// that can't handle them.
|
|
2
14
|
import fs from 'node:fs/promises';
|
|
15
|
+
import path from 'node:path';
|
|
3
16
|
import { tool } from 'ai';
|
|
4
17
|
import { z } from 'zod';
|
|
18
|
+
import { classifyFile } from '../agent/file-ingest.js';
|
|
5
19
|
import { reportProgress } from './progress.js';
|
|
20
|
+
function mediaTypeFor(filePath) {
|
|
21
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
22
|
+
if (ext === '.jpg' || ext === '.jpeg')
|
|
23
|
+
return 'image/jpeg';
|
|
24
|
+
if (ext === '.png')
|
|
25
|
+
return 'image/png';
|
|
26
|
+
if (ext === '.webp')
|
|
27
|
+
return 'image/webp';
|
|
28
|
+
if (ext === '.gif')
|
|
29
|
+
return 'image/gif';
|
|
30
|
+
if (ext === '.bmp')
|
|
31
|
+
return 'image/bmp';
|
|
32
|
+
return 'image/png';
|
|
33
|
+
}
|
|
34
|
+
/** Threshold above which a no-args readFile call returns a partial head plus a
|
|
35
|
+
* hint to re-read specific ranges. Picked empirically: 500 lines of code is
|
|
36
|
+
* a realistic ceiling for "skim the whole thing", and anything bigger is
|
|
37
|
+
* almost always used with grep first. */
|
|
38
|
+
const LARGE_FILE_LINE_THRESHOLD = 500;
|
|
39
|
+
async function readTextResult(filePath, offset, limit) {
|
|
40
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
41
|
+
const lines = content.split('\n');
|
|
42
|
+
const totalLines = lines.length;
|
|
43
|
+
// When the caller passes neither offset nor limit and the file is large,
|
|
44
|
+
// return only the head and tell the model how to request the rest. Without
|
|
45
|
+
// this guard, models happily read 2000-line files "just to see what's in
|
|
46
|
+
// there" and the full content rides along on every subsequent turn. The
|
|
47
|
+
// downstream truncator (tool-result-sanitize) would eventually clip this,
|
|
48
|
+
// but doing it at the tool level preserves intent — the model sees
|
|
49
|
+
// explicitly that the file was large and that it should narrow the range.
|
|
50
|
+
const userSpecifiedRange = offset != null || limit != null;
|
|
51
|
+
if (!userSpecifiedRange && totalLines > LARGE_FILE_LINE_THRESHOLD) {
|
|
52
|
+
const head = lines.slice(0, LARGE_FILE_LINE_THRESHOLD);
|
|
53
|
+
const body = head.map((line, i) => `${i + 1}\t${line}`).join('\n');
|
|
54
|
+
return (body +
|
|
55
|
+
`\n\n[readFile: showing first ${LARGE_FILE_LINE_THRESHOLD}/${totalLines} lines. ` +
|
|
56
|
+
`Call readFile again with offset/limit to view other ranges, or use grep to find specific symbols.]`);
|
|
57
|
+
}
|
|
58
|
+
const start = (offset ?? 1) - 1;
|
|
59
|
+
const end = limit ? start + limit : lines.length;
|
|
60
|
+
const sliced = lines.slice(start, end);
|
|
61
|
+
return sliced.map((line, i) => `${start + i + 1}\t${line}`).join('\n');
|
|
62
|
+
}
|
|
6
63
|
export const readFile = tool({
|
|
7
|
-
description: 'Read the contents of a file at the given path. Returns the
|
|
64
|
+
description: 'Read the contents of a file at the given path. Returns line-numbered text for code/docs, and inline media for images/PDFs so the model can inspect them directly.',
|
|
8
65
|
inputSchema: z.object({
|
|
9
66
|
filePath: z.string().describe('Absolute path to the file'),
|
|
10
|
-
offset: z.number().optional().describe('Start line (1-based)'),
|
|
11
|
-
limit: z.number().optional().describe('Max lines to read'),
|
|
67
|
+
offset: z.number().optional().describe('Start line (1-based, text files only)'),
|
|
68
|
+
limit: z.number().optional().describe('Max lines to read (text files only)'),
|
|
12
69
|
}),
|
|
13
70
|
execute: async ({ filePath, offset, limit }, { toolCallId }) => {
|
|
14
71
|
try {
|
|
15
72
|
reportProgress(toolCallId, `Reading ${filePath}`);
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
73
|
+
const kind = await classifyFile(filePath).catch(() => 'text');
|
|
74
|
+
if (kind === 'image') {
|
|
75
|
+
const buffer = await fs.readFile(filePath);
|
|
76
|
+
// Content tool result: the provider-compat sanitizer decides whether
|
|
77
|
+
// this image survives to the model (multimodal) or gets replaced
|
|
78
|
+
// with an OCR text block (DeepSeek etc.). We attach both an
|
|
79
|
+
// `image-data` part (for providers that can see it) and a trailing
|
|
80
|
+
// text part with the file path (so the model always has a textual
|
|
81
|
+
// anchor to reference).
|
|
82
|
+
return {
|
|
83
|
+
type: 'content',
|
|
84
|
+
value: [
|
|
85
|
+
{ type: 'text', text: `Loaded image: ${filePath}` },
|
|
86
|
+
{
|
|
87
|
+
type: 'image-data',
|
|
88
|
+
data: buffer.toString('base64'),
|
|
89
|
+
mediaType: mediaTypeFor(filePath),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (kind === 'pdf') {
|
|
95
|
+
const buffer = await fs.readFile(filePath);
|
|
96
|
+
return {
|
|
97
|
+
type: 'content',
|
|
98
|
+
value: [
|
|
99
|
+
{ type: 'text', text: `Loaded PDF: ${filePath}` },
|
|
100
|
+
{
|
|
101
|
+
type: 'file-data',
|
|
102
|
+
data: buffer.toString('base64'),
|
|
103
|
+
mediaType: 'application/pdf',
|
|
104
|
+
filename: path.basename(filePath),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Text / Office / unknown → read as text.
|
|
110
|
+
// (Office files are handled up-front by buildUserContent when the user
|
|
111
|
+
// attaches them via @path; if a model calls readFile on a .docx anyway,
|
|
112
|
+
// we fall through to a UTF-8 read which returns gibberish — a follow-up
|
|
113
|
+
// could route Office here too, but it's a rare path worth keeping
|
|
114
|
+
// simple for now.)
|
|
115
|
+
return await readTextResult(filePath, offset, limit);
|
|
23
116
|
}
|
|
24
117
|
catch (err) {
|
|
25
118
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-file.js","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,OAAO,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"read-file.js","sourceRoot":"","sources":["../../src/tools/read-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ResultPromise } from 'execa';
|
|
2
|
+
export type ShellType = 'bash' | 'zsh' | 'powershell';
|
|
3
|
+
export interface ShellSpawnOptions {
|
|
4
|
+
timeout: number;
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ShellProvider {
|
|
9
|
+
type: ShellType;
|
|
10
|
+
spawn(command: string, opts: ShellSpawnOptions): ResultPromise;
|
|
11
|
+
}
|
|
12
|
+
export declare function getShellProvider(): ShellProvider;
|
|
13
|
+
//# sourceMappingURL=shell-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-provider.d.ts","sourceRoot":"","sources":["../../src/tools/shell-provider.ts"],"names":[],"mappings":"AAMA,OAAO,EAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAA;AAGjD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,CAAA;AAErD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAA;CAC/D;AA6DD,wBAAgB,gBAAgB,IAAI,aAAa,CAYhD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// @x-code-cli/core — Cross-platform shell provider abstraction.
|
|
2
|
+
//
|
|
3
|
+
// Each shell (bash/zsh, PowerShell) spawns its own child process with its own
|
|
4
|
+
// quoting/encoding quirks. Keeping those quirks behind a provider interface
|
|
5
|
+
// means the tool-execution layer does not need platform branches and does not
|
|
6
|
+
// hand-roll quote escapes for PowerShell.
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
function createPosixProvider(executable, type) {
|
|
10
|
+
return {
|
|
11
|
+
type,
|
|
12
|
+
spawn(command, opts) {
|
|
13
|
+
return execa(executable, ['-c', command], {
|
|
14
|
+
timeout: opts.timeout,
|
|
15
|
+
cwd: opts.cwd,
|
|
16
|
+
reject: false,
|
|
17
|
+
env: { ...(opts.env ?? process.env), PYTHONIOENCODING: 'utf-8' },
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// PowerShell's -EncodedCommand accepts a base64 UTF-16LE payload. The char set
|
|
23
|
+
// is [A-Za-z0-9+/=] which survives any outer quoting layer (cmd.exe, Node's
|
|
24
|
+
// Windows argv-to-string serializer, etc.), so we never need to escape quotes
|
|
25
|
+
// in the user's command.
|
|
26
|
+
function encodePowerShellCommand(psCommand) {
|
|
27
|
+
return Buffer.from(psCommand, 'utf16le').toString('base64');
|
|
28
|
+
}
|
|
29
|
+
function createPowerShellProvider(executable) {
|
|
30
|
+
return {
|
|
31
|
+
type: 'powershell',
|
|
32
|
+
spawn(command, opts) {
|
|
33
|
+
// Prefix/suffix run inside the same -EncodedCommand payload:
|
|
34
|
+
// • OutputEncoding = UTF-8 — PS 5.1 on zh-CN Windows otherwise writes
|
|
35
|
+
// output in GBK (mojibake when we decode as UTF-8). Avoids the
|
|
36
|
+
// `chcp 65001 >nul && ...` cmd.exe wrapper.
|
|
37
|
+
// • ProgressPreference = SilentlyContinue — first-run module loads
|
|
38
|
+
// emit CLIXML progress records on stderr, which would surface as
|
|
39
|
+
// noise in tool output.
|
|
40
|
+
// • trailing `exit` — PowerShell does NOT propagate $LASTEXITCODE
|
|
41
|
+
// to its own process exit code. Without this, `git push` failing
|
|
42
|
+
// with exit 1 or `tsc` failing with exit 2 all come back as exit 0
|
|
43
|
+
// or a generic 1, losing the signal. Prefer $LASTEXITCODE when a
|
|
44
|
+
// native exe ran; fall back to $? for cmdlet-only pipelines.
|
|
45
|
+
const wrapped = [
|
|
46
|
+
'[Console]::OutputEncoding = [System.Text.Encoding]::UTF8',
|
|
47
|
+
"$ProgressPreference = 'SilentlyContinue'",
|
|
48
|
+
command,
|
|
49
|
+
'$__ec = if ($null -ne $LASTEXITCODE) { $LASTEXITCODE } elseif ($?) { 0 } else { 1 }',
|
|
50
|
+
'exit $__ec',
|
|
51
|
+
].join('\n');
|
|
52
|
+
return execa(executable, ['-NoProfile', '-NonInteractive', '-EncodedCommand', encodePowerShellCommand(wrapped)], {
|
|
53
|
+
timeout: opts.timeout,
|
|
54
|
+
cwd: opts.cwd,
|
|
55
|
+
reject: false,
|
|
56
|
+
env: { ...(opts.env ?? process.env), PYTHONIOENCODING: 'utf-8' },
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function getShellProvider() {
|
|
62
|
+
if (os.platform() === 'win32') {
|
|
63
|
+
// Git Bash / MSYS2 / Cygwin set SHELL to a Unix-style path. Prefer that
|
|
64
|
+
// when present so the Unix tool ecosystem works as expected.
|
|
65
|
+
const shell = process.env.SHELL;
|
|
66
|
+
if (shell && /\b(bash|zsh)$/i.test(shell)) {
|
|
67
|
+
return createPosixProvider(shell, shell.endsWith('zsh') ? 'zsh' : 'bash');
|
|
68
|
+
}
|
|
69
|
+
return createPowerShellProvider('powershell.exe');
|
|
70
|
+
}
|
|
71
|
+
const userShell = process.env.SHELL ?? '/bin/bash';
|
|
72
|
+
return createPosixProvider(userShell, userShell.endsWith('zsh') ? 'zsh' : 'bash');
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=shell-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-provider.js","sourceRoot":"","sources":["../../src/tools/shell-provider.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,0CAA0C;AAC1C,OAAO,EAAE,KAAK,EAAsB,MAAM,OAAO,CAAA;AACjD,OAAO,EAAE,MAAM,SAAS,CAAA;AAexB,SAAS,mBAAmB,CAAC,UAAkB,EAAE,IAAoB;IACnE,OAAO;QACL,IAAI;QACJ,KAAK,CAAC,OAAO,EAAE,IAAI;YACjB,OAAO,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;gBACxC,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,MAAM,EAAE,KAAK;gBACb,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE;aACjE,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,yBAAyB;AACzB,SAAS,uBAAuB,CAAC,SAAiB;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAC7D,CAAC;AAED,SAAS,wBAAwB,CAAC,UAAkB;IAClD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,KAAK,CAAC,OAAO,EAAE,IAAI;YACjB,6DAA6D;YAC7D,wEAAwE;YACxE,mEAAmE;YACnE,gDAAgD;YAChD,qEAAqE;YACrE,qEAAqE;YACrE,4BAA4B;YAC5B,oEAAoE;YACpE,qEAAqE;YACrE,uEAAuE;YACvE,qEAAqE;YACrE,iEAAiE;YACjE,MAAM,OAAO,GAAG;gBACd,0DAA0D;gBAC1D,0CAA0C;gBAC1C,OAAO;gBACP,qFAAqF;gBACrF,YAAY;aACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACZ,OAAO,KAAK,CACV,UAAU,EACV,CAAC,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,OAAO,CAAC,CAAC,EACtF;gBACE,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,MAAM,EAAE,KAAK;gBACb,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,gBAAgB,EAAE,OAAO,EAAE;aACjE,CACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC9B,wEAAwE;QACxE,6DAA6D;QAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA;QAC/B,IAAI,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,OAAO,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC3E,CAAC;QACD,OAAO,wBAAwB,CAAC,gBAAgB,CAAC,CAAA;IACnD,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAA;IAClD,OAAO,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AACnF,CAAC"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
export type ShellType
|
|
2
|
-
export interface ShellConfig {
|
|
3
|
-
executable: string;
|
|
4
|
-
args: string[];
|
|
5
|
-
type: ShellType;
|
|
6
|
-
}
|
|
7
|
-
export declare function getShellConfig(): ShellConfig;
|
|
1
|
+
export type { ShellType } from './shell-provider.js';
|
|
8
2
|
/** Split compound shell commands by pipe/chain operators for permission checking */
|
|
9
3
|
export declare function splitShellCommands(cmd: string): string[];
|
|
10
4
|
/** Check if a sub-command is read-only (safe to auto-allow) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-utils.d.ts","sourceRoot":"","sources":["../../src/tools/shell-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shell-utils.d.ts","sourceRoot":"","sources":["../../src/tools/shell-utils.ts"],"names":[],"mappings":"AAKA,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEpD,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CA0CxD;AAkDD,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGlD"}
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
// @x-code-cli/core — Cross-platform shell detection and abstraction
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
export function getShellConfig() {
|
|
4
|
-
if (os.platform() === 'win32') {
|
|
5
|
-
// Git Bash / MSYS2 / Cygwin set SHELL to a Unix-style path (e.g. /usr/bin/bash).
|
|
6
|
-
// Prefer that shell when available so the Unix tool ecosystem works as expected.
|
|
7
|
-
const shell = process.env.SHELL;
|
|
8
|
-
if (shell && /\b(bash|zsh)$/i.test(shell)) {
|
|
9
|
-
const type = shell.endsWith('zsh') ? 'zsh' : 'bash';
|
|
10
|
-
return { executable: shell, args: ['-c'], type };
|
|
11
|
-
}
|
|
12
|
-
return { executable: 'powershell.exe', args: ['-NoProfile', '-Command'], type: 'powershell' };
|
|
13
|
-
}
|
|
14
|
-
const userShell = process.env.SHELL ?? '/bin/bash';
|
|
15
|
-
const type = userShell.endsWith('zsh') ? 'zsh' : 'bash';
|
|
16
|
-
return { executable: userShell, args: ['-c'], type };
|
|
17
|
-
}
|
|
18
1
|
/** Split compound shell commands by pipe/chain operators for permission checking */
|
|
19
2
|
export function splitShellCommands(cmd) {
|
|
20
3
|
// Split by |, &&, ;, || — but not inside quotes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-utils.js","sourceRoot":"","sources":["../../src/tools/shell-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shell-utils.js","sourceRoot":"","sources":["../../src/tools/shell-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Default per-result line cap. Above this we keep a head/tail slice. */
|
|
2
|
+
export declare const MAX_TOOL_RESULT_LINES = 2000;
|
|
3
|
+
/** Default per-result byte cap (UTF-8). Covers both ASCII single-line
|
|
4
|
+
* minified dumps and non-ASCII content where a modest char count still adds
|
|
5
|
+
* up to a lot of wire bytes. */
|
|
6
|
+
export declare const MAX_TOOL_RESULT_BYTES: number;
|
|
7
|
+
/** Head:tail ratio when slicing. 0.2 keeps the first 20% + last 80%. */
|
|
8
|
+
export declare const DEFAULT_HEAD_RATIO = 0.2;
|
|
9
|
+
/** Per-turn aggregate cap across all tool results in one assistant message.
|
|
10
|
+
* Not enforced yet — tracked via agent loop state for future telemetry and
|
|
11
|
+
* eventual reactive compaction (mirrors claude-code's 200k-char ceiling). */
|
|
12
|
+
export declare const MAX_AGGREGATE_TOOL_RESULT_BYTES: number;
|
|
13
|
+
export interface TruncateOptions {
|
|
14
|
+
/** Max lines before truncation kicks in. Default {@link MAX_TOOL_RESULT_LINES}. */
|
|
15
|
+
maxLines?: number;
|
|
16
|
+
/** Max bytes (UTF-8). Default {@link MAX_TOOL_RESULT_BYTES}. */
|
|
17
|
+
maxBytes?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Where to keep content when truncating:
|
|
20
|
+
* - `head-tail` (default): keep head 20% + tail 80%, drop middle.
|
|
21
|
+
* - `head`: keep first N bytes only, drop tail. Good for streamed shell
|
|
22
|
+
* output where the tail repeats noise (prompt, exit code).
|
|
23
|
+
* - `tail`: keep last N bytes only, drop head. Good for logs where the
|
|
24
|
+
* interesting part is the most recent.
|
|
25
|
+
*/
|
|
26
|
+
direction?: 'head-tail' | 'head' | 'tail';
|
|
27
|
+
/** Head ratio in head-tail mode. Default {@link DEFAULT_HEAD_RATIO}. */
|
|
28
|
+
headRatio?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Truncate tool output to the line / byte budget. Returns the input unchanged
|
|
32
|
+
* if it fits both. Adds a one-line marker so the model can tell intentional
|
|
33
|
+
* omission from corrupted output.
|
|
34
|
+
*/
|
|
35
|
+
export declare function truncateToolResult(result: string, options?: TruncateOptions): string;
|
|
36
|
+
//# sourceMappingURL=truncate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../src/tools/truncate.ts"],"names":[],"mappings":"AAeA,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,OAAO,CAAA;AAEzC;;iCAEiC;AACjC,eAAO,MAAM,qBAAqB,QAAY,CAAA;AAE9C,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC;;8EAE8E;AAC9E,eAAO,MAAM,+BAA+B,QAAa,CAAA;AAEzD,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAAA;IACzC,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA6ED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,MAAM,CAgCxF"}
|