jinzd-ai-cli 0.4.170 → 0.4.172
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 +4 -4
- package/README.zh-CN.md +4 -4
- package/dist/{batch-CAV4XSEF.js → batch-7FOD7UAI.js} +2 -2
- package/dist/{chunk-2C2DGQ5M.js → chunk-3QHN2LKK.js} +2 -2
- package/dist/{chunk-PTXA4BGU.js → chunk-675G3UGO.js} +1 -1
- package/dist/{chunk-SPJ5NO5Z.js → chunk-DCZYF7AK.js} +1 -1
- package/dist/{chunk-7ORSZ7UO.js → chunk-H2X7LKLQ.js} +3 -3
- package/dist/{chunk-Q466H3NV.js → chunk-QZ4TXN6I.js} +1 -1
- package/dist/{chunk-PUUJZGAS.js → chunk-SGD5WSDG.js} +1 -1
- package/dist/{chunk-E5UKN2FB.js → chunk-UEPQH4FK.js} +1 -1
- package/dist/{chunk-NVBUA6YL.js → chunk-VNWZTKRX.js} +1 -1
- package/dist/{ci-VERENT2L.js → ci-AFTGRKJ6.js} +2 -2
- package/dist/{constants-DX4RNM5O.js → constants-J2BZAFWO.js} +1 -1
- package/dist/{doctor-cli-323ZXFCH.js → doctor-cli-YYQ5QXDR.js} +4 -4
- package/dist/electron-server.js +2 -2
- package/dist/{hub-IZL5HKHA.js → hub-7IF37CGA.js} +1 -1
- package/dist/index.js +52 -15
- package/dist/{run-tests-KP7Y34MG.js → run-tests-FXXWLFKS.js} +1 -1
- package/dist/{run-tests-JUG5WK6N.js → run-tests-HLB2NHJO.js} +2 -2
- package/dist/{server-JXCJRJN5.js → server-MZL4VR7M.js} +7 -7
- package/dist/{server-VQTTNO3M.js → server-O3NO5D3X.js} +4 -4
- package/dist/{task-orchestrator-PY5AF2US.js → task-orchestrator-OCMQPD4H.js} +4 -4
- package/dist/web/client/app.js +29 -3
- package/dist/web/client/style.css +146 -131
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/jinzd-ai-cli)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](https://nodejs.org)
|
|
10
|
-
[]()
|
|
11
11
|
[](https://github.com/jinzhengdong/ai-cli/releases)
|
|
12
12
|
[](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
|
|
13
13
|
|
|
14
|
-
**ai-cli** is a powerful AI assistant that connects to
|
|
14
|
+
**ai-cli** is a powerful AI assistant that connects to 9 providers (including local Ollama models) and executes tasks autonomously through agentic tool calling. Use it as a terminal REPL, a browser-based Web UI, or a standalone Electron desktop app.
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
17
|
<img src="https://img.shields.io/badge/CLI-Terminal-blue" alt="CLI" />
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
## Highlights
|
|
23
23
|
|
|
24
|
-
- **
|
|
24
|
+
- **9 Built-in Providers** — Claude, Gemini, DeepSeek, OpenAI, Zhipu GLM, Kimi, **MiniMax (海螺)**, OpenRouter (300+ models), **Ollama** (local models, no API key needed)
|
|
25
25
|
- **3 Interfaces** — Terminal CLI, browser Web UI (`aicli web`), Electron desktop app
|
|
26
26
|
- **Agentic Tool Calling** — AI autonomously runs shell commands, reads/writes files, searches code, fetches web, runs tests (default 200 rounds, configurable up to 10000 via `config.maxToolRounds` or `--max-tool-rounds`)
|
|
27
27
|
- **Prompt Caching** *(v0.4.70+)* — System prompt split into stable/volatile halves so Claude caches the stable part with `cache_control: ephemeral`; cached tokens bill at ~10% of the input price
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
- **Conversation Branching** *(v0.4.74+)* — `/branch list/new/switch/delete/rename` inside the REPL, plus a 🌿 "fork here" button on every replay step — explore alternate directions without losing the original thread
|
|
32
32
|
- **Symbol Index** *(v0.4.76+, multi-language since v0.4.143)* — persistent tree-sitter index for TypeScript / JavaScript / TSX / Python / Go / Rust / Java / C/C++ powers three new AI tools: `find_symbol`, `get_outline`, `find_references`. Orders of magnitude faster than grep for definition lookups; background refresh on REPL startup, `/index status|rebuild|clear` to manage
|
|
33
33
|
- **Semantic Code Search** *(v0.4.77+)* — `search_code` tool finds code by meaning, not name. Local sentence embeddings (multilingual MiniLM, 117 MB one-time download) score symbols by cosine similarity against natural-language queries in English or Chinese ("where are users authenticated", "哪里做了速率限制"). No API key, runs on CPU. Manage with `/index semantic-rebuild|semantic-clear`
|
|
34
|
-
- **MCP Server Mode** *(v0.4.84+)* — `aicli mcp-serve` reverses ai-cli into an MCP server (JSON-RPC 2.0 over stdio), exposing its
|
|
34
|
+
- **MCP Server Mode** *(v0.4.84+)* — `aicli mcp-serve` reverses ai-cli into an MCP server (JSON-RPC 2.0 over stdio), exposing its 28 built-in tools (incl. `find_symbol` / `search_code` / `run_tests`) to Claude Desktop / Cursor / any MCP client. Opt-in destructive-tool allow, `--tools` whitelist, `--cwd` override
|
|
35
35
|
- **Session Sensitive-Data Redaction** *(v0.4.88+)* — unified redactor scrubs `password=` / `api_key` / bearer tokens / OpenAI-style keys from every message **before it hits disk**. Query text is redacted too, so secrets never reach embeddings or logs. `/security status` + `/security scan` to audit
|
|
36
36
|
- **Human-like Long-Term Memory** *(v0.4.89+, B4)* — semantic index over every past chat session + `recall_memory` AI tool + `/memory rebuild|refresh|status|recall` commands. AI is prompted to auto-recall when it sees "last time" / "之前" / ambiguous references. Reuses the same MiniLM embedder as semantic code search
|
|
37
37
|
- **Web UI Memory Panel** *(v0.4.90+, B4)* — new 🧠 Memory sidebar tab with semantic search across past chats; each hit has **➕ Inject** (quotes the snippet into the chat input as a markdown blockquote so you can review/edit before sending — no silent context injection) and **↗ Load** (jumps to source session). Bulk "Inject top 3" for recall bundles
|
package/README.zh-CN.md
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# ai-cli
|
|
4
4
|
|
|
5
|
-
> 跨平台 AI 编程助手 — CLI 终端、Web 界面、桌面应用三合一,支持
|
|
5
|
+
> 跨平台 AI 编程助手 — CLI 终端、Web 界面、桌面应用三合一,支持 9 大 Provider(含本地 Ollama)与 Agentic 工具调用
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/jinzd-ai-cli)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](https://nodejs.org)
|
|
10
|
-
[]()
|
|
11
11
|
[](https://github.com/jinzhengdong/ai-cli/releases)
|
|
12
12
|
[](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
|
|
13
13
|
|
|
14
14
|
## 特性亮点
|
|
15
15
|
|
|
16
|
-
- **
|
|
16
|
+
- **9 大内置 Provider** — Claude、Gemini、DeepSeek、OpenAI、智谱 GLM、Kimi、**MiniMax(海螺)**、OpenRouter(300+ 模型)、**Ollama**(本地模型,无需 API Key)
|
|
17
17
|
- **三种使用方式** — 终端 CLI、浏览器 Web UI(`aicli web`)、Electron 桌面应用
|
|
18
18
|
- **Agentic 工具调用** — AI 自主执行 bash 命令、读写文件、搜索代码、抓取网页、运行测试(默认 200 轮,可通过 `config.maxToolRounds` 或 `--max-tool-rounds` 调整,上限 10000)
|
|
19
19
|
- **Prompt Caching**(v0.4.70+)— system prompt 拆分稳定/易变两段,Claude 对稳定段启用 `cache_control: ephemeral`,命中时按 10% 计费
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
- **对话分支**(v0.4.74+)— REPL 内 `/branch list/new/switch/delete/rename/diff/cherry-pick`,Web UI 回放面板每条消息旁 🌿 "fork here" 按钮,任意位置开辟新分支探索不同方向,原对话保持不变;v0.4.81 起所有子命令支持 id / title / 唯一前缀
|
|
24
24
|
- **符号索引**(v0.4.76+,C1;v0.4.143 起多语言)— tree-sitter 持久化索引(TS / JS / TSX / JSX / Python / Go / Rust / Java / C/C++)+ 3 个只读 AI 工具(`find_symbol` / `get_outline` / `find_references`)+ `/index status/rebuild/clear`;启动后台增量刷新,`write_file` 后自动 upsert
|
|
25
25
|
- **语义代码搜索**(v0.4.77+,C2)— `search_code` AI 工具 + 本地 sentence embedding(`paraphrase-multilingual-MiniLM-L12-v2`,117 MB 一次性下载,384 维,CPU 运行);支持中英文自然语言查询代码;`/index semantic-rebuild/semantic-clear` 管理
|
|
26
|
-
- **MCP Server 模式**(v0.4.84+,E1)— `aicli mcp-serve` 把 aicli 反转为 MCP 服务器(JSON-RPC 2.0 over stdio),把
|
|
26
|
+
- **MCP Server 模式**(v0.4.84+,E1)— `aicli mcp-serve` 把 aicli 反转为 MCP 服务器(JSON-RPC 2.0 over stdio),把 28 个内置工具(含 `find_symbol` / `search_code` / `run_tests`)输出给 Claude Desktop / Cursor / 任何 MCP 客户端;支持 `--tools` 白名单、`--cwd` 覆盖、`--allow-destructive`
|
|
27
27
|
- **Session 敏感数据脱敏**(v0.4.88+)— 统一 redactor 在 session **落盘前**自动替换 `password=` / `api_key` / bearer token / OpenAI key 为 `[REDACTED:*]`;查询文本也走脱敏,secret 不会进 embedding 或日志;`/security status` + `/security scan` 审计
|
|
28
28
|
- **类人长期记忆**(v0.4.89+,B4)— 聊天记录语义索引跨 session 可召回 + `recall_memory` AI 工具 + `/memory rebuild/refresh/status/recall/index-clear`;AI 看到"上次"/"之前"/指代不明时自动回忆。复用 C2 的 MiniLM embedder
|
|
29
29
|
- **Web UI Memory 面板**(v0.4.90+,B4)— sidebar 新增 🧠 Memory 标签页,跨 session 语义搜索;每条 hit 带 **➕ Inject**(把片段作为 markdown 引用块塞进聊天输入框,用户可在上面继续打字编辑——不是静默注入上下文)和 **↗ Load**(跳转对应 session);顶部"➕ Inject top 3"一键批量
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UEPQH4FK.js";
|
|
5
5
|
import "./chunk-TZQHYZKT.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-675G3UGO.js";
|
|
7
7
|
import "./chunk-PDX44BCA.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/batch.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-H2X7LKLQ.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-675G3UGO.js";
|
|
15
15
|
|
|
16
16
|
// src/mcp/client.ts
|
|
17
17
|
import { spawn } from "child_process";
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-HDSKW7Q3.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SGD5WSDG.js";
|
|
9
9
|
import {
|
|
10
10
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DCZYF7AK.js";
|
|
12
12
|
import {
|
|
13
13
|
getDangerLevel,
|
|
14
14
|
isFileWriteTool
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
SUBAGENT_ALLOWED_TOOLS,
|
|
26
26
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
27
27
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-675G3UGO.js";
|
|
29
29
|
import {
|
|
30
30
|
fileCheckpoints
|
|
31
31
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
import "./chunk-NXXNLLSG.js";
|
|
11
11
|
import {
|
|
12
12
|
ConfigManager
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UEPQH4FK.js";
|
|
14
14
|
import "./chunk-TZQHYZKT.js";
|
|
15
15
|
import {
|
|
16
16
|
VERSION
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-675G3UGO.js";
|
|
18
18
|
import "./chunk-PDX44BCA.js";
|
|
19
19
|
|
|
20
20
|
// src/cli/ci.ts
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfigDirUsage,
|
|
4
4
|
listRecentCrashes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QZ4TXN6I.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderRegistry
|
|
8
8
|
} from "./chunk-GNJOC6ZN.js";
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
getTopFailingTools,
|
|
12
12
|
getTopUsedTools,
|
|
13
13
|
resetStats
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-DCZYF7AK.js";
|
|
15
15
|
import "./chunk-NXXNLLSG.js";
|
|
16
16
|
import {
|
|
17
17
|
ConfigManager
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UEPQH4FK.js";
|
|
19
19
|
import "./chunk-TZQHYZKT.js";
|
|
20
20
|
import {
|
|
21
21
|
DEV_STATE_FILE_NAME,
|
|
22
22
|
MEMORY_FILE_NAME,
|
|
23
23
|
VERSION
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-675G3UGO.js";
|
|
25
25
|
import "./chunk-PDX44BCA.js";
|
|
26
26
|
|
|
27
27
|
// src/diagnostics/doctor-cli.ts
|
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-VNWZTKRX.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -13548,7 +13548,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
13548
13548
|
case "test": {
|
|
13549
13549
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
13550
13550
|
try {
|
|
13551
|
-
const { executeTests } = await import("./run-tests-
|
|
13551
|
+
const { executeTests } = await import("./run-tests-FXXWLFKS.js");
|
|
13552
13552
|
const argStr = args.join(" ").trim();
|
|
13553
13553
|
let testArgs = {};
|
|
13554
13554
|
if (argStr) {
|
|
@@ -155,7 +155,7 @@ ${content}`);
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
158
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
158
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-OCMQPD4H.js");
|
|
159
159
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
160
160
|
let interrupted = false;
|
|
161
161
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
saveDevState,
|
|
19
19
|
sessionHasMeaningfulContent,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-3QHN2LKK.js";
|
|
22
22
|
import {
|
|
23
23
|
ToolExecutor,
|
|
24
24
|
ToolRegistry,
|
|
@@ -37,10 +37,10 @@ import {
|
|
|
37
37
|
spawnAgentContext,
|
|
38
38
|
theme,
|
|
39
39
|
undoStack
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-H2X7LKLQ.js";
|
|
41
41
|
import "./chunk-HDSKW7Q3.js";
|
|
42
42
|
import "./chunk-ZWVIDFGY.js";
|
|
43
|
-
import "./chunk-
|
|
43
|
+
import "./chunk-SGD5WSDG.js";
|
|
44
44
|
import {
|
|
45
45
|
SessionManager,
|
|
46
46
|
getContentText
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
getConfigDirUsage,
|
|
50
50
|
listRecentCrashes,
|
|
51
51
|
writeCrashLog
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-QZ4TXN6I.js";
|
|
53
53
|
import {
|
|
54
54
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
55
55
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
@@ -74,11 +74,11 @@ import {
|
|
|
74
74
|
getTopFailingTools,
|
|
75
75
|
getTopUsedTools,
|
|
76
76
|
installFlushOnExit
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-DCZYF7AK.js";
|
|
78
78
|
import "./chunk-NXXNLLSG.js";
|
|
79
79
|
import {
|
|
80
80
|
ConfigManager
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-UEPQH4FK.js";
|
|
82
82
|
import {
|
|
83
83
|
AuthError,
|
|
84
84
|
ProviderError,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
SKILLS_DIR_NAME,
|
|
106
106
|
VERSION,
|
|
107
107
|
buildUserIdentityPrompt
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-675G3UGO.js";
|
|
109
109
|
import {
|
|
110
110
|
formatGitContextForPrompt,
|
|
111
111
|
getGitContext,
|
|
@@ -1786,7 +1786,7 @@ No tools match "${filter}".
|
|
|
1786
1786
|
const { join: join6 } = await import("path");
|
|
1787
1787
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1788
1788
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1789
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1789
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-J2BZAFWO.js");
|
|
1790
1790
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1791
1791
|
const cwd = process.cwd();
|
|
1792
1792
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2847,7 +2847,7 @@ ${hint}` : "")
|
|
|
2847
2847
|
usage: "/test [command|filter]",
|
|
2848
2848
|
async execute(args, ctx) {
|
|
2849
2849
|
try {
|
|
2850
|
-
const { executeTests } = await import("./run-tests-
|
|
2850
|
+
const { executeTests } = await import("./run-tests-HLB2NHJO.js");
|
|
2851
2851
|
const argStr = args.join(" ").trim();
|
|
2852
2852
|
let testArgs = {};
|
|
2853
2853
|
if (argStr) {
|
|
@@ -4761,6 +4761,8 @@ var Repl = class {
|
|
|
4761
4761
|
currentProvider;
|
|
4762
4762
|
currentModel;
|
|
4763
4763
|
running = false;
|
|
4764
|
+
/** 是否已注册 bracketed-paste 的 process.exit 还原钩子(只注册一次) */
|
|
4765
|
+
bracketedPasteRestoreHooked = false;
|
|
4764
4766
|
renderer;
|
|
4765
4767
|
commands;
|
|
4766
4768
|
toolRegistry;
|
|
@@ -5692,6 +5694,7 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5692
5694
|
}
|
|
5693
5695
|
}
|
|
5694
5696
|
this.setupClipboardPaste();
|
|
5697
|
+
this.enableBracketedPaste();
|
|
5695
5698
|
this.rl.on("SIGINT", () => {
|
|
5696
5699
|
if (this.streamAbortController) {
|
|
5697
5700
|
this.streamAbortController.abort();
|
|
@@ -6268,6 +6271,39 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6268
6271
|
* 3. 后续字符正常插入
|
|
6269
6272
|
* 最终 readline 缓冲区包含完整的 @路径,用户可继续追加描述文字后回车发送。
|
|
6270
6273
|
*/
|
|
6274
|
+
/**
|
|
6275
|
+
* 开启终端 bracketed paste 模式(ESC[?2004h)。
|
|
6276
|
+
*
|
|
6277
|
+
* 粘贴时终端把内容包进 `ESC[200~ … ESC[201~`,Node readline 原生识别这对标记,
|
|
6278
|
+
* 把整段粘贴当作**一次**插入渲染——而不是逐字符触发 `_refreshLine()` 整行重绘。
|
|
6279
|
+
* 这消除了长中文(双宽字符)输入折行时多帧重绘叠加产生的“鬼影”
|
|
6280
|
+
* (prompt `[provider] >` 串进正文、文字错位重复)。markers 由 readline 自动剥离,
|
|
6281
|
+
* 不会进入 `rl.line`,多行粘贴的逐行 `line` 事件也保持不变。
|
|
6282
|
+
*
|
|
6283
|
+
* 仅在 TTY 下启用;并注册一次性 `process.exit` 钩子,确保异常退出时也还原终端
|
|
6284
|
+
* (否则之后运行的其它程序会收到带 200~/201~ 标记的粘贴)。
|
|
6285
|
+
*/
|
|
6286
|
+
enableBracketedPaste() {
|
|
6287
|
+
if (!process.stdout.isTTY) return;
|
|
6288
|
+
process.stdout.write("\x1B[?2004h");
|
|
6289
|
+
if (!this.bracketedPasteRestoreHooked) {
|
|
6290
|
+
this.bracketedPasteRestoreHooked = true;
|
|
6291
|
+
process.once("exit", () => {
|
|
6292
|
+
try {
|
|
6293
|
+
if (process.stdout.isTTY) process.stdout.write("\x1B[?2004l");
|
|
6294
|
+
} catch {
|
|
6295
|
+
}
|
|
6296
|
+
});
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
/** 关闭 bracketed paste 模式(ESC[?2004l),还原终端,供正常退出路径调用。 */
|
|
6300
|
+
disableBracketedPaste() {
|
|
6301
|
+
if (!process.stdout.isTTY) return;
|
|
6302
|
+
try {
|
|
6303
|
+
process.stdout.write("\x1B[?2004l");
|
|
6304
|
+
} catch {
|
|
6305
|
+
}
|
|
6306
|
+
}
|
|
6271
6307
|
setupClipboardPaste() {
|
|
6272
6308
|
process.stdin.prependListener("keypress", (_ch, key) => {
|
|
6273
6309
|
if (!key?.ctrl || key?.name !== "v") return;
|
|
@@ -7499,6 +7535,7 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
7499
7535
|
process.stderr.write(`[mcp] cleanup error: ${err instanceof Error ? err.message : err}
|
|
7500
7536
|
`);
|
|
7501
7537
|
});
|
|
7538
|
+
this.disableBracketedPaste();
|
|
7502
7539
|
this.rl.close();
|
|
7503
7540
|
console.log(theme.dim("\nGoodbye!"));
|
|
7504
7541
|
process.exit(0);
|
|
@@ -7596,7 +7633,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7596
7633
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7597
7634
|
process.exit(1);
|
|
7598
7635
|
}
|
|
7599
|
-
const { startWebServer } = await import("./server-
|
|
7636
|
+
const { startWebServer } = await import("./server-MZL4VR7M.js");
|
|
7600
7637
|
await startWebServer({ port, host: options.host });
|
|
7601
7638
|
});
|
|
7602
7639
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -7763,12 +7800,12 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7763
7800
|
console.log(footer + "\n");
|
|
7764
7801
|
});
|
|
7765
7802
|
program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
|
|
7766
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7803
|
+
const { runDoctorCli } = await import("./doctor-cli-YYQ5QXDR.js");
|
|
7767
7804
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7768
7805
|
});
|
|
7769
7806
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
7770
7807
|
try {
|
|
7771
|
-
const batch = await import("./batch-
|
|
7808
|
+
const batch = await import("./batch-7FOD7UAI.js");
|
|
7772
7809
|
switch (action) {
|
|
7773
7810
|
case "submit":
|
|
7774
7811
|
if (!arg) {
|
|
@@ -7811,7 +7848,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7811
7848
|
}
|
|
7812
7849
|
});
|
|
7813
7850
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
7814
|
-
const { startMcpServer } = await import("./server-
|
|
7851
|
+
const { startMcpServer } = await import("./server-O3NO5D3X.js");
|
|
7815
7852
|
await startMcpServer({
|
|
7816
7853
|
allowDestructive: !!options.allowDestructive,
|
|
7817
7854
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7820,7 +7857,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7820
7857
|
});
|
|
7821
7858
|
});
|
|
7822
7859
|
program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).option("--base <ref>", "Base ref for `git diff <ref>...HEAD` (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").action(async (options) => {
|
|
7823
|
-
const { runCi } = await import("./ci-
|
|
7860
|
+
const { runCi } = await import("./ci-AFTGRKJ6.js");
|
|
7824
7861
|
const result = await runCi({
|
|
7825
7862
|
pr: options.pr,
|
|
7826
7863
|
base: options.base,
|
|
@@ -7965,7 +8002,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7965
8002
|
}),
|
|
7966
8003
|
config.get("customProviders")
|
|
7967
8004
|
);
|
|
7968
|
-
const { startHub } = await import("./hub-
|
|
8005
|
+
const { startHub } = await import("./hub-7IF37CGA.js");
|
|
7969
8006
|
await startHub(
|
|
7970
8007
|
{
|
|
7971
8008
|
topic: topic ?? "",
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
loadDevState,
|
|
22
22
|
persistToolRound,
|
|
23
23
|
setupProxy
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-3QHN2LKK.js";
|
|
25
25
|
import {
|
|
26
26
|
ToolExecutor,
|
|
27
27
|
ToolRegistry,
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
spawnAgentContext,
|
|
40
40
|
truncateOutput,
|
|
41
41
|
undoStack
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-H2X7LKLQ.js";
|
|
43
43
|
import "./chunk-HDSKW7Q3.js";
|
|
44
44
|
import "./chunk-ZWVIDFGY.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-SGD5WSDG.js";
|
|
46
46
|
import {
|
|
47
47
|
SessionManager,
|
|
48
48
|
getContentText
|
|
@@ -64,13 +64,13 @@ import {
|
|
|
64
64
|
} from "./chunk-GNJOC6ZN.js";
|
|
65
65
|
import {
|
|
66
66
|
runTool
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-DCZYF7AK.js";
|
|
68
68
|
import {
|
|
69
69
|
getDangerLevel
|
|
70
70
|
} from "./chunk-NXXNLLSG.js";
|
|
71
71
|
import {
|
|
72
72
|
ConfigManager
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-UEPQH4FK.js";
|
|
74
74
|
import "./chunk-TZQHYZKT.js";
|
|
75
75
|
import {
|
|
76
76
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
SKILLS_DIR_NAME,
|
|
91
91
|
VERSION,
|
|
92
92
|
buildUserIdentityPrompt
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-675G3UGO.js";
|
|
94
94
|
import {
|
|
95
95
|
formatGitContextForPrompt,
|
|
96
96
|
getGitContext,
|
|
@@ -2577,7 +2577,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2577
2577
|
case "test": {
|
|
2578
2578
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2579
2579
|
try {
|
|
2580
|
-
const { executeTests } = await import("./run-tests-
|
|
2580
|
+
const { executeTests } = await import("./run-tests-HLB2NHJO.js");
|
|
2581
2581
|
const argStr = args.join(" ").trim();
|
|
2582
2582
|
let testArgs = {};
|
|
2583
2583
|
if (argStr) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-H2X7LKLQ.js";
|
|
5
5
|
import "./chunk-HDSKW7Q3.js";
|
|
6
6
|
import "./chunk-ZWVIDFGY.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-SGD5WSDG.js";
|
|
8
8
|
import {
|
|
9
9
|
runTool
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-DCZYF7AK.js";
|
|
11
11
|
import {
|
|
12
12
|
getDangerLevel,
|
|
13
13
|
schemaToJsonSchema
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import "./chunk-TZQHYZKT.js";
|
|
16
16
|
import {
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-675G3UGO.js";
|
|
19
19
|
import "./chunk-4BKXL7SM.js";
|
|
20
20
|
import "./chunk-MM3F43H6.js";
|
|
21
21
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -3,20 +3,20 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
googleSearchContext,
|
|
5
5
|
truncateOutput
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-H2X7LKLQ.js";
|
|
7
7
|
import "./chunk-HDSKW7Q3.js";
|
|
8
8
|
import "./chunk-ZWVIDFGY.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-SGD5WSDG.js";
|
|
10
10
|
import {
|
|
11
11
|
runTool
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DCZYF7AK.js";
|
|
13
13
|
import {
|
|
14
14
|
getDangerLevel
|
|
15
15
|
} from "./chunk-NXXNLLSG.js";
|
|
16
16
|
import "./chunk-TZQHYZKT.js";
|
|
17
17
|
import {
|
|
18
18
|
SUBAGENT_ALLOWED_TOOLS
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-675G3UGO.js";
|
|
20
20
|
import "./chunk-4BKXL7SM.js";
|
|
21
21
|
import "./chunk-MM3F43H6.js";
|
|
22
22
|
import "./chunk-KHYD3WXE.js";
|
package/dist/web/client/app.js
CHANGED
|
@@ -2566,6 +2566,12 @@ userInput.focus();
|
|
|
2566
2566
|
const btnSidebarToggle = document.getElementById('btn-sidebar-toggle');
|
|
2567
2567
|
const sidebarBackdrop = document.getElementById('sidebar-backdrop');
|
|
2568
2568
|
|
|
2569
|
+
const SIDEBAR_COLLAPSED_KEY = 'aicli-sidebar-collapsed';
|
|
2570
|
+
|
|
2571
|
+
function isMobileView() {
|
|
2572
|
+
return window.innerWidth <= 768;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2569
2575
|
function openSidebar() {
|
|
2570
2576
|
sidebar.classList.add('sidebar-open');
|
|
2571
2577
|
sidebarBackdrop?.classList.remove('hidden');
|
|
@@ -2576,14 +2582,34 @@ function closeSidebar() {
|
|
|
2576
2582
|
sidebarBackdrop?.classList.add('hidden');
|
|
2577
2583
|
}
|
|
2578
2584
|
|
|
2585
|
+
// Desktop: collapse the whole left panel so the chat gets all the space.
|
|
2586
|
+
function setSidebarCollapsed(collapsed) {
|
|
2587
|
+
sidebar.classList.toggle('sidebar-collapsed', collapsed);
|
|
2588
|
+
try { localStorage.setItem(SIDEBAR_COLLAPSED_KEY, collapsed ? '1' : '0'); } catch { /* ignore */ }
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2579
2591
|
function toggleSidebar() {
|
|
2580
|
-
if (
|
|
2581
|
-
|
|
2592
|
+
if (isMobileView()) {
|
|
2593
|
+
// Mobile: slide-over overlay
|
|
2594
|
+
if (sidebar.classList.contains('sidebar-open')) {
|
|
2595
|
+
closeSidebar();
|
|
2596
|
+
} else {
|
|
2597
|
+
openSidebar();
|
|
2598
|
+
}
|
|
2582
2599
|
} else {
|
|
2583
|
-
|
|
2600
|
+
// Desktop: fully collapse / restore the panel
|
|
2601
|
+
setSidebarCollapsed(!sidebar.classList.contains('sidebar-collapsed'));
|
|
2584
2602
|
}
|
|
2585
2603
|
}
|
|
2586
2604
|
|
|
2605
|
+
// Restore the desktop collapsed state from a previous session. The CSS rule
|
|
2606
|
+
// is scoped to ≥769px, so adding the class is inert on mobile.
|
|
2607
|
+
try {
|
|
2608
|
+
if (localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === '1') {
|
|
2609
|
+
sidebar.classList.add('sidebar-collapsed');
|
|
2610
|
+
}
|
|
2611
|
+
} catch { /* ignore */ }
|
|
2612
|
+
|
|
2587
2613
|
if (btnSidebarToggle) {
|
|
2588
2614
|
btnSidebarToggle.addEventListener('click', toggleSidebar);
|
|
2589
2615
|
}
|
|
@@ -724,8 +724,23 @@
|
|
|
724
724
|
font-size: 0.85rem;
|
|
725
725
|
}
|
|
726
726
|
|
|
727
|
-
/* ── Sidebar toggle button
|
|
728
|
-
|
|
727
|
+
/* ── Sidebar toggle button ──────────────────────────── */
|
|
728
|
+
/* Visible on every width: on desktop it collapses the panel to give all
|
|
729
|
+
space to the chat; on mobile (≤768px) it opens/closes the slide-over. */
|
|
730
|
+
.sidebar-toggle-btn { display: flex; }
|
|
731
|
+
|
|
732
|
+
/* Desktop collapse: scoped to ≥769px so it never fights the mobile
|
|
733
|
+
slide-over rules (which use .sidebar-open). width:0 !important is needed
|
|
734
|
+
to override the inline width set by the drag-resize handle. */
|
|
735
|
+
@media (min-width: 769px) {
|
|
736
|
+
.sidebar.sidebar-collapsed {
|
|
737
|
+
width: 0 !important;
|
|
738
|
+
min-width: 0;
|
|
739
|
+
border-right-width: 0;
|
|
740
|
+
overflow: hidden;
|
|
741
|
+
}
|
|
742
|
+
.sidebar.sidebar-collapsed + .sidebar-resize-handle { display: none; }
|
|
743
|
+
}
|
|
729
744
|
|
|
730
745
|
/* ── Sidebar backdrop (mobile overlay) ───────────────── */
|
|
731
746
|
.sidebar-backdrop {
|
|
@@ -845,132 +860,132 @@ button, a, .session-item, .file-tree-row, .template-item, .tool-item, .mcp-serve
|
|
|
845
860
|
@media (display-mode: standalone) {
|
|
846
861
|
.navbar { padding-top: env(safe-area-inset-top, 0px); }
|
|
847
862
|
}
|
|
848
|
-
|
|
849
|
-
/* ── Session Replay (B1) ───────────────────────────── */
|
|
850
|
-
.replay-step {
|
|
851
|
-
border-left: 3px solid hsl(var(--b3));
|
|
852
|
-
padding: 0.5rem 0.6rem;
|
|
853
|
-
background: hsl(var(--b1));
|
|
854
|
-
border-radius: 0 0.35rem 0.35rem 0;
|
|
855
|
-
font-size: 0.85rem;
|
|
856
|
-
}
|
|
857
|
-
.replay-step.role-user { border-left-color: #3b82f6; }
|
|
858
|
-
.replay-step.role-assistant { border-left-color: #10b981; }
|
|
859
|
-
.replay-step.role-tool { border-left-color: #f59e0b; }
|
|
860
|
-
.replay-step.role-tool.error { border-left-color: #ef4444; }
|
|
861
|
-
.replay-step-header {
|
|
862
|
-
display: flex;
|
|
863
|
-
gap: 0.5rem;
|
|
864
|
-
align-items: center;
|
|
865
|
-
font-size: 0.72rem;
|
|
866
|
-
opacity: 0.75;
|
|
867
|
-
margin-bottom: 0.25rem;
|
|
868
|
-
}
|
|
869
|
-
.replay-step-header .role-tag {
|
|
870
|
-
font-weight: 600;
|
|
871
|
-
padding: 0 0.35rem;
|
|
872
|
-
border-radius: 0.25rem;
|
|
873
|
-
background: hsl(var(--b3));
|
|
874
|
-
}
|
|
875
|
-
.replay-step-body {
|
|
876
|
-
white-space: pre-wrap;
|
|
877
|
-
word-break: break-word;
|
|
878
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
879
|
-
font-size: 0.78rem;
|
|
880
|
-
max-height: 18rem;
|
|
881
|
-
overflow-y: auto;
|
|
882
|
-
}
|
|
883
|
-
.replay-step-body.text-body {
|
|
884
|
-
font-family: inherit;
|
|
885
|
-
font-size: 0.85rem;
|
|
886
|
-
}
|
|
887
|
-
.replay-tool-block {
|
|
888
|
-
margin-top: 0.3rem;
|
|
889
|
-
padding: 0.4rem;
|
|
890
|
-
background: hsl(var(--b2));
|
|
891
|
-
border-radius: 0.3rem;
|
|
892
|
-
font-size: 0.78rem;
|
|
893
|
-
}
|
|
894
|
-
.replay-tool-block .tool-name {
|
|
895
|
-
font-weight: 600;
|
|
896
|
-
color: #f59e0b;
|
|
897
|
-
}
|
|
898
|
-
.replay-tool-block pre {
|
|
899
|
-
margin: 0.2rem 0 0;
|
|
900
|
-
white-space: pre-wrap;
|
|
901
|
-
word-break: break-word;
|
|
902
|
-
font-size: 0.72rem;
|
|
903
|
-
max-height: 12rem;
|
|
904
|
-
overflow-y: auto;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
/* ── B2 Branch picker (sidebar) ─────────────────────────── */
|
|
908
|
-
.branch-item {
|
|
909
|
-
display: flex;
|
|
910
|
-
align-items: center;
|
|
911
|
-
gap: 0.35rem;
|
|
912
|
-
padding: 0.35rem 0.5rem;
|
|
913
|
-
border-radius: 0.35rem;
|
|
914
|
-
cursor: pointer;
|
|
915
|
-
border: 1px solid transparent;
|
|
916
|
-
transition: background 0.1s, border-color 0.1s;
|
|
917
|
-
font-size: 0.78rem;
|
|
918
|
-
line-height: 1.25;
|
|
919
|
-
position: relative;
|
|
920
|
-
}
|
|
921
|
-
.branch-item:hover {
|
|
922
|
-
background: rgba(128, 128, 128, 0.12);
|
|
923
|
-
}
|
|
924
|
-
.branch-item.active {
|
|
925
|
-
background: rgba(34, 197, 94, 0.12);
|
|
926
|
-
border-color: rgba(34, 197, 94, 0.45);
|
|
927
|
-
}
|
|
928
|
-
.branch-item .branch-marker {
|
|
929
|
-
flex-shrink: 0;
|
|
930
|
-
width: 0.8rem;
|
|
931
|
-
color: rgb(34, 197, 94);
|
|
932
|
-
}
|
|
933
|
-
.branch-item .branch-title {
|
|
934
|
-
flex: 1;
|
|
935
|
-
min-width: 0;
|
|
936
|
-
overflow: hidden;
|
|
937
|
-
text-overflow: ellipsis;
|
|
938
|
-
white-space: nowrap;
|
|
939
|
-
}
|
|
940
|
-
.branch-item .branch-id {
|
|
941
|
-
flex-shrink: 0;
|
|
942
|
-
opacity: 0.5;
|
|
943
|
-
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
944
|
-
font-size: 0.7rem;
|
|
945
|
-
}
|
|
946
|
-
.branch-item .branch-count {
|
|
947
|
-
flex-shrink: 0;
|
|
948
|
-
opacity: 0.55;
|
|
949
|
-
font-size: 0.7rem;
|
|
950
|
-
}
|
|
951
|
-
.branch-item .branch-actions {
|
|
952
|
-
display: none;
|
|
953
|
-
gap: 0.15rem;
|
|
954
|
-
flex-shrink: 0;
|
|
955
|
-
}
|
|
956
|
-
.branch-item:hover .branch-actions {
|
|
957
|
-
display: flex;
|
|
958
|
-
}
|
|
959
|
-
.branch-item .branch-actions button {
|
|
960
|
-
background: transparent;
|
|
961
|
-
border: none;
|
|
962
|
-
padding: 0 0.2rem;
|
|
963
|
-
font-size: 0.72rem;
|
|
964
|
-
cursor: pointer;
|
|
965
|
-
opacity: 0.7;
|
|
966
|
-
}
|
|
967
|
-
.branch-item .branch-actions button:hover {
|
|
968
|
-
opacity: 1;
|
|
969
|
-
}
|
|
970
|
-
.branch-item .branch-indent {
|
|
971
|
-
flex-shrink: 0;
|
|
972
|
-
color: rgba(128, 128, 128, 0.5);
|
|
973
|
-
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
974
|
-
font-size: 0.72rem;
|
|
975
|
-
white-space: pre;
|
|
976
|
-
}
|
|
863
|
+
|
|
864
|
+
/* ── Session Replay (B1) ───────────────────────────── */
|
|
865
|
+
.replay-step {
|
|
866
|
+
border-left: 3px solid hsl(var(--b3));
|
|
867
|
+
padding: 0.5rem 0.6rem;
|
|
868
|
+
background: hsl(var(--b1));
|
|
869
|
+
border-radius: 0 0.35rem 0.35rem 0;
|
|
870
|
+
font-size: 0.85rem;
|
|
871
|
+
}
|
|
872
|
+
.replay-step.role-user { border-left-color: #3b82f6; }
|
|
873
|
+
.replay-step.role-assistant { border-left-color: #10b981; }
|
|
874
|
+
.replay-step.role-tool { border-left-color: #f59e0b; }
|
|
875
|
+
.replay-step.role-tool.error { border-left-color: #ef4444; }
|
|
876
|
+
.replay-step-header {
|
|
877
|
+
display: flex;
|
|
878
|
+
gap: 0.5rem;
|
|
879
|
+
align-items: center;
|
|
880
|
+
font-size: 0.72rem;
|
|
881
|
+
opacity: 0.75;
|
|
882
|
+
margin-bottom: 0.25rem;
|
|
883
|
+
}
|
|
884
|
+
.replay-step-header .role-tag {
|
|
885
|
+
font-weight: 600;
|
|
886
|
+
padding: 0 0.35rem;
|
|
887
|
+
border-radius: 0.25rem;
|
|
888
|
+
background: hsl(var(--b3));
|
|
889
|
+
}
|
|
890
|
+
.replay-step-body {
|
|
891
|
+
white-space: pre-wrap;
|
|
892
|
+
word-break: break-word;
|
|
893
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
894
|
+
font-size: 0.78rem;
|
|
895
|
+
max-height: 18rem;
|
|
896
|
+
overflow-y: auto;
|
|
897
|
+
}
|
|
898
|
+
.replay-step-body.text-body {
|
|
899
|
+
font-family: inherit;
|
|
900
|
+
font-size: 0.85rem;
|
|
901
|
+
}
|
|
902
|
+
.replay-tool-block {
|
|
903
|
+
margin-top: 0.3rem;
|
|
904
|
+
padding: 0.4rem;
|
|
905
|
+
background: hsl(var(--b2));
|
|
906
|
+
border-radius: 0.3rem;
|
|
907
|
+
font-size: 0.78rem;
|
|
908
|
+
}
|
|
909
|
+
.replay-tool-block .tool-name {
|
|
910
|
+
font-weight: 600;
|
|
911
|
+
color: #f59e0b;
|
|
912
|
+
}
|
|
913
|
+
.replay-tool-block pre {
|
|
914
|
+
margin: 0.2rem 0 0;
|
|
915
|
+
white-space: pre-wrap;
|
|
916
|
+
word-break: break-word;
|
|
917
|
+
font-size: 0.72rem;
|
|
918
|
+
max-height: 12rem;
|
|
919
|
+
overflow-y: auto;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/* ── B2 Branch picker (sidebar) ─────────────────────────── */
|
|
923
|
+
.branch-item {
|
|
924
|
+
display: flex;
|
|
925
|
+
align-items: center;
|
|
926
|
+
gap: 0.35rem;
|
|
927
|
+
padding: 0.35rem 0.5rem;
|
|
928
|
+
border-radius: 0.35rem;
|
|
929
|
+
cursor: pointer;
|
|
930
|
+
border: 1px solid transparent;
|
|
931
|
+
transition: background 0.1s, border-color 0.1s;
|
|
932
|
+
font-size: 0.78rem;
|
|
933
|
+
line-height: 1.25;
|
|
934
|
+
position: relative;
|
|
935
|
+
}
|
|
936
|
+
.branch-item:hover {
|
|
937
|
+
background: rgba(128, 128, 128, 0.12);
|
|
938
|
+
}
|
|
939
|
+
.branch-item.active {
|
|
940
|
+
background: rgba(34, 197, 94, 0.12);
|
|
941
|
+
border-color: rgba(34, 197, 94, 0.45);
|
|
942
|
+
}
|
|
943
|
+
.branch-item .branch-marker {
|
|
944
|
+
flex-shrink: 0;
|
|
945
|
+
width: 0.8rem;
|
|
946
|
+
color: rgb(34, 197, 94);
|
|
947
|
+
}
|
|
948
|
+
.branch-item .branch-title {
|
|
949
|
+
flex: 1;
|
|
950
|
+
min-width: 0;
|
|
951
|
+
overflow: hidden;
|
|
952
|
+
text-overflow: ellipsis;
|
|
953
|
+
white-space: nowrap;
|
|
954
|
+
}
|
|
955
|
+
.branch-item .branch-id {
|
|
956
|
+
flex-shrink: 0;
|
|
957
|
+
opacity: 0.5;
|
|
958
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
959
|
+
font-size: 0.7rem;
|
|
960
|
+
}
|
|
961
|
+
.branch-item .branch-count {
|
|
962
|
+
flex-shrink: 0;
|
|
963
|
+
opacity: 0.55;
|
|
964
|
+
font-size: 0.7rem;
|
|
965
|
+
}
|
|
966
|
+
.branch-item .branch-actions {
|
|
967
|
+
display: none;
|
|
968
|
+
gap: 0.15rem;
|
|
969
|
+
flex-shrink: 0;
|
|
970
|
+
}
|
|
971
|
+
.branch-item:hover .branch-actions {
|
|
972
|
+
display: flex;
|
|
973
|
+
}
|
|
974
|
+
.branch-item .branch-actions button {
|
|
975
|
+
background: transparent;
|
|
976
|
+
border: none;
|
|
977
|
+
padding: 0 0.2rem;
|
|
978
|
+
font-size: 0.72rem;
|
|
979
|
+
cursor: pointer;
|
|
980
|
+
opacity: 0.7;
|
|
981
|
+
}
|
|
982
|
+
.branch-item .branch-actions button:hover {
|
|
983
|
+
opacity: 1;
|
|
984
|
+
}
|
|
985
|
+
.branch-item .branch-indent {
|
|
986
|
+
flex-shrink: 0;
|
|
987
|
+
color: rgba(128, 128, 128, 0.5);
|
|
988
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
989
|
+
font-size: 0.72rem;
|
|
990
|
+
white-space: pre;
|
|
991
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jinzd-ai-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.172",
|
|
4
4
|
"description": "Cross-platform REPL-style AI CLI with multi-provider support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -124,6 +124,7 @@
|
|
|
124
124
|
"extraMetadata": {
|
|
125
125
|
"main": "electron/main.cjs"
|
|
126
126
|
},
|
|
127
|
+
"npmRebuild": false,
|
|
127
128
|
"files": [
|
|
128
129
|
"dist/**/*",
|
|
129
130
|
"electron/**/*.cjs"
|