@xgjktech/xg-openclaw-harness-tools 0.4.1 → 0.4.3

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,148 +1,171 @@
1
- # @xgjktech/xg-openclaw-harness-tools
2
-
3
- OpenClaw 第三方工具插件:企业计划工具 `xg_plan_write` / `xg_plan_view`。
4
-
5
- 用一份持久化的计划(SQLite 落盘)取代内置 `update_plan`(无状态、只回显、不落库),
6
- `xg_plan_write` 整张维护草稿计划,`xg_plan_view` 只读查看计划或最近摘要。
7
-
8
- ## 架构裁决:实时事件当前处于事实性休眠(务必先读)
9
-
10
- **当前 OpenClaw 2026.6.10 版本下,实时事件推送链路休眠**:工具 execute/factory 期没有
11
- 正当途径获取真实 runId(详见 `docs/notes-plugin-entry.md` N2),且 0.3.0 已移除工具侧
12
- `notify.ts`。`xg_plan_write` 落库后不发事件,`xg_plan_view` 全程只读。
13
-
14
- **因此 IM 侧(或任何下游消费方)不得依赖实时事件感知计划进度。** 当前唯一可靠的主感知路径是:
15
-
16
- 1. **SQLite 读取**——IM 用 `openPlanStoreReadonly(dbPath)` 按 origin 只读反查
17
- `<stateDir>/xgjktech/plans.sqlite` 并推送全量快照,这是权威状态源。
18
- 2. **agent 最终回复**——agent 完成任务后的文本回复本身会体现进度。
19
-
20
- 事件契约(`PlanEventPayload` / `isPlanEventPayload` / `planEventStream`)在 shared 中原样保留,
21
- 仅用于下游编译兼容。未来恢复实时事件需要重新实现工具侧生产与 IM 侧消费,并单独发布。
22
-
23
- ## 环境要求
24
-
25
- - **Node ≥ 22.19.0**(依赖 `node:sqlite`,与 OpenClaw 自身 `engines` 一致)。
26
- - monorepo 用 npm workspaces。
27
-
28
- ## 安装与构建
29
-
30
- 本仓库是包含 `@xgjktech/xg-openclaw-shared`(存储层+事件契约层)和
31
- `@xgjktech/xg-openclaw-harness-tools`(本插件)两个 workspace 的 monorepo。**`xg-shared` 必须先于
32
- 本插件构建**(本插件依赖它的编译产物);npm workspaces 拓扑已保证顺序,直接在仓库根执行:
33
-
34
- ```bash
35
- npm install
36
- npm run build
37
- ```
38
-
39
- 产物:`packages/xg-harness-tools/dist/`(含 `index.js` 与 `.d.ts`)。
40
-
41
- 将本插件安装到 OpenClaw 的具体命令/目录约定,请对照 OpenClaw 的第三方插件安装机制
42
- (global / workspace / config origin,本插件按非 bundled 第三方路径运行)以及
43
- `package.json` 里的 `openclaw.*` 字段块(`extensions`/`install.localPath` 等)。
44
- P1 阶段不锁死具体安装命令,避免与实际安装流程漂移(详见 `docs/05-部署文档.md` §3.3)。
45
-
46
- ## 配置
47
-
48
- ### 1. 屏蔽内置 update_plan(deny,唯一权威路径)
49
-
50
- ```jsonc
51
- {
52
- "tools": {
53
- "deny": ["update_plan"]
54
- }
55
- }
56
- ```
57
-
58
- 无论生产 profile / allowlist 取何值(包括 `allow:["*"]`),`deny` 都一票否决,
59
- 与 profile 取值解耦。
60
-
61
- ### 2. 启用本插件两个工具(allow)
62
-
63
- 本插件两个工具都以 `optional:true` 注册,**默认不启用**,必须 allowlist 显式命中才会注册:
64
-
65
- ```jsonc
66
- {
67
- "tools": {
68
- "allow": ["xg_plan_write", "xg_plan_view"],
69
- "deny": ["update_plan"]
70
- }
71
- }
72
- ```
73
-
74
- 可直接套用的完整样例见仓库根 [`deploy/tools.config.sample.jsonc`](../../deploy/tools.config.sample.jsonc)(带注释)。
75
-
76
- ### 3. stateDir 与数据库路径
77
-
78
- 插件运行时数据库路径固定为:
79
-
80
- ```
81
- <stateDir>/xgjktech/plans.sqlite
82
- ```
83
-
84
- `stateDir` 取自 OpenClaw 全局状态目录(`api.runtime.state.resolveStateDir()`,默认
85
- `~/.openclaw/`,`OPENCLAW_STATE_DIR` 覆盖时同步),插件首次运行时通过 `resolvePlanDbPath`
86
- 自动 `mkdir -p` 出 `xgjktech/` 子目录,无需手动创建。IM 插件若要接入同一份数据,应复用
87
- 同一个 `resolvePlanDbPath` 以保证路径约定一致。
88
-
89
- ## 两个工具说明
90
-
91
- ### `xg_plan_write`
92
-
93
- 整张创建或覆盖一份草稿计划(goal + tasks[])并写入 SQLite。更新时必须重交所有要保留的
94
- task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数据。
95
-
96
- ### `xg_plan_view`
97
-
98
- 只读查看计划,**不会执行任何任务**。带 planId 返回完整紧凑 view;不带 planId 返回最近 10 条
99
- 计划摘要,用于跨会话找回 planId。更新进度统一使用 `xg_plan_write` 整张重交。
100
-
101
- > 工具名用 `view` 而非 `execute` 是有意的:`plan_view`/`plan_write` 都只是台账,不执行、不调度、
102
- > 无后台运行。二者 description 均明确"保存/查看 ≠ 执行",且结果带 `reminder` 字段引导模型
103
- > 继续逐项实际执行任务——避免模型调用计划工具后误以为工作已在后台完成而停住。
104
-
105
- 两个工具的完整参数 schema 见 `src/plan-write-tool.ts` / `src/plan-view-tool.ts`
106
- 中的 `PLAN_WRITE_DESCRIPTION` / `PLAN_VIEW_DESCRIPTION`。
107
-
108
- ## 部署 checklist
109
-
110
- - [ ] Node 22.19.0
111
- - [ ] monorepo 构建成功(`xg-shared` 先于本插件构建,workspaces 拓扑自动保证)
112
- - [ ] 插件已安装且被 OpenClaw 识别为已加载的第三方插件(非 bundled)
113
- - [ ] `tools.deny` 含 `update_plan`
114
- - [ ] `tools.allow` `xg_plan_write` + `xg_plan_view`(或经 `group:plugins` / `*` 放行)
115
- - [ ] 实拉一个 agent,验证工具清单**有本插件两工具、无 update_plan**(步骤见下节)
116
- - [ ] `<stateDir>/xgjktech/` 可写,首次运行能生成 `plans.sqlite`
117
- - [ ] (互通)IM 侧已依赖 `@xgjktech/xg-openclaw-shared` 并按 `docs/04-互通设计.md` 接入只读反查
118
-
119
- ## 实机验证步骤(可复现)+ 当前实际执行情况说明
120
-
121
- **验收标准要求部署方按 checklist 实拉一个 agent,确认工具清单里有 `xg_plan_write`/
122
- `xg_plan_view`、没有 `update_plan`。以下是可复现的验证步骤:**
123
-
124
- 1. 按上文"配置"章节把 `tools.deny`/`tools.allow` 写入生产 agent/profile 配置。
125
- 2. 安装并加载本插件(确认加载日志/插件列表里出现 `xg-harness-tools`,origin 为第三方非 bundled)。
126
- 3. 拉起一个真实 agent 会话,触发一次会列出可用工具的动作(例如让 agent 描述自己有哪些工具,
127
- 或查看 gateway/日志里该次 attempt 实际注册的工具名列表)。
128
- 4. 核对该工具列表:应包含 `xg_plan_write` `xg_plan_view`,**不应包含** `update_plan`。
129
- 5. 调用一次 `xg_plan_write` 建一份最小计划,确认返回 `planId + view`;再用该 planId 调
130
- `xg_plan_view`,确认只读 view 一致。用 `openPlanStoreReadonly` 反查并核对落盘内容。
131
-
132
- **本项在本次交付中未在真实 OpenClaw gateway 环境实机执行**——本仓库当前开发环境没有可用的
133
- 真实 OpenClaw gateway/agent 运行环境,因此无法诚实地报告"已实拉 agent 验证通过"。以下是
134
- 已经做过、可以作为间接佐证的验证,但**明确说明这不等于实机验证**:
135
-
136
- - 当前 factory 集成测试用**手工构造的 mock `api`**捕获 2 个工具的注册工厂,并提供带
137
- `sessionKey`/`deliveryContext` `toolContext`:`xg_plan_write` 写入后通过只读存储反查
138
- `origin`,`xg_plan_view` 校验指定计划的 view 与最近计划列表。**这验证的是插件代码本身
139
- 可以被正确加载、注册并贯通当前契约**,但 mock `api` 不是真实 OpenClaw gateway 的
140
- `tools.allow`/`deny` 策略引擎,**不能**佐证"生产 deny/allow 配置生效后工具清单精确符合
141
- 预期"这一条——那一条必须在真实 gateway 环境按上面 5 步实测。
142
- - T6 阶段(`packages/xg-harness-tools/src/integration.test.ts`)用真实的 `SqlitePlanStore`
143
- (临时目录)+ 真实工具函数(`buildPlanWriteTool`/`buildPlanViewTool`)跑通了完整的
144
- 写入→整张重交→execute 只读查看→SQLite 只读反查链路,但同样不经过 OpenClaw 的工具
145
- allowlist/deny 策略引擎。
146
-
147
- **结论:部署方在生产环境落实上述配置后,必须按"实机验证步骤"重新执行一次实拉 agent 验证,
148
- 不能以本仓库现有的 mock/集成测试结果代替。**
1
+ # @xgjktech/xg-openclaw-harness-tools
2
+
3
+ OpenClaw 第三方工具插件:企业计划工具 `xg_plan_write` / `xg_plan_view`。
4
+
5
+ 用一份持久化的计划(SQLite 落盘)取代内置 `update_plan`(无状态、只回显、不落库),
6
+ `xg_plan_write` 整张维护草稿计划,`xg_plan_view` 只读查看计划或最近摘要。
7
+
8
+ ## 架构裁决:实时事件当前处于事实性休眠(务必先读)
9
+
10
+ **当前 OpenClaw 2026.6.10 版本下,实时事件推送链路休眠**:工具 execute/factory 期没有
11
+ 正当途径获取真实 runId(详见 `docs/notes-plugin-entry.md` N2),且 0.3.0 已移除工具侧
12
+ `notify.ts`。`xg_plan_write` 落库后不发事件,`xg_plan_view` 全程只读。
13
+
14
+ **因此 IM 侧(或任何下游消费方)不得依赖实时事件感知计划进度。** 当前唯一可靠的主感知路径是:
15
+
16
+ 1. **SQLite 读取**——IM 用 `openPlanStoreReadonly(dbPath)` 按 origin 只读反查
17
+ `<stateDir>/xgjktech/plans.sqlite` 并推送全量快照,这是权威状态源。
18
+ 2. **agent 最终回复**——agent 完成任务后的文本回复本身会体现进度。
19
+
20
+ 事件契约(`PlanEventPayload` / `isPlanEventPayload` / `planEventStream`)在 shared 中原样保留,
21
+ 仅用于下游编译兼容。未来恢复实时事件需要重新实现工具侧生产与 IM 侧消费,并单独发布。
22
+
23
+ ## 环境要求
24
+
25
+ - **Node ≥ 22.19.0**(依赖 `node:sqlite`,与 OpenClaw 自身 `engines` 一致)。
26
+ - monorepo 用 npm workspaces。
27
+
28
+ ## 安装与构建
29
+
30
+ 本仓库是包含 `@xgjktech/xg-openclaw-shared`(存储层+事件契约层)和
31
+ `@xgjktech/xg-openclaw-harness-tools`(本插件)两个 workspace 的 monorepo。**`xg-shared` 必须先于
32
+ 本插件构建**(本插件依赖它的编译产物);npm workspaces 拓扑已保证顺序,直接在仓库根执行:
33
+
34
+ ```bash
35
+ npm install
36
+ npm run build
37
+ ```
38
+
39
+ 产物:`packages/xg-harness-tools/dist/`(含 `index.js` 与 `.d.ts`)。
40
+
41
+ 将本插件安装到 OpenClaw 的具体命令/目录约定,请对照 OpenClaw 的第三方插件安装机制
42
+ (global / workspace / config origin,本插件按非 bundled 第三方路径运行)以及
43
+ `package.json` 里的 `openclaw.*` 字段块(`extensions`/`install.localPath` 等)。
44
+ P1 阶段不锁死具体安装命令,避免与实际安装流程漂移(详见 `docs/05-部署文档.md` §3.3)。
45
+
46
+ ## 配置
47
+
48
+ ### 1. 屏蔽内置 update_plan(deny,唯一权威路径)
49
+
50
+ ```jsonc
51
+ {
52
+ "tools": {
53
+ "deny": ["update_plan"]
54
+ }
55
+ }
56
+ ```
57
+
58
+ 无论生产 profile / allowlist 取何值(包括 `allow:["*"]`),`deny` 都一票否决,
59
+ 与 profile 取值解耦。
60
+
61
+ ### 2. 启用本插件两个工具(allow)
62
+
63
+ 本插件两个工具都以 `optional:true` 注册,**默认不启用**,必须 allowlist 显式命中才会注册:
64
+
65
+ ```jsonc
66
+ {
67
+ "tools": {
68
+ "allow": ["xg_plan_write", "xg_plan_view"],
69
+ "deny": ["update_plan"]
70
+ }
71
+ }
72
+ ```
73
+
74
+ 可直接套用的完整样例见仓库根 [`deploy/tools.config.sample.jsonc`](../../deploy/tools.config.sample.jsonc)(带注释)。
75
+
76
+ ### 3. stateDir 与数据库路径
77
+
78
+ 插件运行时数据库路径固定为:
79
+
80
+ ```
81
+ <stateDir>/xgjktech/plans.sqlite
82
+ ```
83
+
84
+ `stateDir` 取自 OpenClaw 全局状态目录(`api.runtime.state.resolveStateDir()`,默认
85
+ `~/.openclaw/`,`OPENCLAW_STATE_DIR` 覆盖时同步),插件首次运行时通过 `resolvePlanDbPath`
86
+ 自动 `mkdir -p` 出 `xgjktech/` 子目录,无需手动创建。IM 插件若要接入同一份数据,应复用
87
+ 同一个 `resolvePlanDbPath` 以保证路径约定一致。
88
+
89
+ ## 两个工具说明
90
+
91
+ ### `xg_plan_write`
92
+
93
+ 整张创建或覆盖一份草稿计划(goal + tasks[])并写入 SQLite。更新时必须重交所有要保留的
94
+ task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数据。
95
+
96
+ ### `xg_plan_view`
97
+
98
+ 只读查看计划,**不会执行任何任务**。带 planId 返回完整紧凑 view;不带 planId 返回最近 10 条
99
+ 计划摘要,用于跨会话找回 planId。更新进度统一使用 `xg_plan_write` 整张重交。
100
+
101
+ > 工具名用 `view` 而非 `execute` 是有意的:`plan_view`/`plan_write` 都只是台账,不执行、不调度、
102
+ > 无后台运行。二者 description 均明确"保存/查看 ≠ 执行",且结果带 `reminder` 字段引导模型
103
+ > 继续逐项实际执行任务——避免模型调用计划工具后误以为工作已在后台完成而停住。
104
+
105
+ 两个工具的完整参数 schema 见 `src/plan-write-tool.ts` / `src/plan-view-tool.ts`
106
+ 中的 `PLAN_WRITE_DESCRIPTION` / `PLAN_VIEW_DESCRIPTION`。
107
+
108
+ ## 主动计划提示词注入(before_prompt_build)
109
+
110
+ 插件在 `register` 时挂载 `before_prompt_build` hook,用 `appendSystemContext` 向每个 agent 的
111
+ system prompt 追加一段"主动工作计划"纪律(`src/plan-prompt.ts`):多步工作先建计划、逐项整张回写、
112
+ blocked note、台账≠执行。内容与工具 description 一致,仅抬升"主动触发"的优先级。
113
+
114
+ - **与其他注入不冲突**:IM 通道的 `GroupSystemPrompt` 落在 base system prompt,本段追加在其后,
115
+ 纯叠加不覆盖;对内置 runtime Codex runtime 均生效。
116
+ - **如需关闭**:在部署配置里对该插件入口设 `hooks.allowPromptInjection: false`(默认放行):
117
+
118
+ ```jsonc
119
+ {
120
+ "plugins": {
121
+ "entries": {
122
+ "xg-harness-tools": { "hooks": { "allowPromptInjection": false } }
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ - 若部署方同时手工把 `docs/09-plan-usage-guide.md` System Prompt 模版写进 AGENTS.md/频道
129
+ systemPrompt,会与本段叠加——冗余无害,可按需取舍。
130
+
131
+ ## 部署 checklist
132
+
133
+ - [ ] Node 22.19.0
134
+ - [ ] monorepo 构建成功(`xg-shared` 先于本插件构建,workspaces 拓扑自动保证)
135
+ - [ ] 插件已安装且被 OpenClaw 识别为已加载的第三方插件(非 bundled)
136
+ - [ ] `tools.deny` `update_plan`
137
+ - [ ] `tools.allow` `xg_plan_write` + `xg_plan_view`(或经 `group:plugins` / `*` 放行)
138
+ - [ ] 实拉一个 agent,验证工具清单**有本插件两工具、无 update_plan**(步骤见下节)
139
+ - [ ] `<stateDir>/xgjktech/` 可写,首次运行能生成 `plans.sqlite`
140
+ - [ ] (互通)IM 侧已依赖 `@xgjktech/xg-openclaw-shared` 并按 `docs/04-互通设计.md` 接入只读反查
141
+
142
+ ## 实机验证步骤(可复现)+ 当前实际执行情况说明
143
+
144
+ **验收标准要求部署方按 checklist 实拉一个 agent,确认工具清单里有 `xg_plan_write`/
145
+ `xg_plan_view`、没有 `update_plan`。以下是可复现的验证步骤:**
146
+
147
+ 1. 按上文"配置"章节把 `tools.deny`/`tools.allow` 写入生产 agent/profile 配置。
148
+ 2. 安装并加载本插件(确认加载日志/插件列表里出现 `xg-harness-tools`,origin 为第三方非 bundled)。
149
+ 3. 拉起一个真实 agent 会话,触发一次会列出可用工具的动作(例如让 agent 描述自己有哪些工具,
150
+ 或查看 gateway/日志里该次 attempt 实际注册的工具名列表)。
151
+ 4. 核对该工具列表:应包含 `xg_plan_write` 与 `xg_plan_view`,**不应包含** `update_plan`。
152
+ 5. 调用一次 `xg_plan_write` 建一份最小计划,确认返回 `planId + view`;再用该 planId 调
153
+ `xg_plan_view`,确认只读 view 一致。用 `openPlanStoreReadonly` 反查并核对落盘内容。
154
+
155
+ **本项在本次交付中未在真实 OpenClaw gateway 环境实机执行**——本仓库当前开发环境没有可用的
156
+ 真实 OpenClaw gateway/agent 运行环境,因此无法诚实地报告"已实拉 agent 验证通过"。以下是
157
+ 已经做过、可以作为间接佐证的验证,但**明确说明这不等于实机验证**:
158
+
159
+ - 当前 factory 集成测试用**手工构造的 mock `api`**捕获 2 个工具的注册工厂,并提供带
160
+ `sessionKey`/`deliveryContext` 的 `toolContext`:`xg_plan_write` 写入后通过只读存储反查
161
+ `origin`,`xg_plan_view` 校验指定计划的 view 与最近计划列表。**这验证的是插件代码本身
162
+ 可以被正确加载、注册并贯通当前契约**,但 mock `api` 不是真实 OpenClaw gateway 的
163
+ `tools.allow`/`deny` 策略引擎,**不能**佐证"生产 deny/allow 配置生效后工具清单精确符合
164
+ 预期"这一条——那一条必须在真实 gateway 环境按上面 5 步实测。
165
+ - T6 阶段(`packages/xg-harness-tools/src/integration.test.ts`)用真实的 `SqlitePlanStore`
166
+ (临时目录)+ 真实工具函数(`buildPlanWriteTool`/`buildPlanViewTool`)跑通了完整的
167
+ 写入→整张重交→execute 只读查看→SQLite 只读反查链路,但同样不经过 OpenClaw 的工具
168
+ allowlist/deny 策略引擎。
169
+
170
+ **结论:部署方在生产环境落实上述配置后,必须按"实机验证步骤"重新执行一次实拉 agent 验证,
171
+ 不能以本仓库现有的 mock/集成测试结果代替。**
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare const _default: import("openclaw/plugin-sdk/tool-plugin").DefinedToolPluginEntry;
2
- export default _default;
1
+ declare const pluginEntry: import("openclaw/plugin-sdk/tool-plugin").DefinedToolPluginEntry;
2
+ export default pluginEntry;
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAiBA,wBAqDG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,QAAA,MAAM,WAAW,kEAqDf,CAAC;AAUH,eAAe,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -4,8 +4,9 @@ import { PLAN_WRITE_DESCRIPTION, PlanWriteParams, buildPlanWriteTool } from "./p
4
4
  import { PLAN_VIEW_DESCRIPTION, PlanViewParams, buildPlanViewTool, } from "./plan-view-tool.js";
5
5
  import { ACTION_DISPATCH_DESCRIPTION, ActionDispatchParams, buildActionDispatchTool, } from "./action-dispatch-tool.js";
6
6
  import { toPlanOrigin } from "./plan-origin.js";
7
+ import { buildPlanPromptInjection } from "./plan-prompt.js";
7
8
  const PLUGIN_ID = "xg-harness-tools";
8
- export default defineToolPlugin({
9
+ const pluginEntry = defineToolPlugin({
9
10
  id: PLUGIN_ID,
10
11
  name: "XG Harness Tools",
11
12
  description: "企业工具插件:计划管理与通用动作分发(plan_write / plan_view / action_dispatch)",
@@ -54,3 +55,11 @@ export default defineToolPlugin({
54
55
  ];
55
56
  },
56
57
  });
58
+ // defineToolPlugin 只负责工具注册;主动建计划纪律以 before_prompt_build hook 追加到 system prompt。
59
+ // 就地覆写 register(保留 tool-plugin metadata),先走原工具注册,再挂 prompt 注入。
60
+ const baseRegister = pluginEntry.register;
61
+ pluginEntry.register = (api) => {
62
+ baseRegister(api);
63
+ api.on("before_prompt_build", buildPlanPromptInjection);
64
+ };
65
+ export default pluginEntry;
@@ -0,0 +1,13 @@
1
+ import type { PluginHookBeforePromptBuildResult } from "openclaw/plugin-sdk/types";
2
+ /**
3
+ * 追加到 agent system prompt 的"主动建计划"纪律(appendSystemContext)。
4
+ * 与 IM 通道的 GroupSystemPrompt 纯叠加不冲突:本段拼在 base systemPrompt 之后。
5
+ * 保持稳定文本,利于 provider 缓存。
6
+ */
7
+ export declare const PLAN_FIRST_SYSTEM_CONTEXT: string;
8
+ /**
9
+ * before_prompt_build 钩子处理器:向 agent system prompt 追加主动建计划纪律。
10
+ * 返回 void 语义由宿主管控,插件侧始终返回该静态段。
11
+ */
12
+ export declare function buildPlanPromptInjection(): PluginHookBeforePromptBuildResult;
13
+ //# sourceMappingURL=plan-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-prompt.d.ts","sourceRoot":"","sources":["../src/plan-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAEnF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAO1B,CAAC;AAEb;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,iCAAiC,CAE5E"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 追加到 agent system prompt 的"主动建计划"纪律(appendSystemContext)。
3
+ * 与 IM 通道的 GroupSystemPrompt 纯叠加不冲突:本段拼在 base systemPrompt 之后。
4
+ * 保持稳定文本,利于 provider 缓存。
5
+ */
6
+ export const PLAN_FIRST_SYSTEM_CONTEXT = [
7
+ "## 主动工作计划(xg-harness-tools)",
8
+ "- 开始执行任何多步骤工作之前,应主动调用 xg_plan_write 建立计划,不要等用户要求。",
9
+ "- 触发情形:目标需要两个或更多连续动作;预计跨多轮或中断后继续;需等待用户、审批或外部系统。",
10
+ "- 工作流:开工前建计划 → 每完成一项用 xg_plan_write 整张重交回写状态 → 全部完成提交最终版。",
11
+ "- 无法当场完成:标 in_progress 或 blocked(blocked 必须带 note 写明原因),后续回合继续。",
12
+ "- xg_plan_write / xg_plan_view 只是台账,不执行、不调度、无后台运行;保存/查看之后必须继续逐项实际执行任务。",
13
+ ].join("\n");
14
+ /**
15
+ * before_prompt_build 钩子处理器:向 agent system prompt 追加主动建计划纪律。
16
+ * 返回 void 语义由宿主管控,插件侧始终返回该静态段。
17
+ */
18
+ export function buildPlanPromptInjection() {
19
+ return { appendSystemContext: PLAN_FIRST_SYSTEM_CONTEXT };
20
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"plan-view-tool.d.ts","sourceRoot":"","sources":["../src/plan-view-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EAEf,MAAM,8BAA8B,CAAC;AAKtC,eAAO,MAAM,cAAc;;EAK1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,qBAAqB,QAQtB,CAAC;AAuBb,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,YAAY,CAmD/F"}
1
+ {"version":3,"file":"plan-view-tool.d.ts","sourceRoot":"","sources":["../src/plan-view-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EAEf,MAAM,8BAA8B,CAAC;AAKtC,eAAO,MAAM,cAAc;;EAK1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,eAAO,MAAM,qBAAqB,QAStB,CAAC;AAuBb,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,YAAY,CAmD/F"}
@@ -7,13 +7,14 @@ export const PlanViewParams = Type.Object({
7
7
  planId: Type.Optional(Type.String({ description: "要查看的计划 id;留空则列出最近计划" })),
8
8
  }, { additionalProperties: false });
9
9
  export const PLAN_VIEW_DESCRIPTION = [
10
- "用途:只读查看已保存的 todo 状态,用于前端 UI 展示、恢复工作上下文和汇报进度;不会执行任何任务,也不会修改计划。",
11
- "只能看到当前聊天范围(同一 channel/to)的 todo;在同一部署和 stateDir 下,即使重新创建 agent session,也可找回该范围内的 todo。",
10
+ "用途:只读查看已保存的计划;不会执行任何任务,也不会修改计划。",
11
+ "只能看到当前会话来源的计划。",
12
12
  "",
13
13
  "- 带 planId:返回该计划当前的完整清单。",
14
14
  "- 不带 planId:返回最近计划的摘要列表,用于忘记或跨会话找回 planId。",
15
15
  "",
16
- "重要:查看只恢复记录,不会自动推进状态。若当前请求需要继续这项工作,再按 todo 状态推进,并在状态变化后用 xg_plan_write 回写。",
16
+ "若当前要推进的工作还没有对应计划,应先调用 xg_plan_write 建立计划再开始执行。",
17
+ "重要:查看不等于执行。若计划存在未完成任务,你必须继续实际执行它们,完成一项后用 xg_plan_write 回写状态。",
17
18
  ].join("\n");
18
19
  function summarizePlan(plan) {
19
20
  const taskCounts = { total: 0, completed: 0, blocked: 0, inProgress: 0 };
@@ -66,7 +67,7 @@ export function buildPlanViewTool(deps) {
66
67
  planId: plan.planId,
67
68
  view: renderPlanView(plan),
68
69
  ...(reminder !== undefined
69
- ? { reminder: `该 todo 有未完成项;查看只恢复记录,不会自动推进状态。${reminder}` }
70
+ ? { reminder: `该计划有未完成任务,查看不等于执行。${reminder}` }
70
71
  : {}),
71
72
  };
72
73
  return toolJsonResult(result);
@@ -1,8 +1,8 @@
1
1
  import { type Plan } from "@xgjktech/xg-openclaw-shared";
2
2
  export declare function renderPlanView(plan: Plan): string;
3
3
  /**
4
- * 生成当前 todo 的状态提醒,帮助模型恢复工作上下文并及时回写状态。
5
- * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务)→ 只剩 blocked 时提示等待;
4
+ * 生成"下一步该做什么"的命令式提醒,喂给模型防止其只记录不执行。
5
+ * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务,并先标 in_progress)→ 只剩 blocked 时提示等待/取消;
6
6
  * 全部完成或已取消则返回 undefined。
7
7
  */
8
8
  export declare function buildPlanReminder(plan: Plan): string | undefined;
package/dist/plan-view.js CHANGED
@@ -28,8 +28,8 @@ export function renderPlanView(plan) {
28
28
  return lines.join("\n");
29
29
  }
30
30
  /**
31
- * 生成当前 todo 的状态提醒,帮助模型恢复工作上下文并及时回写状态。
32
- * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务)→ 只剩 blocked 时提示等待;
31
+ * 生成"下一步该做什么"的命令式提醒,喂给模型防止其只记录不执行。
32
+ * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务,并先标 in_progress)→ 只剩 blocked 时提示等待/取消;
33
33
  * 全部完成或已取消则返回 undefined。
34
34
  */
35
35
  export function buildPlanReminder(plan) {
@@ -40,15 +40,15 @@ export function buildPlanReminder(plan) {
40
40
  return undefined;
41
41
  const inProgress = unfinished.find((task) => task.status === "in_progress");
42
42
  if (inProgress !== undefined) {
43
- return `当前 todo:继续处理「${singleLine(inProgress.title)}」;状态变化后用 xg_plan_write 回写`;
43
+ return `下一步:继续执行「${singleLine(inProgress.title)}」,完成后用 xg_plan_write 回写状态`;
44
44
  }
45
45
  const pending = unfinished.find((task) => task.status === "pending");
46
46
  if (pending !== undefined) {
47
- return `当前 todo:待处理「${singleLine(pending.title)}」;开始后将状态更新为 in_progress`;
47
+ return `下一步:开始执行「${singleLine(pending.title)}」,并先把其状态更新为 in_progress`;
48
48
  }
49
49
  const blockedCount = unfinished.filter((task) => task.status === "blocked").length;
50
50
  if (blockedCount > 0) {
51
- return `当前 todo 有 ${blockedCount} 项 blocked,等待 note 中记录的条件满足后再推进`;
51
+ return `当前有 ${blockedCount} 项 blocked,等待 note 中记录的条件满足后再推进;若不再推进请取消计划`;
52
52
  }
53
53
  return undefined;
54
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plan-write-tool.d.ts","sourceRoot":"","sources":["../src/plan-write-tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EAGf,MAAM,8BAA8B,CAAC;AA8BtC,eAAO,MAAM,eAAe;;;;;;;;;EAwB3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,sBAAsB,QA2BvB,CAAC;AA0Eb,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,YAAY,CA0HtF"}
1
+ {"version":3,"file":"plan-write-tool.d.ts","sourceRoot":"","sources":["../src/plan-write-tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EAGf,MAAM,8BAA8B,CAAC;AA8BtC,eAAO,MAAM,eAAe;;;;;;;;;EAwB3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,sBAAsB,QA4BvB,CAAC;AA0Eb,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,YAAY,CA0HtF"}
@@ -33,25 +33,26 @@ export const PlanWriteParams = Type.Object({
33
33
  cancel: Type.Optional(Type.Boolean({ description: "取消该计划;true 时只需带 planId,不带 goal/tasks" })),
34
34
  }, { additionalProperties: false });
35
35
  export const PLAN_WRITE_DESCRIPTION = [
36
- "用途:维护模型当前工作的 todo 状态,供前端 UI 展示,并可在后续回合恢复。每次调用都是整张替换,不是增量更新。",
36
+ "用途:为用户可见、可跨回合保存的工作创建或更新任务清单。每次调用都是整张替换,不是增量更新。",
37
37
  "",
38
- "调用判断:收到执行型请求后,先在内部拆解工作项;满足以下任一条件,必须在开始实际工作前调用本工具,不需要等用户明确要求:",
39
- "- 用户明确要求计划、任务清单或进度追踪。",
40
- "- 需要等待用户回复、审批或外部系统。",
41
- "- 有 3 个或以上用户可感知、可独立汇报完成状态的工作项。",
42
- "- 同时包含调查、实施、验证等多个阶段。",
43
- "- 涉及多个组件且工作项之间存在依赖,或可能中断后继续。",
38
+ "【主动建计划:不要等用户要求】",
39
+ "识别到以下任一情形,都应主动调用本工具建立计划,而不是仅用文字回复或直接闷头推进:",
40
+ "- 目标需要两个或更多连续动作才能完成。",
41
+ "- 预计需要多轮推进,或可能中断后继续(跨回合/跨天)。",
42
+ "- 需要等待人的回复、审批或外部系统。",
43
+ "- 用户交代的是一个完整工作目标,而非单个简单问题。",
44
44
  "",
45
- "以下情况直接执行,不建计划:",
46
- "- 纯问答、查询、解释或闲聊,不涉及后续执行。",
47
- "- 只有 1-2 个原子动作,且无需等待、恢复或向用户展示进度。",
45
+ "工作流:开工前先建计划 → 每完成一项就整张重交更新状态 → 全部完成后提交最终版本。",
48
46
  "",
49
- "判断要求:不要以自己能否在当前回合完成作为判断依据;不要把分析、思考和试错过程写成 task,只记录需要向用户展示的工作项。",
47
+ "无需建计划的窄例外:",
48
+ "- 纯单轮问答、查询、解释概念,不产生需要跟踪的工作。",
49
+ "- 单个动作在当前回合即可直接完成。",
50
+ "- 不要把分析、思考和试错过程写成 task;只记录需要向用户展示的工作项。",
50
51
  "",
51
- "工作协议(必须遵守):",
52
- "- 本工具只记录 todo 状态并供 UI 展示:不执行、不调度、无后台运行。保存 todo ≠ 完成工作。",
53
- "- 写入后继续处理当前请求;任务开始、完成、暂停或阻塞时,用本工具回写最新整张清单。",
54
- "- 无法当场完成或需等待外部条件的项,标 in_progress(进行中)或 blocked(note 写明原因),后续回合恢复时再判断。",
52
+ "执行纪律(必须遵守):",
53
+ "- 本工具只把计划清单落库:不执行、不调度、无后台运行。保存计划 ≠ 完成工作。",
54
+ "- 保存后必须立即继续逐个实际执行 tasks:完成一项 → 回写其状态 → 继续下一项,直至全部 completed。",
55
+ "- 无法当场完成或需等待外部条件的项,标 in_progress(进行中)或 blocked(note 写明原因),后续回合继续。",
55
56
  "",
56
57
  "提交规则:",
57
58
  "- 新建时不传 planId;更新时传入原 planId。",
@@ -203,7 +204,7 @@ export function buildPlanWriteTool(store, origin) {
203
204
  view: renderPlanView(plan),
204
205
  ...(warnings !== undefined ? { warnings } : {}),
205
206
  ...(reminder !== undefined
206
- ? { reminder: `todo 已保存(仅记录,未执行)。${reminder}` }
207
+ ? { reminder: `计划已保存(仅记录,未执行)。${reminder}` }
207
208
  : {}),
208
209
  };
209
210
  return toolJsonResult(result);
@@ -1,14 +1,14 @@
1
- {
2
- "id": "xg-harness-tools",
3
- "name": "XG Harness Tools",
4
- "description": "企业工具插件:计划管理与通用动作分发(plan_write / plan_view / action_dispatch)",
5
- "version": "0.4.1",
6
- "configSchema": {
7
- "type": "object",
8
- "additionalProperties": true,
9
- "properties": {}
10
- },
11
- "contracts": {
12
- "tools": ["xg_plan_write", "xg_plan_view", "xg_action_dispatch"]
13
- }
14
- }
1
+ {
2
+ "id": "xg-harness-tools",
3
+ "name": "XG Harness Tools",
4
+ "description": "企业工具插件:计划管理与通用动作分发(plan_write / plan_view / action_dispatch)",
5
+ "version": "0.4.1",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": true,
9
+ "properties": {}
10
+ },
11
+ "contracts": {
12
+ "tools": ["xg_plan_write", "xg_plan_view", "xg_action_dispatch"]
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,57 +1,57 @@
1
- {
2
- "name": "@xgjktech/xg-openclaw-harness-tools",
3
- "version": "0.4.1",
4
- "description": "企业工具插件:plan_write / plan_view / action_dispatch(OpenClaw 第三方工具插件)",
5
- "license": "MIT",
6
- "type": "module",
7
- "engines": {
8
- "node": ">=22.19.0"
9
- },
10
- "main": "dist/index.js",
11
- "types": "dist/index.d.ts",
12
- "files": [
13
- "dist/**/*",
14
- "!dist/*.test.*",
15
- "openclaw.plugin.json"
16
- ],
17
- "publishConfig": {
18
- "access": "public",
19
- "registry": "https://registry.npmjs.org/"
20
- },
21
- "scripts": {
22
- "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
23
- "prebuild": "npm run clean",
24
- "build": "tsc -p tsconfig.json",
25
- "typecheck": "tsc -p tsconfig.json --noEmit",
26
- "pretest": "npm run build",
27
- "test": "node --test dist/*.test.js",
28
- "prepublishOnly": "npm run build && npm run test"
29
- },
30
- "dependencies": {
31
- "typebox": "1.1.39",
32
- "@xgjktech/xg-openclaw-shared": "^0.2.2"
33
- },
34
- "devDependencies": {
35
- "@types/node": "^22.19.0",
36
- "openclaw": "2026.6.10",
37
- "typescript": "^5.6.0"
38
- },
39
- "peerDependencies": {
40
- "openclaw": ">=2026.6.10"
41
- },
42
- "peerDependenciesMeta": {
43
- "openclaw": {
44
- "optional": true
45
- }
46
- },
47
- "openclaw": {
48
- "extensions": [
49
- "./dist/index.js"
50
- ],
51
- "installDependencies": false,
52
- "install": {
53
- "localPath": ".",
54
- "defaultChoice": "local"
55
- }
56
- }
57
- }
1
+ {
2
+ "name": "@xgjktech/xg-openclaw-harness-tools",
3
+ "version": "0.4.3",
4
+ "description": "企业工具插件:plan_write / plan_view / action_dispatch(OpenClaw 第三方工具插件)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=22.19.0"
9
+ },
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "files": [
13
+ "dist/**/*",
14
+ "!dist/*.test.*",
15
+ "openclaw.plugin.json"
16
+ ],
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "scripts": {
22
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
23
+ "prebuild": "npm run clean",
24
+ "build": "tsc -p tsconfig.json",
25
+ "typecheck": "tsc -p tsconfig.json --noEmit",
26
+ "pretest": "npm run build",
27
+ "test": "node --test dist/*.test.js",
28
+ "prepublishOnly": "npm run build && npm run test"
29
+ },
30
+ "dependencies": {
31
+ "typebox": "1.1.39",
32
+ "@xgjktech/xg-openclaw-shared": "^0.2.2"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.19.0",
36
+ "openclaw": "2026.6.10",
37
+ "typescript": "^5.6.0"
38
+ },
39
+ "peerDependencies": {
40
+ "openclaw": ">=2026.6.10"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "openclaw": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "openclaw": {
48
+ "extensions": [
49
+ "./dist/index.js"
50
+ ],
51
+ "installDependencies": false,
52
+ "install": {
53
+ "localPath": ".",
54
+ "defaultChoice": "local"
55
+ }
56
+ }
57
+ }