@zqagent/core 0.2.4 → 0.2.5

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
@@ -1,60 +1,139 @@
1
1
  # @zqagent/core
2
2
 
3
- zqagent 的引擎核心:`TurnEngine`(异步事件循环)、`ToolRegistry`、`PermissionEngine`、
4
- `OpenAIProvider`,以及 CLI 与**多租户云端 Server**(含 MQTT 节点管理 v2 节点桥)。
3
+ **在终端、桌面或手机上,让 AI 帮你写代码、改文件、跑命令——有副作用的操作先问你。**
5
4
 
6
- 依赖 `@zqagent/shared`(经 tsconfig `paths` 引用其源码,构建期打进 bundle)。
5
+ [![CI](https://github.com/zqagent/zqagent/actions/workflows/ci.yml/badge.svg)](https://github.com/zqagent/zqagent/actions/workflows/ci.yml)
6
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/zqagent/zqagent/blob/main/LICENSE)
7
7
 
8
- ## 目录
8
+ ZQAgent 是可自托管的 AI 编码 Agent。它自己读代码、改文件、跑命令,但**每一个有副作用的动作都会先问你**。
9
9
 
10
- ```
11
- src/
12
- ├── index.ts # 库入口(re-export)
13
- ├── cli/ # CLI(index.ts 入口 / 连接向导 / 输入 / 会话元数据 …)
14
- ├── agents/ # Agent 注册表(运行时维护 agent)
15
- ├── mcp/ # MCP 客户端与管理(stdio / http)
16
- ├── engine/ # TurnEngine / events / compaction / hooks / renderer
17
- ├── permissions/ # 风险分类 + 模式门控 + 审批
18
- ├── providers/ # OpenAI 兼容 provider(流式 / chat)
19
- ├── prompts/ # 中文系统提示词
20
- ├── tools/ # 19 个内置工具(文件/shell/搜索/web/git/补丁/协作/子代理/媒体)
21
- └── server/ # 多租户 API + 项目/节点 + MQTT 节点管理 v2 桥(FleetNodeBridge/FleetCommands)
22
- bin/zqagent # CLI 可执行入口
23
- scripts/ # SEA 单文件构建 / 冒烟 / 探针 / busybox 下载
24
- test/ # Vitest(492 用例,覆盖引擎/server/hub/web 协议)
10
+ - **自带模型 Key**:DeepSeek、OpenAI 或任意 OpenAI 兼容端点,用多少花多少。
11
+ - **审批可控**:讨论 / 计划 / 交互 / 自动四种模式,写文件、执行命令逐次确认。
12
+ - **多端可用**:终端 CLI、桌面应用,以及手机或 QQ 远程派任务。
13
+ - **可扩展**:接入 MCP 外部工具,或用命令工具、自定义 Agent 扩展能力。
14
+
15
+ ## 安装
16
+
17
+ 需要 **Node.js >= 18.17**。
18
+
19
+ ```bash
20
+ npm i -g @zqagent/core
21
+ zqagent
25
22
  ```
26
23
 
27
- ## 使用
24
+ Linux 也可以零依赖安装(下载单文件可执行程序,无需 Node):
28
25
 
29
26
  ```bash
30
- # 库
31
- import { TurnEngine, ToolRegistry, PermissionEngine, OpenAIProvider } from "@zqagent/core";
32
- import { ... } from "@zqagent/core/server"; // 服务端 API
33
- import { ... } from "@zqagent/core/tools/fs"; // 单个工具
27
+ curl -fsSL https://agent.cd-zq.com/install.sh | sh
28
+ ```
34
29
 
35
- # CLI(全局安装)
36
- npm i -g @zqagent/core --registry=https://npm2.cd-zq.com/
37
- zqagent
30
+ 首次启动输入 `/connect`,按提示选择 provider(OpenAI / DeepSeek / 通义千问 / 智谱 GLM / Kimi / 自定义)→
31
+ 填写 API Key → 选择模型 → 设置推理强度。Key 使用 AES-256-GCM 加密保存在本机
32
+ `~/.config/zqagent/`,不会上传。
33
+
34
+ ## 快速开始
35
+
36
+ ```text
37
+ $ zqagent
38
+ [interactive][code] > 读一下这个项目,告诉我它是做什么的
39
+
40
+ ● list_files .
41
+ ● read_file README.md
42
+ ✓ 这是一个 TypeScript 实现的 AI Agent 引擎……
43
+
44
+ [interactive][code] > 把 src/config.ts 里的默认端口改成 8788,然后跑测试
45
+
46
+ ● read_file src/config.ts
47
+ ⏵ replace_in_file 1 处修改,等待审批
48
+ [Y] 允许一次 [A] 总是允许 [D] 拒绝
49
+ > Y
50
+ ● run_shell pnpm test
51
+ ✓ 42 passed
52
+ ✓ 已修改默认端口,测试通过
38
53
  ```
39
54
 
40
- ## 开发与构建(在仓库根 ts/ 或本目录)
55
+ 常用命令:
56
+
57
+ | 命令 | 说明 |
58
+ | --- | --- |
59
+ | `/connect` | 配置模型连接(provider / Key / 模型 / 推理强度) |
60
+ | `/plan` | 计划模式:只读探索,输出方案后等待确认 |
61
+ | `/interactive` | 交互模式:有副作用的操作逐次审批(默认) |
62
+ | `/auto` | 自动模式:全部放行(高风险,建议只在隔离环境使用) |
63
+ | `/discuss` | 讨论模式:纯只读对话 |
64
+ | `/sessions` | 列出并恢复历史会话 |
65
+ | `/agent` | 切换或维护自定义 Agent |
66
+ | `/mcp` | 管理 MCP 服务器 |
67
+ | `/tools` | 查看全部工具及其风险等级 |
68
+
69
+ 任务执行过程中可以直接输入文字追加指示,无需等它跑完;连按两次 `ESC` 中断。
70
+
71
+ ## 内置能力
72
+
73
+ | 类别 | 工具 |
74
+ | --- | --- |
75
+ | 文件 | `read_file` `write_file` `replace_in_file` `list_files` `grep` |
76
+ | Shell | `run_shell` `shell_task_output` `shell_task_kill`(持久化 shell,支持后台任务) |
77
+ | 网络 | `web_search` `web_fetch` |
78
+ | Git | `git_log` `git_status` `git_diff` |
79
+ | 补丁 | `apply_patch` `apply_unified_diff` |
80
+ | 协作 | `ask_user` `propose_plan` `request_directory` `todo_write` |
81
+ | 探索 | `explore`(子代理:跨文件调研,只返回结论) |
82
+ | 媒体 | `media`,检测到本机 ffmpeg 时另有 `ffmpeg` `ffprobe` |
83
+
84
+ 共 21 个内置工具。工具可在运行时新增、删除、禁用,下一次模型调用立即生效。
85
+
86
+ ## 作为库使用
87
+
88
+ ```ts
89
+ import { TurnEngine, ToolRegistry, PermissionEngine, OpenAIProvider } from "@zqagent/core";
90
+ import { ... } from "@zqagent/core/server"; // 多租户 HTTP 服务
91
+ import { ... } from "@zqagent/core/tools/fs"; // 单个工具
92
+ ```
93
+
94
+ ## 安全模型
95
+
96
+ ZQAgent 的前提是**模型输出不可信**:
97
+
98
+ - 写文件、执行命令、访问网络默认需要审批。
99
+ - API Key 加密存储在本机,仓库与日志中不会出现明文。
100
+ - 工作区就是权限边界:以哪个用户、在哪个目录启动,就拥有该用户对该目录的权限。
101
+ - 不要把节点服务直接暴露到公网。
102
+
103
+ 发现安全问题请**不要开公开 issue**,按
104
+ [SECURITY.md](https://github.com/zqagent/zqagent/blob/main/SECURITY.md) 私下报告。
105
+
106
+ ## 文档
107
+
108
+ | 主题 | 文档 |
109
+ | --- | --- |
110
+ | 系统架构 | [docs/architecture.md](https://github.com/zqagent/zqagent/blob/main/docs/architecture.md) |
111
+ | 线协议(帧 / 消息 / 签名) | [docs/wire-protocol.md](https://github.com/zqagent/zqagent/blob/main/docs/wire-protocol.md) |
112
+ | 上下文压缩 | [docs/context-compaction.md](https://github.com/zqagent/zqagent/blob/main/docs/context-compaction.md) |
113
+ | 节点服务 REST API | [docs/server-api.md](https://github.com/zqagent/zqagent/blob/main/docs/server-api.md) |
114
+ | 共享库 | [docs/shared.md](https://github.com/zqagent/zqagent/blob/main/docs/shared.md) |
115
+ | LLM 连接排查 | [docs/llm-connection-troubleshooting.md](https://github.com/zqagent/zqagent/blob/main/docs/llm-connection-troubleshooting.md) |
116
+ | QQ 机器人 | [docs/qq-bot.md](https://github.com/zqagent/zqagent/blob/main/docs/qq-bot.md) |
117
+
118
+ 上述文档同时提供英文版(`docs/en/`)。使用者指南见 <https://agent.cd-zq.com/>。
119
+
120
+ ## 开发
121
+
122
+ 本包是 monorepo 的一部分(与 `@zqagent/shared` 同源构建):
41
123
 
42
124
  ```bash
43
- pnpm run dev # CLI(tsx packages/core/src/cli/index.ts)
44
- pnpm run server # 多租户 Server :8787
45
- pnpm run build # tsup → dist/(含 dts)
46
- pnpm run test # Vitest
47
- pnpm run typecheck # tsc --noEmit
48
- pnpm run build:sea # 单 CJS bundle(供 SEA)
49
- pnpm run build:cli-bin # SEA 单文件可执行 → release/cli/
50
- pnpm run probes:sea # 生成对照探针
51
- pnpm run fetch:busybox # 下载 BusyBox-w32(Windows)
125
+ pnpm install
126
+ pnpm --filter @zqagent/core typecheck
127
+ pnpm --filter @zqagent/core test
128
+ pnpm --filter @zqagent/core build
129
+ pnpm --filter @zqagent/core dev # 以源码方式启动 CLI
52
130
  ```
53
131
 
54
- ## 相关文档
132
+ 贡献前请阅读
133
+ [CONTRIBUTING.md](https://github.com/zqagent/zqagent/blob/main/CONTRIBUTING.md)。
134
+ 涉及权限、审批、命令执行的改动会被重点审查。
135
+
136
+ ## 许可
55
137
 
56
- - 系统架构与构建:[../../docs/architecture.md](../../docs/architecture.md)
57
- - CLI 使用/工具/Agent/MCP:[../../packages/site/docs/guide/](../../packages/site/docs/guide/)
58
- - Server REST API:[../../docs/server-api.md](../../docs/server-api.md)
59
- - 线协议规范(帧/信封/消息/签名):[../../docs/wire-protocol.md](../../docs/wire-protocol.md)
60
- - CLI SEA 故障排查:[../../docs/cli-sea-troubleshooting.md](../../docs/cli-sea-troubleshooting.md)
138
+ [Apache-2.0](https://github.com/zqagent/zqagent/blob/main/LICENSE)。
139
+ `@zqagent` 与 ZQAgent 名称为本项目商标,二次分发或托管服务请勿暗示官方背书。
@@ -13191,7 +13191,7 @@ function buildNodeInfo(store, opts) {
13191
13191
  nodeId: opts.nodeId ?? ensureNodeId2(store),
13192
13192
  platform: process.platform,
13193
13193
  mode: process.env.NODE_MODE ?? "standalone",
13194
- version: "0.2.4",
13194
+ version: "0.2.5",
13195
13195
  admin: opts.admin,
13196
13196
  projects: opts.projects
13197
13197
  };
@@ -14098,7 +14098,7 @@ function buildNodeHost(store, manager, diskPath) {
14098
14098
  arch: process.arch,
14099
14099
  release: os6.release(),
14100
14100
  uptimeSec: Math.round(os6.uptime()),
14101
- version: "0.2.4",
14101
+ version: "0.2.5",
14102
14102
  mode: process.env.NODE_MODE ?? "standalone",
14103
14103
  cpu: {
14104
14104
  count: cpus2.length,
@@ -15631,7 +15631,7 @@ function createApp(store, manager, opts = {}) {
15631
15631
  json(res, 200, {
15632
15632
  status: "ok",
15633
15633
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
15634
- version: "0.2.4",
15634
+ version: "0.2.5",
15635
15635
  features: { mcp: hasServerMcpConfig() }
15636
15636
  });
15637
15637
  return;
@@ -17230,7 +17230,7 @@ var FleetNodeBridge = class {
17230
17230
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17231
17231
  platform: process.platform,
17232
17232
  mode: process.env.NODE_MODE ?? "standalone",
17233
- version: "0.2.4",
17233
+ version: "0.2.5",
17234
17234
  ip: primaryIp()
17235
17235
  };
17236
17236
  }
@@ -17282,7 +17282,7 @@ var FleetNodeBridge = class {
17282
17282
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17283
17283
  platform: process.platform,
17284
17284
  mode: process.env.NODE_MODE ?? "standalone",
17285
- version: "0.2.4",
17285
+ version: "0.2.5",
17286
17286
  ip: primaryIp(),
17287
17287
  projects,
17288
17288
  totals,
@@ -18949,7 +18949,7 @@ init_cjs_shims();
18949
18949
  var path31 = __toESM(require("path"), 1);
18950
18950
  var import_node_module3 = require("module");
18951
18951
  function currentVersion() {
18952
- const injected = "0.2.4"?.trim();
18952
+ const injected = "0.2.5"?.trim();
18953
18953
  if (injected) return injected;
18954
18954
  try {
18955
18955
  const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
@@ -21069,7 +21069,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
21069
21069
  }
21070
21070
  var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
21071
21071
  function cliVersion() {
21072
- const env3 = "0.2.4"?.trim();
21072
+ const env3 = "0.2.5"?.trim();
21073
21073
  if (env3) return env3;
21074
21074
  try {
21075
21075
  const req2 = (0, import_module.createRequire)(importMetaUrl);
package/dist/cli/index.js CHANGED
@@ -13174,7 +13174,7 @@ function buildNodeInfo(store, opts) {
13174
13174
  nodeId: opts.nodeId ?? ensureNodeId2(store),
13175
13175
  platform: process.platform,
13176
13176
  mode: process.env.NODE_MODE ?? "standalone",
13177
- version: "0.2.4",
13177
+ version: "0.2.5",
13178
13178
  admin: opts.admin,
13179
13179
  projects: opts.projects
13180
13180
  };
@@ -14081,7 +14081,7 @@ function buildNodeHost(store, manager, diskPath) {
14081
14081
  arch: process.arch,
14082
14082
  release: os6.release(),
14083
14083
  uptimeSec: Math.round(os6.uptime()),
14084
- version: "0.2.4",
14084
+ version: "0.2.5",
14085
14085
  mode: process.env.NODE_MODE ?? "standalone",
14086
14086
  cpu: {
14087
14087
  count: cpus2.length,
@@ -15614,7 +15614,7 @@ function createApp(store, manager, opts = {}) {
15614
15614
  json(res, 200, {
15615
15615
  status: "ok",
15616
15616
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
15617
- version: "0.2.4",
15617
+ version: "0.2.5",
15618
15618
  features: { mcp: hasServerMcpConfig() }
15619
15619
  });
15620
15620
  return;
@@ -17213,7 +17213,7 @@ var FleetNodeBridge = class {
17213
17213
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17214
17214
  platform: process.platform,
17215
17215
  mode: process.env.NODE_MODE ?? "standalone",
17216
- version: "0.2.4",
17216
+ version: "0.2.5",
17217
17217
  ip: primaryIp()
17218
17218
  };
17219
17219
  }
@@ -17265,7 +17265,7 @@ var FleetNodeBridge = class {
17265
17265
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
17266
17266
  platform: process.platform,
17267
17267
  mode: process.env.NODE_MODE ?? "standalone",
17268
- version: "0.2.4",
17268
+ version: "0.2.5",
17269
17269
  ip: primaryIp(),
17270
17270
  projects,
17271
17271
  totals,
@@ -18932,7 +18932,7 @@ init_esm_shims();
18932
18932
  import * as path32 from "path";
18933
18933
  import { createRequire as createRequire3 } from "module";
18934
18934
  function currentVersion() {
18935
- const injected = "0.2.4"?.trim();
18935
+ const injected = "0.2.5"?.trim();
18936
18936
  if (injected) return injected;
18937
18937
  try {
18938
18938
  const req2 = createRequire3(import.meta.url);
@@ -21052,7 +21052,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
21052
21052
  }
21053
21053
  var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
21054
21054
  function cliVersion() {
21055
- const env3 = "0.2.4"?.trim();
21055
+ const env3 = "0.2.5"?.trim();
21056
21056
  if (env3) return env3;
21057
21057
  try {
21058
21058
  const req2 = createRequire4(import.meta.url);
@@ -11028,7 +11028,7 @@ function buildNodeInfo(store, opts) {
11028
11028
  nodeId: opts.nodeId ?? ensureNodeId(store),
11029
11029
  platform: process.platform,
11030
11030
  mode: process.env.NODE_MODE ?? "standalone",
11031
- version: "0.2.4",
11031
+ version: "0.2.5",
11032
11032
  admin: opts.admin,
11033
11033
  projects: opts.projects
11034
11034
  };
@@ -11935,7 +11935,7 @@ function buildNodeHost(store, manager, diskPath) {
11935
11935
  arch: process.arch,
11936
11936
  release: os6.release(),
11937
11937
  uptimeSec: Math.round(os6.uptime()),
11938
- version: "0.2.4",
11938
+ version: "0.2.5",
11939
11939
  mode: process.env.NODE_MODE ?? "standalone",
11940
11940
  cpu: {
11941
11941
  count: cpus2.length,
@@ -13468,7 +13468,7 @@ function createApp(store, manager, opts = {}) {
13468
13468
  json(res, 200, {
13469
13469
  status: "ok",
13470
13470
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
13471
- version: "0.2.4",
13471
+ version: "0.2.5",
13472
13472
  features: { mcp: hasServerMcpConfig() }
13473
13473
  });
13474
13474
  return;
@@ -15132,7 +15132,7 @@ var FleetNodeBridge = class {
15132
15132
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15133
15133
  platform: process.platform,
15134
15134
  mode: process.env.NODE_MODE ?? "standalone",
15135
- version: "0.2.4",
15135
+ version: "0.2.5",
15136
15136
  ip: primaryIp()
15137
15137
  };
15138
15138
  }
@@ -15184,7 +15184,7 @@ var FleetNodeBridge = class {
15184
15184
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15185
15185
  platform: process.platform,
15186
15186
  mode: process.env.NODE_MODE ?? "standalone",
15187
- version: "0.2.4",
15187
+ version: "0.2.5",
15188
15188
  ip: primaryIp(),
15189
15189
  projects,
15190
15190
  totals,
@@ -16903,7 +16903,7 @@ init_cjs_shims();
16903
16903
  var path27 = __toESM(require("path"), 1);
16904
16904
  var import_node_module3 = require("module");
16905
16905
  function currentVersion() {
16906
- const injected = "0.2.4"?.trim();
16906
+ const injected = "0.2.5"?.trim();
16907
16907
  if (injected) return injected;
16908
16908
  try {
16909
16909
  const req2 = (0, import_node_module3.createRequire)(importMetaUrl);
@@ -11011,7 +11011,7 @@ function buildNodeInfo(store, opts) {
11011
11011
  nodeId: opts.nodeId ?? ensureNodeId(store),
11012
11012
  platform: process.platform,
11013
11013
  mode: process.env.NODE_MODE ?? "standalone",
11014
- version: "0.2.4",
11014
+ version: "0.2.5",
11015
11015
  admin: opts.admin,
11016
11016
  projects: opts.projects
11017
11017
  };
@@ -11918,7 +11918,7 @@ function buildNodeHost(store, manager, diskPath) {
11918
11918
  arch: process.arch,
11919
11919
  release: os6.release(),
11920
11920
  uptimeSec: Math.round(os6.uptime()),
11921
- version: "0.2.4",
11921
+ version: "0.2.5",
11922
11922
  mode: process.env.NODE_MODE ?? "standalone",
11923
11923
  cpu: {
11924
11924
  count: cpus2.length,
@@ -13451,7 +13451,7 @@ function createApp(store, manager, opts = {}) {
13451
13451
  json(res, 200, {
13452
13452
  status: "ok",
13453
13453
  // 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
13454
- version: "0.2.4",
13454
+ version: "0.2.5",
13455
13455
  features: { mcp: hasServerMcpConfig() }
13456
13456
  });
13457
13457
  return;
@@ -15115,7 +15115,7 @@ var FleetNodeBridge = class {
15115
15115
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15116
15116
  platform: process.platform,
15117
15117
  mode: process.env.NODE_MODE ?? "standalone",
15118
- version: "0.2.4",
15118
+ version: "0.2.5",
15119
15119
  ip: primaryIp()
15120
15120
  };
15121
15121
  }
@@ -15167,7 +15167,7 @@ var FleetNodeBridge = class {
15167
15167
  label: this.opts.deps.store.loadNodeLabel() ?? void 0,
15168
15168
  platform: process.platform,
15169
15169
  mode: process.env.NODE_MODE ?? "standalone",
15170
- version: "0.2.4",
15170
+ version: "0.2.5",
15171
15171
  ip: primaryIp(),
15172
15172
  projects,
15173
15173
  totals,
@@ -16886,7 +16886,7 @@ init_esm_shims();
16886
16886
  import * as path28 from "path";
16887
16887
  import { createRequire as createRequire3 } from "module";
16888
16888
  function currentVersion() {
16889
- const injected = "0.2.4"?.trim();
16889
+ const injected = "0.2.5"?.trim();
16890
16890
  if (injected) return injected;
16891
16891
  try {
16892
16892
  const req2 = createRequire3(import.meta.url);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zqagent/core",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "TypeScript agent engine core — TurnEngine, ToolRegistry, PermissionEngine, OpenAI provider with 18 built-in tools",
5
5
  "author": "成都志前科技有限公司",
6
6
  "type": "module",