@kolisachint/hoocode-agent 0.5.49 → 0.5.51
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 +20 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-frontmatter.d.ts +5 -0
- package/dist/core/agent-frontmatter.d.ts.map +1 -1
- package/dist/core/agent-frontmatter.js +10 -7
- package/dist/core/agent-frontmatter.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.js +2 -22
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
- package/dist/core/extensions/plugins/authoring.js +1 -1
- package/dist/core/extensions/plugins/authoring.js.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.js +1 -1
- package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/types.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -33
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +0 -9
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/external-tools.d.ts +3 -3
- package/dist/core/external-tools.d.ts.map +1 -1
- package/dist/core/external-tools.js +5 -5
- package/dist/core/external-tools.js.map +1 -1
- package/dist/core/light.d.ts +2 -2
- package/dist/core/light.d.ts.map +1 -1
- package/dist/core/light.js +2 -2
- package/dist/core/light.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/self-docs.d.ts +1 -1
- package/dist/core/self-docs.d.ts.map +1 -1
- package/dist/core/self-docs.js +1 -1
- package/dist/core/self-docs.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +9 -26
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +326 -101
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/fd-utils.d.ts +3 -17
- package/dist/core/tools/fd-utils.d.ts.map +1 -1
- package/dist/core/tools/fd-utils.js +3 -38
- package/dist/core/tools/fd-utils.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -12
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +2 -11
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/native-search.d.ts +0 -15
- package/dist/core/tools/native-search.d.ts.map +1 -1
- package/dist/core/tools/native-search.js +0 -87
- package/dist/core/tools/native-search.js.map +1 -1
- package/dist/core/tools/propose-plugin.d.ts.map +1 -1
- package/dist/core/tools/propose-plugin.js +1 -1
- package/dist/core/tools/propose-plugin.js.map +1 -1
- package/dist/core/tools/read-dedup.d.ts +14 -1
- package/dist/core/tools/read-dedup.d.ts.map +1 -1
- package/dist/core/tools/read-dedup.js +53 -1
- package/dist/core/tools/read-dedup.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +17 -5
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/search.d.ts +3 -2
- package/dist/core/tools/search.d.ts.map +1 -1
- package/dist/core/tools/search.js +7 -6
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +1 -1
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/warm-subagent-pool.d.ts.map +1 -1
- package/dist/core/warm-subagent-pool.js +1 -1
- package/dist/core/warm-subagent-pool.js.map +1 -1
- package/dist/extensions/core/permission-gate.d.ts.map +1 -1
- package/dist/extensions/core/permission-gate.js +23 -5
- package/dist/extensions/core/permission-gate.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/init-templates.generated.d.ts.map +1 -1
- package/dist/init-templates.generated.js +10 -10
- package/dist/init-templates.generated.js.map +1 -1
- package/dist/modes/interactive/components/tool-chain-summary.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-chain-summary.js +1 -1
- package/dist/modes/interactive/components/tool-chain-summary.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +4 -13
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/extensions.md +2 -4
- package/docs/modes.md +1 -1
- package/docs/quickstart.md +1 -1
- package/docs/sdk.md +8 -10
- package/docs/settings.md +2 -2
- package/docs/usage.md +3 -3
- package/examples/agents/fork-reviewer.md +1 -1
- package/examples/agents/orchestrator.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/minimal-mode.ts +1 -188
- package/examples/extensions/plan-mode/README.md +1 -1
- package/examples/extensions/plan-mode/index.ts +2 -2
- package/examples/extensions/preset.ts +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/truncated-tool.ts +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/05-tools.ts +3 -3
- package/package.json +4 -4
- package/templates/agents/code-review.md +1 -1
- package/templates/agents/explore.md +2 -2
- package/templates/agents/general-purpose.md +1 -1
- package/templates/agents/plan.md +2 -2
- package/templates/agents/security-review.md +1 -1
- package/templates/modes/ask/system.md +1 -1
- package/templates/modes/debug/system.md +1 -1
- package/templates/skills/artifact-design/SKILL.md +1 -1
- package/templates/skills/canvas-design/SKILL.md +1 -1
- package/templates/skills/plugin-authoring/SKILL.md +1 -1
- package/dist/core/tools/find.d.ts +0 -40
- package/dist/core/tools/find.d.ts.map +0 -1
- package/dist/core/tools/find.js +0 -364
- package/dist/core/tools/find.js.map +0 -1
- package/dist/core/tools/grep.d.ts +0 -37
- package/dist/core/tools/grep.d.ts.map +0 -1
- package/dist/core/tools/grep.js +0 -414
- package/dist/core/tools/grep.js.map +0 -1
- package/dist/core/tools/ls.d.ts +0 -49
- package/dist/core/tools/ls.d.ts.map +0 -1
- package/dist/core/tools/ls.js +0 -211
- package/dist/core/tools/ls.js.map +0 -1
package/dist/core/tools/ls.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { Text } from "@kolisachint/hoocode-tui";
|
|
2
|
-
import { existsSync, readdirSync, statSync } from "fs";
|
|
3
|
-
import { readdir as fsReaddir } from "fs/promises";
|
|
4
|
-
import { minimatch } from "minimatch";
|
|
5
|
-
import nodePath from "path";
|
|
6
|
-
import { Type } from "typebox";
|
|
7
|
-
import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
|
|
8
|
-
import { resolveToCwd } from "./path-utils.js";
|
|
9
|
-
import { getTextOutput, invalidArgText, shortenPath, str } from "./render-utils.js";
|
|
10
|
-
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
11
|
-
import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
|
|
12
|
-
const lsSchema = Type.Object({
|
|
13
|
-
path: Type.Optional(Type.String({ description: "Directory to list (default: current directory)" })),
|
|
14
|
-
limit: Type.Optional(Type.Number({ description: "Maximum number of entries to return (default: 500)" })),
|
|
15
|
-
ignore: Type.Optional(Type.Array(Type.String(), {
|
|
16
|
-
description: "Globs matched against entry names to exclude, e.g. ['node_modules', '*.log'].",
|
|
17
|
-
})),
|
|
18
|
-
});
|
|
19
|
-
const DEFAULT_LIMIT = 500;
|
|
20
|
-
const defaultLsOperations = {
|
|
21
|
-
exists: existsSync,
|
|
22
|
-
stat: statSync,
|
|
23
|
-
readdir: readdirSync,
|
|
24
|
-
readdirEntries: (p) => fsReaddir(p, { withFileTypes: true }),
|
|
25
|
-
};
|
|
26
|
-
function formatLsCall(args, theme) {
|
|
27
|
-
const rawPath = str(args?.path);
|
|
28
|
-
const path = rawPath !== null ? shortenPath(rawPath || ".") : null;
|
|
29
|
-
const limit = args?.limit;
|
|
30
|
-
const invalidArg = invalidArgText(theme);
|
|
31
|
-
let text = `${theme.fg("toolTitle", theme.bold("ls"))} ${path === null ? invalidArg : theme.fg("accent", path)}`;
|
|
32
|
-
if (limit !== undefined) {
|
|
33
|
-
text += theme.fg("toolOutput", ` (limit ${limit})`);
|
|
34
|
-
}
|
|
35
|
-
return text;
|
|
36
|
-
}
|
|
37
|
-
function formatLsResult(result, options, theme, showImages) {
|
|
38
|
-
const output = getTextOutput(result, showImages).trim();
|
|
39
|
-
let text = "";
|
|
40
|
-
if (output) {
|
|
41
|
-
const lines = output.split("\n");
|
|
42
|
-
const maxLines = options.expanded ? lines.length : 20;
|
|
43
|
-
const displayLines = lines.slice(0, maxLines);
|
|
44
|
-
const remaining = lines.length - maxLines;
|
|
45
|
-
text += `\n${displayLines.map((line) => theme.fg("toolOutput", line)).join("\n")}`;
|
|
46
|
-
if (remaining > 0) {
|
|
47
|
-
text += `${theme.fg("muted", `\n... (${remaining} more lines,`)} ${keyHint("app.tools.expand", "to expand")})`;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
const entryLimit = result.details?.entryLimitReached;
|
|
51
|
-
const truncation = result.details?.truncation;
|
|
52
|
-
if (entryLimit || truncation?.truncated) {
|
|
53
|
-
const warnings = [];
|
|
54
|
-
if (entryLimit)
|
|
55
|
-
warnings.push(`${entryLimit} entries limit`);
|
|
56
|
-
if (truncation?.truncated)
|
|
57
|
-
warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);
|
|
58
|
-
text += `\n${theme.fg("warning", `[Truncated: ${warnings.join(", ")}]`)}`;
|
|
59
|
-
}
|
|
60
|
-
return text;
|
|
61
|
-
}
|
|
62
|
-
export function createLsToolDefinition(cwd, options) {
|
|
63
|
-
const ops = options?.operations ?? defaultLsOperations;
|
|
64
|
-
return {
|
|
65
|
-
name: "ls",
|
|
66
|
-
label: "ls",
|
|
67
|
-
description: `List one directory (not recursive), sorted alphabetically, '/' suffix for directories. Shows everything on disk including dotfiles and ignored paths; pass 'ignore' globs to skip entries. Truncates at ${DEFAULT_LIMIT} entries / ${DEFAULT_MAX_BYTES / 1024}KB.`,
|
|
68
|
-
promptSnippet: "List directory contents",
|
|
69
|
-
parameters: lsSchema,
|
|
70
|
-
async execute(_toolCallId, { path, limit, ignore }, signal, _onUpdate, _ctx) {
|
|
71
|
-
return new Promise((resolve, reject) => {
|
|
72
|
-
if (signal?.aborted) {
|
|
73
|
-
reject(new Error("Operation aborted"));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const onAbort = () => reject(new Error("Operation aborted"));
|
|
77
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
78
|
-
(async () => {
|
|
79
|
-
try {
|
|
80
|
-
const dirPath = resolveToCwd(path || ".", cwd);
|
|
81
|
-
const effectiveLimit = limit ?? DEFAULT_LIMIT;
|
|
82
|
-
// Check if path exists.
|
|
83
|
-
if (!(await ops.exists(dirPath))) {
|
|
84
|
-
reject(new Error(`Path not found: ${dirPath}`));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
// Check if path is a directory.
|
|
88
|
-
const stat = await ops.stat(dirPath);
|
|
89
|
-
if (!stat.isDirectory()) {
|
|
90
|
-
reject(new Error(`Not a directory: ${dirPath}`));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
// Exclude entries matching any ignore glob. Match on the bare entry
|
|
94
|
-
// name (ls is non-recursive) with dot:true so patterns can target
|
|
95
|
-
// dotfiles like '.git'. Default behavior (no patterns) still shows
|
|
96
|
-
// everything on disk.
|
|
97
|
-
const ignorePatterns = (ignore ?? []).filter((p) => typeof p === "string" && p.length > 0);
|
|
98
|
-
// Fast path: use readdirEntries (single syscall with type info).
|
|
99
|
-
// Slow path: fall back to readdir + per-entry stat.
|
|
100
|
-
const results = [];
|
|
101
|
-
let entryLimitReached = false;
|
|
102
|
-
if (ops.readdirEntries) {
|
|
103
|
-
let dirents;
|
|
104
|
-
try {
|
|
105
|
-
dirents = await ops.readdirEntries(dirPath);
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
reject(new Error(`Cannot read directory: ${dirPath}`));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
let filtered = dirents;
|
|
112
|
-
if (ignorePatterns.length > 0) {
|
|
113
|
-
filtered = dirents.filter((d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: true })));
|
|
114
|
-
}
|
|
115
|
-
filtered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
|
|
116
|
-
for (const entry of filtered) {
|
|
117
|
-
if (results.length >= effectiveLimit) {
|
|
118
|
-
entryLimitReached = true;
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
results.push(entry.name + (entry.isDirectory() ? "/" : ""));
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Fallback: readdir returns strings, stat each entry.
|
|
126
|
-
let entries;
|
|
127
|
-
try {
|
|
128
|
-
entries = await ops.readdir(dirPath);
|
|
129
|
-
}
|
|
130
|
-
catch (e) {
|
|
131
|
-
if (e instanceof Error) {
|
|
132
|
-
reject(new Error(`Cannot read directory: ${e.message}`));
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
reject(new Error(`Cannot read directory: ${String(e)}`));
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
const ignoreFiltered = ignorePatterns.length > 0
|
|
140
|
-
? entries.filter((entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })))
|
|
141
|
-
: entries;
|
|
142
|
-
ignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
143
|
-
for (const entry of ignoreFiltered) {
|
|
144
|
-
if (results.length >= effectiveLimit) {
|
|
145
|
-
entryLimitReached = true;
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
const fullPath = nodePath.join(dirPath, entry);
|
|
149
|
-
let suffix = "";
|
|
150
|
-
try {
|
|
151
|
-
const entryStat = await ops.stat(fullPath);
|
|
152
|
-
if (entryStat.isDirectory())
|
|
153
|
-
suffix = "/";
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
results.push(entry + suffix);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
signal?.removeEventListener("abort", onAbort);
|
|
162
|
-
if (results.length === 0) {
|
|
163
|
-
resolve({ content: [{ type: "text", text: "(empty directory)" }], details: undefined });
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const rawOutput = results.join("\n");
|
|
167
|
-
// Apply byte truncation. There is no separate line limit because entry count is already capped.
|
|
168
|
-
const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
169
|
-
let output = truncation.content;
|
|
170
|
-
const details = {};
|
|
171
|
-
// Build actionable notices for truncation and entry limits.
|
|
172
|
-
const notices = [];
|
|
173
|
-
if (entryLimitReached) {
|
|
174
|
-
notices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);
|
|
175
|
-
details.entryLimitReached = effectiveLimit;
|
|
176
|
-
}
|
|
177
|
-
if (truncation.truncated) {
|
|
178
|
-
notices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);
|
|
179
|
-
details.truncation = truncation;
|
|
180
|
-
}
|
|
181
|
-
if (notices.length > 0) {
|
|
182
|
-
output += `\n\n[${notices.join(". ")}]`;
|
|
183
|
-
}
|
|
184
|
-
resolve({
|
|
185
|
-
content: [{ type: "text", text: output }],
|
|
186
|
-
details: Object.keys(details).length > 0 ? details : undefined,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
catch (e) {
|
|
190
|
-
signal?.removeEventListener("abort", onAbort);
|
|
191
|
-
reject(e);
|
|
192
|
-
}
|
|
193
|
-
})();
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
renderCall(args, theme, context) {
|
|
197
|
-
const text = context.lastComponent ?? new Text("", 0, 0);
|
|
198
|
-
text.setText(formatLsCall(args, theme));
|
|
199
|
-
return text;
|
|
200
|
-
},
|
|
201
|
-
renderResult(result, options, theme, context) {
|
|
202
|
-
const text = context.lastComponent ?? new Text("", 0, 0);
|
|
203
|
-
text.setText(formatLsResult(result, options, theme, context.showImages));
|
|
204
|
-
return text;
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
export function createLsTool(cwd, options) {
|
|
209
|
-
return wrapToolDefinition(createLsToolDefinition(cwd, options));
|
|
210
|
-
}
|
|
211
|
-
//# sourceMappingURL=ls.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/core/tools/ls.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { readdir as fsReaddir } from \"fs/promises\";\nimport { minimatch } from \"minimatch\";\nimport nodePath from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.js\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.js\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.js\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\n\nconst lsSchema = Type.Object({\n\tpath: Type.Optional(Type.String({ description: \"Directory to list (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of entries to return (default: 500)\" })),\n\tignore: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Globs matched against entry names to exclude, e.g. ['node_modules', '*.log'].\",\n\t\t}),\n\t),\n});\n\nexport type LsToolInput = Static<typeof lsSchema>;\n\nconst DEFAULT_LIMIT = 500;\n\nexport interface LsToolDetails {\n\ttruncation?: TruncationResult;\n\tentryLimitReached?: number;\n}\n\n/**\n * Pluggable operations for the ls tool.\n * Override these to delegate directory listing to remote systems (for example SSH).\n */\nexport interface LsOperations {\n\t/** Check if path exists */\n\texists: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Get file or directory stats. Throws if not found. */\n\tstat: (absolutePath: string) => Promise<{ isDirectory: () => boolean }> | { isDirectory: () => boolean };\n\t/** Read directory entries as strings (used when readdirEntries is not provided) */\n\treaddir: (absolutePath: string) => Promise<string[]> | string[];\n\t/**\n\t * Optional: read directory entries with type info in a single syscall.\n\t * When provided, eliminates per-entry stat() calls for the isDirectory check.\n\t */\n\treaddirEntries?: (\n\t\tabsolutePath: string,\n\t) =>\n\t\t| Promise<Array<{ name: string; isDirectory: () => boolean }>>\n\t\t| Array<{ name: string; isDirectory: () => boolean }>;\n}\n\nconst defaultLsOperations: LsOperations = {\n\texists: existsSync,\n\tstat: statSync,\n\treaddir: readdirSync,\n\treaddirEntries: (p) => fsReaddir(p, { withFileTypes: true }),\n};\n\nexport interface LsToolOptions {\n\t/** Custom operations for directory listing. Default: local filesystem */\n\toperations?: LsOperations;\n}\n\nfunction formatLsCall(\n\targs: { path?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n): string {\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${path === null ? invalidArg : theme.fg(\"accent\", path)}`;\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatLsResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: LsToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.js\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst entryLimit = result.details?.entryLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (entryLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (entryLimit) warnings.push(`${entryLimit} entries limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nexport function createLsToolDefinition(\n\tcwd: string,\n\toptions?: LsToolOptions,\n): ToolDefinition<typeof lsSchema, LsToolDetails | undefined> {\n\tconst ops = options?.operations ?? defaultLsOperations;\n\treturn {\n\t\tname: \"ls\",\n\t\tlabel: \"ls\",\n\t\tdescription: `List one directory (not recursive), sorted alphabetically, '/' suffix for directories. Shows everything on disk including dotfiles and ignored paths; pass 'ignore' globs to skip entries. Truncates at ${DEFAULT_LIMIT} entries / ${DEFAULT_MAX_BYTES / 1024}KB.`,\n\t\tpromptSnippet: \"List directory contents\",\n\t\tparameters: lsSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, limit, ignore }: { path?: string; limit?: number; ignore?: string[] },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst onAbort = () => reject(new Error(\"Operation aborted\"));\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst dirPath = resolveToCwd(path || \".\", cwd);\n\t\t\t\t\t\tconst effectiveLimit = limit ?? DEFAULT_LIMIT;\n\n\t\t\t\t\t\t// Check if path exists.\n\t\t\t\t\t\tif (!(await ops.exists(dirPath))) {\n\t\t\t\t\t\t\treject(new Error(`Path not found: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if path is a directory.\n\t\t\t\t\t\tconst stat = await ops.stat(dirPath);\n\t\t\t\t\t\tif (!stat.isDirectory()) {\n\t\t\t\t\t\t\treject(new Error(`Not a directory: ${dirPath}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Exclude entries matching any ignore glob. Match on the bare entry\n\t\t\t\t\t\t// name (ls is non-recursive) with dot:true so patterns can target\n\t\t\t\t\t\t// dotfiles like '.git'. Default behavior (no patterns) still shows\n\t\t\t\t\t\t// everything on disk.\n\t\t\t\t\t\tconst ignorePatterns = (ignore ?? []).filter((p) => typeof p === \"string\" && p.length > 0);\n\n\t\t\t\t\t\t// Fast path: use readdirEntries (single syscall with type info).\n\t\t\t\t\t\t// Slow path: fall back to readdir + per-entry stat.\n\t\t\t\t\t\tconst results: string[] = [];\n\t\t\t\t\t\tlet entryLimitReached = false;\n\n\t\t\t\t\t\tif (ops.readdirEntries) {\n\t\t\t\t\t\t\tlet dirents: Array<{ name: string; isDirectory: () => boolean }>;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tdirents = await ops.readdirEntries(dirPath);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${dirPath}`));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlet filtered = dirents;\n\t\t\t\t\t\t\tif (ignorePatterns.length > 0) {\n\t\t\t\t\t\t\t\tfiltered = dirents.filter(\n\t\t\t\t\t\t\t\t\t(d) => !ignorePatterns.some((pattern) => minimatch(d.name, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfiltered.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of filtered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry.name + (entry.isDirectory() ? \"/\" : \"\"));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Fallback: readdir returns strings, stat each entry.\n\t\t\t\t\t\t\tlet entries: string[];\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tentries = await ops.readdir(dirPath);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tif (e instanceof Error) {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${e.message}`));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treject(new Error(`Cannot read directory: ${String(e)}`));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst ignoreFiltered =\n\t\t\t\t\t\t\t\tignorePatterns.length > 0\n\t\t\t\t\t\t\t\t\t? entries.filter(\n\t\t\t\t\t\t\t\t\t\t\t(entry) => !ignorePatterns.some((pattern) => minimatch(entry, pattern, { dot: true })),\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t: entries;\n\t\t\t\t\t\t\tignoreFiltered.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\t\t\t\tfor (const entry of ignoreFiltered) {\n\t\t\t\t\t\t\t\tif (results.length >= effectiveLimit) {\n\t\t\t\t\t\t\t\t\tentryLimitReached = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst fullPath = nodePath.join(dirPath, entry);\n\t\t\t\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst entryStat = await ops.stat(fullPath);\n\t\t\t\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\n\t\t\t\t\t\tif (results.length === 0) {\n\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"(empty directory)\" }], details: undefined });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = results.join(\"\\n\");\n\t\t\t\t\t\t// Apply byte truncation. There is no separate line limit because entry count is already capped.\n\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\tconst details: LsToolDetails = {};\n\t\t\t\t\t\t// Build actionable notices for truncation and entry limits.\n\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\tif (entryLimitReached) {\n\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} entries limit reached. Use limit=${effectiveLimit * 2} for more`);\n\t\t\t\t\t\t\tdetails.entryLimitReached = effectiveLimit;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (notices.length > 0) {\n\t\t\t\t\t\t\toutput += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\treject(e);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatLsResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createLsTool(cwd: string, options?: LsToolOptions): AgentTool<typeof lsSchema> {\n\treturn wrapToolDefinition(createLsToolDefinition(cwd, options));\n}\n"]}
|