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

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,15 +1,15 @@
1
1
  # @xgjktech/xg-openclaw-harness-tools
2
2
 
3
- OpenClaw 第三方工具插件:企业计划工具 `xg_plan_write` / `xg_plan_execute`。
3
+ OpenClaw 第三方工具插件:企业计划工具 `xg_plan_write` / `xg_plan_view`。
4
4
 
5
5
  用一份持久化的计划(SQLite 落盘)取代内置 `update_plan`(无状态、只回显、不落库),
6
- `xg_plan_write` 整张维护草稿计划,`xg_plan_execute` 只读查看计划或最近摘要。
6
+ `xg_plan_write` 整张维护草稿计划,`xg_plan_view` 只读查看计划或最近摘要。
7
7
 
8
8
  ## 架构裁决:实时事件当前处于事实性休眠(务必先读)
9
9
 
10
10
  **当前 OpenClaw 2026.6.10 版本下,实时事件推送链路休眠**:工具 execute/factory 期没有
11
11
  正当途径获取真实 runId(详见 `docs/notes-plugin-entry.md` N2),且 0.3.0 已移除工具侧
12
- `notify.ts`。`xg_plan_write` 落库后不发事件,`xg_plan_execute` 全程只读。
12
+ `notify.ts`。`xg_plan_write` 落库后不发事件,`xg_plan_view` 全程只读。
13
13
 
14
14
  **因此 IM 侧(或任何下游消费方)不得依赖实时事件感知计划进度。** 当前唯一可靠的主感知路径是:
15
15
 
@@ -65,7 +65,7 @@ P1 阶段不锁死具体安装命令,避免与实际安装流程漂移(详
65
65
  ```jsonc
66
66
  {
67
67
  "tools": {
68
- "allow": ["xg_plan_write", "xg_plan_execute"],
68
+ "allow": ["xg_plan_write", "xg_plan_view"],
69
69
  "deny": ["update_plan"]
70
70
  }
71
71
  }
@@ -93,13 +93,17 @@ P1 阶段不锁死具体安装命令,避免与实际安装流程漂移(详
93
93
  整张创建或覆盖一份草稿计划(goal + tasks[])并写入 SQLite。更新时必须重交所有要保留的
94
94
  task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数据。
95
95
 
96
- ### `xg_plan_execute`
96
+ ### `xg_plan_view`
97
97
 
98
- 只读查看计划。带 planId 返回完整紧凑 view;不带 planId 返回最近 10 条计划摘要,用于跨会话
99
- 找回 planId。更新进度统一使用 `xg_plan_write` 整张重交。
98
+ 只读查看计划,**不会执行任何任务**。带 planId 返回完整紧凑 view;不带 planId 返回最近 10
99
+ 计划摘要,用于跨会话找回 planId。更新进度统一使用 `xg_plan_write` 整张重交。
100
100
 
101
- 两个工具的完整参数 schema `src/plan-write-tool.ts` / `src/plan-execute-tool.ts`
102
- 中的 `PLAN_WRITE_DESCRIPTION` / `PLAN_EXECUTE_DESCRIPTION`。
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`。
103
107
 
104
108
  ## 部署 checklist
105
109
 
@@ -107,7 +111,7 @@ task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数
107
111
  - [ ] monorepo 构建成功(`xg-shared` 先于本插件构建,workspaces 拓扑自动保证)
108
112
  - [ ] 插件已安装且被 OpenClaw 识别为已加载的第三方插件(非 bundled)
109
113
  - [ ] `tools.deny` 含 `update_plan`
110
- - [ ] `tools.allow` 含 `xg_plan_write` + `xg_plan_execute`(或经 `group:plugins` / `*` 放行)
114
+ - [ ] `tools.allow` 含 `xg_plan_write` + `xg_plan_view`(或经 `group:plugins` / `*` 放行)
111
115
  - [ ] 实拉一个 agent,验证工具清单**有本插件两工具、无 update_plan**(步骤见下节)
112
116
  - [ ] `<stateDir>/xgjktech/` 可写,首次运行能生成 `plans.sqlite`
113
117
  - [ ] (互通)IM 侧已依赖 `@xgjktech/xg-openclaw-shared` 并按 `docs/04-互通设计.md` 接入只读反查
@@ -115,15 +119,15 @@ task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数
115
119
  ## 实机验证步骤(可复现)+ 当前实际执行情况说明
116
120
 
117
121
  **验收标准要求部署方按 checklist 实拉一个 agent,确认工具清单里有 `xg_plan_write`/
118
- `xg_plan_execute`、没有 `update_plan`。以下是可复现的验证步骤:**
122
+ `xg_plan_view`、没有 `update_plan`。以下是可复现的验证步骤:**
119
123
 
120
124
  1. 按上文"配置"章节把 `tools.deny`/`tools.allow` 写入生产 agent/profile 配置。
121
125
  2. 安装并加载本插件(确认加载日志/插件列表里出现 `xg-harness-tools`,origin 为第三方非 bundled)。
122
126
  3. 拉起一个真实 agent 会话,触发一次会列出可用工具的动作(例如让 agent 描述自己有哪些工具,
123
127
  或查看 gateway/日志里该次 attempt 实际注册的工具名列表)。
124
- 4. 核对该工具列表:应包含 `xg_plan_write` 与 `xg_plan_execute`,**不应包含** `update_plan`。
128
+ 4. 核对该工具列表:应包含 `xg_plan_write` 与 `xg_plan_view`,**不应包含** `update_plan`。
125
129
  5. 调用一次 `xg_plan_write` 建一份最小计划,确认返回 `planId + view`;再用该 planId 调
126
- `xg_plan_execute`,确认只读 view 一致。用 `openPlanStoreReadonly` 反查并核对落盘内容。
130
+ `xg_plan_view`,确认只读 view 一致。用 `openPlanStoreReadonly` 反查并核对落盘内容。
127
131
 
128
132
  **本项在本次交付中未在真实 OpenClaw gateway 环境实机执行**——本仓库当前开发环境没有可用的
129
133
  真实 OpenClaw gateway/agent 运行环境,因此无法诚实地报告"已实拉 agent 验证通过"。以下是
@@ -131,12 +135,12 @@ task;写入 schema 不接受 steps,但读取旧计划仍兼容旧 steps 数
131
135
 
132
136
  - 当前 factory 集成测试用**手工构造的 mock `api`**捕获 2 个工具的注册工厂,并提供带
133
137
  `sessionKey`/`deliveryContext` 的 `toolContext`:`xg_plan_write` 写入后通过只读存储反查
134
- `origin`,`xg_plan_execute` 校验指定计划的 view 与最近计划列表。**这验证的是插件代码本身
138
+ `origin`,`xg_plan_view` 校验指定计划的 view 与最近计划列表。**这验证的是插件代码本身
135
139
  可以被正确加载、注册并贯通当前契约**,但 mock `api` 不是真实 OpenClaw gateway 的
136
140
  `tools.allow`/`deny` 策略引擎,**不能**佐证"生产 deny/allow 配置生效后工具清单精确符合
137
141
  预期"这一条——那一条必须在真实 gateway 环境按上面 5 步实测。
138
142
  - T6 阶段(`packages/xg-harness-tools/src/integration.test.ts`)用真实的 `SqlitePlanStore`
139
- (临时目录)+ 真实工具函数(`buildPlanWriteTool`/`buildPlanExecuteTool`)跑通了完整的
143
+ (临时目录)+ 真实工具函数(`buildPlanWriteTool`/`buildPlanViewTool`)跑通了完整的
140
144
  写入→整张重交→execute 只读查看→SQLite 只读反查链路,但同样不经过 OpenClaw 的工具
141
145
  allowlist/deny 策略引擎。
142
146
 
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin";
2
2
  import { resolvePlanDbPath, SqlitePlanStore, SqliteActionStore } from "@xgjktech/xg-openclaw-shared";
3
3
  import { PLAN_WRITE_DESCRIPTION, PlanWriteParams, buildPlanWriteTool } from "./plan-write-tool.js";
4
- import { PLAN_EXECUTE_DESCRIPTION, PlanExecuteParams, buildPlanExecuteTool, } from "./plan-execute-tool.js";
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
7
  const PLUGIN_ID = "xg-harness-tools";
8
8
  export default defineToolPlugin({
9
9
  id: PLUGIN_ID,
10
10
  name: "XG Harness Tools",
11
- description: "企业工具插件:计划管理与通用动作分发(plan_write / plan_execute / action_dispatch)",
11
+ description: "企业工具插件:计划管理与通用动作分发(plan_write / plan_view / action_dispatch)",
12
12
  tools: (tool) => {
13
13
  let planStore;
14
14
  let actionStore;
@@ -36,12 +36,12 @@ export default defineToolPlugin({
36
36
  factory: ({ api, toolContext }) => buildPlanWriteTool(getPlanStore(api), toPlanOrigin(toolContext)),
37
37
  }),
38
38
  tool({
39
- name: "xg_plan_execute",
39
+ name: "xg_plan_view",
40
40
  label: "【xg-harness】查看计划",
41
- description: PLAN_EXECUTE_DESCRIPTION,
42
- parameters: PlanExecuteParams,
41
+ description: PLAN_VIEW_DESCRIPTION,
42
+ parameters: PlanViewParams,
43
43
  optional: true,
44
- factory: ({ api, toolContext }) => buildPlanExecuteTool({ store: getPlanStore(api), origin: toPlanOrigin(toolContext) }),
44
+ factory: ({ api, toolContext }) => buildPlanViewTool({ store: getPlanStore(api), origin: toPlanOrigin(toolContext) }),
45
45
  }),
46
46
  tool({
47
47
  name: "xg_action_dispatch",
@@ -1,13 +1,13 @@
1
1
  import { Type, type Static } from "typebox";
2
2
  import type { AnyAgentTool } from "openclaw/plugin-sdk/plugin-entry";
3
3
  import { type PlanOrigin, type PlanStore } from "@xgjktech/xg-openclaw-shared";
4
- export declare const PlanExecuteParams: Type.TObject<{
4
+ export declare const PlanViewParams: Type.TObject<{
5
5
  planId: Type.TOptional<Type.TString>;
6
6
  }>;
7
- export type PlanExecuteParamsT = Static<typeof PlanExecuteParams>;
8
- export declare const PLAN_EXECUTE_DESCRIPTION: string;
9
- export declare function buildPlanExecuteTool(deps: {
7
+ export type PlanViewParamsT = Static<typeof PlanViewParams>;
8
+ export declare const PLAN_VIEW_DESCRIPTION: string;
9
+ export declare function buildPlanViewTool(deps: {
10
10
  store: PlanStore;
11
11
  origin?: PlanOrigin;
12
12
  }): AnyAgentTool;
13
- //# sourceMappingURL=plan-execute-tool.d.ts.map
13
+ //# sourceMappingURL=plan-view-tool.d.ts.map
@@ -0,0 +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,19 +1,19 @@
1
1
  import { Type } from "typebox";
2
2
  import { isPlanCancelled, } from "@xgjktech/xg-openclaw-shared";
3
- import { renderPlanView } from "./plan-view.js";
3
+ import { buildPlanReminder, renderPlanView } from "./plan-view.js";
4
4
  import { planInScope, scopeKey } from "./plan-scope.js";
5
5
  import { toolJsonResult } from "./tool-json-result.js";
6
- export const PlanExecuteParams = Type.Object({
6
+ export const PlanViewParams = Type.Object({
7
7
  planId: Type.Optional(Type.String({ description: "要查看的计划 id;留空则列出最近计划" })),
8
8
  }, { additionalProperties: false });
9
- export const PLAN_EXECUTE_DESCRIPTION = [
10
- "用途:只读查看已保存的计划;不执行任务,也不修改计划。",
11
- "只能看到当前会话来源的计划。",
9
+ export const PLAN_VIEW_DESCRIPTION = [
10
+ "用途:只读查看已保存的 todo 状态,用于前端 UI 展示、恢复工作上下文和汇报进度;不会执行任何任务,也不会修改计划。",
11
+ "只能看到当前聊天范围(同一 channel/to)的 todo;在同一部署和 stateDir 下,即使重新创建 agent session,也可找回该范围内的 todo。",
12
12
  "",
13
13
  "- 带 planId:返回该计划当前的完整清单。",
14
14
  "- 不带 planId:返回最近计划的摘要列表,用于忘记或跨会话找回 planId。",
15
15
  "",
16
- "需要更新进度时,用 xg_plan_write 重新提交整张计划。",
16
+ "重要:查看只恢复记录,不会自动推进状态。若当前请求需要继续这项工作,再按 todo 状态推进,并在状态变化后用 xg_plan_write 回写。",
17
17
  ].join("\n");
18
18
  function summarizePlan(plan) {
19
19
  const taskCounts = { total: 0, completed: 0, blocked: 0, inProgress: 0 };
@@ -33,14 +33,14 @@ function summarizePlan(plan) {
33
33
  taskCounts,
34
34
  };
35
35
  }
36
- export function buildPlanExecuteTool(deps) {
36
+ export function buildPlanViewTool(deps) {
37
37
  const { store, origin } = deps;
38
38
  const scope = scopeKey(origin);
39
39
  return {
40
- name: "xg_plan_execute",
40
+ name: "xg_plan_view",
41
41
  label: "【xg-harness】查看计划",
42
- description: PLAN_EXECUTE_DESCRIPTION,
43
- parameters: PlanExecuteParams,
42
+ description: PLAN_VIEW_DESCRIPTION,
43
+ parameters: PlanViewParams,
44
44
  async execute(_toolCallId, rawParams) {
45
45
  const params = rawParams;
46
46
  try {
@@ -60,10 +60,14 @@ export function buildPlanExecuteTool(deps) {
60
60
  const result = { ok: false, error: { code: "PLAN_NOT_FOUND" } };
61
61
  return toolJsonResult(result);
62
62
  }
63
+ const reminder = buildPlanReminder(plan);
63
64
  const result = {
64
65
  ok: true,
65
66
  planId: plan.planId,
66
67
  view: renderPlanView(plan),
68
+ ...(reminder !== undefined
69
+ ? { reminder: `该 todo 有未完成项;查看只恢复记录,不会自动推进状态。${reminder}` }
70
+ : {}),
67
71
  };
68
72
  return toolJsonResult(result);
69
73
  }
@@ -1,3 +1,9 @@
1
1
  import { type Plan } from "@xgjktech/xg-openclaw-shared";
2
2
  export declare function renderPlanView(plan: Plan): string;
3
+ /**
4
+ * 生成当前 todo 的状态提醒,帮助模型恢复工作上下文并及时回写状态。
5
+ * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务)→ 只剩 blocked 时提示等待;
6
+ * 全部完成或已取消则返回 undefined。
7
+ */
8
+ export declare function buildPlanReminder(plan: Plan): string | undefined;
3
9
  //# sourceMappingURL=plan-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plan-view.d.ts","sourceRoot":"","sources":["../src/plan-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAGV,MAAM,8BAA8B,CAAC;AAoBtC,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAgBjD"}
1
+ {"version":3,"file":"plan-view.d.ts","sourceRoot":"","sources":["../src/plan-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,IAAI,EAGV,MAAM,8BAA8B,CAAC;AAqBtC,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAgBjD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAsBhE"}
package/dist/plan-view.js CHANGED
@@ -1,14 +1,15 @@
1
1
  import { isPlanCancelled, } from "@xgjktech/xg-openclaw-shared";
2
+ // 状态标记直接用枚举原文,模型可零歧义对账(写读一致),不用符号猜测。
2
3
  const TASK_STATUS_MARKERS = {
3
- pending: "[ ]",
4
- in_progress: "[>]",
5
- completed: "[x]",
6
- blocked: "[!]",
4
+ pending: "[pending]",
5
+ in_progress: "[in_progress]",
6
+ completed: "[completed]",
7
+ blocked: "[blocked]",
7
8
  };
8
9
  const STEP_STATUS_MARKERS = {
9
- pending: "[ ]",
10
- in_progress: "[>]",
11
- completed: "[x]",
10
+ pending: "[pending]",
11
+ in_progress: "[in_progress]",
12
+ completed: "[completed]",
12
13
  };
13
14
  /** view 依赖"一行一项"的格式约定;字段内容里的换行统一压成空格,防止伪造出多余的行。 */
14
15
  function singleLine(text) {
@@ -26,3 +27,28 @@ export function renderPlanView(plan) {
26
27
  });
27
28
  return lines.join("\n");
28
29
  }
30
+ /**
31
+ * 生成当前 todo 的状态提醒,帮助模型恢复工作上下文并及时回写状态。
32
+ * 规则:优先 in_progress(继续手头任务)→ 其次 pending(开新任务)→ 只剩 blocked 时提示等待;
33
+ * 全部完成或已取消则返回 undefined。
34
+ */
35
+ export function buildPlanReminder(plan) {
36
+ if (isPlanCancelled(plan))
37
+ return undefined;
38
+ const unfinished = plan.tasks.filter((task) => task.status !== "completed");
39
+ if (unfinished.length === 0)
40
+ return undefined;
41
+ const inProgress = unfinished.find((task) => task.status === "in_progress");
42
+ if (inProgress !== undefined) {
43
+ return `当前 todo:继续处理「${singleLine(inProgress.title)}」;状态变化后用 xg_plan_write 回写`;
44
+ }
45
+ const pending = unfinished.find((task) => task.status === "pending");
46
+ if (pending !== undefined) {
47
+ return `当前 todo:待处理「${singleLine(pending.title)}」;开始后将状态更新为 in_progress`;
48
+ }
49
+ const blockedCount = unfinished.filter((task) => task.status === "blocked").length;
50
+ if (blockedCount > 0) {
51
+ return `当前 todo 有 ${blockedCount} 项 blocked,等待 note 中记录的条件满足后再推进`;
52
+ }
53
+ return undefined;
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,QAmBvB,CAAC;AA0Eb,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,YAAY,CAsHtF"}
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"}
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { Type } from "typebox";
3
3
  import { assertPlanInvariants, isPlanCancelled, } from "@xgjktech/xg-openclaw-shared";
4
4
  import { toolJsonResult } from "./tool-json-result.js";
5
- import { renderPlanView } from "./plan-view.js";
5
+ import { buildPlanReminder, renderPlanView } from "./plan-view.js";
6
6
  import { planInScope, scopeKey } from "./plan-scope.js";
7
7
  const TaskInput = Type.Object({
8
8
  title: Type.String({
@@ -33,21 +33,29 @@ 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
- "用途:维护一份对用户可见、可跨回合保存的任务清单。每次调用都是整张替换,不是增量更新。",
36
+ "用途:维护模型当前工作的 todo 状态,供前端 UI 展示,并可在后续回合恢复。每次调用都是整张替换,不是增量更新。",
37
37
  "",
38
- "何时不用(除非用户明确要求追踪):",
39
- "- 纯问答、查询、解释或闲聊。",
40
- "- 一两个动作即可完成,或预计当前回合可以直接做完。",
41
- "- 不要把分析、思考和试错过程写成 task;只记录需要向用户展示的工作项。",
38
+ "调用判断:收到执行型请求后,先在内部拆解工作项;满足以下任一条件,必须在开始实际工作前调用本工具,不需要等用户明确要求:",
39
+ "- 用户明确要求计划、任务清单或进度追踪。",
40
+ "- 需要等待用户回复、审批或外部系统。",
41
+ "- 3 个或以上用户可感知、可独立汇报完成状态的工作项。",
42
+ "- 同时包含调查、实施、验证等多个阶段。",
43
+ "- 涉及多个组件且工作项之间存在依赖,或可能中断后继续。",
42
44
  "",
43
- "何时用:",
44
- "- 工作有 3 个以上可独立完成的任务,且预计需要多轮推进或中断后继续。",
45
- "- 需要等待人的回复、审批或外部系统,即使任务较少。",
46
- "- 用户明确要求任务清单或进度追踪。",
45
+ "以下情况直接执行,不建计划:",
46
+ "- 纯问答、查询、解释或闲聊,不涉及后续执行。",
47
+ "- 只有 1-2 个原子动作,且无需等待、恢复或向用户展示进度。",
48
+ "",
49
+ "判断要求:不要以自己能否在当前回合完成作为判断依据;不要把分析、思考和试错过程写成 task,只记录需要向用户展示的工作项。",
50
+ "",
51
+ "工作协议(必须遵守):",
52
+ "- 本工具只记录 todo 状态并供 UI 展示:不执行、不调度、无后台运行。保存 todo ≠ 完成工作。",
53
+ "- 写入后继续处理当前请求;任务开始、完成、暂停或阻塞时,用本工具回写最新整张清单。",
54
+ "- 无法当场完成或需等待外部条件的项,标 in_progress(进行中)或 blocked(note 写明原因),后续回合恢复时再判断。",
47
55
  "",
48
56
  "提交规则:",
49
57
  "- 新建时不传 planId;更新时传入原 planId。",
50
- "- 更新计划内容时必须重新提交 goal 和所有要保留的 tasks,包括未变化任务及其当前 status/note。只提交变化项会删除其他任务;记不清时先用 xg_plan_execute 查看。",
58
+ "- 更新计划内容时必须重新提交 goal 和所有要保留的 tasks,包括未变化任务及其当前 status/note。只提交变化项会删除其他任务;记不清时先用 xg_plan_view 查看。",
51
59
  "- goal 用一句话;tasks 通常 3-7 项,每项是能判断是否完成的具体动作,不写 TODO、待定或内部思考。",
52
60
  "- status 为 pending、in_progress、completed 或 blocked。通常只有一项 in_progress,确实并行时可以有多项;blocked 时必须用 note 写明原因和继续所需条件。",
53
61
  "- 同一件工作只维护一份计划;任务方向变化时,先取消不再推进的旧计划({planId, cancel:true})再新建。",
@@ -188,11 +196,15 @@ export function buildPlanWriteTool(store, origin) {
188
196
  const plan = buildPlan(params.goal, params.tasks, existing, planId, origin, new Date().toISOString());
189
197
  assertPlanInvariants(plan);
190
198
  store.set(plan);
199
+ const reminder = buildPlanReminder(plan);
191
200
  const result = {
192
201
  ok: true,
193
202
  planId: plan.planId,
194
203
  view: renderPlanView(plan),
195
204
  ...(warnings !== undefined ? { warnings } : {}),
205
+ ...(reminder !== undefined
206
+ ? { reminder: `todo 已保存(仅记录,未执行)。${reminder}` }
207
+ : {}),
196
208
  };
197
209
  return toolJsonResult(result);
198
210
  }
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "id": "xg-harness-tools",
3
3
  "name": "XG Harness Tools",
4
- "description": "企业工具插件:计划管理与通用动作分发(plan_write / plan_execute / action_dispatch)",
5
- "version": "0.1.0",
4
+ "description": "企业工具插件:计划管理与通用动作分发(plan_write / plan_view / action_dispatch)",
5
+ "version": "0.4.1",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": true,
9
9
  "properties": {}
10
10
  },
11
11
  "contracts": {
12
- "tools": ["xg_plan_write", "xg_plan_execute", "xg_action_dispatch"]
12
+ "tools": ["xg_plan_write", "xg_plan_view", "xg_action_dispatch"]
13
13
  }
14
14
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xgjktech/xg-openclaw-harness-tools",
3
- "version": "0.3.5",
4
- "description": "企业工具插件:plan_write / plan_execute / action_dispatch(OpenClaw 第三方工具插件)",
3
+ "version": "0.4.1",
4
+ "description": "企业工具插件:plan_write / plan_view / action_dispatch(OpenClaw 第三方工具插件)",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "engines": {
@@ -19,6 +19,8 @@
19
19
  "registry": "https://registry.npmjs.org/"
20
20
  },
21
21
  "scripts": {
22
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
23
+ "prebuild": "npm run clean",
22
24
  "build": "tsc -p tsconfig.json",
23
25
  "typecheck": "tsc -p tsconfig.json --noEmit",
24
26
  "pretest": "npm run build",
@@ -52,4 +54,4 @@
52
54
  "defaultChoice": "local"
53
55
  }
54
56
  }
55
- }
57
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"plan-execute-tool.d.ts","sourceRoot":"","sources":["../src/plan-execute-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,iBAAiB;;EAK7B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,eAAO,MAAM,wBAAwB,QAQzB,CAAC;AAuBb,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,YAAY,CA+ClG"}