jinzd-ai-cli 0.4.14 → 0.4.16
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/{chunk-ROMSAKP6.js → chunk-2OKRGXVU.js} +21 -50
- package/dist/{chunk-WIWNSN7U.js → chunk-DMM3XL26.js} +130 -58
- package/dist/{chunk-244SVJXW.js → chunk-KOD3C2CU.js} +1 -1
- package/dist/{chunk-QW2UGW6D.js → chunk-SNUHVNSD.js} +1 -1
- package/dist/{hub-QZXQ6JYS.js → hub-2MUUWFAZ.js} +1 -1
- package/dist/index.js +22 -8
- package/dist/{run-tests-YU52BWHE.js → run-tests-H7IVHUZO.js} +1 -1
- package/dist/{run-tests-QDMBYWZA.js → run-tests-VB4UVV6Q.js} +1 -1
- package/dist/{server-KVHJCPUO.js → server-4JOL6AJL.js} +16 -6
- package/dist/{task-orchestrator-EGJZA6Y4.js → task-orchestrator-USDQ6J6V.js} +2 -2
- package/package.json +1 -1
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
AuthError,
|
|
4
|
+
ConfigError,
|
|
3
5
|
EnvLoader,
|
|
6
|
+
ProviderError,
|
|
7
|
+
ProviderNotFoundError,
|
|
8
|
+
RateLimitError,
|
|
4
9
|
schemaToJsonSchema
|
|
5
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DMM3XL26.js";
|
|
6
11
|
import {
|
|
7
12
|
APP_NAME,
|
|
8
13
|
CONFIG_DIR_NAME,
|
|
@@ -15,7 +20,7 @@ import {
|
|
|
15
20
|
MCP_TOOL_PREFIX,
|
|
16
21
|
PLUGINS_DIR_NAME,
|
|
17
22
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-KOD3C2CU.js";
|
|
19
24
|
|
|
20
25
|
// src/config/config-manager.ts
|
|
21
26
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -152,47 +157,6 @@ var ConfigSchema = z.object({
|
|
|
152
157
|
allowPlugins: z.boolean().default(false)
|
|
153
158
|
});
|
|
154
159
|
|
|
155
|
-
// src/core/errors.ts
|
|
156
|
-
var AiCliError = class extends Error {
|
|
157
|
-
constructor(message, options) {
|
|
158
|
-
super(message, options);
|
|
159
|
-
this.name = "AiCliError";
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
var ProviderError = class extends AiCliError {
|
|
163
|
-
constructor(providerId, message, cause) {
|
|
164
|
-
super(`[${providerId}] ${message}`, cause !== void 0 ? { cause } : void 0);
|
|
165
|
-
this.providerId = providerId;
|
|
166
|
-
this.name = "ProviderError";
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
var AuthError = class extends ProviderError {
|
|
170
|
-
constructor(providerId) {
|
|
171
|
-
super(providerId, "Invalid or missing API key. Run: ai-cli config");
|
|
172
|
-
this.name = "AuthError";
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
var RateLimitError = class extends ProviderError {
|
|
176
|
-
constructor(providerId) {
|
|
177
|
-
super(providerId, "Rate limit exceeded. Please wait before trying again.");
|
|
178
|
-
this.name = "RateLimitError";
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
var ConfigError = class extends AiCliError {
|
|
182
|
-
constructor(message) {
|
|
183
|
-
super(message);
|
|
184
|
-
this.name = "ConfigError";
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
var ProviderNotFoundError = class extends AiCliError {
|
|
188
|
-
constructor(providerId) {
|
|
189
|
-
super(
|
|
190
|
-
`Provider '${providerId}' is not configured. Run: ai-cli config`
|
|
191
|
-
);
|
|
192
|
-
this.name = "ProviderNotFoundError";
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
|
|
196
160
|
// src/config/config-manager.ts
|
|
197
161
|
var ConfigManager = class {
|
|
198
162
|
configDir;
|
|
@@ -978,10 +942,13 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
978
942
|
}
|
|
979
943
|
wrapError(err) {
|
|
980
944
|
if (err instanceof Error) {
|
|
981
|
-
|
|
945
|
+
const msg = err.message;
|
|
946
|
+
const statusMatch = msg.match(/\b(4\d{2}|5\d{2})\b/);
|
|
947
|
+
const status = statusMatch ? Number(statusMatch[1]) : void 0;
|
|
948
|
+
if (msg.includes("API key") || msg.includes("PERMISSION_DENIED") || status === 401 || status === 403) {
|
|
982
949
|
return new AuthError("gemini");
|
|
983
950
|
}
|
|
984
|
-
if (
|
|
951
|
+
if (status === 429 || msg.includes("RESOURCE_EXHAUSTED") || msg.includes("quota")) {
|
|
985
952
|
return new ProviderError(
|
|
986
953
|
"gemini",
|
|
987
954
|
`Rate limit exceeded (429): The current model requires a paid plan or the free quota has been exhausted.
|
|
@@ -990,17 +957,17 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
990
957
|
err
|
|
991
958
|
);
|
|
992
959
|
}
|
|
993
|
-
if (
|
|
960
|
+
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("ETIMEDOUT") || msg.includes("ENOTFOUND") || msg.includes("socket hang up")) {
|
|
994
961
|
return new ProviderError(
|
|
995
962
|
"gemini",
|
|
996
|
-
`Network connection failed: ${
|
|
963
|
+
`Network connection failed: ${msg}
|
|
997
964
|
Node.js does not automatically use system proxies. Try one of the following:
|
|
998
965
|
1. Set environment variable: set HTTPS_PROXY=http://127.0.0.1:<proxy-port>
|
|
999
966
|
2. Configure an accessible Gemini API mirror URL in config.json under customBaseUrls.gemini`,
|
|
1000
967
|
err
|
|
1001
968
|
);
|
|
1002
969
|
}
|
|
1003
|
-
return new ProviderError("gemini",
|
|
970
|
+
return new ProviderError("gemini", msg, err);
|
|
1004
971
|
}
|
|
1005
972
|
return new ProviderError("gemini", String(err));
|
|
1006
973
|
}
|
|
@@ -2920,8 +2887,12 @@ var McpManager = class {
|
|
|
2920
2887
|
* 关闭所有 MCP 服务器连接。
|
|
2921
2888
|
*/
|
|
2922
2889
|
async closeAll() {
|
|
2923
|
-
const promises = [...this.clients.
|
|
2924
|
-
|
|
2890
|
+
const promises = [...this.clients.entries()].map(
|
|
2891
|
+
([id, c]) => c.close().catch((err) => {
|
|
2892
|
+
process.stderr.write(`[mcp] Failed to close ${id}: ${err instanceof Error ? err.message : err}
|
|
2893
|
+
`);
|
|
2894
|
+
})
|
|
2895
|
+
);
|
|
2925
2896
|
await Promise.allSettled(promises);
|
|
2926
2897
|
this.clients.clear();
|
|
2927
2898
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
7
7
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
8
8
|
runTestsTool
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KOD3C2CU.js";
|
|
10
10
|
|
|
11
11
|
// src/tools/builtin/bash.ts
|
|
12
12
|
import { execSync } from "child_process";
|
|
@@ -129,6 +129,61 @@ var UndoStack = class {
|
|
|
129
129
|
};
|
|
130
130
|
var undoStack = new UndoStack();
|
|
131
131
|
|
|
132
|
+
// src/core/errors.ts
|
|
133
|
+
var AiCliError = class extends Error {
|
|
134
|
+
constructor(message, options) {
|
|
135
|
+
super(message, options);
|
|
136
|
+
this.name = "AiCliError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var ProviderError = class extends AiCliError {
|
|
140
|
+
constructor(providerId, message, cause) {
|
|
141
|
+
super(`[${providerId}] ${message}`, cause !== void 0 ? { cause } : void 0);
|
|
142
|
+
this.providerId = providerId;
|
|
143
|
+
this.name = "ProviderError";
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var AuthError = class extends ProviderError {
|
|
147
|
+
constructor(providerId) {
|
|
148
|
+
super(providerId, "Invalid or missing API key. Run: ai-cli config");
|
|
149
|
+
this.name = "AuthError";
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
var RateLimitError = class extends ProviderError {
|
|
153
|
+
constructor(providerId) {
|
|
154
|
+
super(providerId, "Rate limit exceeded. Please wait before trying again.");
|
|
155
|
+
this.name = "RateLimitError";
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
var ConfigError = class extends AiCliError {
|
|
159
|
+
constructor(message) {
|
|
160
|
+
super(message);
|
|
161
|
+
this.name = "ConfigError";
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
var ProviderNotFoundError = class extends AiCliError {
|
|
165
|
+
constructor(providerId) {
|
|
166
|
+
super(
|
|
167
|
+
`Provider '${providerId}' is not configured. Run: ai-cli config`
|
|
168
|
+
);
|
|
169
|
+
this.name = "ProviderNotFoundError";
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
var ToolError = class extends AiCliError {
|
|
173
|
+
constructor(toolName, message, cause) {
|
|
174
|
+
super(`[${toolName}] ${message}`, cause !== void 0 ? { cause } : void 0);
|
|
175
|
+
this.toolName = toolName;
|
|
176
|
+
this.name = "ToolError";
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var NetworkError = class extends AiCliError {
|
|
180
|
+
constructor(message, statusCode, cause) {
|
|
181
|
+
super(message, cause !== void 0 ? { cause } : void 0);
|
|
182
|
+
this.statusCode = statusCode;
|
|
183
|
+
this.name = "NetworkError";
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
132
187
|
// src/tools/builtin/bash.ts
|
|
133
188
|
var IS_WINDOWS = platform() === "win32";
|
|
134
189
|
var SHELL = IS_WINDOWS ? "powershell.exe" : process.env["SHELL"] ?? "/bin/bash";
|
|
@@ -174,7 +229,7 @@ Important rules:
|
|
|
174
229
|
const timeout = Math.min(Math.max(Number(args["timeout"] ?? 3e4), 1e3), MAX_TIMEOUT);
|
|
175
230
|
const cwdArg = args["cwd"] ? String(args["cwd"]) : void 0;
|
|
176
231
|
if (!command.trim()) {
|
|
177
|
-
throw new
|
|
232
|
+
throw new ToolError("bash", "command is required");
|
|
178
233
|
}
|
|
179
234
|
if (!existsSync2(persistentCwd)) {
|
|
180
235
|
const fallback = process.cwd();
|
|
@@ -188,7 +243,8 @@ Important rules:
|
|
|
188
243
|
if (cwdArg) {
|
|
189
244
|
const resolved = resolve(persistentCwd, cwdArg);
|
|
190
245
|
if (!existsSync2(resolved)) {
|
|
191
|
-
throw new
|
|
246
|
+
throw new ToolError(
|
|
247
|
+
"bash",
|
|
192
248
|
`cwd directory does not exist: "${resolved}". Create it first (e.g. mkdir -p "${resolved}") before specifying it as cwd.`
|
|
193
249
|
);
|
|
194
250
|
}
|
|
@@ -232,7 +288,8 @@ Important rules:
|
|
|
232
288
|
const stderr = IS_WINDOWS && Buffer.isBuffer(execErr.stderr) ? execErr.stderr.toString("utf-8").trim() : execErr.stderr?.toString().trim() ?? "";
|
|
233
289
|
const stdout = IS_WINDOWS && Buffer.isBuffer(execErr.stdout) ? execErr.stdout.toString("utf-8").trim() : execErr.stdout?.toString().trim() ?? "";
|
|
234
290
|
const combined = [stdout, stderr].filter(Boolean).join("\n");
|
|
235
|
-
throw new
|
|
291
|
+
throw new ToolError(
|
|
292
|
+
"bash",
|
|
236
293
|
`Exit code ${execErr.status}:
|
|
237
294
|
${combined || (execErr.message ?? "Unknown error")}
|
|
238
295
|
|
|
@@ -479,12 +536,13 @@ var readFileTool = {
|
|
|
479
536
|
async execute(args) {
|
|
480
537
|
const filePath = String(args["path"] ?? "");
|
|
481
538
|
const encoding = args["encoding"] ?? "utf-8";
|
|
482
|
-
if (!filePath) throw new
|
|
539
|
+
if (!filePath) throw new ToolError("read_file", "path is required");
|
|
483
540
|
const normalizedPath = resolve2(filePath);
|
|
484
541
|
if (!existsSync3(normalizedPath)) {
|
|
485
542
|
const suggestions = findSimilarFiles(filePath);
|
|
486
543
|
if (suggestions.length > 0) {
|
|
487
|
-
throw new
|
|
544
|
+
throw new ToolError(
|
|
545
|
+
"read_file",
|
|
488
546
|
`File not found: ${filePath}
|
|
489
547
|
Current working directory: ${process.cwd()}
|
|
490
548
|
Found similar files, did you mean:
|
|
@@ -492,7 +550,8 @@ Found similar files, did you mean:
|
|
|
492
550
|
Please retry with the correct relative path.`
|
|
493
551
|
);
|
|
494
552
|
}
|
|
495
|
-
throw new
|
|
553
|
+
throw new ToolError(
|
|
554
|
+
"read_file",
|
|
496
555
|
`File not found: ${filePath}
|
|
497
556
|
Current working directory: ${process.cwd()}
|
|
498
557
|
Please use list_dir to verify the file path and retry.`
|
|
@@ -599,7 +658,7 @@ Important: For long content (over 500 lines or 3000 chars), you MUST split into
|
|
|
599
658
|
const content = String(args["content"] ?? "");
|
|
600
659
|
const encoding = args["encoding"] ?? "utf-8";
|
|
601
660
|
const appendMode = String(args["append"] ?? "false").toLowerCase() === "true";
|
|
602
|
-
if (!filePath) throw new
|
|
661
|
+
if (!filePath) throw new ToolError("write_file", "path is required");
|
|
603
662
|
undoStack.push(filePath, `write_file${appendMode ? " (append)" : ""}: ${filePath}`);
|
|
604
663
|
mkdirSync(dirname2(filePath), { recursive: true });
|
|
605
664
|
if (appendMode) {
|
|
@@ -739,15 +798,15 @@ Note: Path can be absolute or relative to the current working directory.`,
|
|
|
739
798
|
async execute(args) {
|
|
740
799
|
const filePath = String(args["path"] ?? "");
|
|
741
800
|
const encoding = args["encoding"] ?? "utf-8";
|
|
742
|
-
if (!filePath) throw new
|
|
743
|
-
if (!existsSync4(filePath)) throw new
|
|
801
|
+
if (!filePath) throw new ToolError("edit_file", "path is required");
|
|
802
|
+
if (!existsSync4(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
|
|
744
803
|
const original = readFileSync3(filePath, encoding);
|
|
745
804
|
if (args["old_str"] !== void 0) {
|
|
746
805
|
const oldStr = String(args["old_str"]);
|
|
747
806
|
const newStr = String(args["new_str"] ?? "");
|
|
748
807
|
const ignoreWs = Boolean(args["ignore_whitespace"]);
|
|
749
808
|
const replaceAll = Boolean(args["replace_all"]);
|
|
750
|
-
if (oldStr === "") throw new
|
|
809
|
+
if (oldStr === "") throw new ToolError("edit_file", "old_str cannot be empty");
|
|
751
810
|
if (ignoreWs) {
|
|
752
811
|
const fileLines = original.split("\n");
|
|
753
812
|
const searchLines = oldStr.split("\n");
|
|
@@ -825,7 +884,7 @@ Tip: You can also try ignore_whitespace: true to match ignoring indentation diff
|
|
|
825
884
|
const content = String(args["insert_content"] ?? "");
|
|
826
885
|
const lines = original.split("\n");
|
|
827
886
|
if (afterLine < 0 || afterLine > lines.length) {
|
|
828
|
-
throw new
|
|
887
|
+
throw new ToolError("edit_file", `insert_after_line ${afterLine} is out of range (file has ${lines.length} lines)`);
|
|
829
888
|
}
|
|
830
889
|
undoStack.push(filePath, `edit_file (insert): ${filePath}`);
|
|
831
890
|
lines.splice(afterLine, 0, content);
|
|
@@ -837,7 +896,8 @@ Tip: You can also try ignore_whitespace: true to match ignoring indentation diff
|
|
|
837
896
|
const toLine = Number(args["delete_to_line"] ?? args["delete_from_line"]);
|
|
838
897
|
const lines = original.split("\n");
|
|
839
898
|
if (fromLine < 1 || toLine < fromLine || toLine > lines.length) {
|
|
840
|
-
throw new
|
|
899
|
+
throw new ToolError(
|
|
900
|
+
"edit_file",
|
|
841
901
|
`Invalid line range: ${fromLine}-${toLine} (file has ${lines.length} lines, lines are 1-indexed)`
|
|
842
902
|
);
|
|
843
903
|
}
|
|
@@ -846,7 +906,8 @@ Tip: You can also try ignore_whitespace: true to match ignoring indentation diff
|
|
|
846
906
|
writeFileSync3(filePath, lines.join("\n"), encoding);
|
|
847
907
|
return `Successfully deleted lines ${fromLine}-${toLine} (${deleted.length} lines) from ${filePath}`;
|
|
848
908
|
}
|
|
849
|
-
throw new
|
|
909
|
+
throw new ToolError(
|
|
910
|
+
"edit_file",
|
|
850
911
|
"No operation specified. Provide either: (old_str + new_str) for replace, (insert_after_line + insert_content) for insert, or (delete_from_line + delete_to_line) for delete."
|
|
851
912
|
);
|
|
852
913
|
}
|
|
@@ -894,7 +955,8 @@ var listDirTool = {
|
|
|
894
955
|
} catch {
|
|
895
956
|
}
|
|
896
957
|
if (suggestions.length > 0) {
|
|
897
|
-
throw new
|
|
958
|
+
throw new ToolError(
|
|
959
|
+
"list_dir",
|
|
898
960
|
`Directory not found: ${dirPath}
|
|
899
961
|
Current working directory: ${cwd}
|
|
900
962
|
Found similar directories:
|
|
@@ -902,7 +964,8 @@ Found similar directories:
|
|
|
902
964
|
Please retry with the correct relative path.`
|
|
903
965
|
);
|
|
904
966
|
}
|
|
905
|
-
throw new
|
|
967
|
+
throw new ToolError(
|
|
968
|
+
"list_dir",
|
|
906
969
|
`Directory not found: ${dirPath}
|
|
907
970
|
Current working directory: ${cwd}
|
|
908
971
|
Please use list_dir (without path) to see the current directory structure first.`
|
|
@@ -1008,11 +1071,11 @@ Supports regex. Automatically skips node_modules, dist, .git directories.`,
|
|
|
1008
1071
|
const ignoreCase = Boolean(args["ignore_case"] ?? false);
|
|
1009
1072
|
const contextLines = Math.max(0, Number(args["context_lines"] ?? 0));
|
|
1010
1073
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 50));
|
|
1011
|
-
if (!pattern) throw new
|
|
1012
|
-
if (!existsSync6(rootPath)) throw new
|
|
1074
|
+
if (!pattern) throw new ToolError("grep_files", "pattern is required");
|
|
1075
|
+
if (!existsSync6(rootPath)) throw new ToolError("grep_files", `Path not found: ${rootPath}`);
|
|
1013
1076
|
const MAX_PATTERN_LENGTH = 1e3;
|
|
1014
1077
|
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
1015
|
-
throw new
|
|
1078
|
+
throw new ToolError("grep_files", `Pattern too long (${pattern.length} chars, max ${MAX_PATTERN_LENGTH}). Use a shorter pattern.`);
|
|
1016
1079
|
}
|
|
1017
1080
|
let regex;
|
|
1018
1081
|
try {
|
|
@@ -1169,8 +1232,8 @@ Results sorted by most recent modification time. Automatically skips node_module
|
|
|
1169
1232
|
const pattern = String(args["pattern"] ?? "");
|
|
1170
1233
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
1171
1234
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 100));
|
|
1172
|
-
if (!pattern) throw new
|
|
1173
|
-
if (!existsSync7(rootPath)) throw new
|
|
1235
|
+
if (!pattern) throw new ToolError("glob_files", "pattern is required");
|
|
1236
|
+
if (!existsSync7(rootPath)) throw new ToolError("glob_files", `Path not found: ${rootPath}`);
|
|
1174
1237
|
const regex = globToRegex(pattern);
|
|
1175
1238
|
const matches = [];
|
|
1176
1239
|
collectMatchingFiles(rootPath, rootPath, regex, matches, maxResults);
|
|
@@ -1319,7 +1382,7 @@ var runInteractiveTool = {
|
|
|
1319
1382
|
})() : [];
|
|
1320
1383
|
const timeout = Math.min(Math.max(Number(args["timeout"] ?? 2e4), 1e3), 3e5);
|
|
1321
1384
|
if (!executable) {
|
|
1322
|
-
throw new
|
|
1385
|
+
throw new ToolError("run_interactive", "executable is required");
|
|
1323
1386
|
}
|
|
1324
1387
|
const env = {
|
|
1325
1388
|
...process.env,
|
|
@@ -1461,7 +1524,7 @@ async function resolveAndCheck(hostname) {
|
|
|
1461
1524
|
try {
|
|
1462
1525
|
const { address } = await dnsPromises.lookup(h);
|
|
1463
1526
|
if (isPrivateHost(address)) {
|
|
1464
|
-
throw new
|
|
1527
|
+
throw new NetworkError(`Blocked: "${hostname}" resolves to private address ${address}. web_fetch is restricted to public URLs.`);
|
|
1465
1528
|
}
|
|
1466
1529
|
} catch (e) {
|
|
1467
1530
|
if (e.message.startsWith("Blocked:")) throw e;
|
|
@@ -1488,17 +1551,17 @@ var webFetchTool = {
|
|
|
1488
1551
|
const url = String(args["url"] ?? "").trim();
|
|
1489
1552
|
const selector = args["selector"] ? String(args["selector"]).trim() : "";
|
|
1490
1553
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
1491
|
-
throw new
|
|
1554
|
+
throw new NetworkError(`Invalid URL: "${url}". URL must start with http:// or https://`);
|
|
1492
1555
|
}
|
|
1493
1556
|
try {
|
|
1494
1557
|
const parsedUrl = new URL(url);
|
|
1495
1558
|
if (isPrivateHost(parsedUrl.hostname)) {
|
|
1496
|
-
throw new
|
|
1559
|
+
throw new NetworkError(`Blocked: "${url}" resolves to a private/internal address. web_fetch is restricted to public URLs.`);
|
|
1497
1560
|
}
|
|
1498
1561
|
await resolveAndCheck(parsedUrl.hostname);
|
|
1499
1562
|
} catch (e) {
|
|
1500
1563
|
if (e.message.startsWith("Blocked:")) throw e;
|
|
1501
|
-
throw new
|
|
1564
|
+
throw new NetworkError(`Invalid URL: "${url}"`);
|
|
1502
1565
|
}
|
|
1503
1566
|
const controller = new AbortController();
|
|
1504
1567
|
const timeoutId = setTimeout(() => controller.abort(), 2e4);
|
|
@@ -1517,7 +1580,7 @@ var webFetchTool = {
|
|
|
1517
1580
|
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
1518
1581
|
const parsedHop = new URL(currentUrl);
|
|
1519
1582
|
if (isPrivateHost(parsedHop.hostname)) {
|
|
1520
|
-
throw new
|
|
1583
|
+
throw new NetworkError(`Blocked: redirect to private/internal address "${currentUrl}".`);
|
|
1521
1584
|
}
|
|
1522
1585
|
await resolveAndCheck(parsedHop.hostname);
|
|
1523
1586
|
const r = await fetch(currentUrl, {
|
|
@@ -1528,7 +1591,7 @@ var webFetchTool = {
|
|
|
1528
1591
|
});
|
|
1529
1592
|
if (r.status >= 300 && r.status < 400) {
|
|
1530
1593
|
if (hop >= MAX_REDIRECTS) {
|
|
1531
|
-
throw new
|
|
1594
|
+
throw new NetworkError(`Too many redirects (>${MAX_REDIRECTS}): ${url}`);
|
|
1532
1595
|
}
|
|
1533
1596
|
const location = r.headers.get("Location");
|
|
1534
1597
|
if (!location) {
|
|
@@ -1542,18 +1605,18 @@ var webFetchTool = {
|
|
|
1542
1605
|
break;
|
|
1543
1606
|
}
|
|
1544
1607
|
clearTimeout(timeoutId);
|
|
1545
|
-
if (!resp) throw new
|
|
1608
|
+
if (!resp) throw new NetworkError(`Too many redirects (>${MAX_REDIRECTS}): ${url}`);
|
|
1546
1609
|
finalUrl = currentUrl;
|
|
1547
1610
|
contentType = resp.headers.get("content-type") ?? "";
|
|
1548
1611
|
if (!resp.ok) {
|
|
1549
|
-
throw new
|
|
1612
|
+
throw new NetworkError(`HTTP ${resp.status} ${resp.statusText}`, resp.status);
|
|
1550
1613
|
}
|
|
1551
1614
|
const buf = await resp.arrayBuffer();
|
|
1552
1615
|
rawHtml = new TextDecoder("utf-8", { fatal: false }).decode(buf.slice(0, 2e6));
|
|
1553
1616
|
} catch (err) {
|
|
1554
1617
|
clearTimeout(timeoutId);
|
|
1555
1618
|
if (err.name === "AbortError") {
|
|
1556
|
-
throw new
|
|
1619
|
+
throw new NetworkError(`Request timed out after 20s: ${url}`, void 0, err);
|
|
1557
1620
|
}
|
|
1558
1621
|
throw err;
|
|
1559
1622
|
}
|
|
@@ -1625,10 +1688,10 @@ var saveLastResponseTool = {
|
|
|
1625
1688
|
},
|
|
1626
1689
|
async execute(args) {
|
|
1627
1690
|
const filePath = String(args["path"] ?? "");
|
|
1628
|
-
if (!filePath) throw new
|
|
1691
|
+
if (!filePath) throw new ToolError("save_last_response", "path is required");
|
|
1629
1692
|
const content = lastResponseStore.content;
|
|
1630
1693
|
if (!content) {
|
|
1631
|
-
throw new
|
|
1694
|
+
throw new ToolError("save_last_response", "No content to save: AI has not produced any response yet, or the last response was empty.");
|
|
1632
1695
|
}
|
|
1633
1696
|
undoStack.push(filePath, `save_last_response: ${filePath}`);
|
|
1634
1697
|
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
@@ -1665,7 +1728,7 @@ var saveMemoryTool = {
|
|
|
1665
1728
|
},
|
|
1666
1729
|
async execute(args) {
|
|
1667
1730
|
const content = String(args["content"] ?? "").trim();
|
|
1668
|
-
if (!content) throw new
|
|
1731
|
+
if (!content) throw new ToolError("save_memory", "content is required");
|
|
1669
1732
|
const memoryPath = getMemoryFilePath();
|
|
1670
1733
|
const configDir = join4(homedir2(), CONFIG_DIR_NAME);
|
|
1671
1734
|
if (!existsSync8(configDir)) {
|
|
@@ -1702,9 +1765,9 @@ var askUserTool = {
|
|
|
1702
1765
|
},
|
|
1703
1766
|
async execute(args) {
|
|
1704
1767
|
const question = String(args["question"] ?? "").trim();
|
|
1705
|
-
if (!question) throw new
|
|
1768
|
+
if (!question) throw new ToolError("ask_user", "question parameter is required");
|
|
1706
1769
|
if (!askUserContext.rl) {
|
|
1707
|
-
throw new
|
|
1770
|
+
throw new ToolError("ask_user", "readline not initialized \u2014 not available in this context");
|
|
1708
1771
|
}
|
|
1709
1772
|
const answer = await promptUser(askUserContext.rl, question);
|
|
1710
1773
|
if (answer === null) {
|
|
@@ -1769,30 +1832,30 @@ Valid statuses: pending, in_progress, completed.`,
|
|
|
1769
1832
|
let parsed;
|
|
1770
1833
|
if (typeof raw === "string") {
|
|
1771
1834
|
const trimmed = raw.trim();
|
|
1772
|
-
if (!trimmed) throw new
|
|
1835
|
+
if (!trimmed) throw new ToolError("write_todos", "todos parameter is required");
|
|
1773
1836
|
try {
|
|
1774
1837
|
parsed = JSON.parse(trimmed);
|
|
1775
1838
|
} catch (err) {
|
|
1776
|
-
throw new
|
|
1839
|
+
throw new ToolError("write_todos", `Invalid JSON in todos parameter: ${err.message}`, err);
|
|
1777
1840
|
}
|
|
1778
1841
|
} else if (Array.isArray(raw)) {
|
|
1779
1842
|
parsed = raw;
|
|
1780
1843
|
} else {
|
|
1781
|
-
throw new
|
|
1844
|
+
throw new ToolError("write_todos", "todos parameter must be a JSON array string");
|
|
1782
1845
|
}
|
|
1783
1846
|
if (!Array.isArray(parsed)) {
|
|
1784
|
-
throw new
|
|
1847
|
+
throw new ToolError("write_todos", "todos must be a JSON array");
|
|
1785
1848
|
}
|
|
1786
1849
|
const todos = parsed.map((item, i) => {
|
|
1787
1850
|
if (typeof item !== "object" || item === null) {
|
|
1788
|
-
throw new
|
|
1851
|
+
throw new ToolError("write_todos", `todos[${i}] must be an object`);
|
|
1789
1852
|
}
|
|
1790
1853
|
const obj = item;
|
|
1791
1854
|
const title = String(obj["title"] ?? "").trim();
|
|
1792
1855
|
const status = String(obj["status"] ?? "").trim();
|
|
1793
|
-
if (!title) throw new
|
|
1856
|
+
if (!title) throw new ToolError("write_todos", `todos[${i}].title is required`);
|
|
1794
1857
|
if (!VALID_STATUSES.has(status)) {
|
|
1795
|
-
throw new
|
|
1858
|
+
throw new ToolError("write_todos", `todos[${i}].status must be one of: pending, in_progress, completed (got "${status}")`);
|
|
1796
1859
|
}
|
|
1797
1860
|
return { title, status };
|
|
1798
1861
|
});
|
|
@@ -1854,10 +1917,6 @@ var EnvLoader = class {
|
|
|
1854
1917
|
*/
|
|
1855
1918
|
static getApiKey(providerId) {
|
|
1856
1919
|
const fixedEnvVar = ENV_KEY_MAP[providerId];
|
|
1857
|
-
if (fixedEnvVar) {
|
|
1858
|
-
const val = process.env[fixedEnvVar];
|
|
1859
|
-
if (val) return val;
|
|
1860
|
-
}
|
|
1861
1920
|
const dynamicEnvVar = `AICLI_API_KEY_${providerId.toUpperCase().replace(/-/g, "_")}`;
|
|
1862
1921
|
if (fixedEnvVar && fixedEnvVar !== dynamicEnvVar) {
|
|
1863
1922
|
const fixedVal = process.env[fixedEnvVar];
|
|
@@ -1867,6 +1926,10 @@ var EnvLoader = class {
|
|
|
1867
1926
|
`);
|
|
1868
1927
|
}
|
|
1869
1928
|
}
|
|
1929
|
+
if (fixedEnvVar) {
|
|
1930
|
+
const val = process.env[fixedEnvVar];
|
|
1931
|
+
if (val) return val;
|
|
1932
|
+
}
|
|
1870
1933
|
return process.env[dynamicEnvVar] || void 0;
|
|
1871
1934
|
}
|
|
1872
1935
|
static getDefaultProvider() {
|
|
@@ -1907,7 +1970,7 @@ var googleSearchTool = {
|
|
|
1907
1970
|
},
|
|
1908
1971
|
async execute(args) {
|
|
1909
1972
|
const query = String(args["query"] ?? "").trim();
|
|
1910
|
-
if (!query) throw new
|
|
1973
|
+
if (!query) throw new ToolError("google_search", "query parameter is required");
|
|
1911
1974
|
const numResults = Math.min(
|
|
1912
1975
|
Math.max(Math.floor(Number(args["num_results"] ?? DEFAULT_RESULTS)), 1),
|
|
1913
1976
|
MAX_RESULTS
|
|
@@ -1931,24 +1994,26 @@ var googleSearchTool = {
|
|
|
1931
1994
|
if (!response.ok) {
|
|
1932
1995
|
const errorBody = await response.text().catch(() => "");
|
|
1933
1996
|
if (response.status === 403) {
|
|
1934
|
-
throw new
|
|
1997
|
+
throw new NetworkError(
|
|
1935
1998
|
`Google Search API 403 Forbidden \u2014 Invalid API Key or daily free quota exceeded (100/day).
|
|
1936
|
-
Please check your API Key and Search Engine ID configuration
|
|
1999
|
+
Please check your API Key and Search Engine ID configuration.`,
|
|
2000
|
+
403
|
|
1937
2001
|
);
|
|
1938
2002
|
}
|
|
1939
2003
|
if (response.status === 429) {
|
|
1940
|
-
throw new
|
|
2004
|
+
throw new NetworkError("Google Search API 429 \u2014 Too many requests, please try again later.", 429);
|
|
1941
2005
|
}
|
|
1942
|
-
throw new
|
|
2006
|
+
throw new NetworkError(
|
|
1943
2007
|
`Google Search API error: HTTP ${response.status} ${response.statusText}
|
|
1944
|
-
${errorBody.slice(0, 500)}
|
|
2008
|
+
${errorBody.slice(0, 500)}`,
|
|
2009
|
+
response.status
|
|
1945
2010
|
);
|
|
1946
2011
|
}
|
|
1947
2012
|
const data = await response.json();
|
|
1948
2013
|
return formatResults(query, data, numResults);
|
|
1949
2014
|
} catch (err) {
|
|
1950
2015
|
if (err instanceof Error && err.name === "AbortError") {
|
|
1951
|
-
throw new
|
|
2016
|
+
throw new NetworkError(`Google Search request timed out (${REQUEST_TIMEOUT_MS / 1e3}s). Please check your network or proxy configuration.`, void 0, err);
|
|
1952
2017
|
}
|
|
1953
2018
|
throw err;
|
|
1954
2019
|
} finally {
|
|
@@ -1967,12 +2032,14 @@ function resolveConfig() {
|
|
|
1967
2032
|
cx = EnvLoader.getGoogleSearchEngineId();
|
|
1968
2033
|
}
|
|
1969
2034
|
if (!apiKey) {
|
|
1970
|
-
throw new
|
|
2035
|
+
throw new ToolError(
|
|
2036
|
+
"google_search",
|
|
1971
2037
|
'Google Search API Key not configured.\nConfigure via one of:\n 1. Run /config \u2192 Configure Google Search\n 2. Set env var AICLI_API_KEY_GOOGLESEARCH\n 3. Add apiKeys["google-search"] to ~/.aicli/config.json'
|
|
1972
2038
|
);
|
|
1973
2039
|
}
|
|
1974
2040
|
if (!cx) {
|
|
1975
|
-
throw new
|
|
2041
|
+
throw new ToolError(
|
|
2042
|
+
"google_search",
|
|
1976
2043
|
"Google Search Engine ID (cx) not configured.\nConfigure via one of:\n 1. Run /config \u2192 Configure Google Search\n 2. Set env var AICLI_GOOGLE_CX\n 3. Add googleSearchEngineId to ~/.aicli/config.json\n\nGet one at: https://programmablesearchengine.google.com/ \u2192 Create search engine \u2192 Copy Search Engine ID"
|
|
1977
2044
|
);
|
|
1978
2045
|
}
|
|
@@ -2309,7 +2376,7 @@ var spawnAgentTool = {
|
|
|
2309
2376
|
},
|
|
2310
2377
|
async execute(args) {
|
|
2311
2378
|
const task = String(args["task"] ?? "").trim();
|
|
2312
|
-
if (!task) throw new
|
|
2379
|
+
if (!task) throw new ToolError("spawn_agent", "task parameter is required");
|
|
2313
2380
|
const rawMaxRounds = Number(args["max_rounds"] ?? SUBAGENT_DEFAULT_MAX_ROUNDS);
|
|
2314
2381
|
const maxRounds = Math.min(
|
|
2315
2382
|
Math.max(Math.round(rawMaxRounds), 1),
|
|
@@ -2317,7 +2384,7 @@ var spawnAgentTool = {
|
|
|
2317
2384
|
);
|
|
2318
2385
|
const ctx = spawnAgentContext;
|
|
2319
2386
|
if (!ctx.provider) {
|
|
2320
|
-
throw new
|
|
2387
|
+
throw new ToolError("spawn_agent", "provider not initialized (context not injected)");
|
|
2321
2388
|
}
|
|
2322
2389
|
const subRegistry = new ToolRegistry();
|
|
2323
2390
|
for (const tool of subRegistry.listAll()) {
|
|
@@ -2533,6 +2600,11 @@ var ToolRegistry = class {
|
|
|
2533
2600
|
|
|
2534
2601
|
export {
|
|
2535
2602
|
EnvLoader,
|
|
2603
|
+
ProviderError,
|
|
2604
|
+
AuthError,
|
|
2605
|
+
RateLimitError,
|
|
2606
|
+
ConfigError,
|
|
2607
|
+
ProviderNotFoundError,
|
|
2536
2608
|
isFileWriteTool,
|
|
2537
2609
|
getDangerLevel,
|
|
2538
2610
|
schemaToJsonSchema,
|
|
@@ -381,7 +381,7 @@ ${content}`);
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
384
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
384
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-USDQ6J6V.js");
|
|
385
385
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
386
386
|
let interrupted = false;
|
|
387
387
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
saveDevState,
|
|
24
24
|
sessionHasMeaningfulContent,
|
|
25
25
|
setupProxy
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-2OKRGXVU.js";
|
|
27
27
|
import {
|
|
28
28
|
ToolRegistry,
|
|
29
29
|
askUserContext,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
theme,
|
|
39
39
|
truncateOutput,
|
|
40
40
|
undoStack
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-DMM3XL26.js";
|
|
42
42
|
import {
|
|
43
43
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
44
44
|
AUTHOR,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
REPO_URL,
|
|
59
59
|
SKILLS_DIR_NAME,
|
|
60
60
|
VERSION
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-KOD3C2CU.js";
|
|
62
62
|
|
|
63
63
|
// src/index.ts
|
|
64
64
|
import { program } from "commander";
|
|
@@ -442,8 +442,20 @@ var Renderer = class {
|
|
|
442
442
|
}
|
|
443
443
|
renderError(err) {
|
|
444
444
|
const message = err instanceof Error ? err.message : String(err);
|
|
445
|
+
const lines = [message];
|
|
446
|
+
if (err instanceof Error && err.cause) {
|
|
447
|
+
let cause = err.cause;
|
|
448
|
+
let depth = 0;
|
|
449
|
+
while (cause && depth < 3) {
|
|
450
|
+
const causeMsg = cause instanceof Error ? cause.message : String(cause);
|
|
451
|
+
lines.push(` Caused by: ${causeMsg}`);
|
|
452
|
+
cause = cause instanceof Error ? cause.cause : void 0;
|
|
453
|
+
depth++;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const typeName = err instanceof Error && err.name !== "Error" ? ` [${err.name}]` : "";
|
|
445
457
|
console.error(theme.error(`
|
|
446
|
-
Error: ${
|
|
458
|
+
Error${typeName}: ${lines.join("\n")}
|
|
447
459
|
`));
|
|
448
460
|
}
|
|
449
461
|
/**
|
|
@@ -1914,7 +1926,7 @@ ${hint}` : "")
|
|
|
1914
1926
|
description: "Run project tests and show structured report",
|
|
1915
1927
|
usage: "/test [command|filter]",
|
|
1916
1928
|
async execute(args, _ctx) {
|
|
1917
|
-
const { executeTests } = await import("./run-tests-
|
|
1929
|
+
const { executeTests } = await import("./run-tests-H7IVHUZO.js");
|
|
1918
1930
|
const argStr = args.join(" ").trim();
|
|
1919
1931
|
let testArgs = {};
|
|
1920
1932
|
if (argStr) {
|
|
@@ -5436,7 +5448,9 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
5436
5448
|
if (sessionId) {
|
|
5437
5449
|
this.events.emit("session.end", { sessionId });
|
|
5438
5450
|
}
|
|
5439
|
-
this.mcpManager?.closeAll().catch(() => {
|
|
5451
|
+
this.mcpManager?.closeAll().catch((err) => {
|
|
5452
|
+
process.stderr.write(`[mcp] cleanup error: ${err instanceof Error ? err.message : err}
|
|
5453
|
+
`);
|
|
5440
5454
|
});
|
|
5441
5455
|
this.rl.close();
|
|
5442
5456
|
console.log(theme.dim("\nGoodbye!"));
|
|
@@ -5528,7 +5542,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
5528
5542
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
5529
5543
|
process.exit(1);
|
|
5530
5544
|
}
|
|
5531
|
-
const { startWebServer } = await import("./server-
|
|
5545
|
+
const { startWebServer } = await import("./server-4JOL6AJL.js");
|
|
5532
5546
|
await startWebServer({ port, host: options.host });
|
|
5533
5547
|
});
|
|
5534
5548
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -5761,7 +5775,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
5761
5775
|
}),
|
|
5762
5776
|
config.get("customProviders")
|
|
5763
5777
|
);
|
|
5764
|
-
const { startHub } = await import("./hub-
|
|
5778
|
+
const { startHub } = await import("./hub-2MUUWFAZ.js");
|
|
5765
5779
|
await startHub(
|
|
5766
5780
|
{
|
|
5767
5781
|
topic: topic ?? "",
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
renderDiff,
|
|
19
19
|
runHook,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-2OKRGXVU.js";
|
|
22
22
|
import {
|
|
23
23
|
AuthManager
|
|
24
24
|
} from "./chunk-BYNY5JPB.js";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
spawnAgentContext,
|
|
33
33
|
truncateOutput,
|
|
34
34
|
undoStack
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-DMM3XL26.js";
|
|
36
36
|
import {
|
|
37
37
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
38
38
|
AUTHOR,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
PLUGINS_DIR_NAME,
|
|
50
50
|
SKILLS_DIR_NAME,
|
|
51
51
|
VERSION
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-KOD3C2CU.js";
|
|
53
53
|
|
|
54
54
|
// src/web/server.ts
|
|
55
55
|
import express from "express";
|
|
@@ -658,7 +658,15 @@ var SessionHandler = class _SessionHandler {
|
|
|
658
658
|
await this.handleChatSimple(provider, session.messages);
|
|
659
659
|
}
|
|
660
660
|
} catch (err) {
|
|
661
|
-
const
|
|
661
|
+
const parts = [];
|
|
662
|
+
let current = err;
|
|
663
|
+
let depth = 0;
|
|
664
|
+
while (current && depth < 3) {
|
|
665
|
+
parts.push(current instanceof Error ? current.message : String(current));
|
|
666
|
+
current = current instanceof Error ? current.cause : void 0;
|
|
667
|
+
depth++;
|
|
668
|
+
}
|
|
669
|
+
const message = parts.join(" \u2192 Caused by: ");
|
|
662
670
|
this.send({ type: "error", message });
|
|
663
671
|
} finally {
|
|
664
672
|
this.processing = false;
|
|
@@ -1482,7 +1490,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
1482
1490
|
case "test": {
|
|
1483
1491
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
1484
1492
|
try {
|
|
1485
|
-
const { executeTests } = await import("./run-tests-
|
|
1493
|
+
const { executeTests } = await import("./run-tests-H7IVHUZO.js");
|
|
1486
1494
|
const argStr = args.join(" ").trim();
|
|
1487
1495
|
let testArgs = {};
|
|
1488
1496
|
if (argStr) {
|
|
@@ -1963,7 +1971,9 @@ Add .md files to create commands.` });
|
|
|
1963
1971
|
if (existsSync3(memPath)) {
|
|
1964
1972
|
content = readFileSync3(memPath, "utf-8");
|
|
1965
1973
|
}
|
|
1966
|
-
} catch {
|
|
1974
|
+
} catch (err) {
|
|
1975
|
+
process.stderr.write(`[web] Failed to read memory file: ${err instanceof Error ? err.message : err}
|
|
1976
|
+
`);
|
|
1967
1977
|
}
|
|
1968
1978
|
this.send({
|
|
1969
1979
|
type: "memory_content",
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DMM3XL26.js";
|
|
8
8
|
import {
|
|
9
9
|
SUBAGENT_ALLOWED_TOOLS
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KOD3C2CU.js";
|
|
11
11
|
|
|
12
12
|
// src/hub/task-orchestrator.ts
|
|
13
13
|
import { createInterface } from "readline";
|