jinzd-ai-cli 0.4.170 → 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 CHANGED
@@ -7,11 +7,11 @@
7
7
  [![npm version](https://img.shields.io/npm/v/jinzd-ai-cli)](https://www.npmjs.com/package/jinzd-ai-cli)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
9
  [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
10
- [![Tests](https://img.shields.io/badge/tests-647%20passing-brightgreen)]()
10
+ [![Tests](https://img.shields.io/badge/tests-1097%20passing-brightgreen)]()
11
11
  [![GitHub Release](https://img.shields.io/github/v/release/jinzhengdong/ai-cli)](https://github.com/jinzhengdong/ai-cli/releases)
12
12
  [![CI](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
13
13
 
14
- **ai-cli** is a powerful AI assistant that connects to 8 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.
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
- - **8 Built-in Providers** — Claude, Gemini, DeepSeek, OpenAI, Zhipu GLM, Kimi, OpenRouter (300+ models), **Ollama** (local models, no API key needed)
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 26 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
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 界面、桌面应用三合一,支持 8 大 Provider(含本地 Ollama)与 Agentic 工具调用
5
+ > 跨平台 AI 编程助手 — CLI 终端、Web 界面、桌面应用三合一,支持 9 大 Provider(含本地 Ollama)与 Agentic 工具调用
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/jinzd-ai-cli)](https://www.npmjs.com/package/jinzd-ai-cli)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
9
  [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
10
- [![Tests](https://img.shields.io/badge/tests-647%20passing-brightgreen)]()
10
+ [![Tests](https://img.shields.io/badge/tests-1097%20passing-brightgreen)]()
11
11
  [![GitHub Release](https://img.shields.io/github/v/release/jinzhengdong/ai-cli)](https://github.com/jinzhengdong/ai-cli/releases)
12
12
  [![CI](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/jinzhengdong/ai-cli/actions/workflows/ci.yml)
13
13
 
14
14
  ## 特性亮点
15
15
 
16
- - **8 大内置 Provider** — Claude、Gemini、DeepSeek、OpenAI、智谱 GLM、KimiOpenRouter(300+ 模型)、**Ollama**(本地模型,无需 API Key)
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 个内置工具(含 `find_symbol` / `search_code` / `run_tests`)输出给 Claude Desktop / Cursor / 任何 MCP 客户端;支持 `--tools` 白名单、`--cwd` 覆盖、`--allow-destructive`
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-E5UKN2FB.js";
4
+ } from "./chunk-6JTVUGSF.js";
5
5
  import "./chunk-TZQHYZKT.js";
6
- import "./chunk-PTXA4BGU.js";
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-7ORSZ7UO.js";
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-PTXA4BGU.js";
14
+ } from "./chunk-RSZWLQU4.js";
15
15
 
16
16
  // src/mcp/client.ts
17
17
  import { spawn } from "child_process";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-PTXA4BGU.js";
11
+ } from "./chunk-RSZWLQU4.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR_NAME
4
- } from "./chunk-PTXA4BGU.js";
4
+ } from "./chunk-RSZWLQU4.js";
5
5
 
6
6
  // src/diagnostics/tool-stats.ts
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-PTXA4BGU.js";
5
+ } from "./chunk-RSZWLQU4.js";
6
6
 
7
7
  // src/diagnostics/crash-log.ts
8
8
  import {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-PTXA4BGU.js";
4
+ } from "./chunk-RSZWLQU4.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.170";
4
+ var VERSION = "0.4.171";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-HDSKW7Q3.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-PUUJZGAS.js";
8
+ } from "./chunk-MELFYYS7.js";
9
9
  import {
10
10
  runTool
11
- } from "./chunk-SPJ5NO5Z.js";
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-PTXA4BGU.js";
28
+ } from "./chunk-RSZWLQU4.js";
29
29
  import {
30
30
  fileCheckpoints
31
31
  } from "./chunk-4BKXL7SM.js";
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.170";
9
+ var VERSION = "0.4.171";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -10,11 +10,11 @@ import {
10
10
  import "./chunk-NXXNLLSG.js";
11
11
  import {
12
12
  ConfigManager
13
- } from "./chunk-E5UKN2FB.js";
13
+ } from "./chunk-6JTVUGSF.js";
14
14
  import "./chunk-TZQHYZKT.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-PTXA4BGU.js";
17
+ } from "./chunk-RSZWLQU4.js";
18
18
  import "./chunk-PDX44BCA.js";
19
19
 
20
20
  // src/cli/ci.ts
@@ -36,7 +36,7 @@ import {
36
36
  TEST_TIMEOUT,
37
37
  VERSION,
38
38
  buildUserIdentityPrompt
39
- } from "./chunk-PTXA4BGU.js";
39
+ } from "./chunk-RSZWLQU4.js";
40
40
  import "./chunk-PDX44BCA.js";
41
41
  export {
42
42
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-Q466H3NV.js";
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-SPJ5NO5Z.js";
14
+ } from "./chunk-H53UCPFF.js";
15
15
  import "./chunk-NXXNLLSG.js";
16
16
  import {
17
17
  ConfigManager
18
- } from "./chunk-E5UKN2FB.js";
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-PTXA4BGU.js";
24
+ } from "./chunk-RSZWLQU4.js";
25
25
  import "./chunk-PDX44BCA.js";
26
26
 
27
27
  // src/diagnostics/doctor-cli.ts
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-NVBUA6YL.js";
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-KP7Y34MG.js");
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-PY5AF2US.js");
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-2C2DGQ5M.js";
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-7ORSZ7UO.js";
40
+ } from "./chunk-WG4THOHH.js";
41
41
  import "./chunk-HDSKW7Q3.js";
42
42
  import "./chunk-ZWVIDFGY.js";
43
- import "./chunk-PUUJZGAS.js";
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-Q466H3NV.js";
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-SPJ5NO5Z.js";
77
+ } from "./chunk-H53UCPFF.js";
78
78
  import "./chunk-NXXNLLSG.js";
79
79
  import {
80
80
  ConfigManager
81
- } from "./chunk-E5UKN2FB.js";
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-PTXA4BGU.js";
108
+ } from "./chunk-RSZWLQU4.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-DX4RNM5O.js");
1789
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-OMTUJRKU.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-JUG5WK6N.js");
2850
+ const { executeTests } = await import("./run-tests-AYADOMOF.js");
2851
2851
  const argStr = args.join(" ").trim();
2852
2852
  let testArgs = {};
2853
2853
  if (argStr) {
@@ -7596,7 +7596,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7596
7596
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7597
7597
  process.exit(1);
7598
7598
  }
7599
- const { startWebServer } = await import("./server-JXCJRJN5.js");
7599
+ const { startWebServer } = await import("./server-7B7HTSLE.js");
7600
7600
  await startWebServer({ port, host: options.host });
7601
7601
  });
7602
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) => {
@@ -7763,12 +7763,12 @@ program.command("sessions").description("List recent conversation sessions").opt
7763
7763
  console.log(footer + "\n");
7764
7764
  });
7765
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) => {
7766
- const { runDoctorCli } = await import("./doctor-cli-323ZXFCH.js");
7766
+ const { runDoctorCli } = await import("./doctor-cli-OZJZKETL.js");
7767
7767
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7768
7768
  });
7769
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) => {
7770
7770
  try {
7771
- const batch = await import("./batch-CAV4XSEF.js");
7771
+ const batch = await import("./batch-6WDD57ZG.js");
7772
7772
  switch (action) {
7773
7773
  case "submit":
7774
7774
  if (!arg) {
@@ -7811,7 +7811,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7811
7811
  }
7812
7812
  });
7813
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) => {
7814
- const { startMcpServer } = await import("./server-VQTTNO3M.js");
7814
+ const { startMcpServer } = await import("./server-RXWYMDAH.js");
7815
7815
  await startMcpServer({
7816
7816
  allowDestructive: !!options.allowDestructive,
7817
7817
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7820,7 +7820,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7820
7820
  });
7821
7821
  });
7822
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) => {
7823
- const { runCi } = await import("./ci-VERENT2L.js");
7823
+ const { runCi } = await import("./ci-Y4FEHLDL.js");
7824
7824
  const result = await runCi({
7825
7825
  pr: options.pr,
7826
7826
  base: options.base,
@@ -7965,7 +7965,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7965
7965
  }),
7966
7966
  config.get("customProviders")
7967
7967
  );
7968
- const { startHub } = await import("./hub-IZL5HKHA.js");
7968
+ const { startHub } = await import("./hub-IVVW7BTJ.js");
7969
7969
  await startHub(
7970
7970
  {
7971
7971
  topic: topic ?? "",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-NVBUA6YL.js";
4
+ } from "./chunk-YMH6BKAE.js";
5
5
  import "./chunk-3RG5ZIWI.js";
6
6
  export {
7
7
  executeTests,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-PUUJZGAS.js";
6
- import "./chunk-PTXA4BGU.js";
5
+ } from "./chunk-MELFYYS7.js";
6
+ import "./chunk-RSZWLQU4.js";
7
7
  import "./chunk-PDX44BCA.js";
8
8
  export {
9
9
  executeTests,
@@ -21,7 +21,7 @@ import {
21
21
  loadDevState,
22
22
  persistToolRound,
23
23
  setupProxy
24
- } from "./chunk-2C2DGQ5M.js";
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-7ORSZ7UO.js";
42
+ } from "./chunk-WG4THOHH.js";
43
43
  import "./chunk-HDSKW7Q3.js";
44
44
  import "./chunk-ZWVIDFGY.js";
45
- import "./chunk-PUUJZGAS.js";
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-SPJ5NO5Z.js";
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-E5UKN2FB.js";
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-PTXA4BGU.js";
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-JUG5WK6N.js");
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-7ORSZ7UO.js";
4
+ } from "./chunk-WG4THOHH.js";
5
5
  import "./chunk-HDSKW7Q3.js";
6
6
  import "./chunk-ZWVIDFGY.js";
7
- import "./chunk-PUUJZGAS.js";
7
+ import "./chunk-MELFYYS7.js";
8
8
  import {
9
9
  runTool
10
- } from "./chunk-SPJ5NO5Z.js";
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-PTXA4BGU.js";
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-7ORSZ7UO.js";
6
+ } from "./chunk-WG4THOHH.js";
7
7
  import "./chunk-HDSKW7Q3.js";
8
8
  import "./chunk-ZWVIDFGY.js";
9
- import "./chunk-PUUJZGAS.js";
9
+ import "./chunk-MELFYYS7.js";
10
10
  import {
11
11
  runTool
12
- } from "./chunk-SPJ5NO5Z.js";
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-PTXA4BGU.js";
19
+ } from "./chunk-RSZWLQU4.js";
20
20
  import "./chunk-4BKXL7SM.js";
21
21
  import "./chunk-MM3F43H6.js";
22
22
  import "./chunk-KHYD3WXE.js";
@@ -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 (sidebar.classList.contains('sidebar-open')) {
2581
- closeSidebar();
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
- openSidebar();
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 (hidden on desktop) ──────── */
728
- .sidebar-toggle-btn { display: none; }
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.170",
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"