jinzd-ai-cli 0.4.13 → 0.4.15
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/README.md +2 -3
- package/README.zh-CN.md +2 -3
- package/dist/{chunk-TXCLZ72H.js → chunk-HOOMQACE.js} +5 -5
- package/dist/{chunk-DP3M26PP.js → chunk-KOD3C2CU.js} +1 -1
- package/dist/{chunk-52BIUGQ2.js → chunk-KYWU74D5.js} +2 -2
- package/dist/{chunk-TLOCRYJC.js → chunk-SNUHVNSD.js} +9 -1
- package/dist/{hub-LURPCJ4Z.js → hub-34MLKYPL.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/{run-tests-PVVT37LK.js → run-tests-H7IVHUZO.js} +1 -1
- package/dist/{run-tests-UPW6W4QE.js → run-tests-VB4UVV6Q.js} +1 -1
- package/dist/{server-KPNMFMDU.js → server-CL6Q5R2O.js} +302 -19
- package/dist/{task-orchestrator-XXOS7WHR.js → task-orchestrator-AFMHSW4N.js} +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
- **PWA Support** — Install Web UI as a desktop/mobile app, accessible over LAN
|
|
35
35
|
- **Hierarchical Context** — 3-layer context files (global / project / subdirectory) auto-injected
|
|
36
36
|
- **Headless Mode** — `ai-cli -p "prompt"` for CI/CD pipelines and scripting
|
|
37
|
-
- **
|
|
37
|
+
- **37 REPL Commands** — Session management, checkpointing, code review, scaffolding, and more
|
|
38
38
|
- **GitHub Actions CI/CD** — Automated testing on Node 20/22 + npm publish on release tags
|
|
39
39
|
- **Cross-Platform** — Windows, macOS, Linux
|
|
40
40
|
|
|
@@ -172,7 +172,7 @@ AI autonomously invokes these 16 tools during conversations:
|
|
|
172
172
|
|
|
173
173
|
**Multi-line input**: Use `\` at end of line for continuation, or paste multi-line content directly (auto-detected and merged).
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Type `/help` in the REPL to see all 37 commands.
|
|
176
176
|
|
|
177
177
|
## CLI Parameters
|
|
178
178
|
|
|
@@ -356,7 +356,6 @@ npm run test:watch # Watch mode
|
|
|
356
356
|
|
|
357
357
|
## Documentation
|
|
358
358
|
|
|
359
|
-
- [Full Usage Guide](USAGE.md) — Comprehensive reference for all features
|
|
360
359
|
- [Chinese README](README.zh-CN.md) — 中文说明文档
|
|
361
360
|
|
|
362
361
|
## License
|
package/README.zh-CN.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
- **PWA 支持** — Web UI 可安装为桌面/移动应用,支持局域网访问
|
|
27
27
|
- **三层级上下文** — 全局 / 项目 / 子目录上下文文件自动注入
|
|
28
28
|
- **无头模式** — `aicli -p "提示词"` 用于 CI/CD 管道和脚本
|
|
29
|
-
- **
|
|
29
|
+
- **37 个 REPL 命令** — 会话管理、检查点、代码审查、脚手架等
|
|
30
30
|
- **GitHub Actions CI/CD** — Node 20/22 自动测试 + Release tag 自动发布 npm
|
|
31
31
|
- **跨平台** — Windows、macOS、Linux
|
|
32
32
|
|
|
@@ -164,7 +164,7 @@ AI 在对话中可自主调用 16 个工具:
|
|
|
164
164
|
|
|
165
165
|
**多行输入**:行末加 `\` 续行,或直接粘贴多行内容(自动检测合并)。
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
在 REPL 中输入 `/help` 查看全部 37 个命令。
|
|
168
168
|
|
|
169
169
|
## CLI 参数
|
|
170
170
|
|
|
@@ -369,7 +369,6 @@ npm run test:watch # 监听模式
|
|
|
369
369
|
|
|
370
370
|
## 文档
|
|
371
371
|
|
|
372
|
-
- [完整使用说明](USAGE.md) — 所有功能的详细参考
|
|
373
372
|
- [English README](README.md) — English documentation
|
|
374
373
|
|
|
375
374
|
## License
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
7
7
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
8
8
|
runTestsTool
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KOD3C2CU.js";
|
|
10
10
|
|
|
11
11
|
// src/tools/builtin/bash.ts
|
|
12
12
|
import { execSync } from "child_process";
|
|
@@ -1854,10 +1854,6 @@ var EnvLoader = class {
|
|
|
1854
1854
|
*/
|
|
1855
1855
|
static getApiKey(providerId) {
|
|
1856
1856
|
const fixedEnvVar = ENV_KEY_MAP[providerId];
|
|
1857
|
-
if (fixedEnvVar) {
|
|
1858
|
-
const val = process.env[fixedEnvVar];
|
|
1859
|
-
if (val) return val;
|
|
1860
|
-
}
|
|
1861
1857
|
const dynamicEnvVar = `AICLI_API_KEY_${providerId.toUpperCase().replace(/-/g, "_")}`;
|
|
1862
1858
|
if (fixedEnvVar && fixedEnvVar !== dynamicEnvVar) {
|
|
1863
1859
|
const fixedVal = process.env[fixedEnvVar];
|
|
@@ -1867,6 +1863,10 @@ var EnvLoader = class {
|
|
|
1867
1863
|
`);
|
|
1868
1864
|
}
|
|
1869
1865
|
}
|
|
1866
|
+
if (fixedEnvVar) {
|
|
1867
|
+
const val = process.env[fixedEnvVar];
|
|
1868
|
+
if (val) return val;
|
|
1869
|
+
}
|
|
1870
1870
|
return process.env[dynamicEnvVar] || void 0;
|
|
1871
1871
|
}
|
|
1872
1872
|
static getDefaultProvider() {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
EnvLoader,
|
|
4
4
|
schemaToJsonSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HOOMQACE.js";
|
|
6
6
|
import {
|
|
7
7
|
APP_NAME,
|
|
8
8
|
CONFIG_DIR_NAME,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
MCP_TOOL_PREFIX,
|
|
16
16
|
PLUGINS_DIR_NAME,
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KOD3C2CU.js";
|
|
19
19
|
|
|
20
20
|
// src/config/config-manager.ts
|
|
21
21
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -6,13 +6,14 @@ import { platform } from "os";
|
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
|
|
8
8
|
// src/core/constants.ts
|
|
9
|
-
var VERSION = "0.4.
|
|
9
|
+
var VERSION = "0.4.15";
|
|
10
10
|
var APP_NAME = "ai-cli";
|
|
11
11
|
var CONFIG_DIR_NAME = ".aicli";
|
|
12
12
|
var CONFIG_FILE_NAME = "config.json";
|
|
13
13
|
var HISTORY_DIR_NAME = "history";
|
|
14
14
|
var PLUGINS_DIR_NAME = "plugins";
|
|
15
15
|
var SKILLS_DIR_NAME = "skills";
|
|
16
|
+
var CUSTOM_COMMANDS_DIR_NAME = "commands";
|
|
16
17
|
var CONTEXT_FILE_CANDIDATES = ["AICLI.md", "CLAUDE.md"];
|
|
17
18
|
var MEMORY_FILE_NAME = "memory.md";
|
|
18
19
|
var MEMORY_MAX_CHARS = 1e4;
|
|
@@ -84,6 +85,9 @@ var AGENTIC_BEHAVIOR_GUIDELINE = `# Important Behavioral Guidelines
|
|
|
84
85
|
- Only begin using write/execute tools when the user **explicitly requests** an action (e.g., "generate", "create", "modify", "run", "start", etc.).
|
|
85
86
|
- Project context files (CLAUDE.md, AICLI.md) provide background information about the project. They are NOT instructions to start working. Only use them as reference when the user asks a project-related question or task.
|
|
86
87
|
- If you are unsure about the user's intent, use the ask_user tool to confirm with the user, rather than assuming and executing on your own.`;
|
|
88
|
+
var AUTHOR = "Jin Zhengdong";
|
|
89
|
+
var AUTHOR_EMAIL = "zhengdong.jin@gmail.com";
|
|
90
|
+
var DESCRIPTION = "Cross-platform REPL-style AI conversation tool with multi-provider and agentic tool calling support";
|
|
87
91
|
|
|
88
92
|
// src/tools/builtin/run-tests.ts
|
|
89
93
|
var IS_WINDOWS = platform() === "win32";
|
|
@@ -447,6 +451,7 @@ export {
|
|
|
447
451
|
HISTORY_DIR_NAME,
|
|
448
452
|
PLUGINS_DIR_NAME,
|
|
449
453
|
SKILLS_DIR_NAME,
|
|
454
|
+
CUSTOM_COMMANDS_DIR_NAME,
|
|
450
455
|
CONTEXT_FILE_CANDIDATES,
|
|
451
456
|
MEMORY_FILE_NAME,
|
|
452
457
|
MEMORY_MAX_CHARS,
|
|
@@ -463,6 +468,9 @@ export {
|
|
|
463
468
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
464
469
|
SUBAGENT_ALLOWED_TOOLS,
|
|
465
470
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
471
|
+
AUTHOR,
|
|
472
|
+
AUTHOR_EMAIL,
|
|
473
|
+
DESCRIPTION,
|
|
466
474
|
executeTests,
|
|
467
475
|
runTestsTool
|
|
468
476
|
};
|
|
@@ -381,7 +381,7 @@ ${content}`);
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
384
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
384
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-AFMHSW4N.js");
|
|
385
385
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
386
386
|
let interrupted = false;
|
|
387
387
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
saveDevState,
|
|
24
24
|
sessionHasMeaningfulContent,
|
|
25
25
|
setupProxy
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-KYWU74D5.js";
|
|
27
27
|
import {
|
|
28
28
|
ToolRegistry,
|
|
29
29
|
askUserContext,
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
theme,
|
|
39
39
|
truncateOutput,
|
|
40
40
|
undoStack
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-HOOMQACE.js";
|
|
42
42
|
import {
|
|
43
43
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
44
44
|
AUTHOR,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
REPO_URL,
|
|
59
59
|
SKILLS_DIR_NAME,
|
|
60
60
|
VERSION
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-KOD3C2CU.js";
|
|
62
62
|
|
|
63
63
|
// src/index.ts
|
|
64
64
|
import { program } from "commander";
|
|
@@ -1914,7 +1914,7 @@ ${hint}` : "")
|
|
|
1914
1914
|
description: "Run project tests and show structured report",
|
|
1915
1915
|
usage: "/test [command|filter]",
|
|
1916
1916
|
async execute(args, _ctx) {
|
|
1917
|
-
const { executeTests } = await import("./run-tests-
|
|
1917
|
+
const { executeTests } = await import("./run-tests-H7IVHUZO.js");
|
|
1918
1918
|
const argStr = args.join(" ").trim();
|
|
1919
1919
|
let testArgs = {};
|
|
1920
1920
|
if (argStr) {
|
|
@@ -5528,7 +5528,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
5528
5528
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
5529
5529
|
process.exit(1);
|
|
5530
5530
|
}
|
|
5531
|
-
const { startWebServer } = await import("./server-
|
|
5531
|
+
const { startWebServer } = await import("./server-CL6Q5R2O.js");
|
|
5532
5532
|
await startWebServer({ port, host: options.host });
|
|
5533
5533
|
});
|
|
5534
5534
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -5761,7 +5761,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
5761
5761
|
}),
|
|
5762
5762
|
config.get("customProviders")
|
|
5763
5763
|
);
|
|
5764
|
-
const { startHub } = await import("./hub-
|
|
5764
|
+
const { startHub } = await import("./hub-34MLKYPL.js");
|
|
5765
5765
|
await startHub(
|
|
5766
5766
|
{
|
|
5767
5767
|
topic: topic ?? "",
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
renderDiff,
|
|
19
19
|
runHook,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-KYWU74D5.js";
|
|
22
22
|
import {
|
|
23
23
|
AuthManager
|
|
24
24
|
} from "./chunk-BYNY5JPB.js";
|
|
@@ -32,19 +32,24 @@ import {
|
|
|
32
32
|
spawnAgentContext,
|
|
33
33
|
truncateOutput,
|
|
34
34
|
undoStack
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-HOOMQACE.js";
|
|
36
36
|
import {
|
|
37
37
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
38
|
+
AUTHOR,
|
|
39
|
+
AUTHOR_EMAIL,
|
|
38
40
|
CONTEXT_FILE_CANDIDATES,
|
|
41
|
+
CUSTOM_COMMANDS_DIR_NAME,
|
|
39
42
|
DEFAULT_MAX_TOKENS,
|
|
43
|
+
DESCRIPTION,
|
|
40
44
|
MCP_PROJECT_CONFIG_NAME,
|
|
41
45
|
MEMORY_FILE_NAME,
|
|
42
46
|
MEMORY_MAX_CHARS,
|
|
43
47
|
PLAN_MODE_READONLY_TOOLS,
|
|
44
48
|
PLAN_MODE_SYSTEM_ADDON,
|
|
49
|
+
PLUGINS_DIR_NAME,
|
|
45
50
|
SKILLS_DIR_NAME,
|
|
46
51
|
VERSION
|
|
47
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-KOD3C2CU.js";
|
|
48
53
|
|
|
49
54
|
// src/web/server.ts
|
|
50
55
|
import express from "express";
|
|
@@ -475,6 +480,8 @@ var SessionHandler = class _SessionHandler {
|
|
|
475
480
|
pendingAskUser = /* @__PURE__ */ new Map();
|
|
476
481
|
/** Active system prompt from context files */
|
|
477
482
|
activeSystemPrompt;
|
|
483
|
+
/** Directories added via /add-dir */
|
|
484
|
+
addedDirs = /* @__PURE__ */ new Set();
|
|
478
485
|
constructor(ws, shared) {
|
|
479
486
|
this.ws = ws;
|
|
480
487
|
this.config = shared.config;
|
|
@@ -1078,27 +1085,25 @@ Tokens: in=${this.sessionTokenUsage.inputTokens} out=${this.sessionTokenUsage.ou
|
|
|
1078
1085
|
message: [
|
|
1079
1086
|
"\u{1F4D6} Available Web UI commands:",
|
|
1080
1087
|
"",
|
|
1088
|
+
" /help \u2014 Show this help message",
|
|
1089
|
+
" /about \u2014 Version & author info",
|
|
1081
1090
|
" /provider <id> \u2014 Switch AI provider",
|
|
1082
1091
|
" /model <id> \u2014 Switch model",
|
|
1083
1092
|
" /clear \u2014 Clear conversation & start new session",
|
|
1084
1093
|
" /compact [hint] \u2014 Compress conversation history",
|
|
1085
1094
|
" /think [on|off] \u2014 Toggle extended thinking mode",
|
|
1086
1095
|
" /plan [enter|exit] \u2014 Toggle read-only planning mode",
|
|
1087
|
-
" /session new
|
|
1088
|
-
" /
|
|
1089
|
-
" /
|
|
1090
|
-
" /session delete <id> \u2014 Delete a session",
|
|
1096
|
+
" /session new|list|load|delete <id> \u2014 Session management",
|
|
1097
|
+
" /system [prompt|clear] \u2014 Set/view/reset system prompt",
|
|
1098
|
+
" /context [reload] \u2014 Show/reload context layers",
|
|
1091
1099
|
" /status \u2014 Show session info & token usage",
|
|
1092
1100
|
" /cost \u2014 Show cumulative token usage",
|
|
1093
|
-
" /
|
|
1094
|
-
" /
|
|
1095
|
-
" /
|
|
1096
|
-
" /skill
|
|
1097
|
-
" /
|
|
1098
|
-
" /
|
|
1099
|
-
" /memory add <text> \u2014 Add entry to persistent memory",
|
|
1100
|
-
" /memory clear \u2014 Clear persistent memory",
|
|
1101
|
-
" /yolo [on|off] \u2014 Toggle session auto-approve (skip confirmations)",
|
|
1101
|
+
" /config [show|get|set] \u2014 View/modify configuration",
|
|
1102
|
+
" /tools \u2014 Show tools, MCP servers & skills",
|
|
1103
|
+
" /export [md|json] \u2014 Export conversation",
|
|
1104
|
+
" /skill [name|off|list|reload] \u2014 Manage agent skills",
|
|
1105
|
+
" /memory [show|add|clear] \u2014 Persistent memory management",
|
|
1106
|
+
" /yolo [on|off] \u2014 Toggle auto-approve (skip confirmations)",
|
|
1102
1107
|
" /search <keyword> \u2014 Search across all session histories",
|
|
1103
1108
|
" /undo [list|<n>] \u2014 Undo file operations",
|
|
1104
1109
|
" /diff [--stats] \u2014 Show file modifications in this session",
|
|
@@ -1107,8 +1112,13 @@ Tokens: in=${this.sessionTokenUsage.inputTokens} out=${this.sessionTokenUsage.ou
|
|
|
1107
1112
|
" /review [--staged] \u2014 AI code review from git diff",
|
|
1108
1113
|
" /test [command] \u2014 Run project tests",
|
|
1109
1114
|
" /init [--force] \u2014 Generate AICLI.md by scanning project",
|
|
1115
|
+
" /scaffold <desc> \u2014 Generate project scaffolding with AI",
|
|
1116
|
+
" /add-dir [path|remove] \u2014 Add/remove directory from AI context",
|
|
1117
|
+
" /mcp [reconnect] \u2014 Show/manage MCP servers",
|
|
1118
|
+
" /plugins \u2014 Show loaded plugins",
|
|
1119
|
+
" /commands \u2014 List custom commands",
|
|
1110
1120
|
" /doctor \u2014 Health check (API keys, config, MCP)",
|
|
1111
|
-
" /
|
|
1121
|
+
" /bug \u2014 Generate bug report template",
|
|
1112
1122
|
"",
|
|
1113
1123
|
"\u{1F4A1} Tips:",
|
|
1114
1124
|
" \u2022 Change provider/model with the dropdowns above",
|
|
@@ -1472,7 +1482,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
1472
1482
|
case "test": {
|
|
1473
1483
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
1474
1484
|
try {
|
|
1475
|
-
const { executeTests } = await import("./run-tests-
|
|
1485
|
+
const { executeTests } = await import("./run-tests-H7IVHUZO.js");
|
|
1476
1486
|
const argStr = args.join(" ").trim();
|
|
1477
1487
|
let testArgs = {};
|
|
1478
1488
|
if (argStr) {
|
|
@@ -1560,6 +1570,264 @@ Use /context reload to load it.` });
|
|
|
1560
1570
|
this.send({ type: "info", message: lines.join("\n") });
|
|
1561
1571
|
break;
|
|
1562
1572
|
}
|
|
1573
|
+
// ── /about ──────────────────────────────────────────────────────
|
|
1574
|
+
case "about": {
|
|
1575
|
+
const providerList = this.providers.listAll();
|
|
1576
|
+
const toolCount = this.toolRegistry.getDefinitions().length;
|
|
1577
|
+
const mcpTools = this.mcpManager?.getTotalToolCount() ?? 0;
|
|
1578
|
+
const lines = [
|
|
1579
|
+
`\u{1F916} **ai-cli** v${VERSION}`,
|
|
1580
|
+
"",
|
|
1581
|
+
`${DESCRIPTION}`,
|
|
1582
|
+
`Author: ${AUTHOR} <${AUTHOR_EMAIL}>`,
|
|
1583
|
+
"",
|
|
1584
|
+
`**Providers:** ${providerList.length} (${providerList.map((p) => p.id).join(", ")})`,
|
|
1585
|
+
`**Tools:** ${toolCount + mcpTools} (${toolCount} built-in${mcpTools > 0 ? ` + ${mcpTools} MCP` : ""})`,
|
|
1586
|
+
`**REPL Commands:** 37`,
|
|
1587
|
+
"",
|
|
1588
|
+
`GitHub: https://github.com/jinzhengdong/ai-cli`
|
|
1589
|
+
];
|
|
1590
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
// ── /system ─────────────────────────────────────────────────────
|
|
1594
|
+
case "system": {
|
|
1595
|
+
const text = args.join(" ").trim();
|
|
1596
|
+
if (!text) {
|
|
1597
|
+
const current = this.activeSystemPrompt;
|
|
1598
|
+
if (current) {
|
|
1599
|
+
const preview = current.length > 500 ? current.slice(0, 500) + "..." : current;
|
|
1600
|
+
this.send({ type: "info", message: `\u{1F4CB} Current system prompt (${current.length} chars):
|
|
1601
|
+
|
|
1602
|
+
${preview}` });
|
|
1603
|
+
} else {
|
|
1604
|
+
this.send({ type: "info", message: "No custom system prompt set. Using default.\nUsage: /system <prompt>" });
|
|
1605
|
+
}
|
|
1606
|
+
break;
|
|
1607
|
+
}
|
|
1608
|
+
if (text === "clear" || text === "reset") {
|
|
1609
|
+
this.activeSystemPrompt = this.loadContextFiles();
|
|
1610
|
+
this.send({ type: "info", message: "\u2713 System prompt reset to default (context files)." });
|
|
1611
|
+
} else {
|
|
1612
|
+
this.activeSystemPrompt = text;
|
|
1613
|
+
this.send({ type: "info", message: `\u2713 System prompt set (${text.length} chars).` });
|
|
1614
|
+
}
|
|
1615
|
+
break;
|
|
1616
|
+
}
|
|
1617
|
+
// ── /config ─────────────────────────────────────────────────────
|
|
1618
|
+
case "config": {
|
|
1619
|
+
const sub = args[0];
|
|
1620
|
+
if (sub === "show" || !sub) {
|
|
1621
|
+
this.send({ type: "info", message: `\u2699\uFE0F Configuration:
|
|
1622
|
+
\`\`\`json
|
|
1623
|
+
${this.config.toFormattedJSON()}
|
|
1624
|
+
\`\`\`` });
|
|
1625
|
+
} else if (sub === "get" && args[1]) {
|
|
1626
|
+
const val = this.config.getByPath(args[1]);
|
|
1627
|
+
const display = typeof val === "object" ? JSON.stringify(val, null, 2) : String(val ?? "undefined");
|
|
1628
|
+
this.send({ type: "info", message: `${args[1]} = ${display}` });
|
|
1629
|
+
} else if (sub === "set" && args[1] && args[2] !== void 0) {
|
|
1630
|
+
try {
|
|
1631
|
+
this.config.setByPath(args[1], args.slice(2).join(" "));
|
|
1632
|
+
this.send({ type: "info", message: `\u2713 ${args[1]} = ${args.slice(2).join(" ")}` });
|
|
1633
|
+
} catch (err) {
|
|
1634
|
+
this.send({ type: "error", message: `Config error: ${err.message}` });
|
|
1635
|
+
}
|
|
1636
|
+
} else {
|
|
1637
|
+
this.send({ type: "info", message: "Usage: /config [show] | /config get <key> | /config set <key> <value>" });
|
|
1638
|
+
}
|
|
1639
|
+
break;
|
|
1640
|
+
}
|
|
1641
|
+
// ── /context ────────────────────────────────────────────────────
|
|
1642
|
+
case "context": {
|
|
1643
|
+
const sub = args[0];
|
|
1644
|
+
if (sub === "reload") {
|
|
1645
|
+
this.activeSystemPrompt = this.loadContextFiles();
|
|
1646
|
+
this.send({ type: "info", message: this.activeSystemPrompt ? `\u2713 Context reloaded (${this.activeSystemPrompt.length} chars).` : "\u2713 No context files found." });
|
|
1647
|
+
break;
|
|
1648
|
+
}
|
|
1649
|
+
const configDir = this.config.getConfigDir();
|
|
1650
|
+
const cwd = process.cwd();
|
|
1651
|
+
const gitRoot = getGitRoot(cwd);
|
|
1652
|
+
const projectRoot = gitRoot ?? cwd;
|
|
1653
|
+
const layers = ["\u{1F4DA} **Context Layers:**", ""];
|
|
1654
|
+
const checkLayer = (label, dir) => {
|
|
1655
|
+
for (const name2 of CONTEXT_FILE_CANDIDATES) {
|
|
1656
|
+
const fullPath = join2(dir, name2);
|
|
1657
|
+
if (existsSync3(fullPath)) {
|
|
1658
|
+
try {
|
|
1659
|
+
const size = statSync(fullPath).size;
|
|
1660
|
+
layers.push(` \u2713 ${label}: ${fullPath} (${size} bytes)`);
|
|
1661
|
+
return;
|
|
1662
|
+
} catch {
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
layers.push(` \u2013 ${label}: (none)`);
|
|
1667
|
+
};
|
|
1668
|
+
checkLayer("Global", configDir);
|
|
1669
|
+
checkLayer("Project", projectRoot);
|
|
1670
|
+
if (resolve(cwd) !== resolve(projectRoot)) {
|
|
1671
|
+
checkLayer("Subdir", cwd);
|
|
1672
|
+
}
|
|
1673
|
+
layers.push("");
|
|
1674
|
+
layers.push(`Total prompt length: ${this.activeSystemPrompt?.length ?? 0} chars`);
|
|
1675
|
+
layers.push("Use /context reload to refresh.");
|
|
1676
|
+
this.send({ type: "info", message: layers.join("\n") });
|
|
1677
|
+
break;
|
|
1678
|
+
}
|
|
1679
|
+
// ── /mcp ────────────────────────────────────────────────────────
|
|
1680
|
+
case "mcp": {
|
|
1681
|
+
if (!this.mcpManager) {
|
|
1682
|
+
this.send({ type: "info", message: "MCP not configured. Add mcpServers to config.json." });
|
|
1683
|
+
break;
|
|
1684
|
+
}
|
|
1685
|
+
const sub = args[0];
|
|
1686
|
+
if (sub === "reconnect") {
|
|
1687
|
+
const targetId = args[1];
|
|
1688
|
+
this.send({ type: "info", message: "\u{1F504} Reconnecting MCP servers..." });
|
|
1689
|
+
try {
|
|
1690
|
+
await this.mcpManager.reconnectAll();
|
|
1691
|
+
this.send({ type: "info", message: "\u2713 MCP reconnect complete." });
|
|
1692
|
+
} catch (err) {
|
|
1693
|
+
this.send({ type: "error", message: `Reconnect failed: ${err.message}` });
|
|
1694
|
+
}
|
|
1695
|
+
this.sendToolsList();
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
1698
|
+
const statuses = this.mcpManager.getStatus();
|
|
1699
|
+
if (statuses.length === 0) {
|
|
1700
|
+
this.send({ type: "info", message: "No MCP servers configured." });
|
|
1701
|
+
break;
|
|
1702
|
+
}
|
|
1703
|
+
const lines = [`\u{1F50C} **MCP Servers (${statuses.length}):**`, ""];
|
|
1704
|
+
for (const s of statuses) {
|
|
1705
|
+
const state = s.connected ? `\u2713 connected \xB7 ${s.serverName} \xB7 ${s.toolCount} tools` : `\u2717 disconnected${s.error ? ` \xB7 ${s.error}` : ""}`;
|
|
1706
|
+
lines.push(` ${s.serverId}: ${state}`);
|
|
1707
|
+
}
|
|
1708
|
+
lines.push("");
|
|
1709
|
+
lines.push("Use /mcp reconnect to reconnect.");
|
|
1710
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1711
|
+
break;
|
|
1712
|
+
}
|
|
1713
|
+
// ── /scaffold ───────────────────────────────────────────────────
|
|
1714
|
+
case "scaffold": {
|
|
1715
|
+
const description = args.join(" ").trim();
|
|
1716
|
+
if (!description) {
|
|
1717
|
+
this.send({ type: "error", message: "Usage: /scaffold <project description>" });
|
|
1718
|
+
break;
|
|
1719
|
+
}
|
|
1720
|
+
this.send({ type: "info", message: "\u{1F3D7}\uFE0F Generating project scaffold..." });
|
|
1721
|
+
const scaffoldPrompt = `Please scaffold a project based on this description: ${description}
|
|
1722
|
+
|
|
1723
|
+
Create the necessary files and directory structure. Use write_file and bash tools to set up the project.`;
|
|
1724
|
+
await this.handleChat(scaffoldPrompt);
|
|
1725
|
+
break;
|
|
1726
|
+
}
|
|
1727
|
+
// ── /add-dir ────────────────────────────────────────────────────
|
|
1728
|
+
case "add-dir": {
|
|
1729
|
+
const sub = args[0]?.trim();
|
|
1730
|
+
if (!sub) {
|
|
1731
|
+
this.send({ type: "info", message: this.addedDirs.size > 0 ? `\u{1F4C1} Added directories:
|
|
1732
|
+
${[...this.addedDirs].map((d) => ` \u2022 ${d}`).join("\n")}
|
|
1733
|
+
|
|
1734
|
+
Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path> | /add-dir remove" });
|
|
1735
|
+
break;
|
|
1736
|
+
}
|
|
1737
|
+
if (sub === "remove" || sub === "clear") {
|
|
1738
|
+
this.addedDirs.clear();
|
|
1739
|
+
this.send({ type: "info", message: "\u2713 All added directories removed from context." });
|
|
1740
|
+
break;
|
|
1741
|
+
}
|
|
1742
|
+
const dirPath = resolve(sub);
|
|
1743
|
+
if (!existsSync3(dirPath)) {
|
|
1744
|
+
this.send({ type: "error", message: `Directory not found: ${dirPath}` });
|
|
1745
|
+
break;
|
|
1746
|
+
}
|
|
1747
|
+
if (!statSync(dirPath).isDirectory()) {
|
|
1748
|
+
this.send({ type: "error", message: `Not a directory: ${dirPath}` });
|
|
1749
|
+
break;
|
|
1750
|
+
}
|
|
1751
|
+
this.addedDirs.add(dirPath);
|
|
1752
|
+
this.send({ type: "info", message: `\u2713 Added directory: ${dirPath}
|
|
1753
|
+
It will be included in AI context for subsequent messages.` });
|
|
1754
|
+
break;
|
|
1755
|
+
}
|
|
1756
|
+
// ── /commands ───────────────────────────────────────────────────
|
|
1757
|
+
case "commands": {
|
|
1758
|
+
const configDir = this.config.getConfigDir();
|
|
1759
|
+
const commandsDir = join2(configDir, CUSTOM_COMMANDS_DIR_NAME);
|
|
1760
|
+
if (!existsSync3(commandsDir)) {
|
|
1761
|
+
this.send({ type: "info", message: `No custom commands directory.
|
|
1762
|
+
Create: ${commandsDir}/ with .md files.` });
|
|
1763
|
+
break;
|
|
1764
|
+
}
|
|
1765
|
+
try {
|
|
1766
|
+
const files = readdirSync(commandsDir).filter((f) => f.endsWith(".md"));
|
|
1767
|
+
if (files.length === 0) {
|
|
1768
|
+
this.send({ type: "info", message: `No custom commands found in ${commandsDir}
|
|
1769
|
+
Add .md files to create commands.` });
|
|
1770
|
+
} else {
|
|
1771
|
+
const lines = [`\u{1F4CB} **Custom Commands (${files.length}):**`, `Dir: ${commandsDir}`, ""];
|
|
1772
|
+
for (const f of files) {
|
|
1773
|
+
const name2 = f.replace(/\.md$/, "");
|
|
1774
|
+
lines.push(` /${name2}`);
|
|
1775
|
+
}
|
|
1776
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1777
|
+
}
|
|
1778
|
+
} catch {
|
|
1779
|
+
this.send({ type: "info", message: `Cannot read: ${commandsDir}` });
|
|
1780
|
+
}
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
// ── /plugins ────────────────────────────────────────────────────
|
|
1784
|
+
case "plugins": {
|
|
1785
|
+
const configDir = this.config.getConfigDir();
|
|
1786
|
+
const pluginsDir = join2(configDir, PLUGINS_DIR_NAME);
|
|
1787
|
+
const pluginTools = this.toolRegistry.listPluginTools();
|
|
1788
|
+
const lines = [`\u{1F50C} **Plugins:**`, `Dir: ${pluginsDir}`, ""];
|
|
1789
|
+
if (pluginTools.length === 0) {
|
|
1790
|
+
lines.push("No plugins loaded.");
|
|
1791
|
+
lines.push("Add .js files to the plugins directory and set allowPlugins:true in config.");
|
|
1792
|
+
} else {
|
|
1793
|
+
for (const t of pluginTools) {
|
|
1794
|
+
lines.push(` \u2022 ${t.name} \u2014 ${t.description}`);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1798
|
+
break;
|
|
1799
|
+
}
|
|
1800
|
+
// ── /bug ────────────────────────────────────────────────────────
|
|
1801
|
+
case "bug": {
|
|
1802
|
+
const session = this.sessions.current;
|
|
1803
|
+
const lines = [
|
|
1804
|
+
"\u{1F41B} **Bug Report Template**",
|
|
1805
|
+
"",
|
|
1806
|
+
"**Environment:**",
|
|
1807
|
+
` ai-cli version: ${VERSION}`,
|
|
1808
|
+
` Node.js: ${process.version}`,
|
|
1809
|
+
` OS: ${process.platform} ${process.arch}`,
|
|
1810
|
+
` Provider: ${this.currentProvider}`,
|
|
1811
|
+
` Model: ${this.currentModel}`,
|
|
1812
|
+
` Session: ${session?.id.slice(0, 8) ?? "none"} (${session?.messages.length ?? 0} messages)`,
|
|
1813
|
+
"",
|
|
1814
|
+
"**Description:**",
|
|
1815
|
+
"(Describe the bug)",
|
|
1816
|
+
"",
|
|
1817
|
+
"**Steps to reproduce:**",
|
|
1818
|
+
"1. ...",
|
|
1819
|
+
"",
|
|
1820
|
+
"**Expected behavior:**",
|
|
1821
|
+
"...",
|
|
1822
|
+
"",
|
|
1823
|
+
"**Actual behavior:**",
|
|
1824
|
+
"...",
|
|
1825
|
+
"",
|
|
1826
|
+
"Report at: https://github.com/jinzhengdong/ai-cli/issues"
|
|
1827
|
+
];
|
|
1828
|
+
this.send({ type: "info", message: lines.join("\n") });
|
|
1829
|
+
break;
|
|
1830
|
+
}
|
|
1563
1831
|
default:
|
|
1564
1832
|
this.send({ type: "error", message: `Unknown command: /${name}. Type /help for available commands.` });
|
|
1565
1833
|
}
|
|
@@ -1759,12 +2027,27 @@ Use /context reload to load it.` });
|
|
|
1759
2027
|
buildSystemPrompt() {
|
|
1760
2028
|
const skillContent = this.skillManager?.getActivePromptContent();
|
|
1761
2029
|
const activeSkill = skillContent && this.skillManager?.getActive() ? { name: this.skillManager.getActive().meta.name, content: skillContent } : void 0;
|
|
1762
|
-
|
|
2030
|
+
let prompt = buildSystemPrompt({
|
|
1763
2031
|
activeSystemPrompt: this.activeSystemPrompt,
|
|
1764
2032
|
activeSkill,
|
|
1765
2033
|
planMode: this.planMode,
|
|
1766
2034
|
configDir: this.config.getConfigDir()
|
|
1767
2035
|
});
|
|
2036
|
+
if (this.addedDirs.size > 0) {
|
|
2037
|
+
const MAX_DIR_CONTEXT = 4e4;
|
|
2038
|
+
let dirContext = "\n\n--- Added Directory Context ---\n";
|
|
2039
|
+
let totalLen = 0;
|
|
2040
|
+
for (const dir of this.addedDirs) {
|
|
2041
|
+
if (totalLen > MAX_DIR_CONTEXT) break;
|
|
2042
|
+
dirContext += `
|
|
2043
|
+
[Directory: ${dir}]
|
|
2044
|
+
`;
|
|
2045
|
+
dirContext += this.scanDirTree(dir, 2, 40) + "\n";
|
|
2046
|
+
totalLen = dirContext.length;
|
|
2047
|
+
}
|
|
2048
|
+
prompt += dirContext;
|
|
2049
|
+
}
|
|
2050
|
+
return prompt;
|
|
1768
2051
|
}
|
|
1769
2052
|
getModelParams() {
|
|
1770
2053
|
const allParams = this.config.get("modelParams");
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
getDangerLevel,
|
|
5
5
|
googleSearchContext,
|
|
6
6
|
truncateOutput
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HOOMQACE.js";
|
|
8
8
|
import {
|
|
9
9
|
SUBAGENT_ALLOWED_TOOLS
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KOD3C2CU.js";
|
|
11
11
|
|
|
12
12
|
// src/hub/task-orchestrator.ts
|
|
13
13
|
import { createInterface } from "readline";
|