@mclawnet/swarm 0.1.4 → 0.1.6

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 (240) hide show
  1. package/README.md +118 -0
  2. package/dist/__tests__/action-parser.test.js +29 -82
  3. package/dist/__tests__/action-parser.test.js.map +1 -1
  4. package/dist/__tests__/coordinator-create-tx.test.d.ts +2 -0
  5. package/dist/__tests__/coordinator-create-tx.test.d.ts.map +1 -0
  6. package/dist/__tests__/coordinator-create-tx.test.js +114 -0
  7. package/dist/__tests__/coordinator-create-tx.test.js.map +1 -0
  8. package/dist/__tests__/coordinator-inbox-migration.test.d.ts +2 -0
  9. package/dist/__tests__/coordinator-inbox-migration.test.d.ts.map +1 -0
  10. package/dist/__tests__/coordinator-inbox-migration.test.js +56 -0
  11. package/dist/__tests__/coordinator-inbox-migration.test.js.map +1 -0
  12. package/dist/__tests__/inbox-integration.test.d.ts +2 -0
  13. package/dist/__tests__/inbox-integration.test.d.ts.map +1 -0
  14. package/dist/__tests__/inbox-integration.test.js +120 -0
  15. package/dist/__tests__/inbox-integration.test.js.map +1 -0
  16. package/dist/__tests__/inbox-persistence-recovery.test.d.ts +2 -0
  17. package/dist/__tests__/inbox-persistence-recovery.test.d.ts.map +1 -0
  18. package/dist/__tests__/inbox-persistence-recovery.test.js +139 -0
  19. package/dist/__tests__/inbox-persistence-recovery.test.js.map +1 -0
  20. package/dist/__tests__/inbox-relay-interceptor.test.d.ts +2 -0
  21. package/dist/__tests__/inbox-relay-interceptor.test.d.ts.map +1 -0
  22. package/dist/__tests__/inbox-relay-interceptor.test.js +156 -0
  23. package/dist/__tests__/inbox-relay-interceptor.test.js.map +1 -0
  24. package/dist/__tests__/inbox-relay.test.d.ts +2 -0
  25. package/dist/__tests__/inbox-relay.test.d.ts.map +1 -0
  26. package/dist/__tests__/inbox-relay.test.js +318 -0
  27. package/dist/__tests__/inbox-relay.test.js.map +1 -0
  28. package/dist/__tests__/inbox-store.test.d.ts +2 -0
  29. package/dist/__tests__/inbox-store.test.d.ts.map +1 -0
  30. package/dist/__tests__/inbox-store.test.js +129 -0
  31. package/dist/__tests__/inbox-store.test.js.map +1 -0
  32. package/dist/__tests__/inbox-watcher.test.d.ts +2 -0
  33. package/dist/__tests__/inbox-watcher.test.d.ts.map +1 -0
  34. package/dist/__tests__/inbox-watcher.test.js +104 -0
  35. package/dist/__tests__/inbox-watcher.test.js.map +1 -0
  36. package/dist/__tests__/persistence-path.test.d.ts +2 -0
  37. package/dist/__tests__/persistence-path.test.d.ts.map +1 -0
  38. package/dist/__tests__/persistence-path.test.js +79 -0
  39. package/dist/__tests__/persistence-path.test.js.map +1 -0
  40. package/dist/__tests__/persistence-robust.test.d.ts +2 -0
  41. package/dist/__tests__/persistence-robust.test.d.ts.map +1 -0
  42. package/dist/__tests__/persistence-robust.test.js +125 -0
  43. package/dist/__tests__/persistence-robust.test.js.map +1 -0
  44. package/dist/__tests__/persistence.test.d.ts +2 -0
  45. package/dist/__tests__/persistence.test.d.ts.map +1 -0
  46. package/dist/__tests__/persistence.test.js +105 -0
  47. package/dist/__tests__/persistence.test.js.map +1 -0
  48. package/dist/__tests__/phase4-5-e2e.test.d.ts +2 -0
  49. package/dist/__tests__/phase4-5-e2e.test.d.ts.map +1 -0
  50. package/dist/__tests__/phase4-5-e2e.test.js +203 -0
  51. package/dist/__tests__/phase4-5-e2e.test.js.map +1 -0
  52. package/dist/__tests__/phase6-7-e2e.test.d.ts +2 -0
  53. package/dist/__tests__/phase6-7-e2e.test.d.ts.map +1 -0
  54. package/dist/__tests__/phase6-7-e2e.test.js +93 -0
  55. package/dist/__tests__/phase6-7-e2e.test.js.map +1 -0
  56. package/dist/__tests__/project-files.test.d.ts +2 -0
  57. package/dist/__tests__/project-files.test.d.ts.map +1 -0
  58. package/dist/__tests__/project-files.test.js +143 -0
  59. package/dist/__tests__/project-files.test.js.map +1 -0
  60. package/dist/__tests__/projects-fs.test.d.ts +2 -0
  61. package/dist/__tests__/projects-fs.test.d.ts.map +1 -0
  62. package/dist/__tests__/projects-fs.test.js +107 -0
  63. package/dist/__tests__/projects-fs.test.js.map +1 -0
  64. package/dist/__tests__/recovery-cross-project.test.d.ts +2 -0
  65. package/dist/__tests__/recovery-cross-project.test.d.ts.map +1 -0
  66. package/dist/__tests__/recovery-cross-project.test.js +87 -0
  67. package/dist/__tests__/recovery-cross-project.test.js.map +1 -0
  68. package/dist/__tests__/recovery-forwards-to-coordinator.test.d.ts +2 -0
  69. package/dist/__tests__/recovery-forwards-to-coordinator.test.d.ts.map +1 -0
  70. package/dist/__tests__/recovery-forwards-to-coordinator.test.js +59 -0
  71. package/dist/__tests__/recovery-forwards-to-coordinator.test.js.map +1 -0
  72. package/dist/__tests__/recovery-resume.test.d.ts +2 -0
  73. package/dist/__tests__/recovery-resume.test.d.ts.map +1 -0
  74. package/dist/__tests__/recovery-resume.test.js +132 -0
  75. package/dist/__tests__/recovery-resume.test.js.map +1 -0
  76. package/dist/__tests__/retrospective.test.js +1 -0
  77. package/dist/__tests__/retrospective.test.js.map +1 -1
  78. package/dist/__tests__/role-loader-preamble-all.test.d.ts +2 -0
  79. package/dist/__tests__/role-loader-preamble-all.test.d.ts.map +1 -0
  80. package/dist/__tests__/role-loader-preamble-all.test.js +38 -0
  81. package/dist/__tests__/role-loader-preamble-all.test.js.map +1 -0
  82. package/dist/__tests__/role-loader-tools.test.d.ts +2 -0
  83. package/dist/__tests__/role-loader-tools.test.d.ts.map +1 -0
  84. package/dist/__tests__/role-loader-tools.test.js +39 -0
  85. package/dist/__tests__/role-loader-tools.test.js.map +1 -0
  86. package/dist/__tests__/role-loader.test.js +116 -1
  87. package/dist/__tests__/role-loader.test.js.map +1 -1
  88. package/dist/__tests__/role-prompt-no-legacy-protocol.test.d.ts +2 -0
  89. package/dist/__tests__/role-prompt-no-legacy-protocol.test.d.ts.map +1 -0
  90. package/dist/__tests__/role-prompt-no-legacy-protocol.test.js +37 -0
  91. package/dist/__tests__/role-prompt-no-legacy-protocol.test.js.map +1 -0
  92. package/dist/__tests__/role-tools.test.d.ts +2 -0
  93. package/dist/__tests__/role-tools.test.d.ts.map +1 -0
  94. package/dist/__tests__/role-tools.test.js +80 -0
  95. package/dist/__tests__/role-tools.test.js.map +1 -0
  96. package/dist/__tests__/spawn-role-injects-briefings.test.d.ts +2 -0
  97. package/dist/__tests__/spawn-role-injects-briefings.test.d.ts.map +1 -0
  98. package/dist/__tests__/spawn-role-injects-briefings.test.js +182 -0
  99. package/dist/__tests__/spawn-role-injects-briefings.test.js.map +1 -0
  100. package/dist/__tests__/spawn-role-tool-policy.test.d.ts +2 -0
  101. package/dist/__tests__/spawn-role-tool-policy.test.d.ts.map +1 -0
  102. package/dist/__tests__/spawn-role-tool-policy.test.js +96 -0
  103. package/dist/__tests__/spawn-role-tool-policy.test.js.map +1 -0
  104. package/dist/__tests__/swarm-coordinator-inbox-watcher.test.d.ts +2 -0
  105. package/dist/__tests__/swarm-coordinator-inbox-watcher.test.d.ts.map +1 -0
  106. package/dist/__tests__/swarm-coordinator-inbox-watcher.test.js +61 -0
  107. package/dist/__tests__/swarm-coordinator-inbox-watcher.test.js.map +1 -0
  108. package/dist/__tests__/swarm-coordinator-inbox.test.d.ts +2 -0
  109. package/dist/__tests__/swarm-coordinator-inbox.test.d.ts.map +1 -0
  110. package/dist/__tests__/swarm-coordinator-inbox.test.js +182 -0
  111. package/dist/__tests__/swarm-coordinator-inbox.test.js.map +1 -0
  112. package/dist/__tests__/swarm-coordinator-init.test.js +36 -8
  113. package/dist/__tests__/swarm-coordinator-init.test.js.map +1 -1
  114. package/dist/__tests__/swarm-coordinator-legacy-plan-review-warn.test.d.ts +2 -0
  115. package/dist/__tests__/swarm-coordinator-legacy-plan-review-warn.test.d.ts.map +1 -0
  116. package/dist/__tests__/swarm-coordinator-legacy-plan-review-warn.test.js +113 -0
  117. package/dist/__tests__/swarm-coordinator-legacy-plan-review-warn.test.js.map +1 -0
  118. package/dist/__tests__/swarm-coordinator-plan-review-intercept.test.d.ts +2 -0
  119. package/dist/__tests__/swarm-coordinator-plan-review-intercept.test.d.ts.map +1 -0
  120. package/dist/__tests__/swarm-coordinator-plan-review-intercept.test.js +465 -0
  121. package/dist/__tests__/swarm-coordinator-plan-review-intercept.test.js.map +1 -0
  122. package/dist/__tests__/swarm-coordinator-plan-review-recovery.test.d.ts +2 -0
  123. package/dist/__tests__/swarm-coordinator-plan-review-recovery.test.d.ts.map +1 -0
  124. package/dist/__tests__/swarm-coordinator-plan-review-recovery.test.js +284 -0
  125. package/dist/__tests__/swarm-coordinator-plan-review-recovery.test.js.map +1 -0
  126. package/dist/__tests__/swarm-coordinator-plan-review.test.d.ts +2 -0
  127. package/dist/__tests__/swarm-coordinator-plan-review.test.d.ts.map +1 -0
  128. package/dist/__tests__/swarm-coordinator-plan-review.test.js +294 -0
  129. package/dist/__tests__/swarm-coordinator-plan-review.test.js.map +1 -0
  130. package/dist/__tests__/swarm-coordinator-resume.test.d.ts +2 -0
  131. package/dist/__tests__/swarm-coordinator-resume.test.d.ts.map +1 -0
  132. package/dist/__tests__/swarm-coordinator-resume.test.js +93 -0
  133. package/dist/__tests__/swarm-coordinator-resume.test.js.map +1 -0
  134. package/dist/__tests__/swarm-coordinator-roleId.test.js +2 -2
  135. package/dist/__tests__/swarm-coordinator-roleId.test.js.map +1 -1
  136. package/dist/__tests__/swarm-destroy-detach.test.d.ts +2 -0
  137. package/dist/__tests__/swarm-destroy-detach.test.d.ts.map +1 -0
  138. package/dist/__tests__/swarm-destroy-detach.test.js +135 -0
  139. package/dist/__tests__/swarm-destroy-detach.test.js.map +1 -0
  140. package/dist/action-parser.d.ts +0 -9
  141. package/dist/action-parser.d.ts.map +1 -1
  142. package/dist/action-parser.js +0 -114
  143. package/dist/action-parser.js.map +1 -1
  144. package/dist/inbox-relay.d.ts +50 -0
  145. package/dist/inbox-relay.d.ts.map +1 -0
  146. package/dist/inbox-relay.js +168 -0
  147. package/dist/inbox-relay.js.map +1 -0
  148. package/dist/inbox-store.d.ts +25 -0
  149. package/dist/inbox-store.d.ts.map +1 -0
  150. package/dist/inbox-store.js +95 -0
  151. package/dist/inbox-store.js.map +1 -0
  152. package/dist/inbox-watcher.d.ts +13 -0
  153. package/dist/inbox-watcher.d.ts.map +1 -0
  154. package/dist/inbox-watcher.js +89 -0
  155. package/dist/inbox-watcher.js.map +1 -0
  156. package/dist/index.d.ts +8 -3
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +5 -2
  159. package/dist/index.js.map +1 -1
  160. package/dist/persistence.d.ts +19 -5
  161. package/dist/persistence.d.ts.map +1 -1
  162. package/dist/persistence.js +97 -22
  163. package/dist/persistence.js.map +1 -1
  164. package/dist/project-files.d.ts +60 -0
  165. package/dist/project-files.d.ts.map +1 -0
  166. package/dist/project-files.js +214 -0
  167. package/dist/project-files.js.map +1 -0
  168. package/dist/projects-fs.d.ts +28 -0
  169. package/dist/projects-fs.d.ts.map +1 -0
  170. package/dist/projects-fs.js +111 -0
  171. package/dist/projects-fs.js.map +1 -0
  172. package/dist/recovery.d.ts +12 -0
  173. package/dist/recovery.d.ts.map +1 -1
  174. package/dist/recovery.js +14 -19
  175. package/dist/recovery.js.map +1 -1
  176. package/dist/roles/role-loader.d.ts +28 -1
  177. package/dist/roles/role-loader.d.ts.map +1 -1
  178. package/dist/roles/role-loader.js +73 -1
  179. package/dist/roles/role-loader.js.map +1 -1
  180. package/dist/roles/role-tools.d.ts +16 -0
  181. package/dist/roles/role-tools.d.ts.map +1 -0
  182. package/dist/roles/role-tools.js +25 -0
  183. package/dist/roles/role-tools.js.map +1 -0
  184. package/dist/roles/types.d.ts +4 -0
  185. package/dist/roles/types.d.ts.map +1 -1
  186. package/dist/swarm-coordinator.d.ts +176 -12
  187. package/dist/swarm-coordinator.d.ts.map +1 -1
  188. package/dist/swarm-coordinator.js +863 -370
  189. package/dist/swarm-coordinator.js.map +1 -1
  190. package/dist/types.d.ts +26 -0
  191. package/dist/types.d.ts.map +1 -1
  192. package/package.json +9 -6
  193. package/roles/analyst-livermore.md +6 -30
  194. package/roles/designer-rams.md +2 -30
  195. package/roles/dev-torvalds.md +8 -44
  196. package/roles/developer.md +5 -21
  197. package/roles/director-jia.md +20 -49
  198. package/roles/editor-boyong.md +8 -40
  199. package/roles/macro-dalio.md +6 -30
  200. package/roles/planner-maoni.md +24 -53
  201. package/roles/pm-jobs.md +20 -71
  202. package/roles/preset-analyst-simons.md +2 -18
  203. package/roles/preset-architect-knuth.md +2 -18
  204. package/roles/preset-designer-norman.md +2 -18
  205. package/roles/preset-designer.md +2 -18
  206. package/roles/preset-dev-carmack.md +2 -18
  207. package/roles/preset-dev-gosling.md +2 -18
  208. package/roles/preset-developer.md +7 -23
  209. package/roles/preset-manager-grove.md +2 -18
  210. package/roles/preset-manager-musk.md +2 -18
  211. package/roles/preset-pm.md +7 -34
  212. package/roles/preset-researcher-feynman.md +2 -18
  213. package/roles/preset-reviewer.md +5 -21
  214. package/roles/preset-strategist-buffett.md +2 -18
  215. package/roles/preset-strategist-munger.md +2 -18
  216. package/roles/preset-strategist-sunzi.md +2 -18
  217. package/roles/preset-tester-beck.md +2 -18
  218. package/roles/preset-tester.md +5 -21
  219. package/roles/preset-writer-orwell.md +2 -18
  220. package/roles/preset-writer.md +2 -18
  221. package/roles/quant-simons.md +5 -32
  222. package/roles/queen.md +25 -41
  223. package/roles/reviewer-martin.md +11 -37
  224. package/roles/reviewer.md +20 -21
  225. package/roles/rhythm-tangsan.md +5 -29
  226. package/roles/risk-taleb.md +4 -32
  227. package/roles/script-shitiesheng.md +8 -31
  228. package/roles/storyboard-xuke.md +9 -29
  229. package/roles/strategist-soros.md +16 -73
  230. package/roles/tester-beck.md +4 -40
  231. package/roles/tester.md +5 -21
  232. package/roles/trader-jones.md +4 -32
  233. package/roles/vfx-guchangwei.md +8 -27
  234. package/roles/writer-zhouzi.md +7 -39
  235. package/templates/dev-team-pro.md +4 -1
  236. package/templates/dev-team.md +3 -1
  237. package/templates/minimal.md +2 -1
  238. package/templates/trading-team.md +6 -1
  239. package/templates/video-team.md +4 -1
  240. package/templates/writing-team.md +4 -1
@@ -0,0 +1,168 @@
1
+ import { InboxStore } from "./inbox-store.js";
2
+ import { createLogger } from "@mclawnet/logger";
3
+ const log = createLogger({ module: "swarm/inbox-relay" });
4
+ /**
5
+ * Escape a string for safe inclusion as an XML/HTML attribute value
6
+ * (between double quotes). Order matters: `&` must be replaced first.
7
+ */
8
+ function escapeXmlAttr(s) {
9
+ return s
10
+ .replace(/&/g, "&")
11
+ .replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;")
13
+ .replace(/"/g, "&quot;");
14
+ }
15
+ /**
16
+ * Escape body text so embedded `</message>` / `</info_for_agent>` cannot
17
+ * close the wrapping envelope. Only `<` and `&` need escaping for that.
18
+ */
19
+ function escapeXmlText(s) {
20
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;");
21
+ }
22
+ /**
23
+ * Wrap a batch of inbox messages into a single <info_for_agent> envelope.
24
+ * Host→agent direction; message body is free-form text per design §6.
25
+ */
26
+ function wrapAgentBlock(msgs) {
27
+ const body = msgs
28
+ .map((m) => {
29
+ const taskAttr = m.taskId ? ` taskId="${escapeXmlAttr(m.taskId)}"` : "";
30
+ return `<message from="${escapeXmlAttr(m.from)}" type="${escapeXmlAttr(m.type)}"${taskAttr} id="${escapeXmlAttr(m.id)}">\n${escapeXmlText(m.data)}\n</message>`;
31
+ })
32
+ .join("\n");
33
+ return `\n<info_for_agent>\n${body}\n</info_for_agent>\n`;
34
+ }
35
+ /**
36
+ * InboxRelay: pushes inbox messages to the target agent.
37
+ *
38
+ * Task 7: 4 gates implemented in runDeliver (liveness, lifecycle, single-flight,
39
+ * pending-echo). Single-flight gate sits in deliver(); the other three live
40
+ * inside runDeliver().
41
+ *
42
+ * Task 8 will fill in onAgentTurnSettled() to flush pendingEchoes and
43
+ * markDelivered() in the InboxStore.
44
+ */
45
+ export class InboxRelay {
46
+ sessionAdapter;
47
+ getSwarm;
48
+ messageInterceptor;
49
+ home;
50
+ inFlight = new Map();
51
+ // key → set of messageIds already pushed but awaiting turn-settled ack.
52
+ pendingEchoes = new Map();
53
+ constructor(sessionAdapter, getSwarm, messageInterceptor,
54
+ // Optional override for the user-home root (no `.clawnet` suffix).
55
+ // Threaded down to InboxStore so tests pinned to a tmpdir don't fall
56
+ // through to `homedir()` and write inbox files into the real `~/.clawnet`.
57
+ home) {
58
+ this.sessionAdapter = sessionAdapter;
59
+ this.getSwarm = getSwarm;
60
+ this.messageInterceptor = messageInterceptor;
61
+ this.home = home;
62
+ }
63
+ key(swarmId, instanceId) {
64
+ return `${swarmId}::${instanceId}`;
65
+ }
66
+ async deliver(swarmId, instanceId) {
67
+ const k = this.key(swarmId, instanceId);
68
+ const cur = this.inFlight.get(k);
69
+ if (cur)
70
+ return cur;
71
+ const p = this.runDeliver(swarmId, instanceId).finally(() => {
72
+ this.inFlight.delete(k);
73
+ });
74
+ this.inFlight.set(k, p);
75
+ return p;
76
+ }
77
+ async runDeliver(swarmId, instanceId) {
78
+ // Gate 1: liveness — swarm and role must exist with a workDir.
79
+ const swarm = this.getSwarm(swarmId);
80
+ if (!swarm || !swarm.workDir)
81
+ return;
82
+ const role = swarm.roles.get(instanceId);
83
+ if (!role)
84
+ return;
85
+ // Gate 2: lifecycle — skip agents that are still spawning or already stopped.
86
+ if (role.status === "spawning" || role.status === "stopped")
87
+ return;
88
+ // Read undelivered inbox.
89
+ const store = new InboxStore(swarm.workDir, swarmId, this.home);
90
+ const undelivered = await store.readUndelivered(instanceId);
91
+ if (undelivered.length === 0)
92
+ return;
93
+ // Interceptor pass — give the coordinator a chance to consume system
94
+ // envelopes (plan_review_result etc.) before they reach the LLM. A
95
+ // consumed message is filtered out of the LLM payload AND marked
96
+ // delivered so it does not re-fire on subsequent passes. Throwing
97
+ // interceptors are demoted to no-ops (fail open: message still flows).
98
+ const consumedIds = [];
99
+ const survived = [];
100
+ for (const m of undelivered) {
101
+ let consumed = false;
102
+ if (this.messageInterceptor) {
103
+ try {
104
+ consumed = await this.messageInterceptor(swarmId, instanceId, m);
105
+ }
106
+ catch (err) {
107
+ log.warn({ err, swarmId, instanceId, msgId: m.id, msgType: m.type }, "messageInterceptor threw — falling back to default delivery");
108
+ consumed = false;
109
+ }
110
+ }
111
+ if (consumed)
112
+ consumedIds.push(m.id);
113
+ else
114
+ survived.push(m);
115
+ }
116
+ // Persist consumption so consumed messages don't re-fire next pass.
117
+ if (consumedIds.length > 0) {
118
+ try {
119
+ await store.markDelivered(instanceId, consumedIds);
120
+ }
121
+ catch (err) {
122
+ log.warn({ err, swarmId, instanceId, count: consumedIds.length }, "markDelivered for consumed messages failed (best-effort)");
123
+ }
124
+ }
125
+ if (survived.length === 0)
126
+ return;
127
+ // Gate 3: pending-echo — drop messages already pushed but not yet ack'd.
128
+ const k = this.key(swarmId, instanceId);
129
+ const pending = this.pendingEchoes.get(k) ?? new Set();
130
+ const toPush = survived.filter((m) => !pending.has(m.id));
131
+ if (toPush.length === 0)
132
+ return;
133
+ // Push as a single <info_for_agent> envelope.
134
+ const payload = wrapAgentBlock(toPush);
135
+ this.sessionAdapter.sendInput(role.roleSessionId, payload);
136
+ for (const m of toPush)
137
+ pending.add(m.id);
138
+ this.pendingEchoes.set(k, pending);
139
+ }
140
+ /**
141
+ * Called when the host receives a `result` event signalling the agent
142
+ * finished a turn. Marks all messages currently in pendingEchoes as
143
+ * `delivered=true` in the InboxStore, clears the pending set, then triggers
144
+ * another deliver pass to flush any messages that arrived during the turn.
145
+ *
146
+ * Order: delete-before-mark — protects against (a) the next runDeliver
147
+ * stealing entries from pendingEchoes mid-flight, and (b) markDelivered
148
+ * throwing leaving stale ids in pendingEchoes (the inbox stays
149
+ * delivered=false so the next deliver re-pushes; markDelivered is idempotent).
150
+ */
151
+ async onAgentTurnSettled(swarmId, instanceId) {
152
+ const k = this.key(swarmId, instanceId);
153
+ const pending = this.pendingEchoes.get(k);
154
+ if (!pending || pending.size === 0)
155
+ return;
156
+ const swarm = this.getSwarm(swarmId);
157
+ if (!swarm?.workDir) {
158
+ this.pendingEchoes.delete(k);
159
+ return;
160
+ }
161
+ const ids = [...pending];
162
+ this.pendingEchoes.delete(k);
163
+ const store = new InboxStore(swarm.workDir, swarmId, this.home);
164
+ await store.markDelivered(instanceId, ids);
165
+ void this.deliver(swarmId, instanceId);
166
+ }
167
+ }
168
+ //# sourceMappingURL=inbox-relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-relay.js","sourceRoot":"","sources":["../src/inbox-relay.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAqB,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;AAoB1D;;;GAGG;AACH,SAAS,aAAa,CAAC,CAAS;IAC9B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,CAAS;IAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAoB;IAC1C,MAAM,IAAI,GAAG,IAAI;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,OAAO,kBAAkB,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,QAAQ,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;IAClK,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,uBAAuB,IAAI,uBAAuB,CAAC;AAC5D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,UAAU;IAMX;IACA;IACA;IAIA;IAXF,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IACpD,wEAAwE;IAChE,aAAa,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEvD,YACU,cAA8B,EAC9B,QAAwD,EACxD,kBAA4C;IACpD,mEAAmE;IACnE,qEAAqE;IACrE,2EAA2E;IACnE,IAAa;QANb,mBAAc,GAAd,cAAc,CAAgB;QAC9B,aAAQ,GAAR,QAAQ,CAAgD;QACxD,uBAAkB,GAAlB,kBAAkB,CAA0B;QAI5C,SAAI,GAAJ,IAAI,CAAS;IACpB,CAAC;IAEI,GAAG,CAAC,OAAe,EAAE,UAAkB;QAC7C,OAAO,GAAG,OAAO,KAAK,UAAU,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,UAAkB;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YAC1D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,UAAkB;QAC1D,+DAA+D;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,OAAO;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO;QAElB,8EAA8E;QAC9E,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QAEpE,0BAA0B;QAC1B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAErC,qEAAqE;QACrE,mEAAmE;QACnE,iEAAiE;QACjE,kEAAkE;QAClE,uEAAuE;QACvE,MAAM,WAAW,GAAa,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;gBACnE,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,IAAI,CACN,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,EAC1D,6DAA6D,CAC9D,CAAC;oBACF,QAAQ,GAAG,KAAK,CAAC;gBACnB,CAAC;YACH,CAAC;YACD,IAAI,QAAQ;gBAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;;gBAChC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;QAED,oEAAoE;QACpE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CACN,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,EACvD,0DAA0D,CAC3D,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAElC,yEAAyE;QACzE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QAC/D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEhC,8CAA8C;QAC9C,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAE3D,KAAK,MAAM,CAAC,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,UAAkB;QAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC;QACzB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,MAAM,KAAK,CAAC,aAAa,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAC3C,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,25 @@
1
+ export interface InboxMessage {
2
+ id: string;
3
+ from: string;
4
+ type: string;
5
+ data: string;
6
+ taskId?: string;
7
+ timestamp: number;
8
+ delivered: boolean;
9
+ deliveredAt?: number;
10
+ }
11
+ export declare class InboxStore {
12
+ private workDir;
13
+ private swarmId;
14
+ private homeOverride?;
15
+ constructor(workDir: string, swarmId: string, homeOverride?: string | undefined);
16
+ private home;
17
+ private inboxesDir;
18
+ private validateInstanceId;
19
+ inboxFile(instanceId: string): string;
20
+ readAll(instanceId: string): Promise<InboxMessage[]>;
21
+ append(instanceId: string, msg: InboxMessage): Promise<void>;
22
+ readUndelivered(instanceId: string): Promise<InboxMessage[]>;
23
+ markDelivered(instanceId: string, ids: string[]): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=inbox-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-store.d.ts","sourceRoot":"","sources":["../src/inbox-store.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,UAAU;IAQnB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,YAAY,CAAC;gBAFb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,YAAA;IAG/B,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,kBAAkB;IAM1B,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAK/B,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAUpD,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAe5D,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI5D,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAoBtE"}
@@ -0,0 +1,95 @@
1
+ import { join } from "node:path";
2
+ import { readFileSync, existsSync, writeFileSync, mkdirSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { projectRoot } from "@mclawnet/task";
5
+ import lockfile from "proper-lockfile";
6
+ const LOCK_OPTS = {
7
+ realpath: false,
8
+ retries: { retries: 50, minTimeout: 20, maxTimeout: 200 },
9
+ };
10
+ export class InboxStore {
11
+ workDir;
12
+ swarmId;
13
+ homeOverride;
14
+ // `home` is the user-home root (no `.clawnet` suffix). projectRoot() adds
15
+ // `.clawnet/projects/...` itself. When omitted we honour CLAWNET_HOME first,
16
+ // then fall back to the OS home — matches TaskStore for symmetry. Callers
17
+ // that already plumb a `rootDir` through ToolContext should pass it here so
18
+ // their writes land inside the test harness's tempdir instead of the real
19
+ // `~/.clawnet/projects/...`.
20
+ constructor(workDir, swarmId, homeOverride) {
21
+ this.workDir = workDir;
22
+ this.swarmId = swarmId;
23
+ this.homeOverride = homeOverride;
24
+ }
25
+ home() {
26
+ return this.homeOverride ?? process.env.CLAWNET_HOME ?? homedir();
27
+ }
28
+ inboxesDir() {
29
+ return join(projectRoot(this.workDir, this.home()), "swarms", this.swarmId, "inboxes");
30
+ }
31
+ validateInstanceId(id) {
32
+ if (!id || /[\\/]|\.\./.test(id) || id.includes("\0")) {
33
+ throw new Error(`InboxStore: invalid instanceId: ${JSON.stringify(id)}`);
34
+ }
35
+ }
36
+ inboxFile(instanceId) {
37
+ this.validateInstanceId(instanceId);
38
+ return join(this.inboxesDir(), `${instanceId}.json`);
39
+ }
40
+ async readAll(instanceId) {
41
+ const fp = this.inboxFile(instanceId);
42
+ if (!existsSync(fp))
43
+ return [];
44
+ try {
45
+ return JSON.parse(readFileSync(fp, "utf-8"));
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ }
51
+ async append(instanceId, msg) {
52
+ mkdirSync(this.inboxesDir(), { recursive: true });
53
+ const fp = this.inboxFile(instanceId);
54
+ if (!existsSync(fp))
55
+ writeFileSync(fp, "[]");
56
+ const release = await lockfile.lock(fp, LOCK_OPTS);
57
+ try {
58
+ const cur = JSON.parse(readFileSync(fp, "utf-8"));
59
+ if (cur.some(m => m.id === msg.id))
60
+ return;
61
+ cur.push(msg);
62
+ writeFileSync(fp, JSON.stringify(cur, null, 2));
63
+ }
64
+ finally {
65
+ await release();
66
+ }
67
+ }
68
+ async readUndelivered(instanceId) {
69
+ return (await this.readAll(instanceId)).filter(m => !m.delivered);
70
+ }
71
+ async markDelivered(instanceId, ids) {
72
+ if (ids.length === 0)
73
+ return;
74
+ const fp = this.inboxFile(instanceId);
75
+ if (!existsSync(fp))
76
+ return;
77
+ const release = await lockfile.lock(fp, LOCK_OPTS);
78
+ try {
79
+ const cur = JSON.parse(readFileSync(fp, "utf-8"));
80
+ const set = new Set(ids);
81
+ const now = Date.now();
82
+ for (const m of cur) {
83
+ if (set.has(m.id) && !m.delivered) {
84
+ m.delivered = true;
85
+ m.deliveredAt = now;
86
+ }
87
+ }
88
+ writeFileSync(fp, JSON.stringify(cur, null, 2));
89
+ }
90
+ finally {
91
+ await release();
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=inbox-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-store.js","sourceRoot":"","sources":["../src/inbox-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface InboxRelayLike {
2
+ deliver(swarmId: string, instanceId: string): Promise<void> | void;
3
+ }
4
+ export declare class InboxWatcher {
5
+ private relay;
6
+ private swarms;
7
+ constructor(relay: InboxRelayLike);
8
+ watch(swarmId: string, workDir: string): void;
9
+ unwatch(swarmId: string): void;
10
+ close(): void;
11
+ private schedule;
12
+ }
13
+ //# sourceMappingURL=inbox-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-watcher.d.ts","sourceRoot":"","sources":["../src/inbox-watcher.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACpE;AAiBD,qBAAa,YAAY;IAGX,OAAO,CAAC,KAAK;IAFzB,OAAO,CAAC,MAAM,CAAiC;gBAE3B,KAAK,EAAE,cAAc;IAEzC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA6B7C,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS9B,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,QAAQ;CAWjB"}
@@ -0,0 +1,89 @@
1
+ import { mkdirSync, watch } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { createLogger } from "@mclawnet/logger";
5
+ import { projectRoot as taskProjectRoot } from "@mclawnet/task";
6
+ const log = createLogger({ module: "swarm/inbox-watcher" });
7
+ const DEBOUNCE_MS = 50;
8
+ const VALID_ID_RE = /^[A-Za-z0-9_.-]+$/;
9
+ // Use the canonical layout from @mclawnet/task so the watcher observes the
10
+ // same directory the InboxStore writes into. Previously this used a local
11
+ // `join(home, "projects", ...)` (missing `.clawnet`), which silently created
12
+ // phantom dirs at ~/projects/... while real inboxes lived at ~/.clawnet/...,
13
+ // so fs.watch never fired and task_assigned messages stayed delivered:false.
14
+ function projectRoot(workDir) {
15
+ const home = process.env.CLAWNET_HOME ?? homedir();
16
+ return taskProjectRoot(workDir, home);
17
+ }
18
+ export class InboxWatcher {
19
+ relay;
20
+ swarms = new Map();
21
+ constructor(relay) {
22
+ this.relay = relay;
23
+ }
24
+ watch(swarmId, workDir) {
25
+ if (this.swarms.has(swarmId))
26
+ return;
27
+ const dir = join(projectRoot(workDir), "swarms", swarmId, "inboxes");
28
+ try {
29
+ mkdirSync(dir, { recursive: true });
30
+ }
31
+ catch (err) {
32
+ log.warn({ err, swarmId, dir }, "inbox-watcher: mkdir failed");
33
+ return;
34
+ }
35
+ let fsw;
36
+ try {
37
+ fsw = watch(dir, { persistent: false }, (_evt, filename) => {
38
+ if (!filename)
39
+ return;
40
+ const name = String(filename);
41
+ if (!name.endsWith(".json"))
42
+ return;
43
+ const id = name.slice(0, -".json".length);
44
+ if (!VALID_ID_RE.test(id))
45
+ return;
46
+ this.schedule(swarmId, id);
47
+ });
48
+ }
49
+ catch (err) {
50
+ log.warn({ err, swarmId, dir }, "inbox-watcher: fs.watch failed");
51
+ return;
52
+ }
53
+ fsw.on("error", (err) => {
54
+ log.warn({ err, swarmId }, "inbox-watcher: fs.watch error");
55
+ });
56
+ this.swarms.set(swarmId, { watcher: fsw, timers: new Map() });
57
+ }
58
+ unwatch(swarmId) {
59
+ const entry = this.swarms.get(swarmId);
60
+ if (!entry)
61
+ return;
62
+ for (const t of entry.timers.values())
63
+ clearTimeout(t);
64
+ entry.timers.clear();
65
+ try {
66
+ entry.watcher.close();
67
+ }
68
+ catch { /* ignore */ }
69
+ this.swarms.delete(swarmId);
70
+ }
71
+ close() {
72
+ for (const swarmId of [...this.swarms.keys()])
73
+ this.unwatch(swarmId);
74
+ }
75
+ schedule(swarmId, instanceId) {
76
+ const entry = this.swarms.get(swarmId);
77
+ if (!entry)
78
+ return;
79
+ const existing = entry.timers.get(instanceId);
80
+ if (existing)
81
+ clearTimeout(existing);
82
+ const timer = setTimeout(() => {
83
+ entry.timers.delete(instanceId);
84
+ Promise.resolve(this.relay.deliver(swarmId, instanceId)).catch(() => { });
85
+ }, DEBOUNCE_MS);
86
+ entry.timers.set(instanceId, timer);
87
+ }
88
+ }
89
+ //# sourceMappingURL=inbox-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-watcher.js","sourceRoot":"","sources":["../src/inbox-watcher.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,15 +1,20 @@
1
1
  export { SwarmCoordinator } from "./swarm-coordinator.js";
2
- export { LocalMessageRouter } from "./message-router.js";
3
- export type { MessageRouter } from "./message-router.js";
4
- export { parseSwarmActions } from "./action-parser.js";
5
2
  export { initRoles, loadRole, listRoles, buildRolePrompt, parseRoleFile } from "./roles/role-loader.js";
6
3
  export { saveSwarmSnapshot, loadSwarmSnapshot, deleteSwarmSnapshot, appendMessageLog, readMessageLog, listRecoverableSwarmIds, } from "./persistence.js";
7
4
  export type { SwarmSnapshot } from "./persistence.js";
8
5
  export { runRetrospective } from "./retrospective.js";
9
6
  export type { RetrospectiveResult, RoleEvaluation } from "./retrospective.js";
10
7
  export { listRecoverableSwarms, recoverSwarm } from "./recovery.js";
8
+ export { InboxStore } from "./inbox-store.js";
9
+ export type { InboxMessage } from "./inbox-store.js";
10
+ export { InboxRelay } from "./inbox-relay.js";
11
+ export { InboxWatcher, type InboxRelayLike as InboxWatcherRelayLike } from "./inbox-watcher.js";
11
12
  export type { SessionAdapter, HubAdapter, SwarmInstance, RoleInstance, SwarmAction, SwarmMessage, SwarmCreateOptions, RouteEndpoint, SwarmStatus, PlanStatus, } from "./types.js";
12
13
  export type { RoleDefinition, DelegationMap, DelegationEntry } from "./roles/types.js";
13
14
  export { initTemplates, listTemplates, loadTemplate } from "./templates/template-loader.js";
14
15
  export type { TemplateDefinition, TemplateRoleSpec } from "./templates/types.js";
16
+ export { listProjectDirs, resolveWorkDir, loadProjectSummary, loadSwarmSummaries, listAllProjectSummaries, } from "./projects-fs.js";
17
+ export type { TaskStatus, TaskCounts, ProjectSummary, SwarmSummary, } from "./projects-fs.js";
18
+ export { PROJECT_FILE_WHITELIST, isWhitelistedRelPath, listProjectFiles, readProjectFile, writeProjectFile, ProjectFilesError, } from "./project-files.js";
19
+ export type { ProjectFileRelPath, ProjectFileEntry, ProjectFileContent, } from "./project-files.js";
15
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEpE,YAAY,EACV,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,IAAI,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhG,YAAY,EACV,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EACL,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  // @mclawnet/swarm — Swarm coordination, message routing, and role management
2
2
  export { SwarmCoordinator } from "./swarm-coordinator.js";
3
- export { LocalMessageRouter } from "./message-router.js";
4
- export { parseSwarmActions } from "./action-parser.js";
5
3
  export { initRoles, loadRole, listRoles, buildRolePrompt, parseRoleFile } from "./roles/role-loader.js";
6
4
  export { saveSwarmSnapshot, loadSwarmSnapshot, deleteSwarmSnapshot, appendMessageLog, readMessageLog, listRecoverableSwarmIds, } from "./persistence.js";
7
5
  export { runRetrospective } from "./retrospective.js";
8
6
  export { listRecoverableSwarms, recoverSwarm } from "./recovery.js";
7
+ export { InboxStore } from "./inbox-store.js";
8
+ export { InboxRelay } from "./inbox-relay.js";
9
+ export { InboxWatcher } from "./inbox-watcher.js";
9
10
  export { initTemplates, listTemplates, loadTemplate } from "./templates/template-loader.js";
11
+ export { listProjectDirs, resolveWorkDir, loadProjectSummary, loadSwarmSummaries, listAllProjectSummaries, } from "./projects-fs.js";
12
+ export { PROJECT_FILE_WHITELIST, isWhitelistedRelPath, listProjectFiles, readProjectFile, writeProjectFile, ProjectFilesError, } from "./project-files.js";
10
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAiBpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAgD,MAAM,oBAAoB,CAAC;AAiBhG,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG5F,OAAO,EACL,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
@@ -3,22 +3,36 @@ export interface SwarmSnapshot {
3
3
  id: string;
4
4
  hubSessionId: string;
5
5
  workDir?: string;
6
+ teamName: string;
6
7
  roles: Array<{
7
8
  instanceId: string;
8
9
  roleName: string;
9
10
  status: string;
10
11
  currentTask?: string;
12
+ claudeSessionId?: string;
13
+ type?: "queen" | "worker";
11
14
  }>;
12
15
  plan: unknown;
13
16
  nextInstanceSeq: Record<string, number>;
14
17
  savedAt: number;
15
18
  status?: SwarmStatus;
16
19
  planStatus?: PlanStatus;
20
+ partialRecover?: boolean;
17
21
  }
18
22
  export declare function saveSwarmSnapshot(swarm: SwarmInstance): void;
19
- export declare function loadSwarmSnapshot(swarmId: string): SwarmSnapshot | null;
20
- export declare function deleteSwarmSnapshot(swarmId: string): void;
21
- export declare function readMessageLog(swarmId: string): object[];
22
- export declare function appendMessageLog(swarmId: string, entry: object): void;
23
- export declare function listRecoverableSwarmIds(): string[];
23
+ export declare function loadSwarmSnapshot(workDir: string, swarmId: string): SwarmSnapshot | null;
24
+ export declare function deleteSwarmSnapshot(workDir: string, swarmId: string): void;
25
+ export declare function readMessageLog(workDir: string, swarmId: string): object[];
26
+ export declare function appendMessageLog(workDir: string, swarmId: string, entry: object): void;
27
+ /**
28
+ * List recoverable swarms across all per-project roots. The authoritative
29
+ * `workDir` is read from each snapshot's `workDir` field (snapshots written
30
+ * since 0.1.6 always include it). Falling back on the encoded directory
31
+ * name is lossy for paths whose segments contain `-`, so we deliberately
32
+ * skip entries whose snapshot can't be parsed or doesn't carry `workDir`.
33
+ */
34
+ export declare function listRecoverableSwarmIds(): Array<{
35
+ workDir: string;
36
+ swarmId: string;
37
+ }>;
24
38
  //# sourceMappingURL=persistence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUzE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAoB5D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAQvE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKzD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBxD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIrE;AAED,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAMlD"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgBzE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;KAC3B,CAAC,CAAC;IACH,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CA2C5D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAgBxF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK1E;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBzE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAItF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAyCrF"}