jinzd-ai-cli 0.1.30 → 0.1.32
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/index.js +231 -89
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1663,8 +1663,8 @@ var SessionManager = class {
|
|
|
1663
1663
|
|
|
1664
1664
|
// src/repl/repl.ts
|
|
1665
1665
|
import * as readline from "readline";
|
|
1666
|
-
import { existsSync as
|
|
1667
|
-
import { join as
|
|
1666
|
+
import { existsSync as existsSync19, readFileSync as readFileSync13, readdirSync as readdirSync9, statSync as statSync7 } from "fs";
|
|
1667
|
+
import { join as join14, resolve as resolve4, extname as extname4, dirname as dirname5, basename as basename5 } from "path";
|
|
1668
1668
|
import chalk10 from "chalk";
|
|
1669
1669
|
|
|
1670
1670
|
// src/repl/renderer.ts
|
|
@@ -1982,10 +1982,10 @@ Error: ${message}
|
|
|
1982
1982
|
};
|
|
1983
1983
|
|
|
1984
1984
|
// src/repl/commands/index.ts
|
|
1985
|
-
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as
|
|
1986
|
-
import { execSync as
|
|
1985
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
1986
|
+
import { execSync as execSync3 } from "child_process";
|
|
1987
1987
|
import { platform } from "os";
|
|
1988
|
-
import { resolve, dirname as dirname2, join as
|
|
1988
|
+
import { resolve, dirname as dirname2, join as join5, basename } from "path";
|
|
1989
1989
|
import chalk2 from "chalk";
|
|
1990
1990
|
|
|
1991
1991
|
// src/tools/git-context.ts
|
|
@@ -2148,6 +2148,93 @@ var UndoStack = class {
|
|
|
2148
2148
|
};
|
|
2149
2149
|
var undoStack = new UndoStack();
|
|
2150
2150
|
|
|
2151
|
+
// src/repl/clipboard.ts
|
|
2152
|
+
import { execSync as execSync2 } from "child_process";
|
|
2153
|
+
import { existsSync as existsSync5, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
2154
|
+
import { tmpdir } from "os";
|
|
2155
|
+
import { join as join4 } from "path";
|
|
2156
|
+
var CLIPBOARD_TIMEOUT = 5e3;
|
|
2157
|
+
function readClipboardImage() {
|
|
2158
|
+
const outPath = join4(tmpdir(), `aicli-paste-${Date.now()}.png`);
|
|
2159
|
+
try {
|
|
2160
|
+
if (process.platform === "win32") {
|
|
2161
|
+
_readWin32(outPath);
|
|
2162
|
+
} else if (process.platform === "darwin") {
|
|
2163
|
+
_readDarwin(outPath);
|
|
2164
|
+
} else {
|
|
2165
|
+
_readLinux(outPath);
|
|
2166
|
+
}
|
|
2167
|
+
} catch {
|
|
2168
|
+
_cleanup(outPath);
|
|
2169
|
+
return null;
|
|
2170
|
+
}
|
|
2171
|
+
if (!existsSync5(outPath) || statSync(outPath).size === 0) {
|
|
2172
|
+
_cleanup(outPath);
|
|
2173
|
+
return null;
|
|
2174
|
+
}
|
|
2175
|
+
return outPath;
|
|
2176
|
+
}
|
|
2177
|
+
function _readWin32(outPath) {
|
|
2178
|
+
const escapedPath = outPath.replace(/\\/g, "\\\\");
|
|
2179
|
+
const script = [
|
|
2180
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
2181
|
+
"Add-Type -AssemblyName System.Drawing",
|
|
2182
|
+
"$img = [System.Windows.Forms.Clipboard]::GetImage()",
|
|
2183
|
+
`if ($null -ne $img) { $img.Save('${escapedPath}', [System.Drawing.Imaging.ImageFormat]::Png); exit 0 } else { exit 1 }`
|
|
2184
|
+
].join("; ");
|
|
2185
|
+
execSync2(`powershell -NoProfile -NonInteractive -Command "${script}"`, {
|
|
2186
|
+
stdio: "pipe",
|
|
2187
|
+
timeout: CLIPBOARD_TIMEOUT
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
function _readDarwin(outPath) {
|
|
2191
|
+
try {
|
|
2192
|
+
execSync2(`pngpaste "${outPath}"`, { stdio: "pipe", timeout: CLIPBOARD_TIMEOUT });
|
|
2193
|
+
return;
|
|
2194
|
+
} catch {
|
|
2195
|
+
}
|
|
2196
|
+
const script = [
|
|
2197
|
+
"try",
|
|
2198
|
+
" set d to (the clipboard as \xABclass PNGf\xBB)",
|
|
2199
|
+
` set fp to open for access POSIX file "${outPath}" with write permission`,
|
|
2200
|
+
" write d to fp",
|
|
2201
|
+
" close access fp",
|
|
2202
|
+
"end try"
|
|
2203
|
+
].join("\n");
|
|
2204
|
+
execSync2(`osascript -e '${script}'`, { stdio: "pipe", timeout: CLIPBOARD_TIMEOUT });
|
|
2205
|
+
}
|
|
2206
|
+
function _readLinux(outPath) {
|
|
2207
|
+
try {
|
|
2208
|
+
execSync2(`xclip -selection clipboard -t image/png -o > "${outPath}"`, {
|
|
2209
|
+
shell: "/bin/sh",
|
|
2210
|
+
stdio: "pipe",
|
|
2211
|
+
timeout: CLIPBOARD_TIMEOUT
|
|
2212
|
+
});
|
|
2213
|
+
return;
|
|
2214
|
+
} catch {
|
|
2215
|
+
}
|
|
2216
|
+
execSync2(`wl-paste --type image/png > "${outPath}"`, {
|
|
2217
|
+
shell: "/bin/sh",
|
|
2218
|
+
stdio: "pipe",
|
|
2219
|
+
timeout: CLIPBOARD_TIMEOUT
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
function _cleanup(path) {
|
|
2223
|
+
try {
|
|
2224
|
+
if (existsSync5(path)) unlinkSync2(path);
|
|
2225
|
+
} catch {
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
function getClipboardHint() {
|
|
2229
|
+
if (process.platform === "darwin") {
|
|
2230
|
+
return "\u5982 pngpaste \u672A\u5B89\u88C5\uFF0C\u8BF7\u8FD0\u884C\uFF1Abrew install pngpaste";
|
|
2231
|
+
}
|
|
2232
|
+
if (process.platform === "linux") {
|
|
2233
|
+
return "\u8BF7\u5B89\u88C5 xclip\uFF08X11\uFF09\uFF1Asudo apt install xclip\n\u6216 wl-paste\uFF08Wayland\uFF09\uFF1Asudo apt install wl-clipboard";
|
|
2234
|
+
}
|
|
2235
|
+
return "";
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2151
2238
|
// src/repl/commands/index.ts
|
|
2152
2239
|
function fmtCtx(tokens) {
|
|
2153
2240
|
if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
|
|
@@ -2195,19 +2282,19 @@ function scanDirTree(dir, maxDepth = 2, maxEntries = 80) {
|
|
|
2195
2282
|
}
|
|
2196
2283
|
const filtered = entries.filter((e) => !e.startsWith(".") && !SCAN_SKIP_DIRS.has(e));
|
|
2197
2284
|
const sorted = filtered.sort((a, b) => {
|
|
2198
|
-
const aIsDir =
|
|
2199
|
-
const bIsDir =
|
|
2285
|
+
const aIsDir = statSync2(join5(d, a)).isDirectory();
|
|
2286
|
+
const bIsDir = statSync2(join5(d, b)).isDirectory();
|
|
2200
2287
|
if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
|
|
2201
2288
|
return a.localeCompare(b);
|
|
2202
2289
|
});
|
|
2203
2290
|
for (let i = 0; i < sorted.length && count < maxEntries; i++) {
|
|
2204
2291
|
const name = sorted[i];
|
|
2205
|
-
const fullPath =
|
|
2292
|
+
const fullPath = join5(d, name);
|
|
2206
2293
|
const isLast = i === sorted.length - 1;
|
|
2207
2294
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
2208
2295
|
let isDir;
|
|
2209
2296
|
try {
|
|
2210
|
-
isDir =
|
|
2297
|
+
isDir = statSync2(fullPath).isDirectory();
|
|
2211
2298
|
} catch {
|
|
2212
2299
|
continue;
|
|
2213
2300
|
}
|
|
@@ -2229,7 +2316,7 @@ function scanProject(cwd) {
|
|
|
2229
2316
|
configFiles: [],
|
|
2230
2317
|
directoryStructure: ""
|
|
2231
2318
|
};
|
|
2232
|
-
const check = (file) =>
|
|
2319
|
+
const check = (file) => existsSync6(join5(cwd, file));
|
|
2233
2320
|
const configCandidates = [
|
|
2234
2321
|
"package.json",
|
|
2235
2322
|
"tsconfig.json",
|
|
@@ -2256,7 +2343,7 @@ function scanProject(cwd) {
|
|
|
2256
2343
|
info.type = "node";
|
|
2257
2344
|
info.language = check("tsconfig.json") ? "TypeScript" : "JavaScript";
|
|
2258
2345
|
try {
|
|
2259
|
-
const pkg = JSON.parse(readFileSync4(
|
|
2346
|
+
const pkg = JSON.parse(readFileSync4(join5(cwd, "package.json"), "utf-8"));
|
|
2260
2347
|
const scripts = pkg.scripts ?? {};
|
|
2261
2348
|
info.buildCommand = scripts.build ? `npm run build` : void 0;
|
|
2262
2349
|
info.testCommand = scripts.test ? `npm test` : void 0;
|
|
@@ -2337,14 +2424,14 @@ ${info.directoryStructure}
|
|
|
2337
2424
|
function copyToClipboard(text) {
|
|
2338
2425
|
const plat = platform();
|
|
2339
2426
|
if (plat === "win32") {
|
|
2340
|
-
|
|
2427
|
+
execSync3("clip", { input: text, stdio: ["pipe", "ignore", "ignore"] });
|
|
2341
2428
|
} else if (plat === "darwin") {
|
|
2342
|
-
|
|
2429
|
+
execSync3("pbcopy", { input: text, stdio: ["pipe", "ignore", "ignore"] });
|
|
2343
2430
|
} else {
|
|
2344
2431
|
try {
|
|
2345
|
-
|
|
2432
|
+
execSync3("xclip -selection clipboard", { input: text, stdio: ["pipe", "ignore", "ignore"] });
|
|
2346
2433
|
} catch {
|
|
2347
|
-
|
|
2434
|
+
execSync3("xsel --clipboard --input", { input: text, stdio: ["pipe", "ignore", "ignore"] });
|
|
2348
2435
|
}
|
|
2349
2436
|
}
|
|
2350
2437
|
}
|
|
@@ -3045,9 +3132,9 @@ ${text}
|
|
|
3045
3132
|
const cwd = process.cwd();
|
|
3046
3133
|
const gitRoot = getGitRoot(cwd);
|
|
3047
3134
|
const targetDir = gitRoot ?? cwd;
|
|
3048
|
-
const targetPath =
|
|
3135
|
+
const targetPath = join5(targetDir, "AICLI.md");
|
|
3049
3136
|
const force = args.includes("--force");
|
|
3050
|
-
if (
|
|
3137
|
+
if (existsSync6(targetPath) && !force) {
|
|
3051
3138
|
ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
|
|
3052
3139
|
ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
|
|
3053
3140
|
return;
|
|
@@ -3094,6 +3181,25 @@ ${text}
|
|
|
3094
3181
|
}
|
|
3095
3182
|
}
|
|
3096
3183
|
},
|
|
3184
|
+
{
|
|
3185
|
+
name: "paste",
|
|
3186
|
+
description: "Read image from clipboard and send with optional description",
|
|
3187
|
+
usage: "/paste [description]",
|
|
3188
|
+
async execute(args, ctx) {
|
|
3189
|
+
const imgPath = readClipboardImage();
|
|
3190
|
+
if (!imgPath) {
|
|
3191
|
+
const hint = getClipboardHint();
|
|
3192
|
+
ctx.renderer.renderError(
|
|
3193
|
+
"\u526A\u8D34\u677F\u4E2D\u6CA1\u6709\u56FE\u7247\u3002\u8BF7\u5148\u5728\u5176\u4ED6\u7A0B\u5E8F\u4E2D\u590D\u5236\u4E00\u5F20\u56FE\u7247\uFF0C\u518D\u8FD0\u884C /paste\u3002" + (hint ? `
|
|
3194
|
+
${hint}` : "")
|
|
3195
|
+
);
|
|
3196
|
+
return;
|
|
3197
|
+
}
|
|
3198
|
+
const description = args.join(" ").trim() || "\u8BF7\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247";
|
|
3199
|
+
ctx.renderer.printSuccess(`\u{1F4CB} \u56FE\u7247\u5DF2\u8BFB\u53D6\uFF1A${basename(imgPath)}`);
|
|
3200
|
+
await ctx.sendAsChat(`@${imgPath} ${description}`);
|
|
3201
|
+
}
|
|
3202
|
+
},
|
|
3097
3203
|
{
|
|
3098
3204
|
name: "cost",
|
|
3099
3205
|
description: "Show session token usage summary",
|
|
@@ -3208,7 +3314,7 @@ ${text}
|
|
|
3208
3314
|
let diff;
|
|
3209
3315
|
try {
|
|
3210
3316
|
const cmd = staged ? "git diff --staged" : "git diff";
|
|
3211
|
-
diff =
|
|
3317
|
+
diff = execSync3(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
3212
3318
|
} catch {
|
|
3213
3319
|
ctx.renderer.renderError("Failed to run git diff.");
|
|
3214
3320
|
return;
|
|
@@ -3498,8 +3604,8 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
3498
3604
|
}
|
|
3499
3605
|
|
|
3500
3606
|
// src/tools/builtin/bash.ts
|
|
3501
|
-
import { execSync as
|
|
3502
|
-
import { existsSync as
|
|
3607
|
+
import { execSync as execSync4 } from "child_process";
|
|
3608
|
+
import { existsSync as existsSync7 } from "fs";
|
|
3503
3609
|
import { platform as platform2 } from "os";
|
|
3504
3610
|
import { resolve as resolve2 } from "path";
|
|
3505
3611
|
var IS_WINDOWS = platform2() === "win32";
|
|
@@ -3548,7 +3654,7 @@ var bashTool = {
|
|
|
3548
3654
|
let effectiveCwd = persistentCwd;
|
|
3549
3655
|
if (cwdArg) {
|
|
3550
3656
|
const resolved = resolve2(persistentCwd, cwdArg);
|
|
3551
|
-
if (!
|
|
3657
|
+
if (!existsSync7(resolved)) {
|
|
3552
3658
|
throw new Error(
|
|
3553
3659
|
`cwd directory does not exist: "${resolved}". Create it first (e.g. mkdir -p "${resolved}") before specifying it as cwd.`
|
|
3554
3660
|
);
|
|
@@ -3564,7 +3670,7 @@ var bashTool = {
|
|
|
3564
3670
|
actualCommand = command;
|
|
3565
3671
|
}
|
|
3566
3672
|
try {
|
|
3567
|
-
const output =
|
|
3673
|
+
const output = execSync4(actualCommand, {
|
|
3568
3674
|
timeout,
|
|
3569
3675
|
encoding: IS_WINDOWS ? "buffer" : "utf-8",
|
|
3570
3676
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -3620,7 +3726,7 @@ function updateCwdFromCommand(command, baseCwd) {
|
|
|
3620
3726
|
if (!target || target.startsWith("$") || target === "~") return;
|
|
3621
3727
|
try {
|
|
3622
3728
|
const newDir = resolve2(baseCwd, target);
|
|
3623
|
-
if (
|
|
3729
|
+
if (existsSync7(newDir)) {
|
|
3624
3730
|
persistentCwd = newDir;
|
|
3625
3731
|
}
|
|
3626
3732
|
} catch {
|
|
@@ -3628,7 +3734,7 @@ function updateCwdFromCommand(command, baseCwd) {
|
|
|
3628
3734
|
}
|
|
3629
3735
|
|
|
3630
3736
|
// src/tools/builtin/read-file.ts
|
|
3631
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
3737
|
+
import { readFileSync as readFileSync5, existsSync as existsSync8, statSync as statSync3 } from "fs";
|
|
3632
3738
|
import { extname, resolve as resolve3, basename as basename2, sep } from "path";
|
|
3633
3739
|
import { homedir as homedir2 } from "os";
|
|
3634
3740
|
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
@@ -3721,8 +3827,8 @@ var readFileTool = {
|
|
|
3721
3827
|
const encoding = args["encoding"] ?? "utf-8";
|
|
3722
3828
|
if (!filePath) throw new Error("path is required");
|
|
3723
3829
|
const normalizedPath = resolve3(filePath);
|
|
3724
|
-
if (!
|
|
3725
|
-
const { size } =
|
|
3830
|
+
if (!existsSync8(normalizedPath)) throw new Error(`File not found: ${filePath}`);
|
|
3831
|
+
const { size } = statSync3(normalizedPath);
|
|
3726
3832
|
if (size > MAX_FILE_BYTES) {
|
|
3727
3833
|
const mb = (size / 1024 / 1024).toFixed(1);
|
|
3728
3834
|
return `[File too large: ${filePath} (${mb} MB)]
|
|
@@ -3816,7 +3922,7 @@ var writeFileTool = {
|
|
|
3816
3922
|
};
|
|
3817
3923
|
|
|
3818
3924
|
// src/tools/builtin/edit-file.ts
|
|
3819
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, existsSync as
|
|
3925
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
|
|
3820
3926
|
var editFileTool = {
|
|
3821
3927
|
definition: {
|
|
3822
3928
|
name: "edit_file",
|
|
@@ -3874,7 +3980,7 @@ var editFileTool = {
|
|
|
3874
3980
|
const filePath = String(args["path"] ?? "");
|
|
3875
3981
|
const encoding = args["encoding"] ?? "utf-8";
|
|
3876
3982
|
if (!filePath) throw new Error("path is required");
|
|
3877
|
-
if (!
|
|
3983
|
+
if (!existsSync9(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
3878
3984
|
const original = readFileSync6(filePath, encoding);
|
|
3879
3985
|
if (args["old_str"] !== void 0) {
|
|
3880
3986
|
const oldStr = String(args["old_str"]);
|
|
@@ -3940,8 +4046,8 @@ function truncatePreview(str, maxLen = 80) {
|
|
|
3940
4046
|
}
|
|
3941
4047
|
|
|
3942
4048
|
// src/tools/builtin/list-dir.ts
|
|
3943
|
-
import { readdirSync as readdirSync3, statSync as
|
|
3944
|
-
import { join as
|
|
4049
|
+
import { readdirSync as readdirSync3, statSync as statSync4, existsSync as existsSync10 } from "fs";
|
|
4050
|
+
import { join as join6 } from "path";
|
|
3945
4051
|
var listDirTool = {
|
|
3946
4052
|
definition: {
|
|
3947
4053
|
name: "list_dir",
|
|
@@ -3963,7 +4069,7 @@ var listDirTool = {
|
|
|
3963
4069
|
async execute(args) {
|
|
3964
4070
|
const dirPath = String(args["path"] ?? process.cwd());
|
|
3965
4071
|
const recursive = Boolean(args["recursive"] ?? false);
|
|
3966
|
-
if (!
|
|
4072
|
+
if (!existsSync10(dirPath)) throw new Error(`Directory not found: ${dirPath}`);
|
|
3967
4073
|
const lines = [`Directory: ${dirPath}
|
|
3968
4074
|
`];
|
|
3969
4075
|
listRecursive(dirPath, "", recursive, lines);
|
|
@@ -3992,11 +4098,11 @@ function listRecursive(basePath, indent, recursive, lines) {
|
|
|
3992
4098
|
if (entry.isDirectory()) {
|
|
3993
4099
|
lines.push(`${indent}\u{1F4C1} ${entry.name}/`);
|
|
3994
4100
|
if (recursive) {
|
|
3995
|
-
listRecursive(
|
|
4101
|
+
listRecursive(join6(basePath, entry.name), indent + " ", true, lines);
|
|
3996
4102
|
}
|
|
3997
4103
|
} else {
|
|
3998
4104
|
try {
|
|
3999
|
-
const stat =
|
|
4105
|
+
const stat = statSync4(join6(basePath, entry.name));
|
|
4000
4106
|
const size = formatSize(stat.size);
|
|
4001
4107
|
lines.push(`${indent}\u{1F4C4} ${entry.name} (${size})`);
|
|
4002
4108
|
} catch {
|
|
@@ -4012,8 +4118,8 @@ function formatSize(bytes) {
|
|
|
4012
4118
|
}
|
|
4013
4119
|
|
|
4014
4120
|
// src/tools/builtin/grep-files.ts
|
|
4015
|
-
import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as
|
|
4016
|
-
import { join as
|
|
4121
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync5, existsSync as existsSync11 } from "fs";
|
|
4122
|
+
import { join as join7, relative } from "path";
|
|
4017
4123
|
var grepFilesTool = {
|
|
4018
4124
|
definition: {
|
|
4019
4125
|
name: "grep_files",
|
|
@@ -4064,7 +4170,7 @@ var grepFilesTool = {
|
|
|
4064
4170
|
const contextLines = Math.max(0, Number(args["context_lines"] ?? 0));
|
|
4065
4171
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 50));
|
|
4066
4172
|
if (!pattern) throw new Error("pattern is required");
|
|
4067
|
-
if (!
|
|
4173
|
+
if (!existsSync11(rootPath)) throw new Error(`Path not found: ${rootPath}`);
|
|
4068
4174
|
let regex;
|
|
4069
4175
|
try {
|
|
4070
4176
|
regex = new RegExp(pattern, ignoreCase ? "gi" : "g");
|
|
@@ -4073,7 +4179,7 @@ var grepFilesTool = {
|
|
|
4073
4179
|
regex = new RegExp(escaped, ignoreCase ? "gi" : "g");
|
|
4074
4180
|
}
|
|
4075
4181
|
const results = [];
|
|
4076
|
-
const stat =
|
|
4182
|
+
const stat = statSync5(rootPath);
|
|
4077
4183
|
if (stat.isFile()) {
|
|
4078
4184
|
searchInFile(rootPath, rootPath, regex, contextLines, maxResults, results);
|
|
4079
4185
|
} else {
|
|
@@ -4137,11 +4243,11 @@ function collectFiles(dirPath, filePattern, results, regex, contextLines, maxRes
|
|
|
4137
4243
|
if (results.length >= maxResults) return;
|
|
4138
4244
|
if (entry.isDirectory()) {
|
|
4139
4245
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
4140
|
-
collectFiles(
|
|
4246
|
+
collectFiles(join7(dirPath, entry.name), filePattern, results, regex, contextLines, maxResults, rootPath);
|
|
4141
4247
|
} else if (entry.isFile()) {
|
|
4142
4248
|
if (isBinary(entry.name)) continue;
|
|
4143
4249
|
if (filePattern && !matchesFilePattern(entry.name, filePattern)) continue;
|
|
4144
|
-
const fullPath =
|
|
4250
|
+
const fullPath = join7(dirPath, entry.name);
|
|
4145
4251
|
const relPath = relative(rootPath, fullPath);
|
|
4146
4252
|
searchInFile(fullPath, relPath, regex, contextLines, maxResults, results);
|
|
4147
4253
|
}
|
|
@@ -4182,8 +4288,8 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
|
|
|
4182
4288
|
}
|
|
4183
4289
|
|
|
4184
4290
|
// src/tools/builtin/glob-files.ts
|
|
4185
|
-
import { readdirSync as readdirSync5, statSync as
|
|
4186
|
-
import { join as
|
|
4291
|
+
import { readdirSync as readdirSync5, statSync as statSync6, existsSync as existsSync12 } from "fs";
|
|
4292
|
+
import { join as join8, relative as relative2, basename as basename3 } from "path";
|
|
4187
4293
|
var globFilesTool = {
|
|
4188
4294
|
definition: {
|
|
4189
4295
|
name: "glob_files",
|
|
@@ -4216,7 +4322,7 @@ var globFilesTool = {
|
|
|
4216
4322
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
4217
4323
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 100));
|
|
4218
4324
|
if (!pattern) throw new Error("pattern is required");
|
|
4219
|
-
if (!
|
|
4325
|
+
if (!existsSync12(rootPath)) throw new Error(`Path not found: ${rootPath}`);
|
|
4220
4326
|
const regex = globToRegex(pattern);
|
|
4221
4327
|
const matches = [];
|
|
4222
4328
|
collectMatchingFiles(rootPath, rootPath, regex, matches, maxResults);
|
|
@@ -4293,7 +4399,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
4293
4399
|
}
|
|
4294
4400
|
for (const entry of entries) {
|
|
4295
4401
|
if (results.length >= maxResults) break;
|
|
4296
|
-
const fullPath =
|
|
4402
|
+
const fullPath = join8(dirPath, entry.name);
|
|
4297
4403
|
if (entry.isDirectory()) {
|
|
4298
4404
|
if (SKIP_DIRS2.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
4299
4405
|
collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
|
|
@@ -4301,7 +4407,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
4301
4407
|
const relPath = relative2(rootPath, fullPath).replace(/\\/g, "/");
|
|
4302
4408
|
if (regex.test(relPath) || regex.test(basename3(relPath))) {
|
|
4303
4409
|
try {
|
|
4304
|
-
const stat =
|
|
4410
|
+
const stat = statSync6(fullPath);
|
|
4305
4411
|
results.push({ relPath, absPath: fullPath, mtime: stat.mtimeMs });
|
|
4306
4412
|
} catch {
|
|
4307
4413
|
results.push({ relPath, absPath: fullPath, mtime: 0 });
|
|
@@ -4685,11 +4791,11 @@ var saveLastResponseTool = {
|
|
|
4685
4791
|
};
|
|
4686
4792
|
|
|
4687
4793
|
// src/tools/builtin/save-memory.ts
|
|
4688
|
-
import { existsSync as
|
|
4689
|
-
import { join as
|
|
4794
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8, appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
|
|
4795
|
+
import { join as join9 } from "path";
|
|
4690
4796
|
import { homedir as homedir3 } from "os";
|
|
4691
4797
|
function getMemoryFilePath() {
|
|
4692
|
-
return
|
|
4798
|
+
return join9(homedir3(), CONFIG_DIR_NAME, MEMORY_FILE_NAME);
|
|
4693
4799
|
}
|
|
4694
4800
|
function formatTimestamp() {
|
|
4695
4801
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -4713,8 +4819,8 @@ var saveMemoryTool = {
|
|
|
4713
4819
|
const content = String(args["content"] ?? "").trim();
|
|
4714
4820
|
if (!content) throw new Error("content is required");
|
|
4715
4821
|
const memoryPath = getMemoryFilePath();
|
|
4716
|
-
const configDir =
|
|
4717
|
-
if (!
|
|
4822
|
+
const configDir = join9(homedir3(), CONFIG_DIR_NAME);
|
|
4823
|
+
if (!existsSync13(configDir)) {
|
|
4718
4824
|
mkdirSync7(configDir, { recursive: true });
|
|
4719
4825
|
}
|
|
4720
4826
|
const timestamp = formatTimestamp();
|
|
@@ -5304,8 +5410,8 @@ var spawnAgentTool = {
|
|
|
5304
5410
|
|
|
5305
5411
|
// src/tools/registry.ts
|
|
5306
5412
|
import { pathToFileURL } from "url";
|
|
5307
|
-
import { existsSync as
|
|
5308
|
-
import { join as
|
|
5413
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync6 } from "fs";
|
|
5414
|
+
import { join as join10 } from "path";
|
|
5309
5415
|
var ToolRegistry = class {
|
|
5310
5416
|
tools = /* @__PURE__ */ new Map();
|
|
5311
5417
|
pluginToolNames = /* @__PURE__ */ new Set();
|
|
@@ -5378,7 +5484,7 @@ var ToolRegistry = class {
|
|
|
5378
5484
|
* Returns the number of successfully loaded plugins.
|
|
5379
5485
|
*/
|
|
5380
5486
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
5381
|
-
if (!
|
|
5487
|
+
if (!existsSync14(pluginsDir)) {
|
|
5382
5488
|
try {
|
|
5383
5489
|
mkdirSync8(pluginsDir, { recursive: true });
|
|
5384
5490
|
} catch {
|
|
@@ -5404,12 +5510,12 @@ var ToolRegistry = class {
|
|
|
5404
5510
|
process.stderr.write(
|
|
5405
5511
|
`
|
|
5406
5512
|
[plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
|
|
5407
|
-
` + files.map((f) => ` + ${
|
|
5513
|
+
` + files.map((f) => ` + ${join10(pluginsDir, f)}`).join("\n") + "\n\n"
|
|
5408
5514
|
);
|
|
5409
5515
|
let loaded = 0;
|
|
5410
5516
|
for (const file of files) {
|
|
5411
5517
|
try {
|
|
5412
|
-
const fileUrl = pathToFileURL(
|
|
5518
|
+
const fileUrl = pathToFileURL(join10(pluginsDir, file)).href;
|
|
5413
5519
|
const mod = await import(fileUrl);
|
|
5414
5520
|
const tool = mod.tool ?? mod.default?.tool ?? mod.default;
|
|
5415
5521
|
if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
|
|
@@ -5438,7 +5544,7 @@ var ToolRegistry = class {
|
|
|
5438
5544
|
|
|
5439
5545
|
// src/tools/executor.ts
|
|
5440
5546
|
import chalk8 from "chalk";
|
|
5441
|
-
import { existsSync as
|
|
5547
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
5442
5548
|
|
|
5443
5549
|
// src/tools/diff-utils.ts
|
|
5444
5550
|
import chalk7 from "chalk";
|
|
@@ -5594,7 +5700,7 @@ function simpleDiff(oldLines, newLines) {
|
|
|
5594
5700
|
}
|
|
5595
5701
|
|
|
5596
5702
|
// src/tools/hooks.ts
|
|
5597
|
-
import { execSync as
|
|
5703
|
+
import { execSync as execSync5 } from "child_process";
|
|
5598
5704
|
function runHook(template, vars) {
|
|
5599
5705
|
if (!template) return;
|
|
5600
5706
|
let cmd = template;
|
|
@@ -5603,7 +5709,7 @@ function runHook(template, vars) {
|
|
|
5603
5709
|
cmd = cmd.replace(/\{args\}/g, vars.args ?? "");
|
|
5604
5710
|
cmd = cmd.replace(/\{status\}/g, vars.status ?? "");
|
|
5605
5711
|
try {
|
|
5606
|
-
|
|
5712
|
+
execSync5(cmd, {
|
|
5607
5713
|
timeout: 5e3,
|
|
5608
5714
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5609
5715
|
encoding: "utf-8"
|
|
@@ -5928,7 +6034,7 @@ var ToolExecutor = class {
|
|
|
5928
6034
|
const filePath = String(call.arguments["path"] ?? "");
|
|
5929
6035
|
const newContent = String(call.arguments["content"] ?? "");
|
|
5930
6036
|
if (!filePath) return;
|
|
5931
|
-
if (
|
|
6037
|
+
if (existsSync15(filePath)) {
|
|
5932
6038
|
let oldContent;
|
|
5933
6039
|
try {
|
|
5934
6040
|
oldContent = readFileSync9(filePath, "utf-8");
|
|
@@ -5954,7 +6060,7 @@ var ToolExecutor = class {
|
|
|
5954
6060
|
}
|
|
5955
6061
|
} else if (call.name === "edit_file") {
|
|
5956
6062
|
const filePath = String(call.arguments["path"] ?? "");
|
|
5957
|
-
if (!filePath || !
|
|
6063
|
+
if (!filePath || !existsSync15(filePath)) return;
|
|
5958
6064
|
const oldStr = call.arguments["old_str"];
|
|
5959
6065
|
const newStr = call.arguments["new_str"];
|
|
5960
6066
|
if (oldStr !== void 0) {
|
|
@@ -6294,9 +6400,9 @@ Managing ${displayName} API Key`);
|
|
|
6294
6400
|
};
|
|
6295
6401
|
|
|
6296
6402
|
// src/repl/custom-commands.ts
|
|
6297
|
-
import { existsSync as
|
|
6298
|
-
import { join as
|
|
6299
|
-
import { execSync as
|
|
6403
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync7, mkdirSync as mkdirSync9 } from "fs";
|
|
6404
|
+
import { join as join11, extname as extname3 } from "path";
|
|
6405
|
+
import { execSync as execSync6 } from "child_process";
|
|
6300
6406
|
function parseSimpleYaml(text) {
|
|
6301
6407
|
const result = {};
|
|
6302
6408
|
for (const line of text.split("\n")) {
|
|
@@ -6341,7 +6447,7 @@ function expandTemplate(template, args) {
|
|
|
6341
6447
|
});
|
|
6342
6448
|
result = result.replace(/\{\{git-diff\}\}/g, () => {
|
|
6343
6449
|
try {
|
|
6344
|
-
return
|
|
6450
|
+
return execSync6("git diff", { encoding: "utf-8", timeout: 1e4 }).trim();
|
|
6345
6451
|
} catch {
|
|
6346
6452
|
return "[No git diff available]";
|
|
6347
6453
|
}
|
|
@@ -6359,14 +6465,14 @@ var CustomCommandManager = class {
|
|
|
6359
6465
|
commands = /* @__PURE__ */ new Map();
|
|
6360
6466
|
loadCommands() {
|
|
6361
6467
|
this.commands.clear();
|
|
6362
|
-
if (!
|
|
6468
|
+
if (!existsSync16(this.commandsDir)) {
|
|
6363
6469
|
mkdirSync9(this.commandsDir, { recursive: true });
|
|
6364
6470
|
return 0;
|
|
6365
6471
|
}
|
|
6366
6472
|
let count = 0;
|
|
6367
6473
|
for (const file of readdirSync7(this.commandsDir)) {
|
|
6368
6474
|
if (extname3(file) !== ".md") continue;
|
|
6369
|
-
const cmd = parseCommandFile(
|
|
6475
|
+
const cmd = parseCommandFile(join11(this.commandsDir, file));
|
|
6370
6476
|
if (cmd) {
|
|
6371
6477
|
this.commands.set(cmd.meta.name, cmd);
|
|
6372
6478
|
count++;
|
|
@@ -6383,8 +6489,8 @@ var CustomCommandManager = class {
|
|
|
6383
6489
|
};
|
|
6384
6490
|
|
|
6385
6491
|
// src/repl/dev-state.ts
|
|
6386
|
-
import { existsSync as
|
|
6387
|
-
import { join as
|
|
6492
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3, mkdirSync as mkdirSync10 } from "fs";
|
|
6493
|
+
import { join as join12 } from "path";
|
|
6388
6494
|
import { homedir as homedir4 } from "os";
|
|
6389
6495
|
var DEV_STATE_MAX_CHARS = 4e3;
|
|
6390
6496
|
var SNAPSHOT_PROMPT = `You are about to be replaced by a different AI model. Please generate a structured development state snapshot so the next model can continue seamlessly.
|
|
@@ -6423,11 +6529,11 @@ function sessionHasMeaningfulContent(messages) {
|
|
|
6423
6529
|
return hasUser && hasAssistant;
|
|
6424
6530
|
}
|
|
6425
6531
|
function getDevStatePath() {
|
|
6426
|
-
return
|
|
6532
|
+
return join12(homedir4(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
|
|
6427
6533
|
}
|
|
6428
6534
|
function saveDevState(content) {
|
|
6429
|
-
const configDir =
|
|
6430
|
-
if (!
|
|
6535
|
+
const configDir = join12(homedir4(), CONFIG_DIR_NAME);
|
|
6536
|
+
if (!existsSync17(configDir)) {
|
|
6431
6537
|
mkdirSync10(configDir, { recursive: true });
|
|
6432
6538
|
}
|
|
6433
6539
|
let trimmed = content.trim();
|
|
@@ -6443,15 +6549,15 @@ function saveDevState(content) {
|
|
|
6443
6549
|
}
|
|
6444
6550
|
function loadDevState() {
|
|
6445
6551
|
const path = getDevStatePath();
|
|
6446
|
-
if (!
|
|
6552
|
+
if (!existsSync17(path)) return null;
|
|
6447
6553
|
const content = readFileSync11(path, "utf-8").trim();
|
|
6448
6554
|
return content || null;
|
|
6449
6555
|
}
|
|
6450
6556
|
function clearDevState() {
|
|
6451
6557
|
const path = getDevStatePath();
|
|
6452
|
-
if (
|
|
6558
|
+
if (existsSync17(path)) {
|
|
6453
6559
|
try {
|
|
6454
|
-
|
|
6560
|
+
unlinkSync3(path);
|
|
6455
6561
|
} catch {
|
|
6456
6562
|
}
|
|
6457
6563
|
}
|
|
@@ -6870,8 +6976,8 @@ var McpManager = class {
|
|
|
6870
6976
|
};
|
|
6871
6977
|
|
|
6872
6978
|
// src/skills/manager.ts
|
|
6873
|
-
import { existsSync as
|
|
6874
|
-
import { join as
|
|
6979
|
+
import { existsSync as existsSync18, readdirSync as readdirSync8, mkdirSync as mkdirSync11 } from "fs";
|
|
6980
|
+
import { join as join13 } from "path";
|
|
6875
6981
|
|
|
6876
6982
|
// src/skills/types.ts
|
|
6877
6983
|
import { readFileSync as readFileSync12 } from "fs";
|
|
@@ -6936,7 +7042,7 @@ var SkillManager = class {
|
|
|
6936
7042
|
/** 发现并加载 skillsDir 下所有 .md 文件,返回加载数量 */
|
|
6937
7043
|
loadSkills() {
|
|
6938
7044
|
this.skills.clear();
|
|
6939
|
-
if (!
|
|
7045
|
+
if (!existsSync18(this.skillsDir)) {
|
|
6940
7046
|
try {
|
|
6941
7047
|
mkdirSync11(this.skillsDir, { recursive: true });
|
|
6942
7048
|
} catch {
|
|
@@ -6951,7 +7057,7 @@ var SkillManager = class {
|
|
|
6951
7057
|
}
|
|
6952
7058
|
for (const entry of entries) {
|
|
6953
7059
|
if (!entry.endsWith(".md")) continue;
|
|
6954
|
-
const filePath =
|
|
7060
|
+
const filePath = join13(this.skillsDir, entry);
|
|
6955
7061
|
const skill = parseSkillFile(filePath);
|
|
6956
7062
|
if (skill) {
|
|
6957
7063
|
this.skills.set(skill.meta.name, skill);
|
|
@@ -7019,12 +7125,12 @@ function parseAtReferences(input2, cwd) {
|
|
|
7019
7125
|
const absPath = resolve4(cwd, rawPath);
|
|
7020
7126
|
const ext = extname4(rawPath).toLowerCase();
|
|
7021
7127
|
const mime = IMAGE_MIME[ext];
|
|
7022
|
-
if (!
|
|
7128
|
+
if (!existsSync19(absPath)) {
|
|
7023
7129
|
refs.push({ path: rawPath, type: "notfound" });
|
|
7024
7130
|
continue;
|
|
7025
7131
|
}
|
|
7026
7132
|
if (mime) {
|
|
7027
|
-
const fileSize =
|
|
7133
|
+
const fileSize = statSync7(absPath).size;
|
|
7028
7134
|
if (fileSize > MAX_IMAGE_BYTES) {
|
|
7029
7135
|
refs.push({ path: rawPath, type: "toolarge" });
|
|
7030
7136
|
continue;
|
|
@@ -7137,8 +7243,8 @@ var Repl = class {
|
|
|
7137
7243
|
*/
|
|
7138
7244
|
findContextFile(dir, candidates = CONTEXT_FILE_CANDIDATES) {
|
|
7139
7245
|
for (const candidate of candidates) {
|
|
7140
|
-
const fullPath =
|
|
7141
|
-
if (
|
|
7246
|
+
const fullPath = join14(dir, candidate);
|
|
7247
|
+
if (existsSync19(fullPath)) {
|
|
7142
7248
|
const content = readFileSync13(fullPath, "utf-8").trim();
|
|
7143
7249
|
if (content) return { filePath: fullPath, content };
|
|
7144
7250
|
}
|
|
@@ -7171,7 +7277,7 @@ var Repl = class {
|
|
|
7171
7277
|
);
|
|
7172
7278
|
return { layers: [], mergedContent: "" };
|
|
7173
7279
|
}
|
|
7174
|
-
if (
|
|
7280
|
+
if (existsSync19(fullPath)) {
|
|
7175
7281
|
const content = readFileSync13(fullPath, "utf-8").trim();
|
|
7176
7282
|
if (content) {
|
|
7177
7283
|
const layer = {
|
|
@@ -7229,8 +7335,8 @@ var Repl = class {
|
|
|
7229
7335
|
* 超过 MEMORY_MAX_CHARS 时只取末尾最新部分。
|
|
7230
7336
|
*/
|
|
7231
7337
|
loadMemoryContent() {
|
|
7232
|
-
const memoryPath =
|
|
7233
|
-
if (!
|
|
7338
|
+
const memoryPath = join14(this.config.getConfigDir(), MEMORY_FILE_NAME);
|
|
7339
|
+
if (!existsSync19(memoryPath)) return null;
|
|
7234
7340
|
let content = readFileSync13(memoryPath, "utf-8").trim();
|
|
7235
7341
|
if (!content) return null;
|
|
7236
7342
|
if (content.length > MEMORY_MAX_CHARS) {
|
|
@@ -7507,14 +7613,14 @@ ${response.content.trim()}
|
|
|
7507
7613
|
process.stdout.write(chalk10.dim(` \u{1F50C} Plugins loaded: ${pluginCount} tool(s) from plugins/
|
|
7508
7614
|
`));
|
|
7509
7615
|
}
|
|
7510
|
-
const skillsDir =
|
|
7616
|
+
const skillsDir = join14(this.config.getConfigDir(), SKILLS_DIR_NAME);
|
|
7511
7617
|
this.skillManager = new SkillManager(skillsDir);
|
|
7512
7618
|
const skillCount = this.skillManager.loadSkills();
|
|
7513
7619
|
if (skillCount > 0) {
|
|
7514
7620
|
process.stdout.write(chalk10.dim(` \u{1F3AF} Skills: ${skillCount} available (use /skill to manage)
|
|
7515
7621
|
`));
|
|
7516
7622
|
}
|
|
7517
|
-
const commandsDir =
|
|
7623
|
+
const commandsDir = join14(this.config.getConfigDir(), CUSTOM_COMMANDS_DIR_NAME);
|
|
7518
7624
|
this.customCommandManager = new CustomCommandManager(commandsDir);
|
|
7519
7625
|
const customCmdCount = this.customCommandManager.loadCommands();
|
|
7520
7626
|
if (customCmdCount > 0) {
|
|
@@ -7538,6 +7644,7 @@ ${response.content.trim()}
|
|
|
7538
7644
|
);
|
|
7539
7645
|
}
|
|
7540
7646
|
}
|
|
7647
|
+
this.setupClipboardPaste();
|
|
7541
7648
|
this.rl.on("SIGINT", () => {
|
|
7542
7649
|
if (this.streamAbortController) {
|
|
7543
7650
|
this.streamAbortController.abort();
|
|
@@ -7857,15 +7964,15 @@ ${response.content.trim()}
|
|
|
7857
7964
|
const dir = normalized.includes("/") ? dirname5(normalized) : ".";
|
|
7858
7965
|
const prefix = normalized.includes("/") ? basename5(normalized) : normalized;
|
|
7859
7966
|
const absDir = resolve4(process.cwd(), dir);
|
|
7860
|
-
if (!
|
|
7967
|
+
if (!existsSync19(absDir)) return [];
|
|
7861
7968
|
const entries = readdirSync9(absDir);
|
|
7862
7969
|
const results = [];
|
|
7863
7970
|
for (const entry of entries) {
|
|
7864
7971
|
if (entry.startsWith(".")) continue;
|
|
7865
7972
|
if (!entry.toLowerCase().startsWith(prefix.toLowerCase())) continue;
|
|
7866
7973
|
try {
|
|
7867
|
-
const fullPath =
|
|
7868
|
-
const stat =
|
|
7974
|
+
const fullPath = join14(absDir, entry);
|
|
7975
|
+
const stat = statSync7(fullPath);
|
|
7869
7976
|
const rel = dir === "." ? entry : `${dir}/${entry}`;
|
|
7870
7977
|
results.push(stat.isDirectory() ? `${rel}/` : rel);
|
|
7871
7978
|
} catch {
|
|
@@ -7908,6 +8015,41 @@ ${response.content.trim()}
|
|
|
7908
8015
|
process.stdin.pause();
|
|
7909
8016
|
this.streamAbortController = null;
|
|
7910
8017
|
}
|
|
8018
|
+
/**
|
|
8019
|
+
* 注册 Ctrl+V 剪贴板图片粘贴快捷键。
|
|
8020
|
+
*
|
|
8021
|
+
* 使用 prependListener 先于 readline 的 quotedInsert 处理器运行:
|
|
8022
|
+
* 1. 我们的 handler 在 setImmediate 中调用 rl.write('@imgPath ')
|
|
8023
|
+
* 2. readline 的 quotedInsert 消费第一个字符('@'),字面插入 '@' — 结果相同
|
|
8024
|
+
* 3. 后续字符正常插入
|
|
8025
|
+
* 最终 readline 缓冲区包含完整的 @路径,用户可继续追加描述文字后回车发送。
|
|
8026
|
+
*/
|
|
8027
|
+
setupClipboardPaste() {
|
|
8028
|
+
process.stdin.prependListener("keypress", (_ch, key) => {
|
|
8029
|
+
if (!key?.ctrl || key?.name !== "v") return;
|
|
8030
|
+
if (this.streamAbortController || this.toolExecutor.confirming || askUserContext.prompting || this.selecting) return;
|
|
8031
|
+
const imgPath = readClipboardImage();
|
|
8032
|
+
if (imgPath) {
|
|
8033
|
+
setImmediate(() => {
|
|
8034
|
+
this.rl.write(`@${imgPath} `);
|
|
8035
|
+
process.stdout.write(chalk10.dim(`
|
|
8036
|
+
\u{1F4CB} \u56FE\u7247\u5DF2\u7C98\u8D34\uFF0C\u8BF7\u6DFB\u52A0\u63CF\u8FF0\u540E\u56DE\u8F66\u53D1\u9001
|
|
8037
|
+
`));
|
|
8038
|
+
this.showPrompt();
|
|
8039
|
+
});
|
|
8040
|
+
} else {
|
|
8041
|
+
setImmediate(() => {
|
|
8042
|
+
const hint = getClipboardHint();
|
|
8043
|
+
process.stdout.write(
|
|
8044
|
+
chalk10.dim(`
|
|
8045
|
+
\u2139 \u526A\u8D34\u677F\u4E2D\u6CA1\u6709\u56FE\u7247\u3002\u53EF\u4F7F\u7528 @\u8DEF\u5F84 \u5F15\u7528\u672C\u5730\u56FE\u7247\u6587\u4EF6\u3002`) + (hint ? chalk10.dim(`
|
|
8046
|
+
${hint}`) : "") + "\n"
|
|
8047
|
+
);
|
|
8048
|
+
this.showPrompt();
|
|
8049
|
+
});
|
|
8050
|
+
}
|
|
8051
|
+
});
|
|
8052
|
+
}
|
|
7911
8053
|
async handleChatSimple(provider, messages) {
|
|
7912
8054
|
const session = this.sessions.current;
|
|
7913
8055
|
const useStreaming = this.config.get("ui").streaming;
|