jinzd-ai-cli 0.4.210 → 0.4.211

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
@@ -329,7 +329,65 @@ Control when tools require confirmation. Rules are checked in order — first ma
329
329
  | `action` | `auto-approve` (skip confirmation), `deny` (block), `confirm` (ask user) |
330
330
  | `when.dangerLevel` | Only match when danger level is `safe`, `write`, or `destructive` |
331
331
  | `when.pathPattern` | Substring match against tool's `path` or `command` argument |
332
-
332
+
333
+ ### Permission Profiles
334
+
335
+ Permission profiles provide coarse-grained safety boundaries before fine-grained `permissionRules` run. The default profile is `legacy`, so existing configs keep their old behavior.
336
+
337
+ Built-in profiles:
338
+
339
+ | Profile | Behavior |
340
+ |---------|----------|
341
+ | `legacy` | Backward-compatible mode. Uses `permissionRules` and `defaultPermission` as before. |
342
+ | `read-only` | Allows known read-only/safe tools and safe MCP tools; blocks write and destructive tools. |
343
+ | `workspace-write` | Allows explicit file writes only inside the workspace roots or temp dirs; destructive tools still require confirmation. |
344
+ | `danger-full-access` | Auto-approves non-destructive tools by default; destructive tools still require confirmation. Use only in isolated environments. |
345
+
346
+ ```json
347
+ {
348
+ "defaultPermissionProfile": "workspace-write",
349
+ "allowedPermissionProfiles": ["legacy", "read-only", "workspace-write", "danger-full-access"],
350
+ "permissionProfiles": {
351
+ "workspace-write": {
352
+ "workspaceRoots": ["D:/github/ai-cli"],
353
+ "allowTemp": true,
354
+ "rules": [
355
+ { "tool": "read_file", "action": "auto-approve" },
356
+ { "tool": "list_dir", "action": "auto-approve" }
357
+ ]
358
+ }
359
+ },
360
+ "permissionRules": [
361
+ { "tool": "bash", "action": "deny", "when": { "pathPattern": "rm -rf" } }
362
+ ]
363
+ }
364
+ ```
365
+
366
+ `/status` and `/security status` show the active profile. The Web status payload also includes `permissionProfile` for UI surfaces.
367
+ ### Network Policy
368
+
369
+ `networkPolicy` is disabled by default for backward compatibility. When enabled, it governs network-facing tools before execution: `web_fetch`, `web_search`, `google_search`, MCP tools, and shell commands that look like network access (`curl`, `wget`, `git clone/fetch/pull/push`, package installs, SSH/SCP, etc.).
370
+
371
+ ```json
372
+ {
373
+ "networkPolicy": {
374
+ "enabled": true,
375
+ "defaultAction": "confirm",
376
+ "allowDomains": ["github.com", "docs.anthropic.com", "platform.openai.com"],
377
+ "denyDomains": ["example-danger.test"],
378
+ "allowPrivateNetwork": false,
379
+ "tools": {
380
+ "web_fetch": "confirm",
381
+ "web_search": "allow",
382
+ "google_search": "confirm",
383
+ "shell": "confirm",
384
+ "mcp": "confirm"
385
+ }
386
+ }
387
+ }
388
+ ```
389
+
390
+ Actions are `allow`, `confirm`, or `deny`. Domain entries match the exact host or subdomains; port lists match the resolved URL port. Private/internal hosts such as `localhost`, `127.0.0.1`, `10.0.0.0/8`, `192.168.0.0/16`, and private IPv6 ranges are blocked unless `allowPrivateNetwork` is true.
333
391
  **Recommended minimal config** — auto-approve all read-only tools to reduce y/N prompts:
334
392
 
335
393
  ```json
@@ -422,6 +480,46 @@ npm run test:watch # Watch mode
422
480
 
423
481
  79 offline test files covering: authentication, sessions, tool types & danger levels, permissions, output truncation, diff rendering, edit-file similarity, error hierarchy, config management, env loading, provider registry, web-fetch, grep-files, hub renderer, hub discussion, hub presets, dev-state, token estimator, tool registry budget, parallel tool execution, cost tracker, session tool history.
424
482
 
483
+ ## Releasing (Version Bump → npm Publish → GitHub Push)
484
+
485
+ > **For contributors and AI agents: the entire release is driven by [`scripts/release.mjs`](scripts/release.mjs). Never manually bump the version or run `npm publish` yourself** — a hand-publish of `0.4.207` shipped a version that reported the wrong number and forced a corrective re-release (`0.4.208`). The script's guards exist precisely to stop that.
486
+
487
+ **Prerequisites**
488
+
489
+ - You are on the `main` branch and the changes to ship are already in the working tree.
490
+ - `npx tsc --noEmit` is clean and `npm test` is green (the script enforces both and rolls the bump back on failure).
491
+ - You are logged into npm as the package owner (`npm whoami`).
492
+ - You have push access to the GitHub remote.
493
+
494
+ **Step 1 — Write the milestone entry FIRST (Guard A).** Add a one-line entry to the `## 最近里程碑` section of [`CLAUDE.md`](CLAUDE.md) that contains the exact full-width-parenthesis marker `(vX.Y.Z)` for the target version. The script refuses to start without it. (Full narrative goes in `CHANGELOG.md`; this section is just the index line.)
495
+
496
+ **Step 2 — Run the release script.**
497
+
498
+ ```bash
499
+ # patch: 0.4.209 → 0.4.210 (also accepts: minor / major / an explicit x.y.z)
500
+ node scripts/release.mjs patch -m "fix(scope): one-line commit title"
501
+
502
+ # preview only — validates guards, writes nothing:
503
+ node scripts/release.mjs patch -m "..." --dry-run
504
+ ```
505
+
506
+ - Do **not** put a `(vX.Y.Z)` suffix in `-m`; the script appends it automatically.
507
+ - On Windows PowerShell, call `node` directly — `npm run release -- -m ...` swallows the `-m` argument.
508
+
509
+ **What the script does, in order:**
510
+
511
+ 1. **Guard A** — asserts `CLAUDE.md` contains the `(vX.Y.Z)` milestone entry.
512
+ 2. Bumps the version in **three** places: `package.json`, `src/core/constants.ts` (`VERSION`), and `CLAUDE.md` (`**当前版本**`).
513
+ 3. **Guard B** — re-reads all three files from disk and asserts every bump landed.
514
+ 4. **Guard C** — `tsc --noEmit` must be zero-error (rolls the bump back on failure).
515
+ 5. `npm test` must pass (rolls the bump back on failure).
516
+ 6. Prints the exact file list entering the release commit and blocks if any looks sensitive (`.env`, `*.pem`, `*.key`, `secret`, …). Override consciously with `--allow-sensitive`.
517
+ 7. `git add -A` + commit `"<title> (vX.Y.Z)"` (message passed via argv, not shell-interpolated).
518
+ 8. `npm publish` (the build runs automatically via `prepublishOnly`), then re-queries the registry to confirm the new version is live.
519
+ 9. `git push` to `main`.
520
+
521
+ **Optional flags:** `--dry-run` · `--skip-tests` · `--no-publish` · `--no-push` · `--allow-sensitive`.
522
+
425
523
  ## Documentation
426
524
 
427
525
  - [`docs/USAGE.md`](docs/USAGE.md) — Complete reference manual (commands, tools, config)
package/README.zh-CN.md CHANGED
@@ -441,6 +441,46 @@ npm run test:watch # 监听模式
441
441
 
442
442
  26 个测试套件覆盖:认证、会话、工具类型与危险级别、权限、输出截断、diff 渲染、edit-file 相似度、错误层级、配置管理、环境变量、Provider 注册、web-fetch、grep-files、Hub 渲染、Hub 讨论、Hub 预设、开发状态、Token 估算、工具注册表预算、并行工具执行、费用追踪、会话工具历史。
443
443
 
444
+ ## 发布(版本提升 → npm 发布 → 推送 GitHub)
445
+
446
+ > **给贡献者与 AI 模型:整个发布流程一律走 [`scripts/release.mjs`](scripts/release.mjs),切勿手动 bump 版本号或自己跑 `npm publish`。** 曾经手工 publish 的 `0.4.207` 装上后 `--version` 报错版本号,被迫补发 `0.4.208` 对齐——脚本的四道守卫就是为拦住这类事故而存在。
447
+
448
+ **前置条件**
449
+
450
+ - 当前在 `main` 分支,待发布的改动已在工作区。
451
+ - `npx tsc --noEmit` 零错误、`npm test` 全绿(脚本会强制校验,失败自动回滚版本号)。
452
+ - 已登录 npm 且是包的 owner(`npm whoami`)。
453
+ - 有 GitHub 远端推送权限。
454
+
455
+ **第 1 步 —— 先写里程碑条目(Guard A)。** 在 [`CLAUDE.md`](CLAUDE.md) 的 `## 最近里程碑` 一节加一行,条目中必须含目标版本的**全角括号**标记 `(vX.Y.Z)`,否则脚本拒绝启动。(完整叙事写进 `CHANGELOG.md`,本节只留一行式索引。)
456
+
457
+ **第 2 步 —— 运行发布脚本。**
458
+
459
+ ```bash
460
+ # patch:0.4.209 → 0.4.210(也支持 minor / major / 显式 x.y.z)
461
+ node scripts/release.mjs patch -m "fix(scope): 一句话 commit 标题"
462
+
463
+ # 仅预览,只校验守卫、不改任何文件:
464
+ node scripts/release.mjs patch -m "..." --dry-run
465
+ ```
466
+
467
+ - `-m` 里**不要**自带 `(vX.Y.Z)` 后缀,脚本会自动追加。
468
+ - Windows PowerShell 下请直接用 `node` 调用——`npm run release -- -m ...` 会把 `-m` 参数吞掉。
469
+
470
+ **脚本执行顺序:**
471
+
472
+ 1. **Guard A** —— 断言 `CLAUDE.md` 已含 `(vX.Y.Z)` 里程碑条目。
473
+ 2. bump **三处**版本号:`package.json`、`src/core/constants.ts`(`VERSION`)、`CLAUDE.md`(`**当前版本**`)。
474
+ 3. **Guard B** —— 从磁盘重读这三处,逐一断言都真的改到了。
475
+ 4. **Guard C** —— `tsc --noEmit` 必须零错误(失败则回滚版本号)。
476
+ 5. `npm test` 必须全绿(失败则回滚版本号)。
477
+ 6. 打印进入发布 commit 的完整文件清单,若含疑似敏感文件(`.env`、`*.pem`、`*.key`、`secret`…)直接拦下,确认无误加 `--allow-sensitive`。
478
+ 7. `git add -A` + commit `"<标题> (vX.Y.Z)"`(消息走 argv 传参,不经 shell 拼接)。
479
+ 8. `npm publish`(build 经 `prepublishOnly` 自动跑),再回查 registry 确认新版本已上线。
480
+ 9. `git push` 推送 `main`。
481
+
482
+ **可选 flag:** `--dry-run` · `--skip-tests` · `--no-publish` · `--no-push` · `--allow-sensitive`。
483
+
444
484
  ## 文档
445
485
 
446
486
  - [English README](README.md) — English documentation
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-P6MTFCXB.js";
4
+ } from "./chunk-UOROWTGG.js";
5
5
  import "./chunk-TZQHYZKT.js";
6
- import "./chunk-GRJNQJA5.js";
6
+ import "./chunk-E5XCM4A6.js";
7
7
  import {
8
8
  atomicWriteFileSync
9
9
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-GRJNQJA5.js";
4
+ } from "./chunk-E5XCM4A6.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-GRJNQJA5.js";
5
+ } from "./chunk-E5XCM4A6.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
  truncateForPersist
4
- } from "./chunk-NEPFADHX.js";
4
+ } from "./chunk-ZOPYREL5.js";
5
5
  import {
6
6
  APP_NAME,
7
7
  CONFIG_DIR_NAME,
@@ -13,7 +13,7 @@ import {
13
13
  MCP_PROTOCOL_VERSION,
14
14
  MCP_TOOL_PREFIX,
15
15
  VERSION
16
- } from "./chunk-GRJNQJA5.js";
16
+ } from "./chunk-E5XCM4A6.js";
17
17
  import {
18
18
  atomicWriteFileSync
19
19
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.210";
4
+ var VERSION = "0.4.211";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR_NAME
4
- } from "./chunk-GRJNQJA5.js";
4
+ } from "./chunk-E5XCM4A6.js";
5
5
  import {
6
6
  atomicWriteFileSync
7
7
  } from "./chunk-IW3Q7AE5.js";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-GRJNQJA5.js";
11
+ } from "./chunk-E5XCM4A6.js";
12
12
  import {
13
13
  atomicWriteFileSync
14
14
  } from "./chunk-IW3Q7AE5.js";
@@ -162,7 +162,41 @@ var ConfigSchema = z.object({
162
162
  preToolExecution: z.string().optional(),
163
163
  postToolExecution: z.string().optional()
164
164
  }).optional(),
165
- // 工具权限规则(按顺序匹配第一个生效)
165
+ // 网络访问治理(v0.4.211+):默认关闭以保持兼容;开启后统一治理 web/search/MCP/shell 网络出口。
166
+ networkPolicy: z.object({
167
+ enabled: z.boolean().default(false),
168
+ defaultAction: z.enum(["allow", "confirm", "deny"]).default("confirm"),
169
+ allowDomains: z.array(z.string()).default([]),
170
+ denyDomains: z.array(z.string()).default([]),
171
+ allowPorts: z.array(z.number().int().min(1).max(65535)).default([]),
172
+ denyPorts: z.array(z.number().int().min(1).max(65535)).default([]),
173
+ allowPrivateNetwork: z.boolean().default(false),
174
+ tools: z.object({
175
+ web_fetch: z.enum(["allow", "confirm", "deny"]).optional(),
176
+ web_search: z.enum(["allow", "confirm", "deny"]).optional(),
177
+ google_search: z.enum(["allow", "confirm", "deny"]).optional(),
178
+ shell: z.enum(["allow", "confirm", "deny"]).optional(),
179
+ mcp: z.enum(["allow", "confirm", "deny"]).optional()
180
+ }).default({})
181
+ }).default({ enabled: false, defaultAction: "confirm", allowDomains: [], denyDomains: [], allowPorts: [], denyPorts: [], allowPrivateNetwork: false, tools: {} }),
182
+ // 权限 Profile(v0.4.211+):legacy 保持旧行为;其余 profile 提供更清晰的安全边界。
183
+ defaultPermissionProfile: z.enum(["legacy", "read-only", "workspace-write", "danger-full-access"]).default("legacy"),
184
+ allowedPermissionProfiles: z.array(z.string()).default(["legacy", "read-only", "workspace-write", "danger-full-access"]),
185
+ permissionProfiles: z.record(z.object({
186
+ extends: z.enum(["legacy", "read-only", "workspace-write", "danger-full-access"]).optional(),
187
+ defaultAction: z.enum(["auto-approve", "deny", "confirm"]).optional(),
188
+ workspaceRoots: z.array(z.string()).optional(),
189
+ allowTemp: z.boolean().optional(),
190
+ rules: z.array(z.object({
191
+ tool: z.string(),
192
+ action: z.enum(["auto-approve", "deny", "confirm"]),
193
+ when: z.object({
194
+ dangerLevel: z.enum(["safe", "write", "destructive"]).optional(),
195
+ pathPattern: z.string().optional()
196
+ }).optional()
197
+ })).optional()
198
+ })).default({}),
199
+ // 工具权限规则(按顺序匹配第一个生效;作为当前权限 Profile 内的细粒度规则)
166
200
  permissionRules: z.array(z.object({
167
201
  tool: z.string(),
168
202
  action: z.enum(["auto-approve", "deny", "confirm"]),
@@ -171,7 +205,7 @@ var ConfigSchema = z.object({
171
205
  pathPattern: z.string().optional()
172
206
  }).optional()
173
207
  })).default([]),
174
- // 无规则匹配时的默认权限动作
208
+ // 无规则匹配时的默认权限动作(legacy profile 兼容旧行为)
175
209
  defaultPermission: z.enum(["auto-approve", "deny", "confirm"]).default("confirm"),
176
210
  // 自动上下文压缩开关
177
211
  // 当对话估算 token 数超过模型 contextWindow 的 80% 时,自动触发 compact 压缩旧消息