jinzd-ai-cli 0.4.169 → 0.4.171
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-UA6OWP5B.js → batch-6WDD57ZG.js} +2 -2
- package/dist/{chunk-2QLZGNFP.js → chunk-57H6YNXY.js} +2 -2
- package/dist/{chunk-MD3SNDQ6.js → chunk-6JTVUGSF.js} +1 -1
- package/dist/{chunk-QVHML2M7.js → chunk-H53UCPFF.js} +1 -1
- package/dist/{chunk-I4ZOULB6.js → chunk-IZY4MCKG.js} +1 -1
- package/dist/{chunk-6JVMTB2S.js → chunk-MELFYYS7.js} +1 -1
- package/dist/{chunk-QIFUVX5K.js → chunk-RSZWLQU4.js} +1 -1
- package/dist/{chunk-RNMT4XBQ.js → chunk-WG4THOHH.js} +3 -3
- package/dist/{chunk-X6N4EAMM.js → chunk-YMH6BKAE.js} +1 -1
- package/dist/{ci-34RE6YZA.js → ci-Y4FEHLDL.js} +2 -2
- package/dist/{constants-FJD3QUHI.js → constants-OMTUJRKU.js} +1 -1
- package/dist/{doctor-cli-T4N3V2OT.js → doctor-cli-OZJZKETL.js} +4 -4
- package/dist/electron-server.js +2 -2
- package/dist/{hub-7GSXGHN7.js → hub-IVVW7BTJ.js} +1 -1
- package/dist/index.js +64 -49
- package/dist/{run-tests-X5VFC62T.js → run-tests-A2Q5VMHF.js} +1 -1
- package/dist/{run-tests-OLKEYSWX.js → run-tests-AYADOMOF.js} +2 -2
- package/dist/{server-EOMEJL2N.js → server-7B7HTSLE.js} +7 -7
- package/dist/{server-QK64LBV2.js → server-RXWYMDAH.js} +4 -4
- package/dist/{task-orchestrator-SBTDEKS5.js → task-orchestrator-U7KU4SOS.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-6JTVUGSF.js";
|
|
5
5
|
import "./chunk-TZQHYZKT.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-RSZWLQU4.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-WG4THOHH.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-RSZWLQU4.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-MELFYYS7.js";
|
|
9
9
|
import {
|
|
10
10
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-H53UCPFF.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-RSZWLQU4.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-6JTVUGSF.js";
|
|
14
14
|
import "./chunk-TZQHYZKT.js";
|
|
15
15
|
import {
|
|
16
16
|
VERSION
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-RSZWLQU4.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-IZY4MCKG.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-H53UCPFF.js";
|
|
15
15
|
import "./chunk-NXXNLLSG.js";
|
|
16
16
|
import {
|
|
17
17
|
ConfigManager
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-6JTVUGSF.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-RSZWLQU4.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-YMH6BKAE.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-A2Q5VMHF.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-U7KU4SOS.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-57H6YNXY.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-WG4THOHH.js";
|
|
41
41
|
import "./chunk-HDSKW7Q3.js";
|
|
42
42
|
import "./chunk-ZWVIDFGY.js";
|
|
43
|
-
import "./chunk-
|
|
43
|
+
import "./chunk-MELFYYS7.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-IZY4MCKG.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-H53UCPFF.js";
|
|
78
78
|
import "./chunk-NXXNLLSG.js";
|
|
79
79
|
import {
|
|
80
80
|
ConfigManager
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-6JTVUGSF.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-RSZWLQU4.js";
|
|
109
109
|
import {
|
|
110
110
|
formatGitContextForPrompt,
|
|
111
111
|
getGitContext,
|
|
@@ -208,6 +208,13 @@ function isInterruptedSession(messages) {
|
|
|
208
208
|
import chalk from "chalk";
|
|
209
209
|
import { createWriteStream, mkdirSync } from "fs";
|
|
210
210
|
import { dirname } from "path";
|
|
211
|
+
function partialTagTail(s, tag) {
|
|
212
|
+
const max = Math.min(s.length, tag.length - 1);
|
|
213
|
+
for (let k = max; k > 0; k--) {
|
|
214
|
+
if (s.endsWith(tag.slice(0, k))) return k;
|
|
215
|
+
}
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
211
218
|
function fmtContextWindow(tokens) {
|
|
212
219
|
if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
|
|
213
220
|
if (tokens >= 1e3) return `${Math.round(tokens / 1024)}K`;
|
|
@@ -489,34 +496,46 @@ var Renderer = class {
|
|
|
489
496
|
let fullContent = "";
|
|
490
497
|
let usage;
|
|
491
498
|
let inThinking = false;
|
|
492
|
-
let
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
inThinking = false;
|
|
509
|
-
out = out.slice(closeIdx + "</think>".length);
|
|
510
|
-
buf = out;
|
|
511
|
-
flushBuf();
|
|
512
|
-
return;
|
|
499
|
+
let thinkBuf = "";
|
|
500
|
+
const emitText = (raw) => {
|
|
501
|
+
thinkBuf += raw;
|
|
502
|
+
let out = "";
|
|
503
|
+
while (thinkBuf.length > 0) {
|
|
504
|
+
if (!inThinking) {
|
|
505
|
+
const open = thinkBuf.indexOf("<think>");
|
|
506
|
+
if (open === -1) {
|
|
507
|
+
const keep = partialTagTail(thinkBuf, "<think>");
|
|
508
|
+
out += thinkBuf.slice(0, thinkBuf.length - keep);
|
|
509
|
+
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
out += thinkBuf.slice(0, open);
|
|
513
|
+
thinkBuf = thinkBuf.slice(open + "<think>".length);
|
|
514
|
+
inThinking = true;
|
|
513
515
|
} else {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
+
const close = thinkBuf.indexOf("</think>");
|
|
517
|
+
if (close === -1) {
|
|
518
|
+
const keep = partialTagTail(thinkBuf, "</think>");
|
|
519
|
+
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
thinkBuf = thinkBuf.slice(close + "</think>".length);
|
|
523
|
+
inThinking = false;
|
|
516
524
|
}
|
|
517
525
|
}
|
|
518
|
-
if (out)
|
|
519
|
-
|
|
526
|
+
if (out) {
|
|
527
|
+
process.stdout.write(out);
|
|
528
|
+
if (fileStream) fileStream.write(out);
|
|
529
|
+
fullContent += out;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
const flushTail = () => {
|
|
533
|
+
if (!inThinking && thinkBuf) {
|
|
534
|
+
process.stdout.write(thinkBuf);
|
|
535
|
+
if (fileStream) fileStream.write(thinkBuf);
|
|
536
|
+
fullContent += thinkBuf;
|
|
537
|
+
thinkBuf = "";
|
|
538
|
+
}
|
|
520
539
|
};
|
|
521
540
|
let interrupted = false;
|
|
522
541
|
let streamErr = null;
|
|
@@ -530,23 +549,19 @@ var Renderer = class {
|
|
|
530
549
|
usage = chunk.usage;
|
|
531
550
|
}
|
|
532
551
|
if (chunk.done) {
|
|
533
|
-
flushBuf();
|
|
534
552
|
break;
|
|
535
553
|
}
|
|
536
554
|
if (!chunk.delta) continue;
|
|
537
|
-
|
|
538
|
-
buf += chunk.delta;
|
|
539
|
-
if (fileStream) fileStream.write(chunk.delta);
|
|
540
|
-
flushBuf();
|
|
555
|
+
emitText(chunk.delta);
|
|
541
556
|
}
|
|
542
557
|
} catch (err) {
|
|
543
558
|
if (err?.name === "AbortError") {
|
|
544
559
|
interrupted = true;
|
|
545
|
-
if (!inThinking) flushBuf();
|
|
546
560
|
} else {
|
|
547
561
|
streamErr = err;
|
|
548
562
|
}
|
|
549
563
|
}
|
|
564
|
+
flushTail();
|
|
550
565
|
if (interrupted) {
|
|
551
566
|
process.stdout.write(theme.dim(" [interrupted]\n"));
|
|
552
567
|
}
|
|
@@ -1771,7 +1786,7 @@ No tools match "${filter}".
|
|
|
1771
1786
|
const { join: join6 } = await import("path");
|
|
1772
1787
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1773
1788
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1774
|
-
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-OMTUJRKU.js");
|
|
1775
1790
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1776
1791
|
const cwd = process.cwd();
|
|
1777
1792
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2832,7 +2847,7 @@ ${hint}` : "")
|
|
|
2832
2847
|
usage: "/test [command|filter]",
|
|
2833
2848
|
async execute(args, ctx) {
|
|
2834
2849
|
try {
|
|
2835
|
-
const { executeTests } = await import("./run-tests-
|
|
2850
|
+
const { executeTests } = await import("./run-tests-AYADOMOF.js");
|
|
2836
2851
|
const argStr = args.join(" ").trim();
|
|
2837
2852
|
let testArgs = {};
|
|
2838
2853
|
if (argStr) {
|
|
@@ -4683,7 +4698,7 @@ var FREE_ROUND_TOOLS = /* @__PURE__ */ new Set(["write_todos"]);
|
|
|
4683
4698
|
var MAX_CONSECUTIVE_FREE_ROUNDS = 3;
|
|
4684
4699
|
var MAX_REPEATED_TOOL_CALLS = 2;
|
|
4685
4700
|
var DEFAULT_AUTO_PAUSE_INTERVAL = 50;
|
|
4686
|
-
function
|
|
4701
|
+
function partialTagTail2(s, tag) {
|
|
4687
4702
|
const max = Math.min(s.length, tag.length - 1);
|
|
4688
4703
|
for (let k = max; k > 0; k--) {
|
|
4689
4704
|
if (s.endsWith(tag.slice(0, k))) return k;
|
|
@@ -6381,7 +6396,7 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6381
6396
|
if (!inThink) {
|
|
6382
6397
|
const open = thinkBuf.indexOf("<think>");
|
|
6383
6398
|
if (open === -1) {
|
|
6384
|
-
const keep =
|
|
6399
|
+
const keep = partialTagTail2(thinkBuf, "<think>");
|
|
6385
6400
|
out += thinkBuf.slice(0, thinkBuf.length - keep);
|
|
6386
6401
|
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
6387
6402
|
break;
|
|
@@ -6393,7 +6408,7 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6393
6408
|
} else {
|
|
6394
6409
|
const close = thinkBuf.indexOf("</think>");
|
|
6395
6410
|
if (close === -1) {
|
|
6396
|
-
const keep =
|
|
6411
|
+
const keep = partialTagTail2(thinkBuf, "</think>");
|
|
6397
6412
|
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
6398
6413
|
break;
|
|
6399
6414
|
}
|
|
@@ -7581,7 +7596,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7581
7596
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7582
7597
|
process.exit(1);
|
|
7583
7598
|
}
|
|
7584
|
-
const { startWebServer } = await import("./server-
|
|
7599
|
+
const { startWebServer } = await import("./server-7B7HTSLE.js");
|
|
7585
7600
|
await startWebServer({ port, host: options.host });
|
|
7586
7601
|
});
|
|
7587
7602
|
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) => {
|
|
@@ -7748,12 +7763,12 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7748
7763
|
console.log(footer + "\n");
|
|
7749
7764
|
});
|
|
7750
7765
|
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) => {
|
|
7751
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7766
|
+
const { runDoctorCli } = await import("./doctor-cli-OZJZKETL.js");
|
|
7752
7767
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7753
7768
|
});
|
|
7754
7769
|
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) => {
|
|
7755
7770
|
try {
|
|
7756
|
-
const batch = await import("./batch-
|
|
7771
|
+
const batch = await import("./batch-6WDD57ZG.js");
|
|
7757
7772
|
switch (action) {
|
|
7758
7773
|
case "submit":
|
|
7759
7774
|
if (!arg) {
|
|
@@ -7796,7 +7811,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7796
7811
|
}
|
|
7797
7812
|
});
|
|
7798
7813
|
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) => {
|
|
7799
|
-
const { startMcpServer } = await import("./server-
|
|
7814
|
+
const { startMcpServer } = await import("./server-RXWYMDAH.js");
|
|
7800
7815
|
await startMcpServer({
|
|
7801
7816
|
allowDestructive: !!options.allowDestructive,
|
|
7802
7817
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7805,7 +7820,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7805
7820
|
});
|
|
7806
7821
|
});
|
|
7807
7822
|
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) => {
|
|
7808
|
-
const { runCi } = await import("./ci-
|
|
7823
|
+
const { runCi } = await import("./ci-Y4FEHLDL.js");
|
|
7809
7824
|
const result = await runCi({
|
|
7810
7825
|
pr: options.pr,
|
|
7811
7826
|
base: options.base,
|
|
@@ -7950,7 +7965,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7950
7965
|
}),
|
|
7951
7966
|
config.get("customProviders")
|
|
7952
7967
|
);
|
|
7953
|
-
const { startHub } = await import("./hub-
|
|
7968
|
+
const { startHub } = await import("./hub-IVVW7BTJ.js");
|
|
7954
7969
|
await startHub(
|
|
7955
7970
|
{
|
|
7956
7971
|
topic: topic ?? "",
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
loadDevState,
|
|
22
22
|
persistToolRound,
|
|
23
23
|
setupProxy
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-57H6YNXY.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-WG4THOHH.js";
|
|
43
43
|
import "./chunk-HDSKW7Q3.js";
|
|
44
44
|
import "./chunk-ZWVIDFGY.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-MELFYYS7.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-H53UCPFF.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-6JTVUGSF.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-RSZWLQU4.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-AYADOMOF.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-WG4THOHH.js";
|
|
5
5
|
import "./chunk-HDSKW7Q3.js";
|
|
6
6
|
import "./chunk-ZWVIDFGY.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-MELFYYS7.js";
|
|
8
8
|
import {
|
|
9
9
|
runTool
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-H53UCPFF.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-RSZWLQU4.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-WG4THOHH.js";
|
|
7
7
|
import "./chunk-HDSKW7Q3.js";
|
|
8
8
|
import "./chunk-ZWVIDFGY.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-MELFYYS7.js";
|
|
10
10
|
import {
|
|
11
11
|
runTool
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-H53UCPFF.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-RSZWLQU4.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.171",
|
|
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"
|