@konglx/rotom 2.21.0

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.
Files changed (189) hide show
  1. package/README.md +417 -0
  2. package/bin/mesh-master.sh +439 -0
  3. package/bin/rotom +29 -0
  4. package/bin/rotom-link.sh +136 -0
  5. package/bin/rotom-send-with-status +57 -0
  6. package/bin/rotom-up.sh +428 -0
  7. package/dist/cli/ask.js +62 -0
  8. package/dist/cli/common.js +321 -0
  9. package/dist/cli/config.js +65 -0
  10. package/dist/cli/directory.js +17 -0
  11. package/dist/cli/executor.js +58 -0
  12. package/dist/cli/fed.js +91 -0
  13. package/dist/cli/group.js +273 -0
  14. package/dist/cli/identity.js +62 -0
  15. package/dist/cli/init.js +268 -0
  16. package/dist/cli/issue.js +202 -0
  17. package/dist/cli/join.js +170 -0
  18. package/dist/cli/link.js +47 -0
  19. package/dist/cli/master.js +51 -0
  20. package/dist/cli/memory.js +307 -0
  21. package/dist/cli/note.js +68 -0
  22. package/dist/cli/repo.js +77 -0
  23. package/dist/cli/rotom.js +277 -0
  24. package/dist/cli/routes.js +118 -0
  25. package/dist/cli/run.js +45 -0
  26. package/dist/cli/schedule.js +237 -0
  27. package/dist/cli/skill.js +173 -0
  28. package/dist/cli/team.js +106 -0
  29. package/dist/executor/claude-code-hook.cjs +80 -0
  30. package/dist/executor/cli-executor.js +8 -0
  31. package/dist/executor/executors/claude-code.js +780 -0
  32. package/dist/executor/executors/codex.js +719 -0
  33. package/dist/executor/executors/hermes-cli.js +855 -0
  34. package/dist/executor/executors/openclaw.js +467 -0
  35. package/dist/executor/executors/pi.js +514 -0
  36. package/dist/executor/index.js +269 -0
  37. package/dist/executor/jsonrpc-transport.js +125 -0
  38. package/dist/executor/process-runner.js +101 -0
  39. package/dist/executor/reasoning-status.js +83 -0
  40. package/dist/executor/repo-cache.js +502 -0
  41. package/dist/executor/session-store.js +188 -0
  42. package/dist/executor/worker-chat.js +257 -0
  43. package/dist/executor/worker-connection.js +89 -0
  44. package/dist/executor/worker-issue.js +264 -0
  45. package/dist/executor/worker.js +877 -0
  46. package/dist/link/pending-requests.js +72 -0
  47. package/dist/link/server.js +233 -0
  48. package/dist/link/visibility-store.js +58 -0
  49. package/dist/master/api/agents.js +333 -0
  50. package/dist/master/api/artifacts.js +271 -0
  51. package/dist/master/api/domains.js +64 -0
  52. package/dist/master/api/groups.js +635 -0
  53. package/dist/master/api/guidance-templates.js +147 -0
  54. package/dist/master/api/index.js +89 -0
  55. package/dist/master/api/issues-patrol.js +172 -0
  56. package/dist/master/api/issues.js +663 -0
  57. package/dist/master/api/links-patrol.js +168 -0
  58. package/dist/master/api/links.js +114 -0
  59. package/dist/master/api/memory.js +259 -0
  60. package/dist/master/api/messages.js +157 -0
  61. package/dist/master/api/notes.js +77 -0
  62. package/dist/master/api/schedule-patterns.js +133 -0
  63. package/dist/master/api/schedules.js +272 -0
  64. package/dist/master/api/sessions.js +158 -0
  65. package/dist/master/api/share.js +269 -0
  66. package/dist/master/api/skills.js +190 -0
  67. package/dist/master/api/teams.js +122 -0
  68. package/dist/master/api/uploads.js +245 -0
  69. package/dist/master/auth.js +134 -0
  70. package/dist/master/dashboard/animations/calico-dozing.apng +0 -0
  71. package/dist/master/dashboard/animations/calico-error.apng +0 -0
  72. package/dist/master/dashboard/animations/calico-happy.apng +0 -0
  73. package/dist/master/dashboard/animations/calico-notification.apng +0 -0
  74. package/dist/master/dashboard/animations/calico-sleeping.apng +0 -0
  75. package/dist/master/dashboard/animations/calico-thinking.apng +0 -0
  76. package/dist/master/dashboard/animations/calico-waking.apng +0 -0
  77. package/dist/master/dashboard/assets/ApprovalCard-C38VV6ko.css +1 -0
  78. package/dist/master/dashboard/assets/ApprovalCard-CHPh2dmE.js +17 -0
  79. package/dist/master/dashboard/assets/ArtifactPanel-P_2gAP7v.js +1 -0
  80. package/dist/master/dashboard/assets/ArtifactPanel-aGHySny5.css +1 -0
  81. package/dist/master/dashboard/assets/css.worker-DaIe3gwK.js +84 -0
  82. package/dist/master/dashboard/assets/editor.worker-BCzxt1at.js +12 -0
  83. package/dist/master/dashboard/assets/html.worker-CKrFyw_2.js +461 -0
  84. package/dist/master/dashboard/assets/index-CChrTn81.css +32 -0
  85. package/dist/master/dashboard/assets/index-Dhu4SN1z.js +181 -0
  86. package/dist/master/dashboard/assets/json.worker-B7c_PmGb.js +49 -0
  87. package/dist/master/dashboard/assets/markdown-CeN5IgdF.js +29 -0
  88. package/dist/master/dashboard/assets/monaco-core-DyX1CsEw.css +1 -0
  89. package/dist/master/dashboard/assets/monaco-core-oQiQUisy.js +833 -0
  90. package/dist/master/dashboard/assets/monaco-setup-CiOPQdmo.js +1 -0
  91. package/dist/master/dashboard/assets/react-vendor-C8IxlyCR.js +67 -0
  92. package/dist/master/dashboard/assets/ts.worker-BhkL8olL.js +51334 -0
  93. package/dist/master/dashboard/assets/useMonaco-ILb4vyPh.js +12 -0
  94. package/dist/master/dashboard/assets/vite-preload-CxJPbCTl.js +1 -0
  95. package/dist/master/dashboard/debug-auth.html +197 -0
  96. package/dist/master/dashboard/favicon.ico +0 -0
  97. package/dist/master/dashboard/index.html +20 -0
  98. package/dist/master/dashboard/rotom-avatar.png +0 -0
  99. package/dist/master/db/agent-sessions.js +60 -0
  100. package/dist/master/db/agent-visibility.js +64 -0
  101. package/dist/master/db/agents.js +119 -0
  102. package/dist/master/db/ask-bridges.js +157 -0
  103. package/dist/master/db/build-update.js +59 -0
  104. package/dist/master/db/core.js +82 -0
  105. package/dist/master/db/domains.js +80 -0
  106. package/dist/master/db/groups.js +316 -0
  107. package/dist/master/db/guidance-templates.js +58 -0
  108. package/dist/master/db/index.js +12 -0
  109. package/dist/master/db/internal.js +45 -0
  110. package/dist/master/db/issues-patrol.js +81 -0
  111. package/dist/master/db/issues.js +373 -0
  112. package/dist/master/db/links.js +221 -0
  113. package/dist/master/db/master-node.js +43 -0
  114. package/dist/master/db/memory.js +272 -0
  115. package/dist/master/db/messages.js +210 -0
  116. package/dist/master/db/notes.js +55 -0
  117. package/dist/master/db/schedule-patterns.js +56 -0
  118. package/dist/master/db/schedules.js +135 -0
  119. package/dist/master/db/skills.js +144 -0
  120. package/dist/master/db/team.js +88 -0
  121. package/dist/master/db/types.js +10 -0
  122. package/dist/master/db.js +12 -0
  123. package/dist/master/embedded.js +133 -0
  124. package/dist/master/federation/client.js +283 -0
  125. package/dist/master/federation/identity.js +133 -0
  126. package/dist/master/federation/manager.js +267 -0
  127. package/dist/master/federation/publisher.js +87 -0
  128. package/dist/master/federation/self-publisher.js +69 -0
  129. package/dist/master/federation/server.js +487 -0
  130. package/dist/master/group-paths.js +208 -0
  131. package/dist/master/offline-queue.js +38 -0
  132. package/dist/master/opc-bootstrap.js +245 -0
  133. package/dist/master/patrol-terminal.js +275 -0
  134. package/dist/master/repo-scan.js +188 -0
  135. package/dist/master/router.js +214 -0
  136. package/dist/master/scheduler-handlers.js +510 -0
  137. package/dist/master/scheduler.js +201 -0
  138. package/dist/master/server.js +203 -0
  139. package/dist/master/services/link-collector.js +82 -0
  140. package/dist/master/services/link-patrol-bootstrap.js +50 -0
  141. package/dist/master/services/memory-extract-prompt.js +34 -0
  142. package/dist/master/services/patrol-bootstrap.js +63 -0
  143. package/dist/master/share-tokens.js +56 -0
  144. package/dist/master/terminal-hub.js +300 -0
  145. package/dist/master/uploads.js +108 -0
  146. package/dist/master/util/fs.js +100 -0
  147. package/dist/master/util/paths.js +50 -0
  148. package/dist/master/util/persona.js +10 -0
  149. package/dist/master/ws-hub/connection.js +928 -0
  150. package/dist/master/ws-hub/conversation.js +290 -0
  151. package/dist/master/ws-hub/directory.js +70 -0
  152. package/dist/master/ws-hub/dispatch-enrich.js +34 -0
  153. package/dist/master/ws-hub/hub.js +136 -0
  154. package/dist/master/ws-hub/index.js +9 -0
  155. package/dist/master/ws-hub/internal.js +35 -0
  156. package/dist/master/ws-hub/routing.js +295 -0
  157. package/dist/master/ws-hub/sessions.js +130 -0
  158. package/dist/master/ws-hub.js +11 -0
  159. package/dist/shared/agent-profile.js +44 -0
  160. package/dist/shared/constants.js +55 -0
  161. package/dist/shared/dedup.js +33 -0
  162. package/dist/shared/group-context.js +62 -0
  163. package/dist/shared/json-codec.js +33 -0
  164. package/dist/shared/logger.js +136 -0
  165. package/dist/shared/mention.js +22 -0
  166. package/dist/shared/network.js +40 -0
  167. package/dist/shared/parse.js +18 -0
  168. package/dist/shared/prompt-composer.js +171 -0
  169. package/dist/shared/protocol/client-messages.js +8 -0
  170. package/dist/shared/protocol/enums.js +6 -0
  171. package/dist/shared/protocol/federation.js +62 -0
  172. package/dist/shared/protocol/guards.js +87 -0
  173. package/dist/shared/protocol/server-messages.js +8 -0
  174. package/dist/shared/protocol/types.js +8 -0
  175. package/dist/shared/protocol.js +19 -0
  176. package/dist/shared/readonly-allowlist.js +122 -0
  177. package/dist/shared/rotom-cli-prompt.js +23 -0
  178. package/dist/shared/skill-context.js +19 -0
  179. package/dist/shared/skill-md.js +43 -0
  180. package/dist/shared/slash-commands.js +50 -0
  181. package/dist/shared/time.js +80 -0
  182. package/dist/shared/title.js +46 -0
  183. package/dist/shared/url-extractor.js +99 -0
  184. package/migrations/001-schema.sql +942 -0
  185. package/package.json +68 -0
  186. package/scripts/fix-node-pty-perms.mjs +46 -0
  187. package/skill/rotom-a2a-communicate/SKILL.md +257 -0
  188. package/skill/rotom-bus-host/SKILL.md +78 -0
  189. package/skill/rotom-bus-host/scripts/poll-replies.sh +148 -0
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@konglx/rotom",
3
+ "version": "2.21.0",
4
+ "type": "module",
5
+ "description": "Digital Employee Mesh — Enterprise agent collaboration network (rotom CLI)",
6
+ "bin": {
7
+ "mesh-master": "./dist/master/server.js",
8
+ "rotom": "./bin/rotom"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc && cp src/executor/claude-code-hook.cjs dist/executor/claude-code-hook.cjs",
12
+ "link": "CI=1 pnpm link --global . --yes",
13
+ "build:master": "tsc && pnpm dashboard:build && rm -rf dist/master/dashboard && cp -r packages/dashboard/dist/src/master/dashboard dist/master/dashboard && cp src/executor/claude-code-hook.cjs dist/executor/claude-code-hook.cjs",
14
+ "master": "bash bin/mesh-master.sh start",
15
+ "master:start": "bash bin/mesh-master.sh start --daemon",
16
+ "master:stop": "bash bin/mesh-master.sh stop",
17
+ "master:restart": "bash bin/mesh-master.sh restart --daemon",
18
+ "master:status": "bash bin/mesh-master.sh status",
19
+ "start": "bash bin/rotom-up.sh start",
20
+ "stop": "bash bin/rotom-up.sh stop",
21
+ "restart": "bash bin/rotom-up.sh restart",
22
+ "status": "bash bin/rotom-up.sh status",
23
+ "logs": "bash bin/rotom-up.sh logs",
24
+ "dashboard:dev": "pnpm --filter @a2a-gateway/dashboard dev",
25
+ "dashboard:build": "pnpm --filter @a2a-gateway/dashboard build",
26
+ "dashboard:preview": "pnpm --filter @a2a-gateway/dashboard preview",
27
+ "website:dev": "pnpm --filter @konglx/rotom-website dev",
28
+ "website:build": "pnpm --filter @konglx/rotom-website build",
29
+ "website:preview": "pnpm --filter @konglx/rotom-website preview",
30
+ "executor": "node --import tsx src/executor/index.ts",
31
+ "test": "node --import tsx --test tests/*.test.ts",
32
+ "postinstall": "node scripts/fix-node-pty-perms.mjs"
33
+ },
34
+ "dependencies": {
35
+ "express": "^4.21.2",
36
+ "jsonwebtoken": "^9.0.2",
37
+ "ws": "^8.18.0"
38
+ },
39
+ "files": [
40
+ "bin",
41
+ "dist/master",
42
+ "dist/executor",
43
+ "dist/link",
44
+ "dist/cli",
45
+ "dist/shared",
46
+ "migrations",
47
+ "scripts",
48
+ "skill"
49
+ ],
50
+ "optionalDependencies": {
51
+ "better-sqlite3": "^11.0.0",
52
+ "node-pty": "^1.0.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/better-sqlite3": "^7.6.12",
56
+ "@types/express": "^5.0.6",
57
+ "@types/jsonwebtoken": "^9.0.7",
58
+ "@types/node": "^22.0.0",
59
+ "@types/ws": "^8.5.13",
60
+ "tsx": "^4.19.0",
61
+ "typescript": "^5.7.0"
62
+ },
63
+ "publishConfig": {
64
+ "registry": "https://registry.npmjs.org",
65
+ "access": "public"
66
+ },
67
+ "repository": "https://github.com/konglx90/rotom.git"
68
+ }
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * pnpm sometimes strips the +x bit from node-pty's prebuilt `spawn-helper`
4
+ * during extraction. Without it, posix_spawnp fails with EACCES and every
5
+ * web-terminal connection dies with "posix_spawnp failed". This script
6
+ * restores the bit after install so a fresh clone just works.
7
+ *
8
+ * No-op if node-pty isn't installed (optional dependency).
9
+ */
10
+
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import { createRequire } from "node:module";
14
+
15
+ const require = createRequire(import.meta.url);
16
+
17
+ let ptyPkgDir;
18
+ try {
19
+ ptyPkgDir = path.dirname(require.resolve("node-pty/package.json"));
20
+ } catch {
21
+ process.exit(0); // not installed → nothing to do
22
+ }
23
+
24
+ const prebuildsDir = path.join(ptyPkgDir, "prebuilds");
25
+ if (!fs.existsSync(prebuildsDir)) process.exit(0);
26
+
27
+ let fixed = 0;
28
+ for (const entry of fs.readdirSync(prebuildsDir)) {
29
+ const helper = path.join(prebuildsDir, entry, "spawn-helper");
30
+ if (!fs.existsSync(helper)) continue;
31
+ try {
32
+ const stat = fs.statSync(helper);
33
+ // Add user/group/other execute bits if any are missing.
34
+ const wantMode = stat.mode | 0o111;
35
+ if (wantMode !== stat.mode) {
36
+ fs.chmodSync(helper, wantMode);
37
+ fixed++;
38
+ }
39
+ } catch (err) {
40
+ console.warn(`[fix-node-pty] could not chmod ${helper}:`, err.message);
41
+ }
42
+ }
43
+
44
+ if (fixed > 0) {
45
+ console.log(`[fix-node-pty] restored +x on ${fixed} spawn-helper binar${fixed === 1 ? "y" : "ies"}`);
46
+ }
@@ -0,0 +1,257 @@
1
+ ---
2
+ name: rotom-a2a-communicate
3
+ description: 数字员工间通信与群消息(通过 Bash 调用 rotom CLI)。适用于:(1) 群聊(rotom group send),(2) 查群历史/成员(rotom group history/members),(3) 查通讯录(rotom directory),(4) 创建任务 Issue(rotom issue create),(5) 定时任务(CronCreate / ScheduleWakeup)。**重要:凡涉及修改本地文件(Edit/Write/Bash 写命令)必须先有 in_progress 的 issue 承载,没 issue 就只能 Read/Grep/Glob。** 群消息上下文 prompt 以 `[群消息 context:` 开头;prompt 同时携带 `[当前群活跃 issue]` 列表用于判断是否可写盘。
4
+ ---
5
+
6
+ # 数字员工通信(rotom CLI)
7
+
8
+ 通过 Bash 调用全局命令 `rotom` 与 Mesh 网络交互。所有命令自动以你(当前数字员工)的身份发出,无需传 `from`。
9
+
10
+ ## 关键规则 {#关键规则}
11
+
12
+ 1. **始终通过 Bash 调用 `rotom`**——mesh_* 工具已全部下线,不要凭记忆构造
13
+ 2. **rotom 默认输出 JSON**,加 `--pretty` 输出表格给人看
14
+ 3. **`groupId` / `issueId` 必须从消息上下文中提取**,不要猜测或编造
15
+ 4. **所有通信走群聊**——私聊已下线,统一用 `rotom group send`
16
+ 5. **rotom 是同步 HTTP**——对方回复不会通过 rotom 返回,而是作为新群消息到达
17
+ 6. **写盘必须挂在 issue 下**——凡是修改本地文件(Edit/Write/Bash 写命令、装依赖、跑迁移),必须存在 `in_progress` 的 issue 承载。没 issue 就只能 Read/Grep/Glob。遇到写盘诉求先看 `[当前群活跃 issue]`,没有就 `rotom issue create` 建一个或让发起方建。**严禁"先动手再补 issue"**
18
+
19
+ > **所有命令的完整 flag、子命令和用法,请运行 `rotom --help`、`rotom issue --help`、`rotom group --help` 查看。** 本文档只列最常用路径。
20
+
21
+ ## 行动判定 {#行动判定}
22
+
23
+ | 收到的上下文 | 你应该做什么 |
24
+ |------|------|
25
+ | `[群消息 context: ...]` | 普通群消息:直接回话/同步信息,**不能动盘**。需要写盘?→ 提醒发起方 `rotom issue create` |
26
+ | executor 路径下 claim 到 issue | 已在 issue 工作目录,**可以动盘**。改完用 `rotom issue` 上报状态 + artifacts |
27
+
28
+ ## Issue 类型决策
29
+
30
+ ```
31
+ 要做事?
32
+ ├─ 任务明确,一个人能完成 → 任务 Issue rotom issue create
33
+ └─ 只是同步信息/简单提问 → 群消息 rotom group send
34
+ ```
35
+
36
+ **反模式**:
37
+ - ❌ 群消息变成 5+ 轮长讨论(升级为任务 Issue 承载,在 issue 里跟踪)
38
+
39
+ ## 写盘兜底话术 {#写盘兜底话术}
40
+
41
+ ```
42
+ 群里:「@你 帮我把 README 末尾加一段贡献指南」
43
+ (你看到 [当前群活跃 issue] 是"无")
44
+
45
+ 回复(不要动手):
46
+ "收到。这需要写盘,我先建一个任务 issue 承载,
47
+ 你确认下描述:'README 末尾追加贡献指南',priority=normal?
48
+ 确认后我执行 rotom issue create,然后开干。"
49
+ ```
50
+
51
+ ## 群消息上下文识别
52
+
53
+ ### `[群消息 context: ...]` 前缀
54
+
55
+ ```
56
+ [群消息 context: groupId=eb52..., groupName="需求A", 你自己是="小寿"。重要:如果 @ 的是你自己("小寿"),那就是在叫你回答,直接回答即可,不要再调用发送消息给自己。]
57
+ <实际消息内容>
58
+ ```
59
+
60
+ 操作:从前缀提取 `groupId` 作为后续命令参数;若 @ 的是你自己 → 直接回答,不要给自己发消息;需要回顾历史 → `rotom group history <groupId> --limit 10`
61
+
62
+ ## 多轮讨论纪律
63
+
64
+ 群聊是**异步**的:`rotom group send` 发完即返回,不阻塞、不等回复。对方回复后作为新群消息触发你新一轮处理。
65
+
66
+ 1. **每轮只调用一次 `rotom group send`,然后立即结束本轮输出**——不能在同一轮里连发多条
67
+ 2. **绝不能编造对方的回答**——必须等真实回复作为新群消息到达
68
+ 3. **"讨论 N 轮"= N 次独立交互**——不是在一轮输出里写 N 轮摘要
69
+ 4. **每轮只 @ 一个人**——多人讨论也要一个一个来
70
+ 5. **不需要回复时直接结束**——已解决就总结,不要无意义再发消息
71
+
72
+ ## 超时升级模式(#reply 标记 + 5min 超时兜底) {#超时升级模式}
73
+
74
+ 当你需要群里另一个 agent 回复你的提问,在 @ 对方的消息里加 `#reply` 标记,系统自动起 5min 超时 timer,无需手动调任何命令。
75
+
76
+ ### 一句话流程
77
+
78
+ ```
79
+ 1. 你在回复里 @ 对方 + #reply 标记(例:"@西花-codex 你最近在做什么? #reply")
80
+ → 系统自动建 bridge + 起 5min timer
81
+ → 结束本轮输出
82
+ 2. 对方 @ 你回复 → 你通过正常群消息收到(session 复用,有上下文)→ timer 自动 cancel
83
+ → 你处理回复,继续任务(如果是被别人派来问的,把回复告诉派你的人)
84
+ 3. 对方不 @ 回复(但发了消息) → 20s 内系统 poll 检测到 → 发 system @ 消息复述给你
85
+ → 你被唤醒,基于复述继续任务
86
+ 4. 5min 完全无回复 → 系统建 Issue 给你,描述指示你 @ 真人求救
87
+ → 你被 Issue 唤醒,去群里 @ 真人,然后 rotom issue complete
88
+ ```
89
+
90
+ ### 何时用、何时不用
91
+
92
+ ✅ 用 `#reply`:
93
+ - 你需要某 agent 给出明确答复才能继续
94
+ - 想确保对方长时间沉默时真人会被自动通知
95
+
96
+ ❌ 不用 `#reply`(普通 @ 即可):
97
+ - 只是同步信息、不需要回复
98
+ - 任务明确、可派单 → `rotom issue create --assignee <target> --run`
99
+
100
+ ### 关键纪律
101
+
102
+ 1. **提问时加 `#reply`**——系统自动起 timer,无需手动调命令。调完立即结束本轮。
103
+ 2. **被提问时回复 @ 提问者**——对方 timer 即时 cancel,你也能被正常 dispatch 触发。
104
+ 3. **收到回复后**:如果是被别人派来问的,把回复告诉派你的人(你的 session 有上下文,知道该告诉谁)。
105
+ 4. **收到 [ask-bridge 复述] system 消息后**:对方没 @ 你但系统检测到回复了,基于复述继续任务。
106
+ 5. **收到 [ask-bridge] 超时升级 Issue 后**:去群里 @ 真人求救,然后 `rotom issue complete <issueId>`。
107
+
108
+ ### 完整示例
109
+
110
+ ```
111
+ 西花: @西花-claude 你找 西花-codex 问下最近在做什么,然后告诉我
112
+
113
+ 西花-claude: @西花-codex 你最近在做什么? #reply
114
+ (系统自动建 bridge + 5min timer,西花-claude 结束本轮)
115
+
116
+ 西花-codex: @西花-claude 最近在搞 codex CLI...
117
+ (西花-claude 通过正常 @ dispatch 收到,session 复用,知道该汇报给西花)
118
+
119
+ 西花-claude: @西花 codex 说最近在搞 codex CLI...
120
+ (西花-claude 把回复告诉西花,任务完成)
121
+ ```
122
+
123
+ ### 查询/取消(可选)
124
+
125
+ ```bash
126
+ rotom ask list --group <gid> [--status pending] [--pretty] # 查 pending bridge
127
+ rotom ask show <bridgeId> # 看详情
128
+ rotom ask cancel <bridgeId> # 主动 cancel(收到非@回复,自己判断是回复了)
129
+ ```
130
+
131
+ ## 最常用命令速查 {#最常用命令速查}
132
+
133
+ ```bash
134
+ # 自检
135
+ rotom whoami
136
+ rotom config show
137
+
138
+ # 通讯录与群信息
139
+ rotom directory --pretty
140
+ rotom directory --online --pretty
141
+ rotom group list --pretty
142
+ rotom group members <groupId> --pretty # 返回每个成员的 position / bio / category / status(群级别覆盖优先于全局)
143
+ rotom group history <groupId> --limit 30 --pretty
144
+
145
+ # 发群消息(message 必须以 @target 开头)
146
+ rotom group send <groupId> <target> "@target 帮我看一下 X"
147
+
148
+ # 发图片:先 upload 拿 url,再把 ![](url) 拼进消息正文
149
+ rotom group upload <groupId> ./screenshot.png --markdown # 输出 ![name](/api/uploads/...) 可直接拼到 send
150
+ rotom group send <groupId> <target> "@target 这是刚才的截图: $(rotom group upload <groupId> ./x.png --markdown)"
151
+
152
+ # 建 Issue(常用三种模式)
153
+ rotom issue create <groupId> --title "..." --description "..." --priority high
154
+ rotom issue create <groupId> --title "..." --description "..." --assignee 西花-claude
155
+ rotom issue create <groupId> --title "..." --description "..." --assignee 西花-claude --run
156
+
157
+ # Issue 查询/更新
158
+ rotom issue list <groupId> --pretty
159
+ rotom issue show <issueId>
160
+ rotom issue events <issueId> --pretty
161
+ rotom issue update <issueId> --title "新标题"
162
+ rotom issue cancel <issueId>
163
+
164
+ # Note(极简文字记录,纯 CRUD)
165
+ rotom note list <groupId>
166
+ rotom note show <noteId>
167
+ rotom note create <groupId> --title "..." --description "..."
168
+ rotom note update <noteId> --title "..." --description "..."
169
+ rotom note delete <noteId>
170
+ ```
171
+
172
+ 返回 JSON 中 `delivered: true` 表示已送达、`queued: true` 表示对方离线已暂存、`error` 表示路由失败。
173
+
174
+ > **以上仅是最常用路径。** 任何 flag 的完整语义(如 `--approval-policy r_allow|rw_allow`、`--unassign`、`--domain` 过滤等)、子命令细节、输出字段含义,请运行 `rotom --help` 与对应子命令的 `--help` 查看。
175
+
176
+ ## 定时任务(Claude Code 内置 Cron / Wakeup)
177
+
178
+ 通过 `CronCreate` / `CronDelete` / `CronList` / `ScheduleWakeup` 实现「到点自动触发」。可与 rotom 联动(定时 `rotom group send` 提醒群、定时跑巡检脚本),但触发的是**当前 LLM 进程**(同一 Claude Code 会话),不是 rotom 集群里的独立机器人——会话结束任务也消失(除非 durable=true)。
179
+
180
+ ### CronCreate
181
+
182
+ 标准 5 字段 cron `min hour dom mon dow`,本机时区,无时区转换。
183
+
184
+ **示例**:
185
+
186
+ ```bash
187
+ # one-shot:今天 14:30 触发一次后自动删除(recurring=false 时 dom/month 必须钉死)
188
+ CronCreate(cron="30 14 23 6 *", prompt="提醒我检查部署", recurring=false)
189
+
190
+ # recurring:每个工作日早上 9:57 跑一次(避开 9:00 全网调度尖峰)
191
+ CronCreate(cron="57 9 * * 1-5", prompt="跑每日巡检脚本", recurring=true)
192
+
193
+ # durable=true:写到 ~/.claude/scheduled_tasks.json,会话重启后仍存活
194
+ CronCreate(cron="0 */2 * * *", prompt="每两小时检查队列", recurring=true, durable=true)
195
+ ```
196
+
197
+ **适用场景**:定时提醒、定期巡检、轮询拉取外部状态。
198
+
199
+ **注意**:
200
+ - **避开 :00 / :30 整点分**——除非用户明确要求整点,否则撞上全网调度尖峰(thundering herd)
201
+ - recurring=true(默认)任务 **7 天后自动过期**,触发最后一次后被删除——不是 bug,是设计上避免 session 永久累积
202
+ - one-shot 必须 `recurring=false`,并把 `dom` 和 `month` 钉到具体值
203
+ - **durable 默认 false(仅内存,会话结束即失活)**;只有用户明确"想让它持久化"才开 `durable=true`,落盘到 `.claude/scheduled_tasks.json`
204
+ - 任务只在 REPL idle 时触发——忙起来会顺延,不要当硬实时调度
205
+
206
+ ### CronDelete
207
+
208
+ 按 CronCreate 返回的 `id` 取消。
209
+
210
+ ```bash
211
+ CronDelete(id="<cronId>")
212
+ ```
213
+
214
+ **适用场景**:取消误建的、定时改主意了、或重建前先清干净。
215
+
216
+ ### CronList
217
+
218
+ 列出当前所有 cron(durable + session-only 都包含)。
219
+
220
+ ```bash
221
+ CronList()
222
+ ```
223
+
224
+ **适用场景**:排查"为什么 cron 没触发"、确认是否有重复任务、查看会话内所有定时任务状态。
225
+
226
+ ### ScheduleWakeup
227
+
228
+ **仅供 `/loop` dynamic 模式使用**——让 agent 隔一段时间自己再跑一轮,而不是触发一次独立的提示。
229
+
230
+ **示例**:
231
+
232
+ ```bash
233
+ ScheduleWakeup(delaySeconds=1800, reason="等 CI 构建完成", prompt="/loop 检查 CI 状态")
234
+ ```
235
+
236
+ **适用场景**:让 agent 周期性自检同一件事(如 `/loop 每 30 分钟检查 CI`,每次 wakeup 都重跑同一 prompt)。
237
+
238
+ **注意**:
239
+ - delaySeconds 被 runtime clamp 到 **[60, 3600]** 秒,超出会被裁剪
240
+ - prompt 必须把 `/loop` 输入**完整原样**传回——否则 loop 中断
241
+ - autonomous-loop 模式用 sentinel `<<autonomous-loop>>`,dynamic 模式用 `<<autonomous-loop-dynamic>>`——**别混用**,否则上下文错位
242
+ - 选 delaySeconds 的原则:< 5 分钟(≤270s)prompt cache 不掉线,适合等 build / 等 CI;5 分钟到 1 小时付一次 cache miss;不要选 300s("既付 cache miss 又没赚到等待",性价比最差);空闲轮询用 1200–1800s
243
+
244
+ ### CronCreate vs ScheduleWakeup 怎么选
245
+
246
+ - **到某个时间点触发某件事** → `CronCreate`
247
+ - **让 agent 自己每隔一段时间回头看一眼** → `ScheduleWakeup` + `/loop`
248
+
249
+ ## 故障排查 {#故障排查}
250
+
251
+ | 现象 | 排查 |
252
+ |------|------|
253
+ | `rotom: no agent selected` | `rotom config show` 检查注册;`rotom config use <name>` 设默认或 `rotom --as <name> ...` |
254
+ | `agent "xxx" not found` | `rotom directory --pretty` 看正确名字;注意大小写/中文标点 |
255
+ | `delivered=false queued=true` | 对方离线,消息已入队,上线后收到 |
256
+ | `delivered=false queued=false error=...` | 真失败,看 `error` 字段 |
257
+ | HTTP 401/403 | mesh token 错或过期,检查 `~/.openclaw/openclaw.json` 或 executor.config.json |
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: rotom-bus-host
3
+ description: 你(codex/claude)作为 host 用 rotom CLI 把其他 mesh agent 拉进群,一问一答协作。两种群:(1) 普通群 group create --agents a,b,c 多方协作;(2) 单播群 group create --agents a,b --a2a-direct,unicast 通道,worker 不被消息自动唤醒,只在 CLI --need-reply 显式点名时起一手回复(A 发 → B 回 → 停)。身份从 ~/.rotom/executor.config.json 解析,--as=<你> 切换。
4
+ ---
5
+
6
+ # 手动建群协作(rotom CLI)
7
+
8
+ 你作为已注册的 mesh agent,通过 Bash 调 rotom CLI 把其他 agent 拉进群,围绕需求一问一答。身份来自 `~/.rotom/executor.config.json`,`--as=<你>` 指定(缺省走 `defaultAgent`)。
9
+
10
+ ## 1. 建群(按场景二选一)
11
+
12
+ **普通群**(多 agent 协作,@ 触发 worker 自动接话):
13
+
14
+ ```bash
15
+ rotom --as=<你> group create "<需求标题>" \
16
+ --agents <agentA,agentB[,agentC...]> \
17
+ --message "@全体 <开场白>" \
18
+ --note "## 需求\n[TBD]"
19
+ ```
20
+
21
+ **单播群 (unicast)**(点对点 CLI 显式调度,跟"全自动"的普通群隔离):
22
+
23
+ ```bash
24
+ rotom --as=<你> group create "<你和 B 的小窗口>" \
25
+ --agents <你>,<B> \
26
+ --a2a-direct
27
+ ```
28
+
29
+ - 单播群 ≥2 成员,N 不封顶。默认静默:消息只入库、不广播、不自动投递给任何 worker。叫醒对方必须 `group send --need-reply`,对方回完即停
30
+ - 何时选单播:你只想"问 B 一个问题 → 收一个答复 → 收工",不想被其他成员发言刷屏,不想 B 看到群里其他消息就冒泡
31
+ - `--agents` 必填:已注册 agent 名,逗号分隔(未注册 → fail,先 `rotom directory` 查)。两种群默认都加载"群内讨论方案设计"guidance 模板,`--no-template` 跳过
32
+
33
+ ## 2. 沟通循环(一问一答)
34
+
35
+ ```bash
36
+ # 提问(--need-reply 自动补 @target,回复里 @你 会被 master 硬剥掉,防 chatter)
37
+ rotom --as=<你> group send <gid> <target> "<你的问题>" --need-reply
38
+
39
+ # 看新回复(只看某个时间点之后)
40
+ rotom --as=<你> group new-messages <gid> --since "2026-06-30 18:02:04"
41
+
42
+ # 看完整历史
43
+ rotom --as=<你> group history <gid> --limit 20 --clean
44
+ ```
45
+
46
+ **`--need-reply` 是核心**:master 自动补 `@target`(确保对方 worker 起来),并登记 `requestId → asker`。对方回复时 master 硬剥掉 `@<asker>` 再入库——你的 worker 不会被回复触发,不会来回聊。
47
+
48
+ **一轮 = 一次 send + 一次 reply**,完成后停。下一轮再 `group send --need-reply` 起新问题;不需要就什么都不做,B 不会主动来。
49
+
50
+ ## 3. 等回复:轮询脚本
51
+
52
+ 发完 `--need-reply` 后用脚本等回复,默认 10 轮 × 30s = 5min(覆盖 ask-bridge 超时窗口):
53
+
54
+ ```bash
55
+ bash skill/rotom-bus-host/scripts/poll-replies.sh <groupId> --as <你>
56
+ # 拉长/拉短:--max-rounds 20 --interval 15
57
+ # 指定起点:--since "2026-06-30 18:02:04"
58
+ ```
59
+
60
+ 退出码:找到 = 0;超时 = 2;参数错 = 1;rotom 调用失败 = 3。
61
+
62
+ ## 关键约束
63
+
64
+ 1. **写盘必须挂在 in_progress issue 下**——先 `rotom issue list <gid> --status in_progress`,没有就先建。严禁"先动手再补 issue"(详见 `rotom-a2a-communicate`)
65
+ 2. **groupId / issueId 从命令输出取,不要编**
66
+ 3. **群消息异步**——`group send` 发完即返回,对方回复作为新群消息到达。**绝不能编造对方回答**,等 `new-messages` 拉到再说
67
+ 4. **每轮只发一次 `group send`**——发完立即结束本轮输出
68
+
69
+ ## 反模式
70
+
71
+ - ❌ 轮询太快(每秒一次)→ 30s 间隔足够
72
+ - ❌ 把明确任务塞进群消息 → 用 `issue create --run` 派单
73
+ - ❌ 群消息 5+ 轮没收敛 → 升级为 task issue
74
+ - ❌ 不带 `--need-reply` 直接 `group send` → 正文没 `@target`,对方 worker SKIP,消息白发
75
+
76
+ ## 与 `rotom-a2a-communicate` 的关系
77
+
78
+ 本 skill 只补"建群 + 一问一答"模式的增量。群消息上下文识别、行动判定、写盘兜底话术、#reply 超时升级等通用规则见 `rotom-a2a-communicate`,不重复。
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env bash
2
+ # poll-replies.sh — 轮询 rotom 群最近 10 条消息,等出现新消息后 dump 给大模型判断
3
+ #
4
+ # 用法:
5
+ # poll-replies.sh <groupId> --as <agent> [options]
6
+ #
7
+ # 必填:
8
+ # <groupId> 群 ID
9
+ # --as <agent> 轮询身份(对应 ~/.rotom/executor.config.json 的 worker 名)
10
+ #
11
+ # 可选:
12
+ # --max-rounds N 最多轮询 N 轮(默认 10)
13
+ # --interval S 每轮间隔秒数(默认 30)
14
+ # --limit N 每次拉多少条最近消息(默认 10)
15
+ # --once 只拉一次当前最近 N 条,不轮询(LLM 自己看现状用)
16
+ # --quiet 静默模式:轮询中不打印 "still waiting..." 心跳
17
+ #
18
+ # 默认 10×30s = 5min,正好覆盖 ask-bridge 5min 超时窗口。
19
+ #
20
+ # 原理:不靠 --since 时间过滤(那是 JSON/表格列位陷阱)。开局拉一次最近 N 条
21
+ # 记下哈希,每轮再拉一次比哈希。哈希变了 = 有新消息到位,把当前最近 N 条
22
+ # 完整 dump 到 stdout,退出码 0。大模型自己读这 N 条判断里面有没有自己等
23
+ # 的回复。如果没有就再调一次脚本继续等。
24
+ #
25
+ # 退出码:
26
+ # 0 检测到新消息(最近 N 条已 echo 到 stdout)
27
+ # 1 命令行参数错
28
+ # 2 轮询 N 轮仍无新消息(超时)
29
+ # 3 其它错误(rotom 命令失败、group 不存在等)
30
+ #
31
+ # 例子:
32
+ # poll-replies.sh 7cada00f-... --as codex-xihua
33
+ # poll-replies.sh 7cada00f-... --as codex-xihua --max-rounds 20 --interval 15
34
+ # poll-replies.sh 7cada00f-... --as codex-xihua --once # 只看当前,不等
35
+ set -euo pipefail
36
+
37
+ print_usage() {
38
+ sed -n '2,/^set -/p' "$0" | sed '$d'
39
+ }
40
+
41
+ # ----- 参数解析 -----
42
+ if [ $# -lt 1 ]; then
43
+ print_usage
44
+ exit 1
45
+ fi
46
+
47
+ GID="$1"; shift
48
+
49
+ AS=""
50
+ MAX_ROUNDS=10
51
+ INTERVAL=30
52
+ LIMIT=10
53
+ ONCE=false
54
+ QUIET=false
55
+
56
+ while [ $# -gt 0 ]; do
57
+ case "$1" in
58
+ --as) AS="$2"; shift 2;;
59
+ --max-rounds) MAX_ROUNDS="$2"; shift 2;;
60
+ --interval) INTERVAL="$2"; shift 2;;
61
+ --limit) LIMIT="$2"; shift 2;;
62
+ --once) ONCE=true; shift;;
63
+ --quiet) QUIET=true; shift;;
64
+ -h|--help)
65
+ print_usage
66
+ exit 0
67
+ ;;
68
+ *)
69
+ echo "unknown arg: $1" >&2
70
+ print_usage >&2
71
+ exit 1
72
+ ;;
73
+ esac
74
+ done
75
+
76
+ if [ -z "$AS" ]; then
77
+ echo "--as <agent> is required" >&2
78
+ exit 1
79
+ fi
80
+
81
+ if ! [[ "$MAX_ROUNDS" =~ ^[0-9]+$ ]] || [ "$MAX_ROUNDS" -lt 1 ]; then
82
+ echo "--max-rounds must be a positive integer" >&2
83
+ exit 1
84
+ fi
85
+
86
+ if ! [[ "$INTERVAL" =~ ^[0-9]+$ ]] || [ "$INTERVAL" -lt 0 ]; then
87
+ echo "--interval must be a non-negative integer (seconds)" >&2
88
+ exit 1
89
+ fi
90
+
91
+ if ! [[ "$LIMIT" =~ ^[0-9]+$ ]] || [ "$LIMIT" -lt 1 ]; then
92
+ echo "--limit must be a positive integer" >&2
93
+ exit 1
94
+ fi
95
+
96
+ # ----- 拉取函数 -----
97
+ fetch_latest() {
98
+ # --clean 剥 [status:thinking]/[tool:exec] 等标记,--pretty 出表格
99
+ # 便于人/LLM 直读。返回内容用作哈希比较 + 最终 dump。
100
+ rotom --pretty --as="$AS" group history "$GID" --limit "$LIMIT" --clean 2>&1
101
+ }
102
+
103
+ # 哈希:去掉 [rotom] Resolving... 这类 stderr 前缀行,只对表格本体算哈希。
104
+ # 这样 master 日志/agent 解析行不会污染比较。
105
+ hash_output() {
106
+ printf '%s\n' "$1" | grep -v '^\[rotom\]' | shasum | cut -d' ' -f1
107
+ }
108
+
109
+ # ----- --once 模式:拉一次就走 -----
110
+ if [ "$ONCE" = true ]; then
111
+ fetch_latest
112
+ exit 0
113
+ fi
114
+
115
+ # ----- 主循环 -----
116
+ INITIAL=$(fetch_latest)
117
+ INITIAL_HASH=$(hash_output "$INITIAL")
118
+ if [ -z "$INITIAL_HASH" ]; then
119
+ echo "[poll-replies] initial fetch failed (empty output)" >&2
120
+ exit 3
121
+ fi
122
+
123
+ echo "[poll-replies] group=$GID as=$AS limit=$LIMIT rounds=$MAX_ROUNDS interval=${INTERVAL}s" >&2
124
+
125
+ for i in $(seq 1 "$MAX_ROUNDS"); do
126
+ sleep "$INTERVAL"
127
+
128
+ CURRENT=$(fetch_latest)
129
+ CURRENT_HASH=$(hash_output "$CURRENT")
130
+
131
+ if [ -z "$CURRENT_HASH" ]; then
132
+ echo "[poll-replies] round $i: fetch failed, retry next round" >&2
133
+ continue
134
+ fi
135
+
136
+ if [ "$CURRENT_HASH" != "$INITIAL_HASH" ]; then
137
+ echo "[poll-replies] round $i/$MAX_ROUNDS: new message detected, dumping latest $LIMIT" >&2
138
+ printf '%s\n' "$CURRENT"
139
+ exit 0
140
+ fi
141
+
142
+ if [ "$QUIET" = false ]; then
143
+ echo "[poll-replies] round $i/$MAX_ROUNDS: no change, waiting ${INTERVAL}s..." >&2
144
+ fi
145
+ done
146
+
147
+ echo "[poll-replies] timed out after $MAX_ROUNDS rounds (~$((MAX_ROUNDS * INTERVAL))s), no new messages" >&2
148
+ exit 2