minimal-agent 0.1.8 → 0.1.9
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/main.js +350 -247
- package/package.json +3 -2
- package/plugins/ralph-wiggum/.claude-plugin/plugin.json +9 -0
- package/plugins/ralph-wiggum/README.md +179 -0
- package/plugins/ralph-wiggum/commands/cancel-ralph.md +18 -0
- package/plugins/ralph-wiggum/commands/help.md +126 -0
- package/plugins/ralph-wiggum/commands/ralph-loop.md +69 -0
- package/plugins/ralph-wiggum/hooks/hooks.json +15 -0
- package/plugins/ralph-wiggum/hooks/stop-hook.sh +191 -0
- package/plugins/ralph-wiggum/scripts/setup-ralph-loop.sh +203 -0
- package/skills/config/SKILL.md +27 -1
package/dist/main.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/main.tsx
|
|
4
4
|
import { render } from "ink";
|
|
5
|
-
import { existsSync as
|
|
5
|
+
import { existsSync as existsSync10, mkdirSync } from "fs";
|
|
6
6
|
import { createRequire } from "module";
|
|
7
|
-
import { resolve as
|
|
7
|
+
import { resolve as resolve9 } from "path";
|
|
8
8
|
|
|
9
9
|
// src/bootstrap/cwdArg.ts
|
|
10
10
|
function extractCwdArg(argv) {
|
|
@@ -50,6 +50,7 @@ async function readSavedConfig() {
|
|
|
50
50
|
model: data.model,
|
|
51
51
|
provider: typeof data.provider === "string" ? data.provider : void 0,
|
|
52
52
|
contextWindow: typeof data.contextWindow === "number" && data.contextWindow > 0 ? data.contextWindow : void 0,
|
|
53
|
+
tavilyApiKey: typeof data.tavilyApiKey === "string" && data.tavilyApiKey.length > 0 ? data.tavilyApiKey : void 0,
|
|
53
54
|
savedAt: typeof data.savedAt === "number" ? data.savedAt : 0
|
|
54
55
|
};
|
|
55
56
|
} catch {
|
|
@@ -98,6 +99,13 @@ async function loadProviderLayered() {
|
|
|
98
99
|
contextWindow
|
|
99
100
|
};
|
|
100
101
|
}
|
|
102
|
+
async function applyToolKeysToEnv() {
|
|
103
|
+
const saved = await readSavedConfig();
|
|
104
|
+
if (!saved) return;
|
|
105
|
+
if (!process.env.TAVILY_API_KEY && saved.tavilyApiKey) {
|
|
106
|
+
process.env.TAVILY_API_KEY = saved.tavilyApiKey;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
101
109
|
|
|
102
110
|
// src/context/persistContext.ts
|
|
103
111
|
import { mkdir as mkdir3, readFile as readFile2, readdir, rmdir, unlink, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -221,7 +229,11 @@ async function loadProjectInstructions(cwd) {
|
|
|
221
229
|
|
|
222
230
|
// src/prompts/skillList.ts
|
|
223
231
|
import { readFile as readFile4, readdir as readdir2 } from "fs/promises";
|
|
224
|
-
import { join as
|
|
232
|
+
import { join as join6 } from "path";
|
|
233
|
+
|
|
234
|
+
// src/utils/resourcePaths.ts
|
|
235
|
+
import { existsSync as existsSync2 } from "fs";
|
|
236
|
+
import { join as join5, resolve as resolve4 } from "path";
|
|
225
237
|
|
|
226
238
|
// src/utils/packageRoot.ts
|
|
227
239
|
import { existsSync } from "fs";
|
|
@@ -245,8 +257,26 @@ function findPackageRoot(metaUrl) {
|
|
|
245
257
|
throw new Error(`packageRoot: \u627E\u4E0D\u5230 package.json\uFF08\u8D77\u70B9 ${metaUrl}\uFF09`);
|
|
246
258
|
}
|
|
247
259
|
|
|
260
|
+
// src/utils/resourcePaths.ts
|
|
261
|
+
function getResourceSearchPaths(name, metaUrl) {
|
|
262
|
+
const paths = [];
|
|
263
|
+
const cwdPath = resolve4(join5(getWorkingDir(), name));
|
|
264
|
+
if (existsSync2(cwdPath)) {
|
|
265
|
+
paths.push(cwdPath);
|
|
266
|
+
}
|
|
267
|
+
let pkgPath;
|
|
268
|
+
try {
|
|
269
|
+
pkgPath = resolve4(join5(findPackageRoot(metaUrl), name));
|
|
270
|
+
} catch {
|
|
271
|
+
return paths;
|
|
272
|
+
}
|
|
273
|
+
if (pkgPath !== cwdPath && existsSync2(pkgPath)) {
|
|
274
|
+
paths.push(pkgPath);
|
|
275
|
+
}
|
|
276
|
+
return paths;
|
|
277
|
+
}
|
|
278
|
+
|
|
248
279
|
// src/prompts/skillList.ts
|
|
249
|
-
var SKILLS_DIR = join5(findPackageRoot(import.meta.url), "skills");
|
|
250
280
|
function stripQuotes(s) {
|
|
251
281
|
const trimmed = s.trim();
|
|
252
282
|
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
@@ -254,7 +284,7 @@ function stripQuotes(s) {
|
|
|
254
284
|
}
|
|
255
285
|
return trimmed;
|
|
256
286
|
}
|
|
257
|
-
function parseFrontmatter(content) {
|
|
287
|
+
function parseFrontmatter(content, sourceDir) {
|
|
258
288
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
259
289
|
if (!match) return null;
|
|
260
290
|
const frontmatter = match[1];
|
|
@@ -267,26 +297,33 @@ function parseFrontmatter(content) {
|
|
|
267
297
|
name: stripQuotes(nameMatch[1]),
|
|
268
298
|
description: stripQuotes(descMatch[1]),
|
|
269
299
|
type: typeMatch ? stripQuotes(typeMatch[1]) : void 0,
|
|
270
|
-
triggers: triggersMatch ? stripQuotes(triggersMatch[1]) : void 0
|
|
300
|
+
triggers: triggersMatch ? stripQuotes(triggersMatch[1]) : void 0,
|
|
301
|
+
sourceDir
|
|
271
302
|
};
|
|
272
303
|
}
|
|
273
304
|
async function getSkillList() {
|
|
274
305
|
const skills = [];
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
306
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
307
|
+
const searchPaths = getResourceSearchPaths("skills", import.meta.url);
|
|
308
|
+
for (const root of searchPaths) {
|
|
309
|
+
try {
|
|
310
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
311
|
+
for (const entry of entries) {
|
|
312
|
+
if (!entry.isDirectory()) continue;
|
|
313
|
+
const sourceDir = join6(root, entry.name);
|
|
314
|
+
const skillPath = join6(sourceDir, "SKILL.md");
|
|
315
|
+
try {
|
|
316
|
+
const content = await readFile4(skillPath, "utf8");
|
|
317
|
+
const meta = parseFrontmatter(content, sourceDir);
|
|
318
|
+
if (meta && !seenNames.has(meta.name)) {
|
|
319
|
+
seenNames.add(meta.name);
|
|
320
|
+
skills.push(meta);
|
|
321
|
+
}
|
|
322
|
+
} catch {
|
|
285
323
|
}
|
|
286
|
-
} catch {
|
|
287
324
|
}
|
|
325
|
+
} catch {
|
|
288
326
|
}
|
|
289
|
-
} catch {
|
|
290
327
|
}
|
|
291
328
|
return skills;
|
|
292
329
|
}
|
|
@@ -297,13 +334,11 @@ function formatSkillHint(skills) {
|
|
|
297
334
|
const lines = [];
|
|
298
335
|
lines.push("# \u53EF\u7528\u6280\u80FD\uFF08/\u547D\u4EE4\uFF09");
|
|
299
336
|
lines.push("");
|
|
300
|
-
lines.push(`> Skills \u6839\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF1A\`${SKILLS_DIR}\``);
|
|
301
|
-
lines.push("");
|
|
302
337
|
lines.push(
|
|
303
|
-
"\u4EE5\u4E0B\u662F\u5F53\u524D\u53EF\u7528\u7684\u6280\u80FD\u3002**\u5F53\u7528\u6237\u610F\u56FE\u5339\u914D\u67D0\u4E2A\u6280\u80FD\u7684\u89E6\u53D1\u65F6\u673A\u65F6\uFF0C\u4F60\u5E94\u8BE5\u4E3B\u52A8\u4F7F\u7528\u5B83**\u3002"
|
|
338
|
+
"\u4EE5\u4E0B\u662F\u5F53\u524D\u53EF\u7528\u7684\u6280\u80FD\uFF08**\u53CC\u6E90**\uFF1A\u7528\u6237\u9879\u76EE\u76EE\u5F55 + minimal-agent \u5305\u76EE\u5F55\uFF0C\u540C\u540D\u65F6\u9879\u76EE\u4F18\u5148\uFF09\u3002**\u5F53\u7528\u6237\u610F\u56FE\u5339\u914D\u67D0\u4E2A\u6280\u80FD\u7684\u89E6\u53D1\u65F6\u673A\u65F6\uFF0C\u4F60\u5E94\u8BE5\u4E3B\u52A8\u4F7F\u7528\u5B83**\u3002"
|
|
304
339
|
);
|
|
305
340
|
lines.push(
|
|
306
|
-
|
|
341
|
+
"\u5728\u4F7F\u7528\u524D\uFF0C\u5148\u7528 Read \u5DE5\u5177\u8BFB\u53D6\u4E0B\u65B9\u6BCF\u4E2A\u6280\u80FD\u5361\u7247\u91CC\u7684 `**\u6280\u80FD\u76EE\u5F55**` \u8DEF\u5F84 + `/SKILL.md` \u4E86\u89E3\u5B8C\u6574\u6D41\u7A0B\u3002"
|
|
307
342
|
);
|
|
308
343
|
lines.push("");
|
|
309
344
|
for (const skill of skills) {
|
|
@@ -313,14 +348,14 @@ function formatSkillHint(skills) {
|
|
|
313
348
|
lines.push(`- **\u89E6\u53D1\u65F6\u673A**: ${triggers}`);
|
|
314
349
|
lines.push(`- **\u529F\u80FD**: ${skill.description}`);
|
|
315
350
|
lines.push(`- **\u7C7B\u578B**: ${type}`);
|
|
316
|
-
lines.push(`- **\u6280\u80FD\u76EE\u5F55**: \`${
|
|
351
|
+
lines.push(`- **\u6280\u80FD\u76EE\u5F55**: \`${skill.sourceDir}\``);
|
|
317
352
|
lines.push("");
|
|
318
353
|
}
|
|
319
354
|
lines.push("## \u6280\u80FD\u8C03\u7528\u6D41\u7A0B");
|
|
320
355
|
lines.push("");
|
|
321
356
|
lines.push("```");
|
|
322
357
|
lines.push("1. \u5728 T \u9636\u6BB5\u5224\u65AD\u7528\u6237\u610F\u56FE\u662F\u5426\u5339\u914D\u67D0\u4E2A\u6280\u80FD\u7684\u89E6\u53D1\u65F6\u673A");
|
|
323
|
-
lines.push(
|
|
358
|
+
lines.push('2. \u5339\u914D \u2192 \u5728 A \u9636\u6BB5\u7528 Read \u5DE5\u5177\u8BFB\u53D6\u8BE5\u6280\u80FD\u5361\u7247\u7684"\u6280\u80FD\u76EE\u5F55"/SKILL.md');
|
|
324
359
|
lines.push("3. \u6309\u7167 SKILL.md \u7684 Quick Reference \u548C\u6D41\u7A0B\u6267\u884C");
|
|
325
360
|
lines.push("4. \u6280\u80FD\u811A\u672C\uFF08scripts/\uFF09\u4E0E SKILL.md \u4F4D\u4E8E\u540C\u4E00\u76EE\u5F55\u4E0B\uFF0C\u7528\u7EDD\u5BF9\u8DEF\u5F84\u6267\u884C");
|
|
326
361
|
lines.push("5. \u5982\u679C\u6280\u80FD\u7C7B\u578B\u662F prompt\uFF0C\u5C06\u5176\u5185\u5BB9\u4F5C\u4E3A\u989D\u5916\u4E0A\u4E0B\u6587\u6307\u5BFC\u540E\u7EED\u64CD\u4F5C");
|
|
@@ -382,6 +417,18 @@ ${toolList}
|
|
|
382
417
|
# \u6280\u80FD\u7CFB\u7EDF\uFF08\u79EF\u6781\u4F7F\u7528\uFF09
|
|
383
418
|
${skillHint}
|
|
384
419
|
|
|
420
|
+
# \u63D2\u4EF6\u7CFB\u7EDF\uFF08\u88AB\u52A8\u89E6\u53D1\uFF09
|
|
421
|
+
- minimal-agent \u5728 \`plugins/\` \u76EE\u5F55\u4E0B\u52A0\u8F7D\u7528\u6237\u5B89\u88C5\u7684\u63D2\u4EF6\uFF0C\u66B4\u9732\u5F62\u5982 \`/ralph-loop\` \u7684\u547D\u4EE4\u3002
|
|
422
|
+
\u4E0E skill \u4E0D\u540C\uFF0C**\u63D2\u4EF6\u547D\u4EE4\u5FC5\u987B\u7531\u7528\u6237\u4E3B\u52A8\u8F93\u5165\u624D\u89E6\u53D1**\u2014\u2014\u4F60**\u4E0D\u8981**\u4E3B\u52A8\u8C03\u7528\u6216\u6A21\u62DF\u8FD9\u4E9B\u547D\u4EE4\uFF0C
|
|
423
|
+
\u4E5F\u4E0D\u8981\u5728\u5DE5\u5177\u8C03\u7528\u91CC\u5047\u88C5\u5728\u8DD1\u63D2\u4EF6\u3002
|
|
424
|
+
- \u5F53\u7528\u6237\u7684\u9700\u6C42\u662F **"\u81EA\u52A8\u91CD\u590D\u5C1D\u8BD5\u76F4\u5230\u6210\u529F / \u8FED\u4EE3\u4FEE\u590D\u6D4B\u8BD5\u76F4\u5230\u5168\u7EFF / \u53CD\u590D\u6253\u78E8\u540C\u4E00\u4EFD\u4EA7\u7269"** \u7B49
|
|
425
|
+
\u957F\u5FAA\u73AF\u573A\u666F\u65F6\uFF0C\u53EF\u4EE5\u5EFA\u8BAE\u7528\u6237\u6539\u7528\uFF1A\`/ralph-loop "<\u76EE\u6807>" [--max-iterations N] [--verify ...]\`
|
|
426
|
+
\uFF08\u5185\u7F6E\u7684\u590D\u5236\u4EFB\u52A1\u5FAA\u73AF\uFF0C\u4E94\u9636\u6BB5 FSM\uFF1APLAN \u2192 BUILD \u2192 VERIFY \u2192 HEAL \u2192 DONE\uFF09\u3002
|
|
427
|
+
- \u5982\u679C\u5F53\u8F6E\u7528\u6237\u6D88\u606F\u91CC\u51FA\u73B0 \`<promise>DONE</promise>\` / \`<PROMISE>NEED_REPLAN</PROMISE>\` \u54E8\u5175
|
|
428
|
+
\u6216 PLAN/BUILD/VERIFY/HEAL \u9636\u6BB5\u6807\u8BB0\uFF0C\u8BF4\u660E\u4F60\u6B63\u8FD0\u884C\u5728 ralph-loop \u5185\u2014\u2014\u4E25\u683C\u6309\u7167\u5F53\u8F6E\u6CE8\u5165\u7684
|
|
429
|
+
freshContext \u6307\u5F15\u884C\u52A8\uFF0C**\u4EC5\u5728\u4EFB\u52A1\u771F\u6B63\u5B8C\u6210\u65F6**\u8F93\u51FA \`<promise>DONE</promise>\`\u3002
|
|
430
|
+
- \u5728**\u5E38\u89C4\u5BF9\u8BDD**\uFF08\u65E0\u4E0A\u8FF0\u9636\u6BB5\u6807\u8BB0\uFF09\u4E2D**\u7981\u6B62**\u4F7F\u7528\u8FD9\u4E9B\u54E8\u5175\u548C\u9636\u6BB5\u8BCD\u3002
|
|
431
|
+
|
|
385
432
|
# \u6587\u4EF6\u8BFB\u53D6\u89C4\u8303\uFF08\u91CD\u8981\uFF01\u9632\u6B62\u4E0A\u4E0B\u6587\u6C61\u67D3\uFF09
|
|
386
433
|
## \u8BFB\u53D6\u7B56\u7565\uFF08\u6309\u573A\u666F\u9009\u62E9\uFF09
|
|
387
434
|
### \u573A\u666F 1\uFF1A\u4E0D\u786E\u5B9A\u6587\u4EF6\u5185\u5BB9
|
|
@@ -861,14 +908,14 @@ var bashTool = {
|
|
|
861
908
|
|
|
862
909
|
// src/tools/edit/edit.ts
|
|
863
910
|
import { readFile as readFile6, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
|
|
864
|
-
import { existsSync as
|
|
911
|
+
import { existsSync as existsSync4 } from "fs";
|
|
865
912
|
import { dirname as dirname5 } from "path";
|
|
866
|
-
import { z as
|
|
913
|
+
import { z as z3 } from "zod";
|
|
867
914
|
|
|
868
915
|
// src/tools/shared/fileUtils.ts
|
|
869
916
|
import { open, readFile as readFile5 } from "fs/promises";
|
|
870
917
|
import { homedir as homedir4 } from "os";
|
|
871
|
-
import { extname, resolve as
|
|
918
|
+
import { extname, resolve as resolve5 } from "path";
|
|
872
919
|
var BLOCKED_DEVICE_PATHS = /* @__PURE__ */ new Set([
|
|
873
920
|
"/dev/zero",
|
|
874
921
|
"/dev/random",
|
|
@@ -904,7 +951,7 @@ function validateAndResolvePath(rawPath, workingDir) {
|
|
|
904
951
|
return { ok: false, error: `\u4E0D\u5141\u8BB8\u8BFB\u53D6\u8BBE\u5907\u6587\u4EF6\uFF1A${rawPath}\u3002\u8BE5\u8DEF\u5F84\u53EF\u80FD\u4EA7\u751F\u65E0\u9650\u8F93\u51FA\u6216\u963B\u585E\u8FDB\u7A0B\u3002` };
|
|
905
952
|
}
|
|
906
953
|
const expanded = expandPath(rawPath);
|
|
907
|
-
const resolved =
|
|
954
|
+
const resolved = resolve5(workingDir, expanded);
|
|
908
955
|
if (isBlockedDevicePath(resolved)) {
|
|
909
956
|
return { ok: false, error: `\u4E0D\u5141\u8BB8\u8BFB\u53D6\u8BBE\u5907\u6587\u4EF6\uFF1A${resolved}\u3002\u8BE5\u8DEF\u5F84\u53EF\u80FD\u4EA7\u751F\u65E0\u9650\u8F93\u51FA\u6216\u963B\u585E\u8FDB\u7A0B\u3002` };
|
|
910
957
|
}
|
|
@@ -915,10 +962,13 @@ function validateAndResolvePath(rawPath, workingDir) {
|
|
|
915
962
|
}
|
|
916
963
|
function expandPath(p) {
|
|
917
964
|
if (p.startsWith("~/") || p === "~") {
|
|
918
|
-
return
|
|
965
|
+
return resolve5(homedir4(), p.slice(2));
|
|
919
966
|
}
|
|
920
967
|
return p;
|
|
921
968
|
}
|
|
969
|
+
function resolveToolPath(rawPath) {
|
|
970
|
+
return validateAndResolvePath(rawPath, getWorkingDir());
|
|
971
|
+
}
|
|
922
972
|
function detectLineEndingsForString(content) {
|
|
923
973
|
let crlfCount = 0;
|
|
924
974
|
let lfCount = 0;
|
|
@@ -1108,9 +1158,28 @@ function applyCurlySingleQuotes(str) {
|
|
|
1108
1158
|
}
|
|
1109
1159
|
return result.join("");
|
|
1110
1160
|
}
|
|
1161
|
+
function countOccurrences(haystack, needle) {
|
|
1162
|
+
if (needle.length === 0) return 0;
|
|
1163
|
+
let count = 0;
|
|
1164
|
+
let pos = 0;
|
|
1165
|
+
while ((pos = haystack.indexOf(needle, pos)) !== -1) {
|
|
1166
|
+
count++;
|
|
1167
|
+
pos += needle.length;
|
|
1168
|
+
}
|
|
1169
|
+
return count;
|
|
1170
|
+
}
|
|
1171
|
+
function splitReplaceAll(haystack, needle, replacement) {
|
|
1172
|
+
return haystack.split(needle).join(replacement);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// src/tools/shared/schemas.ts
|
|
1176
|
+
import { z as z2 } from "zod";
|
|
1177
|
+
function filePathField(action) {
|
|
1178
|
+
return z2.string().min(1, "\u5FC5\u987B\u63D0\u4F9B file_path").describe(`\u8981${action}\u7684\u6587\u4EF6\u8DEF\u5F84\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u4F18\u5148\uFF0C\u76F8\u5BF9\u8DEF\u5F84\u57FA\u4E8E working dir \u89E3\u6790\uFF09`);
|
|
1179
|
+
}
|
|
1111
1180
|
|
|
1112
1181
|
// src/tools/shared/fileState.ts
|
|
1113
|
-
import { existsSync as
|
|
1182
|
+
import { existsSync as existsSync3, statSync } from "fs";
|
|
1114
1183
|
var fileState = /* @__PURE__ */ new Map();
|
|
1115
1184
|
function recordRead(absPath) {
|
|
1116
1185
|
try {
|
|
@@ -1122,7 +1191,7 @@ function recordRead(absPath) {
|
|
|
1122
1191
|
function assertFresh(absPath) {
|
|
1123
1192
|
const entry = fileState.get(absPath);
|
|
1124
1193
|
if (!entry) {
|
|
1125
|
-
if (
|
|
1194
|
+
if (existsSync3(absPath)) {
|
|
1126
1195
|
return {
|
|
1127
1196
|
ok: false,
|
|
1128
1197
|
error: `\u6587\u4EF6 ${absPath} \u5DF2\u5B58\u5728\u4F46\u672A\u5728\u672C\u4F1A\u8BDD Read \u8FC7\u3002\u8BF7\u5148\u7528 Read \u5DE5\u5177\u8BFB\u53D6\uFF0C\u786E\u8BA4\u5185\u5BB9\u540E\u518D\u4FEE\u6539\u3002`
|
|
@@ -1149,13 +1218,13 @@ function clearFileState() {
|
|
|
1149
1218
|
|
|
1150
1219
|
// src/tools/edit/edit.ts
|
|
1151
1220
|
var MAX_EDIT_FILE_SIZE_BYTES = 1024 * 1024 * 1024;
|
|
1152
|
-
var inputSchema2 =
|
|
1153
|
-
file_path:
|
|
1154
|
-
old_string:
|
|
1221
|
+
var inputSchema2 = z3.object({
|
|
1222
|
+
file_path: filePathField("\u7F16\u8F91"),
|
|
1223
|
+
old_string: z3.string().describe(
|
|
1155
1224
|
"\u8981\u66FF\u6362\u7684\u539F\u6587\u672C\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u9664\u975E replace_all=true\uFF09\uFF1B\u4E3A\u7A7A\u5B57\u7B26\u4E32\u4E14\u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u521B\u5EFA\u65B0\u6587\u4EF6"
|
|
1156
1225
|
),
|
|
1157
|
-
new_string:
|
|
1158
|
-
replace_all:
|
|
1226
|
+
new_string: z3.string().describe("\u66FF\u6362\u4E3A\u7684\u65B0\u6587\u672C\uFF08\u4E0E old_string \u5FC5\u987B\u4E0D\u540C\uFF09"),
|
|
1227
|
+
replace_all: z3.boolean().optional().describe("\u662F\u5426\u66FF\u6362\u6240\u6709\u51FA\u73B0\u4F4D\u7F6E\uFF08\u9ED8\u8BA4 false\uFF09")
|
|
1159
1228
|
});
|
|
1160
1229
|
var parameters2 = toToolParameters(inputSchema2);
|
|
1161
1230
|
var description2 = `Performs exact string replacements in files.
|
|
@@ -1164,7 +1233,8 @@ Usage:
|
|
|
1164
1233
|
- You MUST use your \`Read\` tool to read the current content of the file BEFORE calling Edit.
|
|
1165
1234
|
Memory is unreliable \u2014 if you think you "remember" how the code looks, you are probably wrong.
|
|
1166
1235
|
Re-read the relevant sections (function, module, or area you plan to change) every time.
|
|
1167
|
-
- To create a new file, pass an empty \`old_string\` and the desired contents as \`new_string\`.
|
|
1236
|
+
- To create a new file, pass an empty \`old_string\` and the desired contents as \`new_string\`. When creating a new file (path does not yet exist), you may call Edit directly \u2014 no prior Read is needed.
|
|
1237
|
+
- If the file already exists and you pass an empty \`old_string\`, the edit is rejected with a clear error. To replace the entire content of an existing file, use the Write tool instead.
|
|
1168
1238
|
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
|
|
1169
1239
|
- The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`.
|
|
1170
1240
|
- Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.
|
|
@@ -1172,7 +1242,7 @@ Usage:
|
|
|
1172
1242
|
async function call2(input) {
|
|
1173
1243
|
const { old_string, new_string } = input;
|
|
1174
1244
|
const replaceAll = input.replace_all ?? false;
|
|
1175
|
-
const pathResult =
|
|
1245
|
+
const pathResult = resolveToolPath(input.file_path);
|
|
1176
1246
|
if (!pathResult.ok) return pathResult;
|
|
1177
1247
|
const filePath = pathResult.resolvedPath;
|
|
1178
1248
|
const freshness = assertFresh(filePath);
|
|
@@ -1182,10 +1252,11 @@ async function call2(input) {
|
|
|
1182
1252
|
if (old_string === new_string) {
|
|
1183
1253
|
return { ok: false, error: "old_string \u4E0E new_string \u5B8C\u5168\u76F8\u540C\uFF0C\u6CA1\u6709\u53EF\u6539\u7684\u5185\u5BB9\u3002" };
|
|
1184
1254
|
}
|
|
1185
|
-
if (old_string === "" && !
|
|
1255
|
+
if (old_string === "" && !existsSync4(filePath)) {
|
|
1186
1256
|
try {
|
|
1187
1257
|
await mkdir4(dirname5(filePath), { recursive: true });
|
|
1188
1258
|
await writeFile3(filePath, new_string, "utf8");
|
|
1259
|
+
recordRead(filePath);
|
|
1189
1260
|
return {
|
|
1190
1261
|
ok: true,
|
|
1191
1262
|
content: `\u5DF2\u521B\u5EFA\u65B0\u6587\u4EF6\uFF1A${filePath}\uFF08${new_string.length} \u5B57\u7B26\uFF09`
|
|
@@ -1194,7 +1265,7 @@ async function call2(input) {
|
|
|
1194
1265
|
return { ok: false, error: `\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e.message}` };
|
|
1195
1266
|
}
|
|
1196
1267
|
}
|
|
1197
|
-
if (!
|
|
1268
|
+
if (!existsSync4(filePath)) {
|
|
1198
1269
|
return {
|
|
1199
1270
|
ok: false,
|
|
1200
1271
|
error: `\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}
|
|
@@ -1250,6 +1321,7 @@ async function call2(input) {
|
|
|
1250
1321
|
const normalizedReplaced = applyLineEnding(replaced, originalLineEnding);
|
|
1251
1322
|
try {
|
|
1252
1323
|
await writeFile3(filePath, normalizedReplaced, "utf8");
|
|
1324
|
+
recordRead(filePath);
|
|
1253
1325
|
} catch (e) {
|
|
1254
1326
|
return { ok: false, error: `\u5199\u5165\u5931\u8D25\uFF1A${e.message}` };
|
|
1255
1327
|
}
|
|
@@ -1262,19 +1334,6 @@ async function call2(input) {
|
|
|
1262
1334
|
\u884C\u6570\uFF1A${linesBefore} \u2192 ${linesAfter}`
|
|
1263
1335
|
};
|
|
1264
1336
|
}
|
|
1265
|
-
function countOccurrences(haystack, needle) {
|
|
1266
|
-
if (needle.length === 0) return 0;
|
|
1267
|
-
let count = 0;
|
|
1268
|
-
let pos = 0;
|
|
1269
|
-
while ((pos = haystack.indexOf(needle, pos)) !== -1) {
|
|
1270
|
-
count++;
|
|
1271
|
-
pos += needle.length;
|
|
1272
|
-
}
|
|
1273
|
-
return count;
|
|
1274
|
-
}
|
|
1275
|
-
function splitReplaceAll(haystack, needle, replacement) {
|
|
1276
|
-
return haystack.split(needle).join(replacement);
|
|
1277
|
-
}
|
|
1278
1337
|
function findFuzzyMatchHint(fileContent, target) {
|
|
1279
1338
|
const MIN_OVERLAP_RATIO = 0.5;
|
|
1280
1339
|
const MAX_HINTS = 3;
|
|
@@ -1349,16 +1408,16 @@ var editTool = {
|
|
|
1349
1408
|
|
|
1350
1409
|
// src/tools/edit/multi-edit.ts
|
|
1351
1410
|
import { readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
1352
|
-
import { existsSync as
|
|
1353
|
-
import { z as
|
|
1354
|
-
var editItemSchema =
|
|
1355
|
-
old_string:
|
|
1356
|
-
new_string:
|
|
1357
|
-
replace_all:
|
|
1411
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1412
|
+
import { z as z4 } from "zod";
|
|
1413
|
+
var editItemSchema = z4.object({
|
|
1414
|
+
old_string: z4.string().min(1).describe("\u8981\u66FF\u6362\u7684\u539F\u6587\u672C\uFF08\u4E0D\u5141\u8BB8\u4E3A\u7A7A \u2014\u2014 \u521B\u5EFA\u65B0\u6587\u4EF6\u8BF7\u7528 Edit \u5DE5\u5177\uFF09"),
|
|
1415
|
+
new_string: z4.string().describe("\u66FF\u6362\u4E3A\u7684\u65B0\u6587\u672C"),
|
|
1416
|
+
replace_all: z4.boolean().optional().describe("\u662F\u5426\u66FF\u6362\u6240\u6709\u51FA\u73B0\u4F4D\u7F6E\uFF08\u9ED8\u8BA4 false\uFF0C\u8981\u6C42 old_string \u5728\u5F53\u524D\u5185\u5BB9\u4E2D\u552F\u4E00\uFF09")
|
|
1358
1417
|
});
|
|
1359
|
-
var inputSchema3 =
|
|
1360
|
-
file_path:
|
|
1361
|
-
edits:
|
|
1418
|
+
var inputSchema3 = z4.object({
|
|
1419
|
+
file_path: filePathField("\u7F16\u8F91"),
|
|
1420
|
+
edits: z4.array(editItemSchema).min(1).max(50).describe("\u6309\u987A\u5E8F\u5E94\u7528\u7684 edit \u5217\u8868\uFF081-50 \u6761\uFF09\uFF0C\u539F\u5B50\u5316\u6267\u884C\uFF1A\u5168\u90E8\u6210\u529F\u624D\u843D\u76D8")
|
|
1362
1421
|
});
|
|
1363
1422
|
var parameters3 = toToolParameters(inputSchema3);
|
|
1364
1423
|
var description3 = `Performs multiple exact string replacements in a single file, applied atomically (all-or-nothing).
|
|
@@ -1371,28 +1430,15 @@ Usage:
|
|
|
1371
1430
|
- Each \`old_string\` must be unique in the current content (after prior edits) unless \`replace_all=true\`.
|
|
1372
1431
|
- Empty \`old_string\` is NOT allowed in MultiEdit. To create a new file, use the \`Edit\` tool with a single empty-old_string call.
|
|
1373
1432
|
- Preserve exact indentation (tabs/spaces).`;
|
|
1374
|
-
function countOccurrences2(haystack, needle) {
|
|
1375
|
-
if (needle.length === 0) return 0;
|
|
1376
|
-
let count = 0;
|
|
1377
|
-
let pos = 0;
|
|
1378
|
-
while ((pos = haystack.indexOf(needle, pos)) !== -1) {
|
|
1379
|
-
count++;
|
|
1380
|
-
pos += needle.length;
|
|
1381
|
-
}
|
|
1382
|
-
return count;
|
|
1383
|
-
}
|
|
1384
|
-
function splitReplaceAll2(haystack, needle, replacement) {
|
|
1385
|
-
return haystack.split(needle).join(replacement);
|
|
1386
|
-
}
|
|
1387
1433
|
async function call3(input) {
|
|
1388
|
-
const pathResult =
|
|
1434
|
+
const pathResult = resolveToolPath(input.file_path);
|
|
1389
1435
|
if (!pathResult.ok) return pathResult;
|
|
1390
1436
|
const filePath = pathResult.resolvedPath;
|
|
1391
1437
|
const freshness = assertFresh(filePath);
|
|
1392
1438
|
if (!freshness.ok) {
|
|
1393
1439
|
return { ok: false, error: freshness.error };
|
|
1394
1440
|
}
|
|
1395
|
-
if (!
|
|
1441
|
+
if (!existsSync5(filePath)) {
|
|
1396
1442
|
return {
|
|
1397
1443
|
ok: false,
|
|
1398
1444
|
error: `\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${filePath}
|
|
@@ -1433,7 +1479,7 @@ async function call3(input) {
|
|
|
1433
1479
|
searchTarget = actualOld;
|
|
1434
1480
|
processedNewString = preserveQuoteStyle(edit.old_string, actualOld, edit.new_string);
|
|
1435
1481
|
}
|
|
1436
|
-
const occurrences =
|
|
1482
|
+
const occurrences = countOccurrences(currentContent, searchTarget);
|
|
1437
1483
|
if (occurrences === 0) {
|
|
1438
1484
|
return {
|
|
1439
1485
|
ok: false,
|
|
@@ -1446,12 +1492,13 @@ async function call3(input) {
|
|
|
1446
1492
|
error: `edits[${i}].old_string \u5728\u5F53\u524D\u5185\u5BB9\u4E2D\u51FA\u73B0 ${occurrences} \u6B21\uFF0C\u4E0D\u552F\u4E00\u3002\u8BF7\u6269\u5927 old_string \u5305\u542B\u66F4\u591A\u4E0A\u4E0B\u6587\uFF0C\u6216\u663E\u5F0F\u4F20 replace_all=true\u3002`
|
|
1447
1493
|
};
|
|
1448
1494
|
}
|
|
1449
|
-
currentContent = replaceAll ?
|
|
1495
|
+
currentContent = replaceAll ? splitReplaceAll(currentContent, searchTarget, processedNewString) : currentContent.replace(searchTarget, processedNewString);
|
|
1450
1496
|
}
|
|
1451
1497
|
const lineEnding = await detectFileLineEndings(filePath);
|
|
1452
1498
|
const finalContent = applyLineEnding(currentContent, lineEnding);
|
|
1453
1499
|
try {
|
|
1454
1500
|
await writeFile4(filePath, finalContent, "utf8");
|
|
1501
|
+
recordRead(filePath);
|
|
1455
1502
|
} catch (e) {
|
|
1456
1503
|
return { ok: false, error: `\u5199\u5165\u5931\u8D25\uFF1A${e.message}` };
|
|
1457
1504
|
}
|
|
@@ -1473,12 +1520,12 @@ var multiEditTool = {
|
|
|
1473
1520
|
|
|
1474
1521
|
// src/tools/glob/glob.ts
|
|
1475
1522
|
import { stat as stat2 } from "fs/promises";
|
|
1476
|
-
import { isAbsolute, resolve as
|
|
1523
|
+
import { isAbsolute, resolve as resolve6 } from "path";
|
|
1477
1524
|
import fg from "fast-glob";
|
|
1478
|
-
import { z as
|
|
1479
|
-
var inputSchema4 =
|
|
1480
|
-
pattern:
|
|
1481
|
-
path:
|
|
1525
|
+
import { z as z5 } from "zod";
|
|
1526
|
+
var inputSchema4 = z5.object({
|
|
1527
|
+
pattern: z5.string().min(1).describe('glob \u6A21\u5F0F\uFF0C\u4F8B\u5982 "**/*.ts" \u6216 "src/components/**/*.tsx"'),
|
|
1528
|
+
path: z5.string().optional().describe('\u641C\u7D22\u7684\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1B\u7701\u7565\u65F6\u4E0D\u8981\u4F20 "undefined" \u5B57\u7B26\u4E32')
|
|
1482
1529
|
});
|
|
1483
1530
|
var parameters4 = toToolParameters(inputSchema4);
|
|
1484
1531
|
var description4 = `- Fast file pattern matching tool that works with any codebase size
|
|
@@ -1487,7 +1534,7 @@ var description4 = `- Fast file pattern matching tool that works with any codeba
|
|
|
1487
1534
|
- Use this tool when you need to find files by name patterns
|
|
1488
1535
|
- When you need to do an open ended search that may require multiple rounds, prefer the Grep tool for content search`;
|
|
1489
1536
|
async function call4(input) {
|
|
1490
|
-
const cwd = input.path ?
|
|
1537
|
+
const cwd = input.path ? resolve6(input.path) : getWorkingDir();
|
|
1491
1538
|
const pattern = input.pattern.replace(/\\/g, "/");
|
|
1492
1539
|
let matches;
|
|
1493
1540
|
try {
|
|
@@ -1508,7 +1555,7 @@ async function call4(input) {
|
|
|
1508
1555
|
}
|
|
1509
1556
|
const withMtime = await Promise.all(
|
|
1510
1557
|
matches.map(async (rel) => {
|
|
1511
|
-
const abs = isAbsolute(rel) ? rel :
|
|
1558
|
+
const abs = isAbsolute(rel) ? rel : resolve6(cwd, rel);
|
|
1512
1559
|
try {
|
|
1513
1560
|
const st = await stat2(abs);
|
|
1514
1561
|
return { path: rel, mtime: st.mtimeMs };
|
|
@@ -1544,13 +1591,13 @@ var globTool = {
|
|
|
1544
1591
|
|
|
1545
1592
|
// src/tools/grep/grep.ts
|
|
1546
1593
|
import { spawn as spawn3 } from "child_process";
|
|
1547
|
-
import { resolve as
|
|
1548
|
-
import { z as
|
|
1594
|
+
import { resolve as resolve8 } from "path";
|
|
1595
|
+
import { z as z6 } from "zod";
|
|
1549
1596
|
|
|
1550
1597
|
// src/tools/grep/rgPath.ts
|
|
1551
1598
|
import { spawn as spawn2 } from "child_process";
|
|
1552
|
-
import { chmodSync, existsSync as
|
|
1553
|
-
import { resolve as
|
|
1599
|
+
import { chmodSync, existsSync as existsSync6 } from "fs";
|
|
1600
|
+
import { resolve as resolve7 } from "path";
|
|
1554
1601
|
var cached;
|
|
1555
1602
|
async function resolveRgPath() {
|
|
1556
1603
|
if (cached !== void 0) return cached;
|
|
@@ -1559,15 +1606,15 @@ async function resolveRgPath() {
|
|
|
1559
1606
|
}
|
|
1560
1607
|
async function detect() {
|
|
1561
1608
|
const fromEnv = process.env.MINIMAL_AGENT_RIPGREP_PATH;
|
|
1562
|
-
if (fromEnv &&
|
|
1609
|
+
if (fromEnv && existsSync6(fromEnv)) return fromEnv;
|
|
1563
1610
|
const vendored = vendoredRgPath();
|
|
1564
|
-
if (vendored &&
|
|
1611
|
+
if (vendored && existsSync6(vendored)) {
|
|
1565
1612
|
ensureExecutable(vendored);
|
|
1566
1613
|
return vendored;
|
|
1567
1614
|
}
|
|
1568
1615
|
if (await trySpawn("rg")) return "rg";
|
|
1569
1616
|
for (const candidate of claudeCodeCandidates()) {
|
|
1570
|
-
if (
|
|
1617
|
+
if (existsSync6(candidate)) {
|
|
1571
1618
|
ensureExecutable(candidate);
|
|
1572
1619
|
return candidate;
|
|
1573
1620
|
}
|
|
@@ -1577,7 +1624,7 @@ async function detect() {
|
|
|
1577
1624
|
function vendoredRgPath() {
|
|
1578
1625
|
try {
|
|
1579
1626
|
const projectRoot = findPackageRoot(import.meta.url);
|
|
1580
|
-
return
|
|
1627
|
+
return resolve7(projectRoot, "vendor", "ripgrep", subdir(), exeName());
|
|
1581
1628
|
} catch {
|
|
1582
1629
|
return null;
|
|
1583
1630
|
}
|
|
@@ -1636,42 +1683,42 @@ function claudeCodeCandidates() {
|
|
|
1636
1683
|
const npmRoots = [];
|
|
1637
1684
|
if (platform === "win32") {
|
|
1638
1685
|
if (process.env.APPDATA) {
|
|
1639
|
-
npmRoots.push(
|
|
1686
|
+
npmRoots.push(resolve7(process.env.APPDATA, "npm", "node_modules"));
|
|
1640
1687
|
}
|
|
1641
1688
|
if (process.env.USERPROFILE) {
|
|
1642
1689
|
npmRoots.push(
|
|
1643
|
-
|
|
1690
|
+
resolve7(process.env.USERPROFILE, "AppData", "Roaming", "npm", "node_modules")
|
|
1644
1691
|
);
|
|
1645
1692
|
}
|
|
1646
1693
|
} else {
|
|
1647
1694
|
const home = process.env.HOME ?? "";
|
|
1648
1695
|
if (home) {
|
|
1649
|
-
npmRoots.push(
|
|
1650
|
-
npmRoots.push(
|
|
1651
|
-
npmRoots.push(
|
|
1696
|
+
npmRoots.push(resolve7(home, ".npm-global", "lib", "node_modules"));
|
|
1697
|
+
npmRoots.push(resolve7(home, ".npm", "lib", "node_modules"));
|
|
1698
|
+
npmRoots.push(resolve7(home, "node_modules"));
|
|
1652
1699
|
}
|
|
1653
1700
|
npmRoots.push("/usr/local/lib/node_modules");
|
|
1654
1701
|
npmRoots.push("/usr/lib/node_modules");
|
|
1655
1702
|
npmRoots.push("/opt/homebrew/lib/node_modules");
|
|
1656
1703
|
}
|
|
1657
1704
|
return npmRoots.map(
|
|
1658
|
-
(root) =>
|
|
1705
|
+
(root) => resolve7(root, "@anthropic-ai", "claude-code", "vendor", "ripgrep", subdir2, exe)
|
|
1659
1706
|
);
|
|
1660
1707
|
}
|
|
1661
1708
|
|
|
1662
1709
|
// src/tools/grep/grep.ts
|
|
1663
|
-
var inputSchema5 =
|
|
1664
|
-
pattern:
|
|
1665
|
-
path:
|
|
1666
|
-
glob:
|
|
1667
|
-
type:
|
|
1668
|
-
output_mode:
|
|
1669
|
-
"-i":
|
|
1670
|
-
"-n":
|
|
1671
|
-
"-A":
|
|
1672
|
-
"-B":
|
|
1673
|
-
"-C":
|
|
1674
|
-
head_limit:
|
|
1710
|
+
var inputSchema5 = z6.object({
|
|
1711
|
+
pattern: z6.string().min(1).describe("\u6B63\u5219\u8868\u8FBE\u5F0F\uFF08ripgrep \u517C\u5BB9\u8BED\u6CD5\uFF09"),
|
|
1712
|
+
path: z6.string().optional().describe("\u641C\u7D22\u7684\u6839\u76EE\u5F55\u6216\u6587\u4EF6\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09"),
|
|
1713
|
+
glob: z6.string().optional().describe('\u6587\u4EF6\u540D glob \u8FC7\u6EE4\uFF0C\u5982 "*.ts"'),
|
|
1714
|
+
type: z6.string().optional().describe('rg \u7684\u6587\u4EF6\u7C7B\u578B\u5FEB\u6377\u540D\uFF0C\u5982 "py"\u3001"rust"\u3001"js"'),
|
|
1715
|
+
output_mode: z6.enum(["content", "files_with_matches", "count"]).optional().describe("\u8F93\u51FA\u6A21\u5F0F\uFF1Acontent=\u5339\u914D\u884C\uFF1Bfiles_with_matches=\u53EA\u5217\u6587\u4EF6\uFF1Bcount=\u6BCF\u6587\u4EF6\u8BA1\u6570"),
|
|
1716
|
+
"-i": z6.boolean().optional().describe("\u5FFD\u7565\u5927\u5C0F\u5199"),
|
|
1717
|
+
"-n": z6.boolean().optional().describe("\u663E\u793A\u884C\u53F7\uFF08\u4EC5 content \u6A21\u5F0F\uFF09"),
|
|
1718
|
+
"-A": z6.number().int().min(0).optional().describe("\u5339\u914D\u540E\u5C55\u793A\u51E0\u884C\u4E0A\u4E0B\u6587"),
|
|
1719
|
+
"-B": z6.number().int().min(0).optional().describe("\u5339\u914D\u524D\u5C55\u793A\u51E0\u884C\u4E0A\u4E0B\u6587"),
|
|
1720
|
+
"-C": z6.number().int().min(0).optional().describe("\u5339\u914D\u524D\u540E\u5404\u5C55\u793A\u51E0\u884C\uFF08\u8986\u76D6 -A/-B\uFF09"),
|
|
1721
|
+
head_limit: z6.number().int().positive().optional().describe("\u8F93\u51FA\u6700\u591A\u4FDD\u7559\u524D N \u884C\uFF08\u9632\u6B62\u7ED3\u679C\u8FC7\u5927\uFF09")
|
|
1675
1722
|
});
|
|
1676
1723
|
var parameters5 = toToolParameters(inputSchema5);
|
|
1677
1724
|
var description5 = `A powerful search tool built on ripgrep.
|
|
@@ -1701,7 +1748,7 @@ async function call5(input, signal) {
|
|
|
1701
1748
|
args.push("--max-columns-preview");
|
|
1702
1749
|
args.push("--sort", "modified");
|
|
1703
1750
|
args.push("-e", input.pattern);
|
|
1704
|
-
args.push(input.path ?
|
|
1751
|
+
args.push(input.path ? resolve8(input.path) : ".");
|
|
1705
1752
|
const rgPath = await resolveRgPath();
|
|
1706
1753
|
if (!rgPath) {
|
|
1707
1754
|
return {
|
|
@@ -1772,18 +1819,18 @@ var grepTool = {
|
|
|
1772
1819
|
import { createReadStream } from "fs";
|
|
1773
1820
|
import { readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
1774
1821
|
import { createInterface } from "readline";
|
|
1775
|
-
import { z as
|
|
1776
|
-
var inputSchema6 =
|
|
1777
|
-
file_path:
|
|
1778
|
-
offset:
|
|
1779
|
-
limit:
|
|
1822
|
+
import { z as z7 } from "zod";
|
|
1823
|
+
var inputSchema6 = z7.object({
|
|
1824
|
+
file_path: filePathField("\u8BFB\u53D6"),
|
|
1825
|
+
offset: z7.number().int().positive().optional().describe("\u8D77\u59CB\u884C\u53F7\uFF081-indexed\uFF09\uFF1B\u4E0D\u586B\u5219\u4ECE\u6587\u4EF6\u5F00\u5934\u8BFB"),
|
|
1826
|
+
limit: z7.number().int().positive().optional().describe(`\u6700\u591A\u8BFB\u591A\u5C11\u884C\uFF1B\u4E0D\u586B\u5219\u7528\u9ED8\u8BA4\u503C ${MAX_LINES_TO_READ}`)
|
|
1780
1827
|
});
|
|
1781
1828
|
var parameters6 = toToolParameters(inputSchema6);
|
|
1782
1829
|
var description6 = `Reads a file from the local filesystem. You can access any file directly by using this tool.
|
|
1783
1830
|
Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
|
|
1784
1831
|
|
|
1785
1832
|
Usage:
|
|
1786
|
-
- The file_path parameter
|
|
1833
|
+
- The file_path parameter is preferably an absolute path. Relative paths are accepted and will be resolved against the agent's working directory (locked at startup via \`-d <dir>\` or process cwd).
|
|
1787
1834
|
- By default, it reads up to ${MAX_LINES_TO_READ} lines starting from the beginning of the file
|
|
1788
1835
|
- You can optionally specify a line offset and limit (especially handy for long files)
|
|
1789
1836
|
- Results are returned using cat -n format, with line numbers starting at 1
|
|
@@ -1794,10 +1841,8 @@ var STREAM_THRESHOLD = 1024 * 1024;
|
|
|
1794
1841
|
async function call6(input) {
|
|
1795
1842
|
const offset = input.offset ?? 1;
|
|
1796
1843
|
const limit = input.limit ?? MAX_LINES_TO_READ;
|
|
1797
|
-
const pathResult =
|
|
1798
|
-
if (!pathResult.ok)
|
|
1799
|
-
return { ok: false, error: pathResult.error };
|
|
1800
|
-
}
|
|
1844
|
+
const pathResult = resolveToolPath(input.file_path);
|
|
1845
|
+
if (!pathResult.ok) return pathResult;
|
|
1801
1846
|
const filePath = pathResult.resolvedPath;
|
|
1802
1847
|
if (isBlockedDevicePath(filePath)) {
|
|
1803
1848
|
return { ok: false, error: `\u4E0D\u5141\u8BB8\u8BFB\u53D6\u8BBE\u5907\u6587\u4EF6\uFF1A${filePath}\u3002\u8BE5\u8DEF\u5F84\u53EF\u80FD\u4EA7\u751F\u65E0\u9650\u8F93\u51FA\u6216\u963B\u585E\u8FDB\u7A0B\u3002` };
|
|
@@ -1929,7 +1974,7 @@ var readTool = {
|
|
|
1929
1974
|
};
|
|
1930
1975
|
|
|
1931
1976
|
// src/tools/webfetch/webfetch.ts
|
|
1932
|
-
import { z as
|
|
1977
|
+
import { z as z8 } from "zod";
|
|
1933
1978
|
|
|
1934
1979
|
// src/tools/webfetch/preapproved.ts
|
|
1935
1980
|
var PREAPPROVED_HOSTS = /* @__PURE__ */ new Set([
|
|
@@ -2214,9 +2259,9 @@ function cleanCache() {
|
|
|
2214
2259
|
}
|
|
2215
2260
|
}
|
|
2216
2261
|
}
|
|
2217
|
-
var inputSchema7 =
|
|
2218
|
-
url:
|
|
2219
|
-
prompt:
|
|
2262
|
+
var inputSchema7 = z8.object({
|
|
2263
|
+
url: z8.string().describe("\u8981\u83B7\u53D6\u5185\u5BB9\u7684 URL"),
|
|
2264
|
+
prompt: z8.string().describe("\u5BF9\u5185\u5BB9\u8FDB\u884C\u5904\u7406\u7684\u6307\u4EE4\uFF0C\u63CF\u8FF0\u4F60\u60F3\u4ECE\u9875\u9762\u63D0\u53D6\u4EC0\u4E48\u4FE1\u606F")
|
|
2220
2265
|
});
|
|
2221
2266
|
var parameters7 = toToolParameters(inputSchema7);
|
|
2222
2267
|
var description7 = `- Fetches content from a specified URL and processes it using an AI model.
|
|
@@ -2436,7 +2481,7 @@ var webfetchTool = {
|
|
|
2436
2481
|
};
|
|
2437
2482
|
|
|
2438
2483
|
// src/tools/webbrowser/webbrowser.ts
|
|
2439
|
-
import { z as
|
|
2484
|
+
import { z as z9 } from "zod";
|
|
2440
2485
|
|
|
2441
2486
|
// src/tools/webbrowser/browser.ts
|
|
2442
2487
|
import os from "os";
|
|
@@ -2472,12 +2517,12 @@ function screenshotPath(prefix = "browser") {
|
|
|
2472
2517
|
}
|
|
2473
2518
|
|
|
2474
2519
|
// src/tools/webbrowser/webbrowser.ts
|
|
2475
|
-
var inputSchema8 =
|
|
2476
|
-
action:
|
|
2477
|
-
url:
|
|
2478
|
-
selector:
|
|
2479
|
-
value:
|
|
2480
|
-
timeout:
|
|
2520
|
+
var inputSchema8 = z9.object({
|
|
2521
|
+
action: z9.enum(["navigate", "screenshot", "getContent", "click", "fill", "submit"]).describe("Browser action to perform"),
|
|
2522
|
+
url: z9.string().url().optional().describe("URL to navigate to (required for navigate action)"),
|
|
2523
|
+
selector: z9.string().optional().describe("CSS selector for click/fill/submit actions"),
|
|
2524
|
+
value: z9.string().optional().describe("Value to fill in input fields"),
|
|
2525
|
+
timeout: z9.number().int().positive().optional().describe("Timeout in milliseconds (default: 30000)")
|
|
2481
2526
|
});
|
|
2482
2527
|
var parameters8 = toToolParameters(inputSchema8);
|
|
2483
2528
|
var description8 = `Control a headless web browser. Navigate to URLs, take screenshots, and interact with web pages.
|
|
@@ -2625,12 +2670,12 @@ var webbrowserTool = {
|
|
|
2625
2670
|
};
|
|
2626
2671
|
|
|
2627
2672
|
// src/tools/websearch/websearch.ts
|
|
2628
|
-
import { z as
|
|
2629
|
-
var inputSchema9 =
|
|
2630
|
-
query:
|
|
2631
|
-
max_results:
|
|
2632
|
-
search_depth:
|
|
2633
|
-
topic:
|
|
2673
|
+
import { z as z10 } from "zod";
|
|
2674
|
+
var inputSchema9 = z10.object({
|
|
2675
|
+
query: z10.string().min(1, "\u5FC5\u987B\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD").max(400, "\u641C\u7D22\u5173\u952E\u8BCD\u592A\u957F\uFF08>400 \u5B57\uFF09").describe("\u641C\u7D22\u5173\u952E\u8BCD\uFF0C\u5EFA\u8BAE\u81EA\u7136\u8BED\u8A00\u63CF\u8FF0\u9700\u8981\u67E5\u7684\u4FE1\u606F"),
|
|
2676
|
+
max_results: z10.number().int().min(1).max(20).optional().describe("\u8FD4\u56DE\u7ED3\u679C\u6570\u91CF\uFF0C1-20\uFF0C\u9ED8\u8BA4 5"),
|
|
2677
|
+
search_depth: z10.enum(["basic", "advanced"]).optional().describe("basic \u5FEB\u4F46\u6D45\uFF1Badvanced \u6162\u4F46\u6DF1\uFF08\u542B answer \u6458\u8981\uFF09\uFF0C\u9ED8\u8BA4 basic"),
|
|
2678
|
+
topic: z10.enum(["general", "news"]).optional().describe("general=\u901A\u7528\u7F51\u9875\uFF1Bnews=\u504F\u65B0\u95FB\u6E90\uFF1B\u9ED8\u8BA4 general")
|
|
2634
2679
|
});
|
|
2635
2680
|
var parameters9 = toToolParameters(inputSchema9);
|
|
2636
2681
|
var description9 = `- Searches the public web via the Tavily Search API and returns structured results.
|
|
@@ -2730,14 +2775,14 @@ var webSearchTool = {
|
|
|
2730
2775
|
};
|
|
2731
2776
|
|
|
2732
2777
|
// src/tools/write/write.ts
|
|
2733
|
-
import { existsSync as
|
|
2778
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2734
2779
|
import { mkdir as mkdir5, stat as stat4, writeFile as writeFile5 } from "fs/promises";
|
|
2735
2780
|
import { dirname as dirname6 } from "path";
|
|
2736
|
-
import { z as
|
|
2781
|
+
import { z as z11 } from "zod";
|
|
2737
2782
|
var MAX_WRITE_SIZE_BYTES = 1024 * 1024 * 1024;
|
|
2738
|
-
var inputSchema10 =
|
|
2739
|
-
file_path:
|
|
2740
|
-
content:
|
|
2783
|
+
var inputSchema10 = z11.object({
|
|
2784
|
+
file_path: filePathField("\u5199\u5165"),
|
|
2785
|
+
content: z11.string().describe("\u6587\u4EF6\u5B8C\u6574\u5185\u5BB9\uFF08\u4F1A\u8986\u76D6\u65E2\u6709\u5185\u5BB9\uFF09")
|
|
2741
2786
|
});
|
|
2742
2787
|
var parameters10 = toToolParameters(inputSchema10);
|
|
2743
2788
|
var description10 = `Writes a file to the local filesystem.
|
|
@@ -2749,7 +2794,7 @@ Usage:
|
|
|
2749
2794
|
- ALWAYS prefer editing existing files in the codebase via the Edit tool. NEVER write new files unless explicitly required.
|
|
2750
2795
|
- NEVER create documentation files (*.md) or README files unless explicitly requested by the User.`;
|
|
2751
2796
|
async function call10(input) {
|
|
2752
|
-
const pathResult =
|
|
2797
|
+
const pathResult = resolveToolPath(input.file_path);
|
|
2753
2798
|
if (!pathResult.ok) return pathResult;
|
|
2754
2799
|
const filePath = pathResult.resolvedPath;
|
|
2755
2800
|
const freshness = assertFresh(filePath);
|
|
@@ -2766,7 +2811,7 @@ async function call10(input) {
|
|
|
2766
2811
|
try {
|
|
2767
2812
|
await mkdir5(dirname6(filePath), { recursive: true });
|
|
2768
2813
|
let originalSize = 0;
|
|
2769
|
-
const fileExisted =
|
|
2814
|
+
const fileExisted = existsSync7(filePath);
|
|
2770
2815
|
if (fileExisted) {
|
|
2771
2816
|
try {
|
|
2772
2817
|
const st = await stat4(filePath);
|
|
@@ -2795,8 +2840,10 @@ async function call10(input) {
|
|
|
2795
2840
|
} else {
|
|
2796
2841
|
await writeFile5(filePath, contentToWrite, "utf8");
|
|
2797
2842
|
}
|
|
2843
|
+
recordRead(filePath);
|
|
2798
2844
|
const action = fileExisted ? "\u5DF2\u8986\u76D6" : "\u5DF2\u521B\u5EFA\u65B0\u6587\u4EF6";
|
|
2799
|
-
const
|
|
2845
|
+
const newSize = Buffer.byteLength(contentToWrite, "utf8");
|
|
2846
|
+
const sizeInfo = fileExisted ? `\uFF08\u539F\u6587\u4EF6 ${originalSize} \u5B57\u8282 \u2192 \u65B0\u5185\u5BB9 ${newSize} \u5B57\u8282\uFF09` : `\uFF08${newSize} \u5B57\u8282\uFF09`;
|
|
2800
2847
|
const bomInfo = bomEncoding === "utf8-bom" ? "\uFF0C\u5DF2\u4FDD\u7559 UTF-8 BOM" : "";
|
|
2801
2848
|
return {
|
|
2802
2849
|
ok: true,
|
|
@@ -2876,39 +2923,52 @@ import { Box as Box7, Text as Text7 } from "ink";
|
|
|
2876
2923
|
import { useCallback, useMemo, useState } from "react";
|
|
2877
2924
|
import { Box, Text, useApp, useInput } from "ink";
|
|
2878
2925
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2879
|
-
var
|
|
2926
|
+
var FALLBACK_CONTEXT_WINDOW = 128e3;
|
|
2880
2927
|
var PRESETS = [
|
|
2881
2928
|
{
|
|
2882
2929
|
name: "minimax",
|
|
2883
2930
|
label: "MiniMax (\u6D77\u87BA)",
|
|
2884
2931
|
baseURL: "https://api.minimax.chat/v1",
|
|
2885
|
-
models: ["MiniMax-M2.7", "MiniMax-M1", "abab6.5s-chat"]
|
|
2932
|
+
models: ["MiniMax-M2.7", "MiniMax-M1", "abab6.5s-chat"],
|
|
2933
|
+
contextWindow: 204800
|
|
2886
2934
|
},
|
|
2887
2935
|
{
|
|
2888
2936
|
name: "deepseek",
|
|
2889
2937
|
label: "DeepSeek",
|
|
2890
2938
|
baseURL: "https://api.deepseek.com/v1",
|
|
2891
|
-
models: ["deepseek-chat", "deepseek-reasoner"]
|
|
2939
|
+
models: ["deepseek-chat", "deepseek-reasoner"],
|
|
2940
|
+
contextWindow: 128e3
|
|
2892
2941
|
},
|
|
2893
2942
|
{
|
|
2894
2943
|
name: "openai",
|
|
2895
2944
|
label: "OpenAI",
|
|
2896
2945
|
baseURL: "https://api.openai.com/v1",
|
|
2897
|
-
models: ["gpt-4o", "gpt-4o-mini"]
|
|
2946
|
+
models: ["gpt-4o", "gpt-4o-mini"],
|
|
2947
|
+
contextWindow: 128e3
|
|
2898
2948
|
},
|
|
2899
2949
|
{
|
|
2900
2950
|
name: "moonshot",
|
|
2901
2951
|
label: "Moonshot (Kimi)",
|
|
2902
2952
|
baseURL: "https://api.moonshot.cn/v1",
|
|
2903
|
-
models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"]
|
|
2953
|
+
models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
|
|
2954
|
+
contextWindow: 128e3,
|
|
2955
|
+
modelContextWindows: {
|
|
2956
|
+
"moonshot-v1-8k": 8e3,
|
|
2957
|
+
"moonshot-v1-32k": 32e3,
|
|
2958
|
+
"moonshot-v1-128k": 128e3
|
|
2959
|
+
}
|
|
2904
2960
|
},
|
|
2905
2961
|
{
|
|
2906
2962
|
name: "custom",
|
|
2907
2963
|
label: "\u81EA\u5B9A\u4E49\uFF08\u624B\u52A8\u586B baseURL\uFF09",
|
|
2908
2964
|
baseURL: "",
|
|
2909
|
-
models: []
|
|
2965
|
+
models: [],
|
|
2966
|
+
contextWindow: FALLBACK_CONTEXT_WINDOW
|
|
2910
2967
|
}
|
|
2911
2968
|
];
|
|
2969
|
+
function resolveContextWindow(preset, model) {
|
|
2970
|
+
return preset.modelContextWindows?.[model] ?? preset.contextWindow ?? FALLBACK_CONTEXT_WINDOW;
|
|
2971
|
+
}
|
|
2912
2972
|
function ConfigWizard({ onSuccess }) {
|
|
2913
2973
|
const { exit } = useApp();
|
|
2914
2974
|
const [step, setStep] = useState("preset");
|
|
@@ -2937,51 +2997,68 @@ function ConfigWizard({ onSuccess }) {
|
|
|
2937
2997
|
},
|
|
2938
2998
|
[baseURL, model, preset]
|
|
2939
2999
|
);
|
|
2940
|
-
const handleTest = useCallback(
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3000
|
+
const handleTest = useCallback(
|
|
3001
|
+
async (finalModel) => {
|
|
3002
|
+
setStep("testing");
|
|
3003
|
+
setErrorMsg(null);
|
|
3004
|
+
try {
|
|
3005
|
+
const url = `${baseURL.replace(/\/$/, "")}/chat/completions`;
|
|
3006
|
+
const resp = await fetch(url, {
|
|
3007
|
+
method: "POST",
|
|
3008
|
+
headers: {
|
|
3009
|
+
"Content-Type": "application/json",
|
|
3010
|
+
Authorization: `Bearer ${apiKey}`
|
|
3011
|
+
},
|
|
3012
|
+
body: JSON.stringify({
|
|
3013
|
+
model: finalModel,
|
|
3014
|
+
messages: [{ role: "user", content: "ping" }],
|
|
3015
|
+
max_tokens: 5,
|
|
3016
|
+
stream: false
|
|
3017
|
+
})
|
|
3018
|
+
});
|
|
3019
|
+
if (!resp.ok) {
|
|
3020
|
+
const body = await resp.text().catch(() => "");
|
|
3021
|
+
throw new Error(
|
|
3022
|
+
`HTTP ${resp.status}: ${body.slice(0, 200) || resp.statusText}`
|
|
3023
|
+
);
|
|
3024
|
+
}
|
|
3025
|
+
const data = await resp.json();
|
|
3026
|
+
if (!Array.isArray(data.choices)) {
|
|
3027
|
+
throw new Error("\u54CD\u5E94\u4E2D\u6CA1\u6709 choices \u5B57\u6BB5\uFF0C\u53EF\u80FD\u4E0D\u662F OpenAI \u517C\u5BB9\u534F\u8BAE");
|
|
3028
|
+
}
|
|
3029
|
+
setDraft("");
|
|
3030
|
+
setStep("tavily");
|
|
3031
|
+
} catch (e) {
|
|
3032
|
+
setErrorMsg(e.message || "\u8FDE\u63A5\u5931\u8D25");
|
|
3033
|
+
setStep("error");
|
|
2965
3034
|
}
|
|
3035
|
+
},
|
|
3036
|
+
[apiKey, baseURL]
|
|
3037
|
+
);
|
|
3038
|
+
const finalize = useCallback(
|
|
3039
|
+
async (finalModel, tavilyApiKey) => {
|
|
3040
|
+
const contextWindow = resolveContextWindow(preset, finalModel);
|
|
2966
3041
|
await saveConfig({
|
|
2967
3042
|
baseURL,
|
|
2968
3043
|
apiKey,
|
|
2969
|
-
model,
|
|
3044
|
+
model: finalModel,
|
|
2970
3045
|
provider: preset.name,
|
|
2971
|
-
contextWindow
|
|
3046
|
+
contextWindow,
|
|
3047
|
+
tavilyApiKey
|
|
2972
3048
|
});
|
|
3049
|
+
if (tavilyApiKey) {
|
|
3050
|
+
process.env.TAVILY_API_KEY = tavilyApiKey;
|
|
3051
|
+
}
|
|
2973
3052
|
onSuccess({
|
|
2974
3053
|
name: preset.name,
|
|
2975
3054
|
baseURL,
|
|
2976
3055
|
apiKey,
|
|
2977
|
-
model,
|
|
2978
|
-
contextWindow
|
|
3056
|
+
model: finalModel,
|
|
3057
|
+
contextWindow
|
|
2979
3058
|
});
|
|
2980
|
-
}
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
}
|
|
2984
|
-
}, [apiKey, baseURL, model, onSuccess, preset.name]);
|
|
3059
|
+
},
|
|
3060
|
+
[apiKey, baseURL, onSuccess, preset]
|
|
3061
|
+
);
|
|
2985
3062
|
useInput((input, key) => {
|
|
2986
3063
|
if (key.escape || key.ctrl && input === "c") {
|
|
2987
3064
|
exit();
|
|
@@ -3036,9 +3113,10 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3036
3113
|
}
|
|
3037
3114
|
}
|
|
3038
3115
|
if (key.return) {
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3116
|
+
const finalModel = draft.trim();
|
|
3117
|
+
if (finalModel.length === 0) return;
|
|
3118
|
+
setModel(finalModel);
|
|
3119
|
+
void handleTest(finalModel);
|
|
3042
3120
|
} else if (key.backspace || key.delete) {
|
|
3043
3121
|
setDraft((s) => s.slice(0, -1));
|
|
3044
3122
|
} else if (input && !key.meta && !key.ctrl && !key.upArrow && !key.downArrow) {
|
|
@@ -3046,6 +3124,17 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3046
3124
|
}
|
|
3047
3125
|
return;
|
|
3048
3126
|
}
|
|
3127
|
+
if (step === "tavily") {
|
|
3128
|
+
if (key.return) {
|
|
3129
|
+
const tavilyApiKey = draft.trim().length > 0 ? draft.trim() : void 0;
|
|
3130
|
+
void finalize(model, tavilyApiKey);
|
|
3131
|
+
} else if (key.backspace || key.delete) {
|
|
3132
|
+
setDraft((s) => s.slice(0, -1));
|
|
3133
|
+
} else if (input && !key.meta && !key.ctrl) {
|
|
3134
|
+
setDraft((s) => s + input);
|
|
3135
|
+
}
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3049
3138
|
if (step === "error") {
|
|
3050
3139
|
if (key.return) {
|
|
3051
3140
|
enterStep("preset");
|
|
@@ -3058,7 +3147,7 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3058
3147
|
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "minimal-agent \xB7 \u9996\u6B21\u914D\u7F6E\u5411\u5BFC" }) }),
|
|
3059
3148
|
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u6309 ESC \u6216 Ctrl+C \u9000\u51FA\uFF08\u4E0D\u5199\u914D\u7F6E\uFF0C\u4E0B\u6B21\u542F\u52A8\u7EE7\u7EED\u5411\u5BFC\uFF09" }) }),
|
|
3060
3149
|
step === "preset" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3061
|
-
/* @__PURE__ */ jsx(Text, { children: "Step 1/
|
|
3150
|
+
/* @__PURE__ */ jsx(Text, { children: "Step 1/5 \xB7 \u9009\u62E9 provider \u9884\u8BBE\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09" }),
|
|
3062
3151
|
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: PRESETS.map((p, i) => /* @__PURE__ */ jsxs(Text, { color: i === presetIndex ? "cyan" : void 0, children: [
|
|
3063
3152
|
i === presetIndex ? "> " : " ",
|
|
3064
3153
|
p.label,
|
|
@@ -3066,12 +3155,12 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3066
3155
|
] }, p.name)) })
|
|
3067
3156
|
] }),
|
|
3068
3157
|
step === "baseURL" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3069
|
-
/* @__PURE__ */ jsx(Text, { children: "Step 2/
|
|
3158
|
+
/* @__PURE__ */ jsx(Text, { children: "Step 2/5 \xB7 \u8F93\u5165 API base URL\uFF08\u9ED8\u8BA4\u4E3A\u9884\u8BBE\u503C\uFF0C\u53EF\u6539\uFF09" }),
|
|
3070
3159
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsx(Text, { children: draft || " " }) }),
|
|
3071
3160
|
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Enter \u786E\u8BA4 \xB7 Backspace \u5220\u9664" })
|
|
3072
3161
|
] }),
|
|
3073
3162
|
step === "apiKey" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3074
|
-
/* @__PURE__ */ jsx(Text, { children: "Step 3/
|
|
3163
|
+
/* @__PURE__ */ jsx(Text, { children: "Step 3/5 \xB7 \u8F93\u5165 API key\uFF08\u8F93\u5165\u5185\u5BB9\u4E0D\u4F1A\u663E\u793A\uFF09" }),
|
|
3075
3164
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsx(Text, { children: maskedApiKey || " " }) }),
|
|
3076
3165
|
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
3077
3166
|
"Enter \u786E\u8BA4 \xB7 Backspace \u5220\u9664\uFF08\u5DF2\u8F93\u5165 ",
|
|
@@ -3081,7 +3170,7 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3081
3170
|
] }),
|
|
3082
3171
|
step === "model" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3083
3172
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3084
|
-
"Step 4/
|
|
3173
|
+
"Step 4/5 \xB7 \u8F93\u5165\u6216\u9009\u62E9 model",
|
|
3085
3174
|
preset.models.length > 0 ? "\uFF08\u2191\u2193 \u5207\u6362\u9884\u8BBE\uFF0C\u6216\u76F4\u63A5\u7F16\u8F91\uFF09" : ""
|
|
3086
3175
|
] }),
|
|
3087
3176
|
preset.models.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: preset.models.map((m, i) => /* @__PURE__ */ jsxs(Text, { color: i === modelIndex ? "cyan" : "gray", children: [
|
|
@@ -3102,6 +3191,17 @@ function ConfigWizard({ onSuccess }) {
|
|
|
3102
3191
|
model
|
|
3103
3192
|
] })
|
|
3104
3193
|
] }),
|
|
3194
|
+
step === "tavily" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3195
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "\u2713 LLM \u8FDE\u63A5\u6D4B\u8BD5\u901A\u8FC7" }),
|
|
3196
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: "Step 5/5 \xB7 \u53EF\u9009 - Tavily API key\uFF08\u7528\u4E8E WebSearch \u5DE5\u5177\uFF09" }) }),
|
|
3197
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsx(Text, { children: maskedApiKey || " " }) }),
|
|
3198
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "\u76F4\u63A5 Enter \u8DF3\u8FC7\uFF08\u4E4B\u540E\u53EF\u5728\u5BF9\u8BDD\u91CC\u8F93\u5165 /config \u6DFB\u52A0\uFF0C\u6216\u8BBE env TAVILY_API_KEY\uFF09" }),
|
|
3199
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
3200
|
+
"\u514D\u8D39 key \u7533\u8BF7\uFF1Ahttps://tavily.com/ \xB7 \u5DF2\u8F93\u5165 ",
|
|
3201
|
+
draft.length,
|
|
3202
|
+
" \u5B57\u7B26"
|
|
3203
|
+
] })
|
|
3204
|
+
] }),
|
|
3105
3205
|
step === "error" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3106
3206
|
/* @__PURE__ */ jsx(Text, { color: "red", children: "\u2717 \u8FDE\u63A5\u6D4B\u8BD5\u5931\u8D25" }),
|
|
3107
3207
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: errorMsg ?? "\u672A\u77E5\u9519\u8BEF" }) }),
|
|
@@ -4231,8 +4331,7 @@ async function reactiveCompactIfApplicable(messages, provider, error, state = de
|
|
|
4231
4331
|
|
|
4232
4332
|
// src/plugins/commandRouter.ts
|
|
4233
4333
|
import { readFile as readFile9, readdir as readdir3 } from "fs/promises";
|
|
4234
|
-
import { join as
|
|
4235
|
-
var PLUGINS_DIR = join6(findPackageRoot(import.meta.url), "plugins");
|
|
4334
|
+
import { join as join7 } from "path";
|
|
4236
4335
|
var pluginCache = /* @__PURE__ */ new Map();
|
|
4237
4336
|
var discoveryDone = false;
|
|
4238
4337
|
function stripQuotes2(s) {
|
|
@@ -4257,7 +4356,7 @@ function parseMarkdownFrontmatter(content) {
|
|
|
4257
4356
|
}
|
|
4258
4357
|
async function loadPlugin(pluginDirPath) {
|
|
4259
4358
|
const dirName = pluginDirPath.split("/").pop() ?? pluginDirPath;
|
|
4260
|
-
const manifestPath =
|
|
4359
|
+
const manifestPath = join7(pluginDirPath, ".claude-plugin", "plugin.json");
|
|
4261
4360
|
let manifestName = dirName;
|
|
4262
4361
|
let manifestVersion;
|
|
4263
4362
|
let manifestDesc;
|
|
@@ -4269,13 +4368,13 @@ async function loadPlugin(pluginDirPath) {
|
|
|
4269
4368
|
manifestDesc = parsed.description;
|
|
4270
4369
|
} catch {
|
|
4271
4370
|
}
|
|
4272
|
-
const commandsDir =
|
|
4371
|
+
const commandsDir = join7(pluginDirPath, "commands");
|
|
4273
4372
|
const commands = [];
|
|
4274
4373
|
try {
|
|
4275
4374
|
const entries = await readdir3(commandsDir, { withFileTypes: true });
|
|
4276
4375
|
for (const entry of entries) {
|
|
4277
4376
|
if (!entry.name.endsWith(".md")) continue;
|
|
4278
|
-
const cmdPath =
|
|
4377
|
+
const cmdPath = join7(commandsDir, entry.name);
|
|
4279
4378
|
try {
|
|
4280
4379
|
const content = await readFile9(cmdPath, "utf8");
|
|
4281
4380
|
const fm = parseMarkdownFrontmatter(content);
|
|
@@ -4294,7 +4393,7 @@ async function loadPlugin(pluginDirPath) {
|
|
|
4294
4393
|
}
|
|
4295
4394
|
} catch {
|
|
4296
4395
|
}
|
|
4297
|
-
const hooksJsonPath =
|
|
4396
|
+
const hooksJsonPath = join7(pluginDirPath, "hooks", "hooks.json");
|
|
4298
4397
|
let hasStopHook = false;
|
|
4299
4398
|
try {
|
|
4300
4399
|
const hooksRaw = await readFile9(hooksJsonPath, "utf8");
|
|
@@ -4321,17 +4420,20 @@ async function discoverPlugins() {
|
|
|
4321
4420
|
}
|
|
4322
4421
|
pluginCache.clear();
|
|
4323
4422
|
discoveryDone = true;
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4423
|
+
const searchPaths = getResourceSearchPaths("plugins", import.meta.url);
|
|
4424
|
+
for (const root of searchPaths) {
|
|
4425
|
+
try {
|
|
4426
|
+
const entries = await readdir3(root, { withFileTypes: true });
|
|
4427
|
+
for (const entry of entries) {
|
|
4428
|
+
if (!entry.isDirectory()) continue;
|
|
4429
|
+
if (entry.name.startsWith(".")) continue;
|
|
4430
|
+
const plugin = await loadPlugin(join7(root, entry.name));
|
|
4431
|
+
if (!plugin) continue;
|
|
4432
|
+
if (pluginCache.has(plugin.name)) continue;
|
|
4331
4433
|
pluginCache.set(plugin.name, plugin);
|
|
4332
4434
|
}
|
|
4435
|
+
} catch {
|
|
4333
4436
|
}
|
|
4334
|
-
} catch {
|
|
4335
4437
|
}
|
|
4336
4438
|
return Array.from(pluginCache.values());
|
|
4337
4439
|
}
|
|
@@ -4391,10 +4493,10 @@ function getActiveStopHookPlugins() {
|
|
|
4391
4493
|
|
|
4392
4494
|
// src/plugins/stopHook.ts
|
|
4393
4495
|
import { readFile as readFile10 } from "fs/promises";
|
|
4394
|
-
import { join as
|
|
4496
|
+
import { join as join8 } from "path";
|
|
4395
4497
|
import { spawn as spawn4 } from "child_process";
|
|
4396
4498
|
async function loadStopHookConfig(pluginRoot) {
|
|
4397
|
-
const hooksJsonPath =
|
|
4499
|
+
const hooksJsonPath = join8(pluginRoot, "hooks", "hooks.json");
|
|
4398
4500
|
try {
|
|
4399
4501
|
const raw = await readFile10(hooksJsonPath, "utf8");
|
|
4400
4502
|
const parsed = JSON.parse(raw);
|
|
@@ -4433,7 +4535,7 @@ async function executeStopHooks(pluginRoots, transcriptText) {
|
|
|
4433
4535
|
}
|
|
4434
4536
|
function runSingleStopHook(hookConfig, pluginRoot, transcriptText) {
|
|
4435
4537
|
const resolvedCommand = hookConfig.command.replaceAll("${CLAUDE_PLUGIN_ROOT}", pluginRoot);
|
|
4436
|
-
return new Promise((
|
|
4538
|
+
return new Promise((resolve10) => {
|
|
4437
4539
|
const child = spawn4("bash", [resolvedCommand], {
|
|
4438
4540
|
env: {
|
|
4439
4541
|
...process.env,
|
|
@@ -4445,31 +4547,31 @@ function runSingleStopHook(hookConfig, pluginRoot, transcriptText) {
|
|
|
4445
4547
|
stdout += data.toString();
|
|
4446
4548
|
});
|
|
4447
4549
|
child.on("error", () => {
|
|
4448
|
-
|
|
4550
|
+
resolve10({ decision: "pass" });
|
|
4449
4551
|
});
|
|
4450
4552
|
child.on("close", (code) => {
|
|
4451
4553
|
if (code !== 0) {
|
|
4452
|
-
|
|
4554
|
+
resolve10({ decision: "pass" });
|
|
4453
4555
|
return;
|
|
4454
4556
|
}
|
|
4455
4557
|
const trimmed = stdout.trim();
|
|
4456
4558
|
if (!trimmed) {
|
|
4457
|
-
|
|
4559
|
+
resolve10({ decision: "pass" });
|
|
4458
4560
|
return;
|
|
4459
4561
|
}
|
|
4460
4562
|
try {
|
|
4461
4563
|
const parsed = JSON.parse(trimmed);
|
|
4462
4564
|
if (parsed.decision === "block") {
|
|
4463
|
-
|
|
4565
|
+
resolve10({
|
|
4464
4566
|
decision: "block",
|
|
4465
4567
|
reason: typeof parsed.reason === "string" ? parsed.reason : void 0,
|
|
4466
4568
|
systemMessage: typeof parsed.systemMessage === "string" ? parsed.systemMessage : void 0
|
|
4467
4569
|
});
|
|
4468
4570
|
return;
|
|
4469
4571
|
}
|
|
4470
|
-
|
|
4572
|
+
resolve10({ decision: "pass" });
|
|
4471
4573
|
} catch {
|
|
4472
|
-
|
|
4574
|
+
resolve10({ decision: "pass" });
|
|
4473
4575
|
}
|
|
4474
4576
|
});
|
|
4475
4577
|
child.stdin.write(transcriptText);
|
|
@@ -4478,7 +4580,7 @@ function runSingleStopHook(hookConfig, pluginRoot, transcriptText) {
|
|
|
4478
4580
|
}
|
|
4479
4581
|
|
|
4480
4582
|
// src/plugins/verificationGate.ts
|
|
4481
|
-
import { existsSync as
|
|
4583
|
+
import { existsSync as existsSync8, readFileSync } from "fs";
|
|
4482
4584
|
import { spawn as spawn5 } from "child_process";
|
|
4483
4585
|
function parseVerifyArg(arg) {
|
|
4484
4586
|
const colonIdx = arg.indexOf(":");
|
|
@@ -4520,7 +4622,7 @@ function parseVerifyArgs(args) {
|
|
|
4520
4622
|
return checks;
|
|
4521
4623
|
}
|
|
4522
4624
|
function runShell(command, timeout) {
|
|
4523
|
-
return new Promise((
|
|
4625
|
+
return new Promise((resolve10) => {
|
|
4524
4626
|
const isWin = process.platform === "win32";
|
|
4525
4627
|
const child = isWin ? spawn5("cmd", ["/c", command], { timeout, env: process.env }) : spawn5("bash", ["-c", command], { timeout, env: process.env });
|
|
4526
4628
|
let stdout = "";
|
|
@@ -4532,10 +4634,10 @@ function runShell(command, timeout) {
|
|
|
4532
4634
|
stderr += d.toString();
|
|
4533
4635
|
});
|
|
4534
4636
|
child.on("error", () => {
|
|
4535
|
-
|
|
4637
|
+
resolve10({ exitCode: null, stdout, stderr, errored: true });
|
|
4536
4638
|
});
|
|
4537
4639
|
child.on("close", (code) => {
|
|
4538
|
-
|
|
4640
|
+
resolve10({ exitCode: code, stdout, stderr, errored: false });
|
|
4539
4641
|
});
|
|
4540
4642
|
});
|
|
4541
4643
|
}
|
|
@@ -4555,7 +4657,7 @@ async function verifyShell(command, timeout) {
|
|
|
4555
4657
|
};
|
|
4556
4658
|
}
|
|
4557
4659
|
function verifyFileExists(file) {
|
|
4558
|
-
const exists =
|
|
4660
|
+
const exists = existsSync8(file);
|
|
4559
4661
|
return {
|
|
4560
4662
|
check: { type: "file_exists", file },
|
|
4561
4663
|
passed: exists,
|
|
@@ -4656,8 +4758,8 @@ function formatCheckName(check) {
|
|
|
4656
4758
|
|
|
4657
4759
|
// src/plugins/goalState.ts
|
|
4658
4760
|
import { mkdir as mkdir6, appendFile, writeFile as writeFile6, unlink as unlink2, rmdir as rmdir2 } from "fs/promises";
|
|
4659
|
-
import { existsSync as
|
|
4660
|
-
import { join as
|
|
4761
|
+
import { existsSync as existsSync9, readFileSync as readFileSync2 } from "fs";
|
|
4762
|
+
import { join as join9 } from "path";
|
|
4661
4763
|
var Phase = /* @__PURE__ */ ((Phase2) => {
|
|
4662
4764
|
Phase2["PLAN"] = "plan";
|
|
4663
4765
|
Phase2["BUILD"] = "build";
|
|
@@ -4699,13 +4801,13 @@ var GoalState = class {
|
|
|
4699
4801
|
dir;
|
|
4700
4802
|
constructor(workspaceDir, sessionTag) {
|
|
4701
4803
|
const suffix = sessionTag ? `-${sessionTag}` : "";
|
|
4702
|
-
this.dir =
|
|
4804
|
+
this.dir = join9(workspaceDir, `.minimal-agent${suffix}`);
|
|
4703
4805
|
}
|
|
4704
4806
|
async reset() {
|
|
4705
4807
|
const files = ["goal.md", "completion.md", "phase.md", "progress.md", "learnings.md", "decisions.md"];
|
|
4706
4808
|
for (const f of files) {
|
|
4707
4809
|
try {
|
|
4708
|
-
await unlink2(
|
|
4810
|
+
await unlink2(join9(this.dir, f));
|
|
4709
4811
|
} catch {
|
|
4710
4812
|
}
|
|
4711
4813
|
}
|
|
@@ -4724,22 +4826,22 @@ ${goal}
|
|
|
4724
4826
|
decisions: ""
|
|
4725
4827
|
};
|
|
4726
4828
|
for (const [name, content] of Object.entries(files)) {
|
|
4727
|
-
const path2 =
|
|
4728
|
-
if (!
|
|
4829
|
+
const path2 = join9(this.dir, `${name}.md`);
|
|
4830
|
+
if (!existsSync9(path2)) {
|
|
4729
4831
|
await writeFile6(path2, content);
|
|
4730
4832
|
}
|
|
4731
4833
|
}
|
|
4732
4834
|
}
|
|
4733
4835
|
get goal() {
|
|
4734
4836
|
try {
|
|
4735
|
-
return readFileSync2(
|
|
4837
|
+
return readFileSync2(join9(this.dir, "goal.md"), "utf8").trim();
|
|
4736
4838
|
} catch {
|
|
4737
4839
|
return "";
|
|
4738
4840
|
}
|
|
4739
4841
|
}
|
|
4740
4842
|
get completionCriteria() {
|
|
4741
4843
|
try {
|
|
4742
|
-
const raw = readFileSync2(
|
|
4844
|
+
const raw = readFileSync2(join9(this.dir, "completion.md"), "utf8").trim();
|
|
4743
4845
|
return JSON.parse(raw);
|
|
4744
4846
|
} catch {
|
|
4745
4847
|
return [];
|
|
@@ -4747,7 +4849,7 @@ ${goal}
|
|
|
4747
4849
|
}
|
|
4748
4850
|
get currentPhase() {
|
|
4749
4851
|
try {
|
|
4750
|
-
const raw = readFileSync2(
|
|
4852
|
+
const raw = readFileSync2(join9(this.dir, "phase.md"), "utf8").trim();
|
|
4751
4853
|
if (VALID_PHASES.has(raw)) {
|
|
4752
4854
|
return raw;
|
|
4753
4855
|
}
|
|
@@ -4770,24 +4872,24 @@ ${goal}
|
|
|
4770
4872
|
`\u975E\u6CD5\u9636\u6BB5\u5207\u6362: ${current} \u2192 ${phase}\u3002\u8BE5\u76EE\u6807\u9636\u6BB5\u4E0D\u5728 PHASE_TRANSITIONS[${current}] \u7684\u53EF\u8FBE\u96C6\u5408\u5185\uFF0C\u9700\u8981\u8D70 forceSetPhase\u3002`
|
|
4771
4873
|
);
|
|
4772
4874
|
}
|
|
4773
|
-
await writeFile6(
|
|
4875
|
+
await writeFile6(join9(this.dir, "phase.md"), phase);
|
|
4774
4876
|
await this.appendProgress(`PHASE \u2192 ${phase}: ${reason}`);
|
|
4775
4877
|
}
|
|
4776
4878
|
async forceSetPhase(phase, reason) {
|
|
4777
4879
|
if (!VALID_PHASES.has(phase)) {
|
|
4778
4880
|
throw new Error(`Invalid phase: ${phase}`);
|
|
4779
4881
|
}
|
|
4780
|
-
await writeFile6(
|
|
4882
|
+
await writeFile6(join9(this.dir, "phase.md"), phase);
|
|
4781
4883
|
await this.appendProgress(`PHASE \u2192 ${phase}: ${reason}`);
|
|
4782
4884
|
}
|
|
4783
4885
|
async appendProgress(line) {
|
|
4784
4886
|
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
4785
|
-
await appendFile(
|
|
4887
|
+
await appendFile(join9(this.dir, "progress.md"), `[${timestamp}] ${line}
|
|
4786
4888
|
`);
|
|
4787
4889
|
}
|
|
4788
4890
|
tailProgress(n) {
|
|
4789
4891
|
try {
|
|
4790
|
-
const content = readFileSync2(
|
|
4892
|
+
const content = readFileSync2(join9(this.dir, "progress.md"), "utf8");
|
|
4791
4893
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
4792
4894
|
return lines.slice(-n).join("\n");
|
|
4793
4895
|
} catch {
|
|
@@ -4795,12 +4897,12 @@ ${goal}
|
|
|
4795
4897
|
}
|
|
4796
4898
|
}
|
|
4797
4899
|
async appendLearning(lesson) {
|
|
4798
|
-
await appendFile(
|
|
4900
|
+
await appendFile(join9(this.dir, "learnings.md"), `- ${lesson}
|
|
4799
4901
|
`);
|
|
4800
4902
|
}
|
|
4801
4903
|
get learnings() {
|
|
4802
4904
|
try {
|
|
4803
|
-
const raw = readFileSync2(
|
|
4905
|
+
const raw = readFileSync2(join9(this.dir, "learnings.md"), "utf8").trim();
|
|
4804
4906
|
if (!raw) return "";
|
|
4805
4907
|
const lines = raw.split("\n").filter(Boolean);
|
|
4806
4908
|
return lines.slice(-LEARNINGS_TAIL_LINES).join("\n");
|
|
@@ -4818,12 +4920,12 @@ ${goal}
|
|
|
4818
4920
|
reasoning
|
|
4819
4921
|
};
|
|
4820
4922
|
const line = JSON.stringify(entry);
|
|
4821
|
-
await appendFile(
|
|
4923
|
+
await appendFile(join9(this.dir, "decisions.md"), `${line}
|
|
4822
4924
|
`);
|
|
4823
4925
|
}
|
|
4824
4926
|
findSimilarDecisions(ctx, k = 3) {
|
|
4825
4927
|
try {
|
|
4826
|
-
const content = readFileSync2(
|
|
4928
|
+
const content = readFileSync2(join9(this.dir, "decisions.md"), "utf8");
|
|
4827
4929
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
4828
4930
|
const entries = [];
|
|
4829
4931
|
for (const line of lines) {
|
|
@@ -4843,7 +4945,7 @@ ${goal}
|
|
|
4843
4945
|
}
|
|
4844
4946
|
summarizeDecisions(maxEntries = 5) {
|
|
4845
4947
|
try {
|
|
4846
|
-
const content = readFileSync2(
|
|
4948
|
+
const content = readFileSync2(join9(this.dir, "decisions.md"), "utf8");
|
|
4847
4949
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
4848
4950
|
const entries = [];
|
|
4849
4951
|
for (const line of lines.slice(-maxEntries * 2)) {
|
|
@@ -4889,7 +4991,7 @@ ${recentProgress}`);
|
|
|
4889
4991
|
const files = ["goal.md", "completion.md", "phase.md", "progress.md", "learnings.md", "decisions.md"];
|
|
4890
4992
|
for (const f of files) {
|
|
4891
4993
|
try {
|
|
4892
|
-
await unlink2(
|
|
4994
|
+
await unlink2(join9(this.dir, f));
|
|
4893
4995
|
} catch {
|
|
4894
4996
|
}
|
|
4895
4997
|
}
|
|
@@ -5715,13 +5817,13 @@ function handleEvent2(event, output, verbose) {
|
|
|
5715
5817
|
}
|
|
5716
5818
|
}
|
|
5717
5819
|
function readFromStdin() {
|
|
5718
|
-
return new Promise((
|
|
5820
|
+
return new Promise((resolve10) => {
|
|
5719
5821
|
let data = "";
|
|
5720
5822
|
let settled = false;
|
|
5721
5823
|
const timer = setTimeout(() => {
|
|
5722
5824
|
if (!settled) {
|
|
5723
5825
|
settled = true;
|
|
5724
|
-
|
|
5826
|
+
resolve10("");
|
|
5725
5827
|
}
|
|
5726
5828
|
}, STDIN_TIMEOUT_MS);
|
|
5727
5829
|
process.stdin.setEncoding("utf8");
|
|
@@ -5732,7 +5834,7 @@ function readFromStdin() {
|
|
|
5732
5834
|
if (!settled) {
|
|
5733
5835
|
clearTimeout(timer);
|
|
5734
5836
|
settled = true;
|
|
5735
|
-
|
|
5837
|
+
resolve10(data.trim());
|
|
5736
5838
|
}
|
|
5737
5839
|
}
|
|
5738
5840
|
process.stdin.on("data", onData);
|
|
@@ -5748,14 +5850,15 @@ async function main() {
|
|
|
5748
5850
|
const args = process.argv.slice(2);
|
|
5749
5851
|
const dirArg = extractCwdArg(args);
|
|
5750
5852
|
if (dirArg) {
|
|
5751
|
-
const abs =
|
|
5752
|
-
if (!
|
|
5853
|
+
const abs = resolve9(dirArg);
|
|
5854
|
+
if (!existsSync10(abs)) {
|
|
5753
5855
|
mkdirSync(abs, { recursive: true });
|
|
5754
5856
|
}
|
|
5755
5857
|
process.chdir(abs);
|
|
5756
5858
|
}
|
|
5757
5859
|
initWorkingDir();
|
|
5758
5860
|
await migrateLegacyContext(getWorkingDir());
|
|
5861
|
+
await applyToolKeysToEnv();
|
|
5759
5862
|
if (args.includes("-h") || args.includes("--help")) {
|
|
5760
5863
|
printHelp();
|
|
5761
5864
|
return;
|