shenxiang-ai-cli 0.4.4 → 0.5.0
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 +138 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// src/commands/chat.ts
|
|
7
7
|
import inquirer from "inquirer";
|
|
8
|
+
import fs5 from "fs/promises";
|
|
9
|
+
import path5 from "path";
|
|
10
|
+
import { glob as glob4 } from "glob";
|
|
8
11
|
|
|
9
12
|
// src/core/providers/openai-compatible.ts
|
|
10
13
|
import OpenAI from "openai";
|
|
@@ -737,7 +740,7 @@ function banner() {
|
|
|
737
740
|
const w = chalk.white.bold;
|
|
738
741
|
const lines = [
|
|
739
742
|
``,
|
|
740
|
-
` ${p("/\\_/\\")} ${b("\u6C88\u7FD4\u7684AI\u52A9\u624B")} ${m("v0.
|
|
743
|
+
` ${p("/\\_/\\")} ${b("\u6C88\u7FD4\u7684AI\u52A9\u624B")} ${m("v0.5.0")}`,
|
|
741
744
|
` ${p("(")} ${y("o")}${p(".")}${y("o")} ${p(")")} ${d("\u7EC8\u7AEF\u91CC\u7684AI\u5168\u6808\u5F00\u53D1\u642D\u6863")}`,
|
|
742
745
|
` ${p("> ")}${r("^")}${p(" <")}`,
|
|
743
746
|
` ${p("/|")}${p(" |")}${p("\\")} ${d("\u4F60\u7684\u7F16\u7A0B\u597D\u4F19\u4F34")} ${chalk.hex("#A78BFA")("\u{1F43E}")}`,
|
|
@@ -2071,6 +2074,30 @@ var Agent = class {
|
|
|
2071
2074
|
printWarning(t("errors.tokenLimit"));
|
|
2072
2075
|
}
|
|
2073
2076
|
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Add file content to conversation context (for /read command)
|
|
2079
|
+
*/
|
|
2080
|
+
addFileContext(filePath, content) {
|
|
2081
|
+
const maxChars = 5e4;
|
|
2082
|
+
const truncated = content.length > maxChars ? content.substring(0, maxChars) + `
|
|
2083
|
+
|
|
2084
|
+
... [\u6587\u4EF6\u88AB\u622A\u65AD\uFF0C\u5171 ${content.length} \u5B57\u7B26\uFF0C\u53EA\u663E\u793A\u524D ${maxChars} \u5B57\u7B26]` : content;
|
|
2085
|
+
this.messages.push({
|
|
2086
|
+
role: "user",
|
|
2087
|
+
content: `[\u7528\u6237\u52A0\u8F7D\u4E86\u6587\u4EF6: ${filePath}]
|
|
2088
|
+
|
|
2089
|
+
\u4EE5\u4E0B\u662F\u6587\u4EF6\u5185\u5BB9\uFF0C\u8BF7\u8BB0\u4F4F\u5B83\uFF0C\u540E\u7EED\u6211\u4F1A\u57FA\u4E8E\u8FD9\u4E2A\u6587\u4EF6\u5185\u5BB9\u7ED9\u4F60\u6307\u4EE4\uFF1A
|
|
2090
|
+
|
|
2091
|
+
---
|
|
2092
|
+
${truncated}
|
|
2093
|
+
---`
|
|
2094
|
+
});
|
|
2095
|
+
this.messages.push({
|
|
2096
|
+
role: "assistant",
|
|
2097
|
+
content: `\u597D\u7684\uFF0C\u6211\u5DF2\u7ECF\u8BFB\u53D6\u4E86 ${filePath} \u7684\u5185\u5BB9\u3002\u8BF7\u544A\u8BC9\u6211\u4F60\u60F3\u57FA\u4E8E\u8FD9\u4E2A\u6587\u4EF6\u505A\u4EC0\u4E48\u3002`
|
|
2098
|
+
});
|
|
2099
|
+
this.trimMessages();
|
|
2100
|
+
}
|
|
2074
2101
|
/**
|
|
2075
2102
|
* Clear conversation history (keep system prompt)
|
|
2076
2103
|
*/
|
|
@@ -2240,6 +2267,25 @@ async function chatCommand(options = {}) {
|
|
|
2240
2267
|
if (projectCtx?.projectMemory) {
|
|
2241
2268
|
console.log(theme.dim(` \u{1F4CB} \u5DF2\u52A0\u8F7D SXAI.md \u9879\u76EE\u6307\u4EE4`));
|
|
2242
2269
|
}
|
|
2270
|
+
try {
|
|
2271
|
+
const docHintPatterns = ["*.md", "\u9700\u6C42*.md", "PRD*", "prd*", "\u8BBE\u8BA1*.md", "docs/*.md"];
|
|
2272
|
+
const foundDocs = [];
|
|
2273
|
+
for (const p of docHintPatterns) {
|
|
2274
|
+
const files = await glob4(p, {
|
|
2275
|
+
cwd: process.cwd(),
|
|
2276
|
+
ignore: ["node_modules/**", ".git/**", "dist/**", "SXAI.md"],
|
|
2277
|
+
nodir: true
|
|
2278
|
+
});
|
|
2279
|
+
for (const f of files) {
|
|
2280
|
+
if (!foundDocs.includes(f) && foundDocs.length < 5) foundDocs.push(f);
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
if (foundDocs.length > 0) {
|
|
2284
|
+
console.log(theme.dim(` \u{1F4C4} \u68C0\u6D4B\u5230\u6587\u6863: ${foundDocs.join(", ")}`));
|
|
2285
|
+
console.log(theme.dim(` \u8F93\u5165 /read <\u6587\u4EF6\u540D> \u52A0\u8F7D\u5230\u5BF9\u8BDD\uFF0C\u6216 /docs \u67E5\u770B\u5168\u90E8`));
|
|
2286
|
+
}
|
|
2287
|
+
} catch {
|
|
2288
|
+
}
|
|
2243
2289
|
printSeparator();
|
|
2244
2290
|
console.log();
|
|
2245
2291
|
} catch (err) {
|
|
@@ -2358,15 +2404,18 @@ async function handleSlashCommand(input, agent) {
|
|
|
2358
2404
|
case "/h":
|
|
2359
2405
|
console.log(`
|
|
2360
2406
|
\u53EF\u7528\u547D\u4EE4:
|
|
2361
|
-
/
|
|
2362
|
-
/
|
|
2363
|
-
/
|
|
2364
|
-
/
|
|
2365
|
-
/
|
|
2366
|
-
/
|
|
2367
|
-
/
|
|
2368
|
-
/
|
|
2369
|
-
/
|
|
2407
|
+
/read <\u8DEF\u5F84> \u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9\u5582\u7ED9AI\uFF08\u5982 /read \u9700\u6C42\u6587\u6863.md\uFF09
|
|
2408
|
+
/docs \u626B\u63CF\u9879\u76EE\u4E2D\u7684\u6587\u6863\u6587\u4EF6
|
|
2409
|
+
/model \u67E5\u770B/\u5207\u6362\u6A21\u578B
|
|
2410
|
+
/auto \u5207\u6362\u81EA\u52A8\u6A21\u5F0F\uFF08\u8DF3\u8FC7\u786E\u8BA4\uFF09
|
|
2411
|
+
/clear \u6E05\u9664\u5BF9\u8BDD\u5386\u53F2
|
|
2412
|
+
/account \u67E5\u770B\u8D26\u6237\u4FE1\u606F
|
|
2413
|
+
/status \u67E5\u770B\u9879\u76EE\u4FE1\u606F
|
|
2414
|
+
/config \u67E5\u770B\u914D\u7F6E
|
|
2415
|
+
/logout \u9000\u51FA\u767B\u5F55
|
|
2416
|
+
/exit \u9000\u51FA\u7A0B\u5E8F
|
|
2417
|
+
|
|
2418
|
+
\u63D0\u793A: \u53EF\u4EE5\u76F4\u63A5\u8BF4"\u8BF7\u8BFB\u53D6 xxx \u6587\u4EF6"\u8BA9AI\u81EA\u5DF1\u53BB\u8BFB
|
|
2370
2419
|
`);
|
|
2371
2420
|
break;
|
|
2372
2421
|
case "/auto":
|
|
@@ -2380,6 +2429,82 @@ async function handleSlashCommand(input, agent) {
|
|
|
2380
2429
|
}
|
|
2381
2430
|
break;
|
|
2382
2431
|
}
|
|
2432
|
+
case "/read": {
|
|
2433
|
+
const filePath = args.join(" ").trim();
|
|
2434
|
+
if (!filePath) {
|
|
2435
|
+
printError("\u7528\u6CD5: /read <\u6587\u4EF6\u8DEF\u5F84> \u4F8B\u5982: /read \u9700\u6C42\u6587\u6863.md");
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
try {
|
|
2439
|
+
const absPath = path5.resolve(process.cwd(), filePath);
|
|
2440
|
+
const content = await fs5.readFile(absPath, "utf-8");
|
|
2441
|
+
const lines = content.split("\n").length;
|
|
2442
|
+
const sizeKB = (Buffer.byteLength(content, "utf-8") / 1024).toFixed(1);
|
|
2443
|
+
printSuccess(`\u5DF2\u8BFB\u53D6: ${filePath} (${lines} \u884C, ${sizeKB}KB)`);
|
|
2444
|
+
agent.addFileContext(filePath, content);
|
|
2445
|
+
console.log(theme.dim(` \u6587\u4EF6\u5185\u5BB9\u5DF2\u6DFB\u52A0\u5230\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u73B0\u5728\u53EF\u4EE5\u57FA\u4E8E\u5B83\u63D0\u95EE\u6216\u6307\u4EE4\u3002`));
|
|
2446
|
+
console.log(theme.dim(` \u4F8B\u5982: "\u6839\u636E\u8FD9\u4E2A\u9700\u6C42\u6587\u6863\u5F00\u59CB\u5F00\u53D1" \u6216 "\u5206\u6790\u8FD9\u4E2A\u6587\u4EF6\u7684\u95EE\u9898"`));
|
|
2447
|
+
} catch (err) {
|
|
2448
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2449
|
+
if (msg.includes("ENOENT")) {
|
|
2450
|
+
printError(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
|
|
2451
|
+
} else {
|
|
2452
|
+
printError(`\u8BFB\u53D6\u5931\u8D25: ${msg}`);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
break;
|
|
2456
|
+
}
|
|
2457
|
+
case "/docs": {
|
|
2458
|
+
const docPatterns = [
|
|
2459
|
+
"*.md",
|
|
2460
|
+
"*.txt",
|
|
2461
|
+
"docs/**/*.md",
|
|
2462
|
+
"doc/**/*.md",
|
|
2463
|
+
"\u9700\u6C42*.md",
|
|
2464
|
+
"PRD*",
|
|
2465
|
+
"prd*",
|
|
2466
|
+
"\u8BBE\u8BA1*.md",
|
|
2467
|
+
"DESIGN*",
|
|
2468
|
+
"TODO*",
|
|
2469
|
+
"CHANGELOG*",
|
|
2470
|
+
"ARCHITECTURE*"
|
|
2471
|
+
];
|
|
2472
|
+
const docFiles = [];
|
|
2473
|
+
for (const pattern of docPatterns) {
|
|
2474
|
+
try {
|
|
2475
|
+
const files = await glob4(pattern, {
|
|
2476
|
+
cwd: process.cwd(),
|
|
2477
|
+
ignore: ["node_modules/**", ".git/**", "dist/**"],
|
|
2478
|
+
nodir: true
|
|
2479
|
+
});
|
|
2480
|
+
for (const f of files) {
|
|
2481
|
+
if (!docFiles.includes(f)) docFiles.push(f);
|
|
2482
|
+
}
|
|
2483
|
+
} catch {
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
if (docFiles.length === 0) {
|
|
2487
|
+
printInfo("\u672A\u627E\u5230\u6587\u6863\u6587\u4EF6\u3002");
|
|
2488
|
+
} else {
|
|
2489
|
+
console.log(theme.dim(`
|
|
2490
|
+
\u2500\u2500 \u9879\u76EE\u6587\u6863 \u2500\u2500`));
|
|
2491
|
+
for (const f of docFiles.sort().slice(0, 20)) {
|
|
2492
|
+
try {
|
|
2493
|
+
const stat = await fs5.stat(path5.resolve(process.cwd(), f));
|
|
2494
|
+
const sizeKB = (stat.size / 1024).toFixed(1);
|
|
2495
|
+
console.log(` \u{1F4C4} ${theme.info(f)} ${theme.dim(`(${sizeKB}KB)`)}`);
|
|
2496
|
+
} catch {
|
|
2497
|
+
console.log(` \u{1F4C4} ${theme.info(f)}`);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
if (docFiles.length > 20) {
|
|
2501
|
+
console.log(theme.dim(` ... \u8FD8\u6709 ${docFiles.length - 20} \u4E2A\u6587\u4EF6`));
|
|
2502
|
+
}
|
|
2503
|
+
console.log(theme.dim(`
|
|
2504
|
+
\u4F7F\u7528 /read <\u6587\u4EF6\u540D> \u52A0\u8F7D\u6587\u4EF6\u5230\u5BF9\u8BDD\u4E0A\u4E0B\u6587`));
|
|
2505
|
+
}
|
|
2506
|
+
break;
|
|
2507
|
+
}
|
|
2383
2508
|
case "/clear":
|
|
2384
2509
|
agent.clearHistory();
|
|
2385
2510
|
printSuccess("\u5BF9\u8BDD\u5386\u53F2\u5DF2\u6E05\u9664\u3002");
|
|
@@ -2904,8 +3029,8 @@ async function adminCommand() {
|
|
|
2904
3029
|
break;
|
|
2905
3030
|
}
|
|
2906
3031
|
}
|
|
2907
|
-
async function adminFetch(config3,
|
|
2908
|
-
const response = await fetch(`${config3.apiBaseUrl}${
|
|
3032
|
+
async function adminFetch(config3, path6, options) {
|
|
3033
|
+
const response = await fetch(`${config3.apiBaseUrl}${path6}`, {
|
|
2909
3034
|
...options,
|
|
2910
3035
|
headers: {
|
|
2911
3036
|
"Content-Type": "application/json",
|
|
@@ -3175,7 +3300,7 @@ function fmtTokens3(n) {
|
|
|
3175
3300
|
var program = new Command();
|
|
3176
3301
|
var config2 = getConfig();
|
|
3177
3302
|
setLocale(config2.locale);
|
|
3178
|
-
program.name("sxai").description(t("description")).version("0.
|
|
3303
|
+
program.name("sxai").description(t("description")).version("0.5.0");
|
|
3179
3304
|
program.command("chat", { isDefault: true }).description("\u542F\u52A8\u4EA4\u4E92\u5F0FAI\u5BF9\u8BDD\uFF08\u9ED8\u8BA4\u547D\u4EE4\uFF09").option("-m, --model <model>", "\u6307\u5B9AAI\u6A21\u578B", config2.model).option("-y, --yolo", "\u81EA\u52A8\u6A21\u5F0F\uFF1A\u8DF3\u8FC7\u6240\u6709\u786E\u8BA4\uFF0C\u8BA9AI\u81EA\u4E3B\u6267\u884C").action(async (options) => {
|
|
3180
3305
|
if (options.model && options.model !== config2.model) {
|
|
3181
3306
|
setConfig("model", options.model);
|