reflectt-node 0.1.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 (486) hide show
  1. package/LICENSE +178 -0
  2. package/README.md +188 -0
  3. package/dist/activationEvents.d.ts +110 -0
  4. package/dist/activationEvents.d.ts.map +1 -0
  5. package/dist/activationEvents.js +378 -0
  6. package/dist/activationEvents.js.map +1 -0
  7. package/dist/activity-signal.d.ts +30 -0
  8. package/dist/activity-signal.d.ts.map +1 -0
  9. package/dist/activity-signal.js +93 -0
  10. package/dist/activity-signal.js.map +1 -0
  11. package/dist/alert-integrity.d.ts +100 -0
  12. package/dist/alert-integrity.d.ts.map +1 -0
  13. package/dist/alert-integrity.js +333 -0
  14. package/dist/alert-integrity.js.map +1 -0
  15. package/dist/alert-preflight.d.ts +40 -0
  16. package/dist/alert-preflight.d.ts.map +1 -0
  17. package/dist/alert-preflight.js +235 -0
  18. package/dist/alert-preflight.js.map +1 -0
  19. package/dist/analytics.d.ts +131 -0
  20. package/dist/analytics.d.ts.map +1 -0
  21. package/dist/analytics.js +371 -0
  22. package/dist/analytics.js.map +1 -0
  23. package/dist/artifact-mirror.d.ts +26 -0
  24. package/dist/artifact-mirror.d.ts.map +1 -0
  25. package/dist/artifact-mirror.js +170 -0
  26. package/dist/artifact-mirror.js.map +1 -0
  27. package/dist/artifact-resolver.d.ts +48 -0
  28. package/dist/artifact-resolver.d.ts.map +1 -0
  29. package/dist/artifact-resolver.js +164 -0
  30. package/dist/artifact-resolver.js.map +1 -0
  31. package/dist/assignment.d.ts +116 -0
  32. package/dist/assignment.d.ts.map +1 -0
  33. package/dist/assignment.js +475 -0
  34. package/dist/assignment.js.map +1 -0
  35. package/dist/auditLedger.d.ts +50 -0
  36. package/dist/auditLedger.d.ts.map +1 -0
  37. package/dist/auditLedger.js +136 -0
  38. package/dist/auditLedger.js.map +1 -0
  39. package/dist/boardHealthWorker.d.ts +134 -0
  40. package/dist/boardHealthWorker.d.ts.map +1 -0
  41. package/dist/boardHealthWorker.js +882 -0
  42. package/dist/boardHealthWorker.js.map +1 -0
  43. package/dist/bootstrap-team.d.ts +42 -0
  44. package/dist/bootstrap-team.d.ts.map +1 -0
  45. package/dist/bootstrap-team.js +111 -0
  46. package/dist/bootstrap-team.js.map +1 -0
  47. package/dist/buildInfo.d.ts +17 -0
  48. package/dist/buildInfo.d.ts.map +1 -0
  49. package/dist/buildInfo.js +56 -0
  50. package/dist/buildInfo.js.map +1 -0
  51. package/dist/calendar-events.d.ts +133 -0
  52. package/dist/calendar-events.d.ts.map +1 -0
  53. package/dist/calendar-events.js +615 -0
  54. package/dist/calendar-events.js.map +1 -0
  55. package/dist/calendar-ical.d.ts +41 -0
  56. package/dist/calendar-ical.d.ts.map +1 -0
  57. package/dist/calendar-ical.js +413 -0
  58. package/dist/calendar-ical.js.map +1 -0
  59. package/dist/calendar-reminder-engine.d.ts +10 -0
  60. package/dist/calendar-reminder-engine.d.ts.map +1 -0
  61. package/dist/calendar-reminder-engine.js +143 -0
  62. package/dist/calendar-reminder-engine.js.map +1 -0
  63. package/dist/calendar.d.ts +75 -0
  64. package/dist/calendar.d.ts.map +1 -0
  65. package/dist/calendar.js +391 -0
  66. package/dist/calendar.js.map +1 -0
  67. package/dist/canvas-multiplexer.d.ts +44 -0
  68. package/dist/canvas-multiplexer.d.ts.map +1 -0
  69. package/dist/canvas-multiplexer.js +150 -0
  70. package/dist/canvas-multiplexer.js.map +1 -0
  71. package/dist/canvas-slots.d.ts +83 -0
  72. package/dist/canvas-slots.d.ts.map +1 -0
  73. package/dist/canvas-slots.js +144 -0
  74. package/dist/canvas-slots.js.map +1 -0
  75. package/dist/canvas-types.d.ts +56 -0
  76. package/dist/canvas-types.d.ts.map +1 -0
  77. package/dist/canvas-types.js +54 -0
  78. package/dist/canvas-types.js.map +1 -0
  79. package/dist/cf-keepalive.d.ts +40 -0
  80. package/dist/cf-keepalive.d.ts.map +1 -0
  81. package/dist/cf-keepalive.js +153 -0
  82. package/dist/cf-keepalive.js.map +1 -0
  83. package/dist/changeFeed.d.ts +38 -0
  84. package/dist/changeFeed.d.ts.map +1 -0
  85. package/dist/changeFeed.js +324 -0
  86. package/dist/changeFeed.js.map +1 -0
  87. package/dist/channels.d.ts +28 -0
  88. package/dist/channels.d.ts.map +1 -0
  89. package/dist/channels.js +23 -0
  90. package/dist/channels.js.map +1 -0
  91. package/dist/chat-approval-detector.d.ts +47 -0
  92. package/dist/chat-approval-detector.d.ts.map +1 -0
  93. package/dist/chat-approval-detector.js +224 -0
  94. package/dist/chat-approval-detector.js.map +1 -0
  95. package/dist/chat.d.ts +119 -0
  96. package/dist/chat.d.ts.map +1 -0
  97. package/dist/chat.js +666 -0
  98. package/dist/chat.js.map +1 -0
  99. package/dist/cli.d.ts +3 -0
  100. package/dist/cli.d.ts.map +1 -0
  101. package/dist/cli.js +1142 -0
  102. package/dist/cli.js.map +1 -0
  103. package/dist/cloud.d.ts +45 -0
  104. package/dist/cloud.d.ts.map +1 -0
  105. package/dist/cloud.js +962 -0
  106. package/dist/cloud.js.map +1 -0
  107. package/dist/config.d.ts +17 -0
  108. package/dist/config.d.ts.map +1 -0
  109. package/dist/config.js +33 -0
  110. package/dist/config.js.map +1 -0
  111. package/dist/connectivity.d.ts +59 -0
  112. package/dist/connectivity.d.ts.map +1 -0
  113. package/dist/connectivity.js +173 -0
  114. package/dist/connectivity.js.map +1 -0
  115. package/dist/contacts.d.ts +59 -0
  116. package/dist/contacts.d.ts.map +1 -0
  117. package/dist/contacts.js +183 -0
  118. package/dist/contacts.js.map +1 -0
  119. package/dist/content.d.ts +130 -0
  120. package/dist/content.d.ts.map +1 -0
  121. package/dist/content.js +186 -0
  122. package/dist/content.js.map +1 -0
  123. package/dist/context-budget.d.ts +87 -0
  124. package/dist/context-budget.d.ts.map +1 -0
  125. package/dist/context-budget.js +459 -0
  126. package/dist/context-budget.js.map +1 -0
  127. package/dist/continuity-loop.d.ts +55 -0
  128. package/dist/continuity-loop.d.ts.map +1 -0
  129. package/dist/continuity-loop.js +267 -0
  130. package/dist/continuity-loop.js.map +1 -0
  131. package/dist/dashboard.d.ts +6 -0
  132. package/dist/dashboard.d.ts.map +1 -0
  133. package/dist/dashboard.js +2348 -0
  134. package/dist/dashboard.js.map +1 -0
  135. package/dist/db.d.ts +44 -0
  136. package/dist/db.d.ts.map +1 -0
  137. package/dist/db.js +648 -0
  138. package/dist/db.js.map +1 -0
  139. package/dist/doctor.d.ts +30 -0
  140. package/dist/doctor.d.ts.map +1 -0
  141. package/dist/doctor.js +159 -0
  142. package/dist/doctor.js.map +1 -0
  143. package/dist/duplicateClosureGuard.d.ts +31 -0
  144. package/dist/duplicateClosureGuard.d.ts.map +1 -0
  145. package/dist/duplicateClosureGuard.js +83 -0
  146. package/dist/duplicateClosureGuard.js.map +1 -0
  147. package/dist/embeddings.d.ts +13 -0
  148. package/dist/embeddings.d.ts.map +1 -0
  149. package/dist/embeddings.js +78 -0
  150. package/dist/embeddings.js.map +1 -0
  151. package/dist/escalation.d.ts +80 -0
  152. package/dist/escalation.d.ts.map +1 -0
  153. package/dist/escalation.js +213 -0
  154. package/dist/escalation.js.map +1 -0
  155. package/dist/events.d.ts +130 -0
  156. package/dist/events.d.ts.map +1 -0
  157. package/dist/events.js +382 -0
  158. package/dist/events.js.map +1 -0
  159. package/dist/executionSweeper.d.ts +97 -0
  160. package/dist/executionSweeper.d.ts.map +1 -0
  161. package/dist/executionSweeper.js +875 -0
  162. package/dist/executionSweeper.js.map +1 -0
  163. package/dist/experiments.d.ts +47 -0
  164. package/dist/experiments.d.ts.map +1 -0
  165. package/dist/experiments.js +133 -0
  166. package/dist/experiments.js.map +1 -0
  167. package/dist/feedback.d.ts +179 -0
  168. package/dist/feedback.d.ts.map +1 -0
  169. package/dist/feedback.js +397 -0
  170. package/dist/feedback.js.map +1 -0
  171. package/dist/files.d.ts +52 -0
  172. package/dist/files.d.ts.map +1 -0
  173. package/dist/files.js +172 -0
  174. package/dist/files.js.map +1 -0
  175. package/dist/format-duration.d.ts +19 -0
  176. package/dist/format-duration.d.ts.map +1 -0
  177. package/dist/format-duration.js +33 -0
  178. package/dist/format-duration.js.map +1 -0
  179. package/dist/github-actor-auth.d.ts +20 -0
  180. package/dist/github-actor-auth.d.ts.map +1 -0
  181. package/dist/github-actor-auth.js +54 -0
  182. package/dist/github-actor-auth.js.map +1 -0
  183. package/dist/github-ci.d.ts +16 -0
  184. package/dist/github-ci.d.ts.map +1 -0
  185. package/dist/github-ci.js +37 -0
  186. package/dist/github-ci.js.map +1 -0
  187. package/dist/github-identity.d.ts +30 -0
  188. package/dist/github-identity.d.ts.map +1 -0
  189. package/dist/github-identity.js +96 -0
  190. package/dist/github-identity.js.map +1 -0
  191. package/dist/github-reviews.d.ts +24 -0
  192. package/dist/github-reviews.d.ts.map +1 -0
  193. package/dist/github-reviews.js +56 -0
  194. package/dist/github-reviews.js.map +1 -0
  195. package/dist/health.d.ts +391 -0
  196. package/dist/health.d.ts.map +1 -0
  197. package/dist/health.js +1841 -0
  198. package/dist/health.js.map +1 -0
  199. package/dist/host-keepalive.d.ts +22 -0
  200. package/dist/host-keepalive.d.ts.map +1 -0
  201. package/dist/host-keepalive.js +126 -0
  202. package/dist/host-keepalive.js.map +1 -0
  203. package/dist/host-registry.d.ts +43 -0
  204. package/dist/host-registry.d.ts.map +1 -0
  205. package/dist/host-registry.js +93 -0
  206. package/dist/host-registry.js.map +1 -0
  207. package/dist/inbox.d.ts +87 -0
  208. package/dist/inbox.d.ts.map +1 -0
  209. package/dist/inbox.js +410 -0
  210. package/dist/inbox.js.map +1 -0
  211. package/dist/index.d.ts +2 -0
  212. package/dist/index.d.ts.map +1 -0
  213. package/dist/index.js +306 -0
  214. package/dist/index.js.map +1 -0
  215. package/dist/insight-mutation.d.ts +32 -0
  216. package/dist/insight-mutation.d.ts.map +1 -0
  217. package/dist/insight-mutation.js +160 -0
  218. package/dist/insight-mutation.js.map +1 -0
  219. package/dist/insight-promotion.d.ts +89 -0
  220. package/dist/insight-promotion.d.ts.map +1 -0
  221. package/dist/insight-promotion.js +278 -0
  222. package/dist/insight-promotion.js.map +1 -0
  223. package/dist/insight-task-bridge.d.ts +77 -0
  224. package/dist/insight-task-bridge.d.ts.map +1 -0
  225. package/dist/insight-task-bridge.js +556 -0
  226. package/dist/insight-task-bridge.js.map +1 -0
  227. package/dist/insights.d.ts +222 -0
  228. package/dist/insights.d.ts.map +1 -0
  229. package/dist/insights.js +871 -0
  230. package/dist/insights.js.map +1 -0
  231. package/dist/intake-pipeline.d.ts +74 -0
  232. package/dist/intake-pipeline.d.ts.map +1 -0
  233. package/dist/intake-pipeline.js +199 -0
  234. package/dist/intake-pipeline.js.map +1 -0
  235. package/dist/intensity.d.ts +31 -0
  236. package/dist/intensity.d.ts.map +1 -0
  237. package/dist/intensity.js +94 -0
  238. package/dist/intensity.js.map +1 -0
  239. package/dist/knowledge-auto-index.d.ts +37 -0
  240. package/dist/knowledge-auto-index.d.ts.map +1 -0
  241. package/dist/knowledge-auto-index.js +149 -0
  242. package/dist/knowledge-auto-index.js.map +1 -0
  243. package/dist/knowledge-docs.d.ts +45 -0
  244. package/dist/knowledge-docs.d.ts.map +1 -0
  245. package/dist/knowledge-docs.js +188 -0
  246. package/dist/knowledge-docs.js.map +1 -0
  247. package/dist/lane-config.d.ts +25 -0
  248. package/dist/lane-config.d.ts.map +1 -0
  249. package/dist/lane-config.js +105 -0
  250. package/dist/lane-config.js.map +1 -0
  251. package/dist/lineage.d.ts +86 -0
  252. package/dist/lineage.d.ts.map +1 -0
  253. package/dist/lineage.js +303 -0
  254. package/dist/lineage.js.map +1 -0
  255. package/dist/logStore.d.ts +25 -0
  256. package/dist/logStore.d.ts.map +1 -0
  257. package/dist/logStore.js +83 -0
  258. package/dist/logStore.js.map +1 -0
  259. package/dist/manage.d.ts +12 -0
  260. package/dist/manage.d.ts.map +1 -0
  261. package/dist/manage.js +253 -0
  262. package/dist/manage.js.map +1 -0
  263. package/dist/mcp.d.ts +5 -0
  264. package/dist/mcp.d.ts.map +1 -0
  265. package/dist/mcp.js +604 -0
  266. package/dist/mcp.js.map +1 -0
  267. package/dist/memory.d.ts +47 -0
  268. package/dist/memory.d.ts.map +1 -0
  269. package/dist/memory.js +149 -0
  270. package/dist/memory.js.map +1 -0
  271. package/dist/mention-ack.d.ts +80 -0
  272. package/dist/mention-ack.d.ts.map +1 -0
  273. package/dist/mention-ack.js +175 -0
  274. package/dist/mention-ack.js.map +1 -0
  275. package/dist/messageRouter.d.ts +60 -0
  276. package/dist/messageRouter.d.ts.map +1 -0
  277. package/dist/messageRouter.js +309 -0
  278. package/dist/messageRouter.js.map +1 -0
  279. package/dist/mutationAlert.d.ts +44 -0
  280. package/dist/mutationAlert.d.ts.map +1 -0
  281. package/dist/mutationAlert.js +174 -0
  282. package/dist/mutationAlert.js.map +1 -0
  283. package/dist/noise-budget.d.ts +136 -0
  284. package/dist/noise-budget.d.ts.map +1 -0
  285. package/dist/noise-budget.js +340 -0
  286. package/dist/noise-budget.js.map +1 -0
  287. package/dist/notifications.d.ts +67 -0
  288. package/dist/notifications.d.ts.map +1 -0
  289. package/dist/notifications.js +253 -0
  290. package/dist/notifications.js.map +1 -0
  291. package/dist/openclaw.d.ts +34 -0
  292. package/dist/openclaw.d.ts.map +1 -0
  293. package/dist/openclaw.js +208 -0
  294. package/dist/openclaw.js.map +1 -0
  295. package/dist/pause-controls.d.ts +31 -0
  296. package/dist/pause-controls.d.ts.map +1 -0
  297. package/dist/pause-controls.js +130 -0
  298. package/dist/pause-controls.js.map +1 -0
  299. package/dist/pidlock.d.ts +25 -0
  300. package/dist/pidlock.d.ts.map +1 -0
  301. package/dist/pidlock.js +179 -0
  302. package/dist/pidlock.js.map +1 -0
  303. package/dist/policy.d.ts +139 -0
  304. package/dist/policy.d.ts.map +1 -0
  305. package/dist/policy.js +264 -0
  306. package/dist/policy.js.map +1 -0
  307. package/dist/polls.d.ts +47 -0
  308. package/dist/polls.d.ts.map +1 -0
  309. package/dist/polls.js +162 -0
  310. package/dist/polls.js.map +1 -0
  311. package/dist/portability.d.ts +55 -0
  312. package/dist/portability.d.ts.map +1 -0
  313. package/dist/portability.js +292 -0
  314. package/dist/portability.js.map +1 -0
  315. package/dist/pr-integrity.d.ts +45 -0
  316. package/dist/pr-integrity.d.ts.map +1 -0
  317. package/dist/pr-integrity.js +124 -0
  318. package/dist/pr-integrity.js.map +1 -0
  319. package/dist/prAutoMerge.d.ts +62 -0
  320. package/dist/prAutoMerge.d.ts.map +1 -0
  321. package/dist/prAutoMerge.js +493 -0
  322. package/dist/prAutoMerge.js.map +1 -0
  323. package/dist/preflight.d.ts +66 -0
  324. package/dist/preflight.d.ts.map +1 -0
  325. package/dist/preflight.js +864 -0
  326. package/dist/preflight.js.map +1 -0
  327. package/dist/presence.d.ts +98 -0
  328. package/dist/presence.d.ts.map +1 -0
  329. package/dist/presence.js +347 -0
  330. package/dist/presence.js.map +1 -0
  331. package/dist/provisioning.d.ts +101 -0
  332. package/dist/provisioning.d.ts.map +1 -0
  333. package/dist/provisioning.js +430 -0
  334. package/dist/provisioning.js.map +1 -0
  335. package/dist/reflection-automation.d.ts +59 -0
  336. package/dist/reflection-automation.d.ts.map +1 -0
  337. package/dist/reflection-automation.js +350 -0
  338. package/dist/reflection-automation.js.map +1 -0
  339. package/dist/reflections.d.ts +65 -0
  340. package/dist/reflections.d.ts.map +1 -0
  341. package/dist/reflections.js +306 -0
  342. package/dist/reflections.js.map +1 -0
  343. package/dist/release.d.ts +67 -0
  344. package/dist/release.d.ts.map +1 -0
  345. package/dist/release.js +275 -0
  346. package/dist/release.js.map +1 -0
  347. package/dist/request-tracker.d.ts +36 -0
  348. package/dist/request-tracker.d.ts.map +1 -0
  349. package/dist/request-tracker.js +109 -0
  350. package/dist/request-tracker.js.map +1 -0
  351. package/dist/research.d.ts +75 -0
  352. package/dist/research.d.ts.map +1 -0
  353. package/dist/research.js +171 -0
  354. package/dist/research.js.map +1 -0
  355. package/dist/routing-approvals.d.ts +73 -0
  356. package/dist/routing-approvals.d.ts.map +1 -0
  357. package/dist/routing-approvals.js +88 -0
  358. package/dist/routing-approvals.js.map +1 -0
  359. package/dist/routing-override.d.ts +94 -0
  360. package/dist/routing-override.d.ts.map +1 -0
  361. package/dist/routing-override.js +290 -0
  362. package/dist/routing-override.js.map +1 -0
  363. package/dist/scope-routing.d.ts +18 -0
  364. package/dist/scope-routing.d.ts.map +1 -0
  365. package/dist/scope-routing.js +29 -0
  366. package/dist/scope-routing.js.map +1 -0
  367. package/dist/secrets.d.ts +77 -0
  368. package/dist/secrets.d.ts.map +1 -0
  369. package/dist/secrets.js +287 -0
  370. package/dist/secrets.js.map +1 -0
  371. package/dist/server.d.ts +3 -0
  372. package/dist/server.d.ts.map +1 -0
  373. package/dist/server.js +10887 -0
  374. package/dist/server.js.map +1 -0
  375. package/dist/service-probe.d.ts +53 -0
  376. package/dist/service-probe.d.ts.map +1 -0
  377. package/dist/service-probe.js +225 -0
  378. package/dist/service-probe.js.map +1 -0
  379. package/dist/shared-workspace-api.d.ts +73 -0
  380. package/dist/shared-workspace-api.d.ts.map +1 -0
  381. package/dist/shared-workspace-api.js +281 -0
  382. package/dist/shared-workspace-api.js.map +1 -0
  383. package/dist/shipped-heartbeat.d.ts +91 -0
  384. package/dist/shipped-heartbeat.d.ts.map +1 -0
  385. package/dist/shipped-heartbeat.js +272 -0
  386. package/dist/shipped-heartbeat.js.map +1 -0
  387. package/dist/starter-team.d.ts +23 -0
  388. package/dist/starter-team.d.ts.map +1 -0
  389. package/dist/starter-team.js +88 -0
  390. package/dist/starter-team.js.map +1 -0
  391. package/dist/suppression-ledger.d.ts +73 -0
  392. package/dist/suppression-ledger.d.ts.map +1 -0
  393. package/dist/suppression-ledger.js +125 -0
  394. package/dist/suppression-ledger.js.map +1 -0
  395. package/dist/system-loop-state.d.ts +4 -0
  396. package/dist/system-loop-state.d.ts.map +1 -0
  397. package/dist/system-loop-state.js +40 -0
  398. package/dist/system-loop-state.js.map +1 -0
  399. package/dist/taskCommentIngest.d.ts +43 -0
  400. package/dist/taskCommentIngest.d.ts.map +1 -0
  401. package/dist/taskCommentIngest.js +59 -0
  402. package/dist/taskCommentIngest.js.map +1 -0
  403. package/dist/taskPrecheck.d.ts +20 -0
  404. package/dist/taskPrecheck.d.ts.map +1 -0
  405. package/dist/taskPrecheck.js +329 -0
  406. package/dist/taskPrecheck.js.map +1 -0
  407. package/dist/taskStateSync.d.ts +8 -0
  408. package/dist/taskStateSync.d.ts.map +1 -0
  409. package/dist/taskStateSync.js +79 -0
  410. package/dist/taskStateSync.js.map +1 -0
  411. package/dist/tasks.d.ts +140 -0
  412. package/dist/tasks.d.ts.map +1 -0
  413. package/dist/tasks.js +1281 -0
  414. package/dist/tasks.js.map +1 -0
  415. package/dist/team-config.d.ts +24 -0
  416. package/dist/team-config.d.ts.map +1 -0
  417. package/dist/team-config.js +221 -0
  418. package/dist/team-config.js.map +1 -0
  419. package/dist/team-doctor.d.ts +22 -0
  420. package/dist/team-doctor.d.ts.map +1 -0
  421. package/dist/team-doctor.js +270 -0
  422. package/dist/team-doctor.js.map +1 -0
  423. package/dist/team-pulse.d.ts +52 -0
  424. package/dist/team-pulse.d.ts.map +1 -0
  425. package/dist/team-pulse.js +176 -0
  426. package/dist/team-pulse.js.map +1 -0
  427. package/dist/telemetry.d.ts +74 -0
  428. package/dist/telemetry.d.ts.map +1 -0
  429. package/dist/telemetry.js +256 -0
  430. package/dist/telemetry.js.map +1 -0
  431. package/dist/test-task-filter.d.ts +21 -0
  432. package/dist/test-task-filter.d.ts.map +1 -0
  433. package/dist/test-task-filter.js +48 -0
  434. package/dist/test-task-filter.js.map +1 -0
  435. package/dist/types.d.ts +126 -0
  436. package/dist/types.d.ts.map +1 -0
  437. package/dist/types.js +4 -0
  438. package/dist/types.js.map +1 -0
  439. package/dist/usage-tracking.d.ts +101 -0
  440. package/dist/usage-tracking.d.ts.map +1 -0
  441. package/dist/usage-tracking.js +325 -0
  442. package/dist/usage-tracking.js.map +1 -0
  443. package/dist/vector-store.d.ts +87 -0
  444. package/dist/vector-store.d.ts.map +1 -0
  445. package/dist/vector-store.js +247 -0
  446. package/dist/vector-store.js.map +1 -0
  447. package/dist/watchdog/idleNudgeLane.d.ts +22 -0
  448. package/dist/watchdog/idleNudgeLane.d.ts.map +1 -0
  449. package/dist/watchdog/idleNudgeLane.js +98 -0
  450. package/dist/watchdog/idleNudgeLane.js.map +1 -0
  451. package/dist/webhooks.d.ts +103 -0
  452. package/dist/webhooks.d.ts.map +1 -0
  453. package/dist/webhooks.js +398 -0
  454. package/dist/webhooks.js.map +1 -0
  455. package/dist/working-contract.d.ts +42 -0
  456. package/dist/working-contract.d.ts.map +1 -0
  457. package/dist/working-contract.js +228 -0
  458. package/dist/working-contract.js.map +1 -0
  459. package/dist/ws-heartbeat.d.ts +66 -0
  460. package/dist/ws-heartbeat.d.ts.map +1 -0
  461. package/dist/ws-heartbeat.js +174 -0
  462. package/dist/ws-heartbeat.js.map +1 -0
  463. package/package.json +87 -0
  464. package/plugins/reflectt-channel/README.md +96 -0
  465. package/plugins/reflectt-channel/index.ts +789 -0
  466. package/plugins/reflectt-channel/openclaw.plugin.json +23 -0
  467. package/plugins/reflectt-channel/package.json +23 -0
  468. package/plugins/reflectt-channel/src/channel.ts +433 -0
  469. package/plugins/reflectt-channel/src/types.ts +29 -0
  470. package/public/avatars/echo.png +0 -0
  471. package/public/avatars/harmony.png +0 -0
  472. package/public/avatars/kai.png +0 -0
  473. package/public/avatars/link.png +0 -0
  474. package/public/avatars/pixel.png +0 -0
  475. package/public/avatars/rhythm.png +0 -0
  476. package/public/avatars/ryan.png +0 -0
  477. package/public/avatars/sage.png +0 -0
  478. package/public/avatars/scout.png +0 -0
  479. package/public/avatars/spark.png +0 -0
  480. package/public/dashboard-animations.css +381 -0
  481. package/public/dashboard.js +3479 -0
  482. package/public/docs.md +1062 -0
  483. package/public/file-upload-mock.html +1097 -0
  484. package/public/og-card.png +0 -0
  485. package/public/ui-kit.html +318 -0
  486. package/public/widget/feedback.js +194 -0
package/dist/cloud.js ADDED
@@ -0,0 +1,962 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) Reflectt AI
3
+ /**
4
+ * Cloud Integration Module
5
+ *
6
+ * Connects reflectt-node to Reflectt Cloud via @reflectt/host-agent SDK.
7
+ * When REFLECTT_HOST_TOKEN is set, this module:
8
+ * 1. Registers with the cloud on startup
9
+ * 2. Sends periodic heartbeats with agent presence + task counts
10
+ * 3. Syncs local task state to the cloud
11
+ *
12
+ * When env vars are not set, this module does nothing (graceful skip).
13
+ */
14
+ import { presenceManager } from './presence.js';
15
+ import { taskManager } from './tasks.js';
16
+ import { chatManager } from './chat.js';
17
+ import { slotManager } from './canvas-slots.js';
18
+ import { getDb } from './db.js';
19
+ import { getUsageSummary, getUsageByAgent, getUsageByModel, listCaps, checkCaps, getRoutingSuggestions } from './usage-tracking.js';
20
+ import { readFileSync, existsSync, watch } from 'fs';
21
+ import { join } from 'path';
22
+ import { REFLECTT_HOME } from './config.js';
23
+ /**
24
+ * Docker identity guard: detect when a container has inherited cloud
25
+ * credentials from a host volume mount. Without explicit opt-in, skip
26
+ * cloud integration to prevent the container from silently appearing
27
+ * as the host team.
28
+ */
29
+ function isDockerIdentityInherited(fileConfig) {
30
+ // Only applies inside Docker
31
+ const isDocker = existsSync('/.dockerenv') || process.env.REFLECTT_HOME === '/data';
32
+ if (!isDocker)
33
+ return false;
34
+ // If credentials come from env vars (not config.json), the user explicitly set them — allow
35
+ if (process.env.REFLECTT_HOST_TOKEN || process.env.REFLECTT_HOST_ID)
36
+ return false;
37
+ // If config.json has cloud credentials and user didn't opt in, flag it
38
+ if (fileConfig?.hostId && fileConfig?.credential) {
39
+ if (process.env.REFLECTT_INHERIT_IDENTITY === '1' || process.env.REFLECTT_INHERIT_IDENTITY === 'true') {
40
+ console.log(`☁️ Docker identity guard: inheriting identity from config.json (REFLECTT_INHERIT_IDENTITY=1)`);
41
+ console.log(` Host: ${fileConfig.hostName || 'unnamed'} (hostId: ${fileConfig.hostId})`);
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+ const DEFAULT_HEARTBEAT_MS = 30_000;
49
+ const DEFAULT_TASK_SYNC_MS = 60_000;
50
+ const DEFAULT_CHAT_SYNC_MS = 5_000;
51
+ const DEFAULT_CHAT_SYNC_MIN_INTERVAL_MS = 1_500;
52
+ const DEFAULT_CHAT_SYNC_MAX_BACKOFF_MS = 30_000;
53
+ // Adaptive sync: idle detection + interval scaling
54
+ const IDLE_THRESHOLD_MS = 2 * 60_000; // 2 min without activity → idle mode
55
+ const IDLE_SYNC_MS = 60_000; // Slow sync when idle (60s)
56
+ const ACTIVE_CANVAS_SYNC_MS = 5_000; // Fast canvas sync when active
57
+ const ACTIVE_USAGE_SYNC_MS = 15_000; // Fast usage sync when active
58
+ let lastActivityAt = Date.now();
59
+ /** Mark recent activity (call from event handlers) */
60
+ export function markCloudActivity() {
61
+ lastActivityAt = Date.now();
62
+ }
63
+ /** Check if the system is idle */
64
+ function isIdle() {
65
+ return Date.now() - lastActivityAt > IDLE_THRESHOLD_MS;
66
+ }
67
+ let config = null;
68
+ let state = {
69
+ hostId: null,
70
+ credential: null,
71
+ heartbeatTimer: null,
72
+ taskSyncTimer: null,
73
+ chatSyncTimer: null,
74
+ canvasSyncTimer: null,
75
+ usageSyncTimer: null,
76
+ heartbeatCount: 0,
77
+ lastHeartbeat: null,
78
+ lastTaskSync: null,
79
+ lastChatSync: null,
80
+ lastCanvasSync: null,
81
+ errors: 0,
82
+ running: false,
83
+ startedAt: Date.now(),
84
+ };
85
+ let configWatcher = null;
86
+ /**
87
+ * Load cloud config from ~/.reflectt/config.json (written by `reflectt host connect`)
88
+ */
89
+ function loadCloudConfigFromFile() {
90
+ try {
91
+ const configPath = join(REFLECTT_HOME, 'config.json');
92
+ if (!existsSync(configPath))
93
+ return null;
94
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
95
+ if (!config?.cloud)
96
+ return null;
97
+ return {
98
+ cloudUrl: config.cloud.cloudUrl,
99
+ hostId: config.cloud.hostId,
100
+ credential: config.cloud.credential,
101
+ hostName: config.cloud.hostName,
102
+ hostType: config.cloud.hostType,
103
+ };
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Check if cloud integration is configured
111
+ */
112
+ export function isCloudConfigured() {
113
+ // Check env vars first
114
+ if (process.env.REFLECTT_HOST_TOKEN)
115
+ return true;
116
+ if (process.env.REFLECTT_HOST_ID && process.env.REFLECTT_HOST_CREDENTIAL)
117
+ return true;
118
+ // Check config.json (written by `reflectt host connect`)
119
+ const fileConfig = loadCloudConfigFromFile();
120
+ return Boolean(fileConfig?.hostId && fileConfig?.credential);
121
+ }
122
+ /**
123
+ * Get current cloud connection status
124
+ */
125
+ export function getCloudStatus() {
126
+ const configured = isCloudConfigured();
127
+ const registered = state.hostId !== null;
128
+ const connected = registered && state.running && state.heartbeatCount > 0;
129
+ // Derive a user-friendly connection phase for the UI
130
+ let phase;
131
+ if (!configured)
132
+ phase = 'unconfigured';
133
+ else if (state.errors > 0 && !connected)
134
+ phase = 'error';
135
+ else if (!registered)
136
+ phase = 'registering';
137
+ else if (!connected)
138
+ phase = 'configured';
139
+ else
140
+ phase = 'connected';
141
+ // Sync health: count dirty/pending records
142
+ let dirtyTaskCount = 0;
143
+ try {
144
+ const db = getDb();
145
+ const row = db.prepare("SELECT COUNT(*) as cnt FROM sync_ledger WHERE record_type='task' AND (cloud_synced_at IS NULL OR cloud_synced_at < local_updated_at OR sync_status != 'synced')").get();
146
+ dirtyTaskCount = row.cnt;
147
+ }
148
+ catch { /* DB may not be ready */ }
149
+ return {
150
+ configured,
151
+ registered,
152
+ connected,
153
+ phase,
154
+ hostId: state.hostId,
155
+ running: state.running,
156
+ heartbeatCount: state.heartbeatCount,
157
+ lastHeartbeat: state.lastHeartbeat,
158
+ lastTaskSync: state.lastTaskSync,
159
+ lastChatSync: state.lastChatSync,
160
+ lastCanvasSync: state.lastCanvasSync,
161
+ errors: state.errors,
162
+ uptimeMs: state.running ? Date.now() - state.startedAt : 0,
163
+ syncHealth: {
164
+ dirtyTaskCount,
165
+ healthy: dirtyTaskCount < 50,
166
+ },
167
+ };
168
+ }
169
+ /**
170
+ * Initialize and start cloud integration.
171
+ * Call this after the server is listening.
172
+ */
173
+ export async function startCloudIntegration() {
174
+ if (!isCloudConfigured()) {
175
+ console.log('☁️ Cloud integration: skipped (REFLECTT_HOST_TOKEN not set)');
176
+ return;
177
+ }
178
+ // Load from env vars first, then fall back to config.json
179
+ const fileConfig = loadCloudConfigFromFile();
180
+ // Docker identity guard: refuse to connect with inherited credentials
181
+ if (isDockerIdentityInherited(fileConfig)) {
182
+ console.warn('');
183
+ console.warn('⚠️ Docker identity guard: found cloud credentials in config.json');
184
+ console.warn(` This container would connect as "${fileConfig?.hostName || 'unknown'}" (hostId: ${fileConfig?.hostId})`);
185
+ console.warn(' This likely means you mounted a host directory containing existing team data.');
186
+ console.warn('');
187
+ console.warn(' To fix:');
188
+ console.warn(' • Use a named volume (docker-compose default) for a clean identity');
189
+ console.warn(' • Or set REFLECTT_INHERIT_IDENTITY=1 to intentionally reuse this identity');
190
+ console.warn('');
191
+ console.warn(' Cloud integration skipped to prevent identity collision.');
192
+ console.warn('');
193
+ return;
194
+ }
195
+ config = {
196
+ cloudUrl: (process.env.REFLECTT_CLOUD_URL || fileConfig?.cloudUrl || 'https://api.reflectt.ai').replace(/\/+$/, ''),
197
+ token: process.env.REFLECTT_HOST_TOKEN || '',
198
+ hostName: process.env.REFLECTT_HOST_NAME || fileConfig?.hostName || 'unnamed-host',
199
+ hostType: process.env.REFLECTT_HOST_TYPE || fileConfig?.hostType || 'openclaw',
200
+ heartbeatIntervalMs: Number(process.env.REFLECTT_HEARTBEAT_MS) || DEFAULT_HEARTBEAT_MS,
201
+ taskSyncIntervalMs: Number(process.env.REFLECTT_TASK_SYNC_MS) || DEFAULT_TASK_SYNC_MS,
202
+ capabilities: (process.env.REFLECTT_HOST_CAPABILITIES || 'tasks,chat,presence').split(',').map(s => s.trim()),
203
+ };
204
+ console.log(`☁️ Cloud integration: connecting to ${config.cloudUrl}`);
205
+ console.log(` Host: ${config.hostName} (${config.hostType})`);
206
+ if (fileConfig?.hostId)
207
+ console.log(` Source: config.json (auto-connect from host connect)`);
208
+ // Check if we already have a persisted host ID + credential (env or config.json)
209
+ const persistedHostId = process.env.REFLECTT_HOST_ID || fileConfig?.hostId;
210
+ const persistedCredential = process.env.REFLECTT_HOST_CREDENTIAL || fileConfig?.credential;
211
+ if (persistedHostId && persistedCredential) {
212
+ state.hostId = persistedHostId;
213
+ state.credential = persistedCredential;
214
+ console.log(` ✅ Using persisted credential (hostId: ${state.hostId})`);
215
+ }
216
+ else {
217
+ // Register with cloud via /api/hosts/claim
218
+ // Cloud API expects: { joinToken, name, capabilities? }
219
+ // Cloud API returns: { host: { id, ... }, credential: { token, revealPolicy } }
220
+ try {
221
+ const result = await cloudPost('/api/hosts/claim', {
222
+ joinToken: config.token,
223
+ name: config.hostName,
224
+ capabilities: config.capabilities,
225
+ });
226
+ if (result.data?.host?.id && result.data?.credential?.token) {
227
+ state.hostId = result.data.host.id;
228
+ state.credential = result.data.credential.token;
229
+ console.log(` ✅ Registered (hostId: ${state.hostId})`);
230
+ }
231
+ else {
232
+ console.warn(` ⚠ Registration failed: ${result.error || 'unexpected response shape'}`);
233
+ state.errors++;
234
+ return;
235
+ }
236
+ }
237
+ catch (err) {
238
+ console.warn(` ⚠ Registration failed: ${err?.message || 'network error'}`);
239
+ state.errors++;
240
+ return;
241
+ }
242
+ }
243
+ // Start loops
244
+ state.running = true;
245
+ state.startedAt = Date.now();
246
+ // Immediate first heartbeat
247
+ sendHeartbeat().catch(() => { });
248
+ state.heartbeatTimer = setInterval(() => {
249
+ sendHeartbeat().catch(() => { });
250
+ pollAndProcessCommands().catch(() => { }); // Piggyback on heartbeat tick
251
+ }, config.heartbeatIntervalMs);
252
+ state.taskSyncTimer = setInterval(() => {
253
+ syncTasks().catch(() => { });
254
+ }, config.taskSyncIntervalMs);
255
+ // Chat sync — event-driven with adaptive polling fallback
256
+ // When active: 5s poll. When idle: 60s poll. Events always trigger immediate sync.
257
+ const chatSyncActiveMs = Number(process.env.REFLECTT_CHAT_SYNC_MS) || DEFAULT_CHAT_SYNC_MS;
258
+ let lastChatPollAt = 0;
259
+ requestChatSync('startup').catch(() => { });
260
+ state.chatSyncTimer = setInterval(() => {
261
+ const now = Date.now();
262
+ const interval = isIdle() ? IDLE_SYNC_MS : chatSyncActiveMs;
263
+ if (now - lastChatPollAt < interval)
264
+ return;
265
+ lastChatPollAt = now;
266
+ requestChatSync('interval').catch(() => { });
267
+ }, chatSyncActiveMs);
268
+ // Event-driven: sync immediately when new messages arrive (debounced 500ms)
269
+ let chatSyncDebounce = null;
270
+ chatManager.subscribe(() => {
271
+ if (!state.running)
272
+ return;
273
+ markCloudActivity(); // Mark as active on new chat
274
+ if (chatSyncDebounce)
275
+ clearTimeout(chatSyncDebounce);
276
+ chatSyncDebounce = setTimeout(() => {
277
+ requestChatSync('event').catch(() => { });
278
+ }, 500);
279
+ });
280
+ // Task changes also mark activity (ensures burst mode on task updates)
281
+ taskManager.subscribe(() => {
282
+ if (!state.running)
283
+ return;
284
+ markCloudActivity();
285
+ });
286
+ // Canvas slot updates mark activity (ensures burst mode on canvas changes)
287
+ slotManager.subscribe(() => {
288
+ if (!state.running)
289
+ return;
290
+ markCloudActivity();
291
+ });
292
+ // Canvas sync — adaptive: 5s when active, 60s when idle
293
+ // Uses a single 5s tick that skips when idle (unless enough time has passed)
294
+ let lastCanvasSyncAt = 0;
295
+ syncCanvas().catch(() => { });
296
+ state.canvasSyncTimer = setInterval(() => {
297
+ const now = Date.now();
298
+ const interval = isIdle() ? IDLE_SYNC_MS : ACTIVE_CANVAS_SYNC_MS;
299
+ if (now - lastCanvasSyncAt < interval)
300
+ return;
301
+ lastCanvasSyncAt = now;
302
+ syncCanvas().catch(() => { });
303
+ }, ACTIVE_CANVAS_SYNC_MS);
304
+ // Usage sync — adaptive: 15s when active, 60s when idle
305
+ let lastUsageSyncAt = 0;
306
+ syncUsage().catch(() => { });
307
+ state.usageSyncTimer = setInterval(() => {
308
+ const now = Date.now();
309
+ const interval = isIdle() ? IDLE_SYNC_MS : ACTIVE_USAGE_SYNC_MS;
310
+ if (now - lastUsageSyncAt < interval)
311
+ return;
312
+ lastUsageSyncAt = now;
313
+ syncUsage().catch(() => { });
314
+ }, ACTIVE_USAGE_SYNC_MS);
315
+ // Command polling — adaptive: 10s active, 60s idle
316
+ // Uses the same tick as canvas (5s) with interval gate
317
+ pollAndProcessCommands().catch(() => { });
318
+ console.log(` ✅ Heartbeat every ${config.heartbeatIntervalMs / 1000}s, task sync every ${config.taskSyncIntervalMs / 1000}s`);
319
+ console.log(` 📊 Adaptive sync: chat/canvas/usage ${chatSyncActiveMs / 1000}s active → ${IDLE_SYNC_MS / 1000}s idle (idle after ${IDLE_THRESHOLD_MS / 1000}s)`);
320
+ console.log(` 📬 Command polling: ${COMMAND_POLL_ACTIVE_MS / 1000}s active → ${COMMAND_POLL_IDLE_MS / 1000}s idle`);
321
+ }
322
+ /**
323
+ * Stop cloud integration (call on shutdown)
324
+ */
325
+ /**
326
+ * Watch config.json for changes and auto-start cloud integration.
327
+ * Enables zero-restart enrollment: agent writes config.json via
328
+ * `reflectt host connect`, running server auto-detects and connects.
329
+ */
330
+ export function watchConfigForCloudChanges() {
331
+ if (configWatcher)
332
+ return;
333
+ try {
334
+ let debounce = null;
335
+ configWatcher = watch(join(REFLECTT_HOME), { persistent: false }, (_event, filename) => {
336
+ if (filename !== 'config.json')
337
+ return;
338
+ if (debounce)
339
+ clearTimeout(debounce);
340
+ debounce = setTimeout(async () => {
341
+ debounce = null;
342
+ if (state.running)
343
+ return; // already connected, skip
344
+ const fileConfig = loadCloudConfigFromFile();
345
+ if (!fileConfig?.hostId || !fileConfig?.credential)
346
+ return;
347
+ console.log('☁️ Config change detected — auto-starting cloud integration...');
348
+ try {
349
+ await startCloudIntegration();
350
+ }
351
+ catch (err) {
352
+ console.warn(`☁️ Cloud auto-start failed: ${err?.message || err}`);
353
+ }
354
+ }, 1000);
355
+ });
356
+ console.log(`☁️ Watching ${REFLECTT_HOME}/config.json for cloud config changes`);
357
+ }
358
+ catch (err) {
359
+ console.warn(`☁️ Config watcher setup failed: ${err?.message || err}`);
360
+ }
361
+ }
362
+ export function stopConfigWatcher() {
363
+ if (configWatcher) {
364
+ configWatcher.close();
365
+ configWatcher = null;
366
+ }
367
+ }
368
+ export function stopCloudIntegration() {
369
+ state.running = false;
370
+ if (state.heartbeatTimer) {
371
+ clearInterval(state.heartbeatTimer);
372
+ state.heartbeatTimer = null;
373
+ }
374
+ if (state.taskSyncTimer) {
375
+ clearInterval(state.taskSyncTimer);
376
+ state.taskSyncTimer = null;
377
+ }
378
+ if (state.chatSyncTimer) {
379
+ clearInterval(state.chatSyncTimer);
380
+ state.chatSyncTimer = null;
381
+ }
382
+ if (state.canvasSyncTimer) {
383
+ clearInterval(state.canvasSyncTimer);
384
+ state.canvasSyncTimer = null;
385
+ }
386
+ if (state.usageSyncTimer) {
387
+ clearInterval(state.usageSyncTimer);
388
+ state.usageSyncTimer = null;
389
+ }
390
+ console.log('☁️ Cloud integration: stopped');
391
+ }
392
+ // ---- Data providers ----
393
+ function getAgents() {
394
+ const presences = presenceManager.getAllPresence();
395
+ return presences.map(p => ({
396
+ name: p.agent,
397
+ status: p.status === 'working' || p.status === 'reviewing' ? 'active'
398
+ : p.status === 'offline' ? 'offline'
399
+ : 'idle',
400
+ currentTask: p.task,
401
+ lastSeen: p.lastUpdate,
402
+ }));
403
+ }
404
+ function getTasks() {
405
+ const tasks = taskManager.listTasks({});
406
+ return tasks.map(t => ({
407
+ id: t.id,
408
+ title: t.title,
409
+ status: t.status,
410
+ assignee: t.assignee,
411
+ priority: t.priority,
412
+ updatedAt: t.updatedAt || t.createdAt,
413
+ }));
414
+ }
415
+ // ---- Cloud communication ----
416
+ async function sendHeartbeat() {
417
+ if (!state.hostId || !config)
418
+ return;
419
+ const agents = getAgents();
420
+ const tasks = getTasks();
421
+ const doingTasks = tasks.filter(t => t.status === 'doing');
422
+ // Cloud API: POST /api/hosts/:hostId/heartbeat
423
+ // Expects: { status, agents?, activeTasks? }
424
+ const hostStatus = agents.some(a => a.status === 'active') ? 'online'
425
+ : agents.length > 0 ? 'degraded'
426
+ : 'online';
427
+ const result = await cloudPost(`/api/hosts/${state.hostId}/heartbeat`, {
428
+ contractVersion: 'host-heartbeat.v1',
429
+ status: hostStatus,
430
+ timestamp: Date.now(),
431
+ agents: agents.map(a => ({
432
+ id: a.name,
433
+ name: a.name,
434
+ status: a.status,
435
+ currentTaskId: a.currentTask || undefined,
436
+ lastSeenAt: a.lastSeen || Date.now(),
437
+ })),
438
+ activeTasks: doingTasks.map(t => ({
439
+ id: t.id,
440
+ title: t.title,
441
+ status: t.status,
442
+ assignee: t.assignee || undefined,
443
+ priority: t.priority || undefined,
444
+ updatedAt: t.updatedAt || Date.now(),
445
+ })),
446
+ source: {
447
+ hostId: state.hostId,
448
+ hostName: config.hostName,
449
+ hostType: config.hostType,
450
+ uptimeMs: Date.now() - state.startedAt,
451
+ },
452
+ });
453
+ if (result.success || result.data) {
454
+ state.lastHeartbeat = Date.now();
455
+ state.heartbeatCount++;
456
+ // Reset consecutive error count on success
457
+ if (state.errors > 0) {
458
+ console.log(`☁️ Heartbeat recovered after ${state.errors} errors`);
459
+ state.errors = 0;
460
+ }
461
+ }
462
+ else {
463
+ state.errors++;
464
+ if (state.errors <= 5 || state.errors % 20 === 0) {
465
+ console.warn(`☁️ Heartbeat failed (${state.errors} consecutive): ${result.error}`);
466
+ }
467
+ }
468
+ }
469
+ function refreshTaskLedger(tasks) {
470
+ const db = getDb();
471
+ const snapshotIds = new Set(tasks.map((task) => task.id));
472
+ const upsert = db.prepare(`
473
+ INSERT INTO sync_ledger (
474
+ record_type,
475
+ record_id,
476
+ local_updated_at,
477
+ cloud_synced_at,
478
+ sync_status,
479
+ attempt_count,
480
+ last_error
481
+ ) VALUES ('task', ?, ?, NULL, 'pending', 0, NULL)
482
+ ON CONFLICT(record_type, record_id) DO UPDATE SET
483
+ local_updated_at = excluded.local_updated_at,
484
+ sync_status = CASE
485
+ WHEN sync_ledger.local_updated_at = excluded.local_updated_at THEN sync_ledger.sync_status
486
+ ELSE 'pending'
487
+ END,
488
+ last_error = CASE
489
+ WHEN sync_ledger.local_updated_at = excluded.local_updated_at THEN sync_ledger.last_error
490
+ ELSE NULL
491
+ END
492
+ `);
493
+ const listTaskLedgerIds = db.prepare(`
494
+ SELECT record_id
495
+ FROM sync_ledger
496
+ WHERE record_type = 'task'
497
+ `);
498
+ const deleteLedgerRow = db.prepare(`
499
+ DELETE FROM sync_ledger
500
+ WHERE record_type = 'task' AND record_id = ?
501
+ `);
502
+ const tx = db.transaction((snapshot) => {
503
+ for (const task of snapshot) {
504
+ const updatedAt = Number(task.updatedAt || Date.now());
505
+ upsert.run(task.id, updatedAt);
506
+ }
507
+ const ledgerIds = listTaskLedgerIds.all();
508
+ for (const row of ledgerIds) {
509
+ if (!snapshotIds.has(row.record_id)) {
510
+ deleteLedgerRow.run(row.record_id);
511
+ }
512
+ }
513
+ });
514
+ tx(tasks);
515
+ }
516
+ function getDirtyTaskLedgerRows(limit = 200) {
517
+ const db = getDb();
518
+ return db.prepare(`
519
+ SELECT record_id, local_updated_at
520
+ FROM sync_ledger
521
+ WHERE record_type = 'task'
522
+ AND (
523
+ cloud_synced_at IS NULL
524
+ OR cloud_synced_at < local_updated_at
525
+ OR sync_status != 'synced'
526
+ )
527
+ ORDER BY local_updated_at ASC
528
+ LIMIT ?
529
+ `).all(limit);
530
+ }
531
+ function markTaskRowsSynced(rows, syncedAt) {
532
+ if (rows.length === 0)
533
+ return;
534
+ const db = getDb();
535
+ const markSynced = db.prepare(`
536
+ UPDATE sync_ledger
537
+ SET cloud_synced_at = ?,
538
+ sync_status = 'synced',
539
+ attempt_count = attempt_count + 1,
540
+ last_error = NULL
541
+ WHERE record_type = 'task'
542
+ AND record_id = ?
543
+ AND local_updated_at = ?
544
+ `);
545
+ const tx = db.transaction((items) => {
546
+ for (const row of items) {
547
+ markSynced.run(syncedAt, row.id, row.local_updated_at);
548
+ }
549
+ });
550
+ tx(rows);
551
+ }
552
+ function markTaskRowsErrored(rows, errorMessage) {
553
+ if (rows.length === 0)
554
+ return;
555
+ const db = getDb();
556
+ const markError = db.prepare(`
557
+ UPDATE sync_ledger
558
+ SET sync_status = 'error',
559
+ attempt_count = attempt_count + 1,
560
+ last_error = ?
561
+ WHERE record_type = 'task'
562
+ AND record_id = ?
563
+ AND local_updated_at = ?
564
+ `);
565
+ const tx = db.transaction((items) => {
566
+ for (const row of items) {
567
+ markError.run(errorMessage, row.id, row.local_updated_at);
568
+ }
569
+ });
570
+ tx(rows);
571
+ }
572
+ async function syncTasks() {
573
+ if (!state.hostId || !config)
574
+ return;
575
+ const tasksSnapshot = getTasks();
576
+ refreshTaskLedger(tasksSnapshot);
577
+ const taskById = new Map(tasksSnapshot.map((task) => [task.id, task]));
578
+ const dirtyLedgerRows = getDirtyTaskLedgerRows();
579
+ const dirtyRows = dirtyLedgerRows
580
+ .map((ledgerRow) => {
581
+ const task = taskById.get(ledgerRow.record_id);
582
+ if (!task)
583
+ return null;
584
+ return {
585
+ id: task.id,
586
+ title: task.title,
587
+ status: task.status,
588
+ assignee: task.assignee,
589
+ priority: task.priority,
590
+ local_updated_at: ledgerRow.local_updated_at,
591
+ };
592
+ })
593
+ .filter((row) => row !== null);
594
+ if (dirtyRows.length === 0) {
595
+ state.lastTaskSync = Date.now();
596
+ return;
597
+ }
598
+ // Alert when dirty count is high (potential sync backlog)
599
+ const DIRTY_ALERT_THRESHOLD = 50;
600
+ if (dirtyRows.length >= DIRTY_ALERT_THRESHOLD) {
601
+ console.warn(`[cloud-sync] High dirty task count: ${dirtyRows.length} records pending sync (threshold: ${DIRTY_ALERT_THRESHOLD})`);
602
+ }
603
+ const tasksPayload = dirtyRows.map((row) => ({
604
+ id: row.id,
605
+ title: row.title,
606
+ status: row.status,
607
+ assignee: row.assignee ?? undefined,
608
+ priority: row.priority ?? undefined,
609
+ updatedAt: new Date(row.local_updated_at).toISOString(),
610
+ }));
611
+ const result = await cloudPost(`/api/hosts/${state.hostId}/tasks/sync`, {
612
+ tasks: tasksPayload,
613
+ });
614
+ if (result.success || result.data) {
615
+ const syncedAt = Date.now();
616
+ markTaskRowsSynced(dirtyRows, syncedAt);
617
+ state.lastTaskSync = syncedAt;
618
+ }
619
+ else {
620
+ const errorMessage = result.error || 'task sync failed';
621
+ markTaskRowsErrored(dirtyRows, errorMessage);
622
+ state.errors++;
623
+ }
624
+ }
625
+ // ---- Chat sync ----
626
+ /** Timestamp of last chat sync — only send messages newer than this */
627
+ let chatSyncCursor = Date.now() - 60_000; // Start with last minute of history
628
+ let chatSyncErrors = 0;
629
+ let chatSyncInFlight = false;
630
+ let chatSyncQueued = false;
631
+ let chatSyncTimerRef = null;
632
+ let chatSyncBackoffMs = 0;
633
+ let chatSyncNextAllowedAt = 0;
634
+ const chatSyncMinIntervalMs = Number(process.env.REFLECTT_CHAT_SYNC_MIN_INTERVAL_MS) || DEFAULT_CHAT_SYNC_MIN_INTERVAL_MS;
635
+ const chatSyncMaxBackoffMs = Number(process.env.REFLECTT_CHAT_SYNC_MAX_BACKOFF_MS) || DEFAULT_CHAT_SYNC_MAX_BACKOFF_MS;
636
+ function computeBackoffWithJitter(currentMs) {
637
+ const base = currentMs > 0 ? Math.min(currentMs * 2, chatSyncMaxBackoffMs) : 1_000;
638
+ const jitter = Math.floor(Math.random() * 500);
639
+ return Math.min(base + jitter, chatSyncMaxBackoffMs);
640
+ }
641
+ async function requestChatSync(_reason) {
642
+ if (!state.running)
643
+ return;
644
+ if (chatSyncInFlight) {
645
+ chatSyncQueued = true;
646
+ return;
647
+ }
648
+ const now = Date.now();
649
+ if (now < chatSyncNextAllowedAt) {
650
+ const waitMs = Math.max(0, chatSyncNextAllowedAt - now);
651
+ if (!chatSyncTimerRef) {
652
+ chatSyncTimerRef = setTimeout(() => {
653
+ chatSyncTimerRef = null;
654
+ requestChatSync('event').catch(() => { });
655
+ }, waitMs);
656
+ }
657
+ return;
658
+ }
659
+ await syncChat();
660
+ if (chatSyncQueued) {
661
+ chatSyncQueued = false;
662
+ await requestChatSync('event');
663
+ }
664
+ }
665
+ async function syncChat() {
666
+ if (!state.hostId || !config)
667
+ return;
668
+ if (chatSyncInFlight)
669
+ return;
670
+ chatSyncInFlight = true;
671
+ // Enforce minimum sync interval + active backoff window
672
+ const now = Date.now();
673
+ if (now < chatSyncNextAllowedAt) {
674
+ chatSyncInFlight = false;
675
+ return;
676
+ }
677
+ // Get recent messages since last sync
678
+ const recentMessages = chatManager.getMessages({
679
+ since: chatSyncCursor,
680
+ limit: 50,
681
+ });
682
+ // Send to cloud and get pending outbound messages
683
+ const payload = recentMessages.map(m => ({
684
+ id: m.id,
685
+ from: m.from,
686
+ content: m.content,
687
+ timestamp: m.timestamp,
688
+ channel: m.channel || 'general',
689
+ }));
690
+ const result = await cloudPost(`/api/hosts/${state.hostId}/chat/sync`, { messages: payload });
691
+ if (result.success && result.data) {
692
+ state.lastChatSync = Date.now();
693
+ if (chatSyncErrors > 0) {
694
+ console.log(`☁️ [Chat] Sync recovered after ${chatSyncErrors} errors`);
695
+ chatSyncErrors = 0;
696
+ }
697
+ // Reset backoff window on success, enforce minimum interval
698
+ chatSyncBackoffMs = 0;
699
+ chatSyncNextAllowedAt = Date.now() + chatSyncMinIntervalMs;
700
+ // Update cursor to now
701
+ if (recentMessages.length > 0) {
702
+ chatSyncCursor = Math.max(...recentMessages.map(m => m.timestamp));
703
+ }
704
+ // Process pending outbound messages from cloud (dashboard user messages)
705
+ if (result.data.pending && result.data.pending.length > 0) {
706
+ for (const msg of result.data.pending) {
707
+ // Inject into local chat as if the user posted it
708
+ try {
709
+ await chatManager.sendMessage({
710
+ from: msg.from,
711
+ content: msg.content,
712
+ channel: msg.channel || 'general',
713
+ metadata: { source: 'cloud-relay', cloudMessageId: msg.id },
714
+ });
715
+ console.log(`☁️ [Chat] Relayed message from ${msg.from}: "${msg.content.slice(0, 50)}..."`);
716
+ }
717
+ catch (err) {
718
+ console.warn(`☁️ [Chat] Failed to relay message: ${err?.message}`);
719
+ }
720
+ }
721
+ }
722
+ }
723
+ else {
724
+ chatSyncErrors++;
725
+ // Exponential backoff + jitter on repeated failures
726
+ chatSyncBackoffMs = computeBackoffWithJitter(chatSyncBackoffMs);
727
+ chatSyncNextAllowedAt = Date.now() + Math.max(chatSyncBackoffMs, chatSyncMinIntervalMs);
728
+ // Log first few, then every 20th to avoid spam
729
+ if (chatSyncErrors <= 3 || chatSyncErrors % 20 === 0) {
730
+ console.warn(`☁️ [Chat] Sync failed (${chatSyncErrors}): ${result.error}; next attempt in ~${chatSyncBackoffMs}ms`);
731
+ }
732
+ }
733
+ chatSyncInFlight = false;
734
+ }
735
+ // ---- Canvas sync ----
736
+ let canvasSyncErrors = 0;
737
+ async function syncCanvas() {
738
+ if (!state.hostId || !config)
739
+ return;
740
+ // Get active (non-stale) canvas slots
741
+ const activeSlots = slotManager.getActive();
742
+ // Push to cloud
743
+ const result = await cloudPost(`/api/hosts/${state.hostId}/canvas`, { slots: activeSlots });
744
+ if (result.success && result.data) {
745
+ state.lastCanvasSync = Date.now();
746
+ if (canvasSyncErrors > 0) {
747
+ console.log(`☁️ [Canvas] Sync recovered after ${canvasSyncErrors} errors`);
748
+ canvasSyncErrors = 0;
749
+ }
750
+ }
751
+ else {
752
+ canvasSyncErrors++;
753
+ if (canvasSyncErrors <= 3 || canvasSyncErrors % 20 === 0) {
754
+ console.warn(`☁️ [Canvas] Sync failed (${canvasSyncErrors}): ${result.error}`);
755
+ }
756
+ }
757
+ }
758
+ // ---- Usage Sync ----
759
+ let usageSyncErrors = 0;
760
+ async function syncUsage() {
761
+ if (!state.hostId || !config)
762
+ return;
763
+ try {
764
+ const since = Date.now() - 30 * 24 * 60 * 60 * 1000; // last 30 days
765
+ const summaries = getUsageSummary({ since, group_by: 'month' });
766
+ const summary = summaries.length > 0 ? summaries[0] : { period: 'monthly', total_cost_usd: 0, total_input_tokens: 0, total_output_tokens: 0, event_count: 0 };
767
+ const byAgent = getUsageByAgent({ since });
768
+ const byModel = getUsageByModel({ since });
769
+ const caps = listCaps();
770
+ const capStatuses = checkCaps();
771
+ const routingSuggestions = getRoutingSuggestions({ since });
772
+ const result = await cloudPost(`/api/hosts/${state.hostId}/usage/sync`, { summary, byAgent, byModel, caps, capStatuses, routingSuggestions });
773
+ if (result.success) {
774
+ if (usageSyncErrors > 0) {
775
+ console.log(`☁️ [Usage] Sync recovered after ${usageSyncErrors} errors`);
776
+ usageSyncErrors = 0;
777
+ }
778
+ }
779
+ else {
780
+ usageSyncErrors++;
781
+ if (usageSyncErrors <= 3 || usageSyncErrors % 20 === 0) {
782
+ console.warn(`☁️ [Usage] Sync failed (${usageSyncErrors}): ${result.error}`);
783
+ }
784
+ }
785
+ }
786
+ catch (err) {
787
+ usageSyncErrors++;
788
+ if (usageSyncErrors <= 3) {
789
+ console.warn(`☁️ [Usage] Sync error: ${err.message}`);
790
+ }
791
+ }
792
+ }
793
+ // ---- Command polling + context_sync handler ----
794
+ const COMMAND_POLL_ACTIVE_MS = 10_000; // 10s when active
795
+ const COMMAND_POLL_IDLE_MS = 60_000; // 60s when idle
796
+ let commandPollErrors = 0;
797
+ let lastCommandPollAt = 0;
798
+ async function pollAndProcessCommands() {
799
+ if (!state.hostId || !config || !state.running)
800
+ return;
801
+ const now = Date.now();
802
+ const interval = isIdle() ? COMMAND_POLL_IDLE_MS : COMMAND_POLL_ACTIVE_MS;
803
+ if (now - lastCommandPollAt < interval)
804
+ return;
805
+ lastCommandPollAt = now;
806
+ const result = await cloudGet(`/api/hosts/${state.hostId}/commands?status=pending`);
807
+ if (!result.success || !result.data?.commands) {
808
+ commandPollErrors++;
809
+ if (commandPollErrors <= 3 || commandPollErrors % 20 === 0) {
810
+ console.warn(`☁️ [Commands] Poll failed (${commandPollErrors}): ${result.error}`);
811
+ }
812
+ return;
813
+ }
814
+ if (commandPollErrors > 0) {
815
+ console.log(`☁️ [Commands] Poll recovered after ${commandPollErrors} errors`);
816
+ commandPollErrors = 0;
817
+ }
818
+ for (const cmd of result.data.commands) {
819
+ try {
820
+ await handleCommand(cmd);
821
+ }
822
+ catch (err) {
823
+ console.warn(`☁️ [Commands] Failed to handle ${cmd.type} (${cmd.id}): ${err?.message}`);
824
+ // Ack as failed so it doesn't re-run
825
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
826
+ action: 'fail',
827
+ error: err?.message || 'Handler error',
828
+ }).catch(() => { });
829
+ }
830
+ }
831
+ }
832
+ async function handleCommand(cmd) {
833
+ if (cmd.type === 'context_sync') {
834
+ await handleContextSync(cmd);
835
+ }
836
+ else {
837
+ console.log(`☁️ [Commands] Unknown command type: ${cmd.type} (${cmd.id}) — skipping`);
838
+ // Ack unknown commands so they don't pile up
839
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
840
+ action: 'complete',
841
+ result: { skipped: true, reason: 'unknown_type' },
842
+ });
843
+ }
844
+ }
845
+ async function handleContextSync(cmd) {
846
+ if (!state.hostId)
847
+ return;
848
+ // Require explicit agent — no hardcoded fallback
849
+ const agent = cmd.payload?.agent?.trim();
850
+ if (!agent) {
851
+ console.warn(`☁️ [Commands] context_sync missing payload.agent (${cmd.id}) — failing`);
852
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
853
+ action: 'fail',
854
+ error: 'payload.agent is required',
855
+ });
856
+ return;
857
+ }
858
+ console.log(`☁️ [Commands] Processing context_sync for agent=${agent} (${cmd.id})`);
859
+ // Ack immediately (in-progress)
860
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
861
+ action: 'ack',
862
+ });
863
+ // Fetch context snapshot from local node
864
+ const port = process.env.REFLECTT_NODE_PORT || '4445';
865
+ let contextData;
866
+ try {
867
+ const localRes = await fetch(`http://127.0.0.1:${port}/context/inject/${encodeURIComponent(agent)}`);
868
+ if (!localRes.ok)
869
+ throw new Error(`Local context fetch failed: ${localRes.status}`);
870
+ contextData = await localRes.json();
871
+ }
872
+ catch (err) {
873
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
874
+ action: 'fail',
875
+ error: `Failed to fetch local context: ${err?.message}`,
876
+ });
877
+ throw err;
878
+ }
879
+ // Push to cloud — use computed_at from injection payload when available
880
+ const computedAt = (typeof contextData.computed_at === 'number' && contextData.computed_at > 0)
881
+ ? contextData.computed_at
882
+ : Date.now();
883
+ const syncResult = await cloudPost(`/api/hosts/${state.hostId}/context/sync`, {
884
+ agent,
885
+ computed_at: computedAt,
886
+ budgets: contextData.budgets || { totalTokens: 0, layers: {} },
887
+ autosummary_enabled: Boolean(contextData.autosummary_enabled),
888
+ layers: contextData.layers || {},
889
+ });
890
+ if (syncResult.success) {
891
+ console.log(`☁️ [Commands] context_sync completed for ${agent} (${cmd.id})`);
892
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
893
+ action: 'complete',
894
+ result: { syncedAt: Date.now(), agent },
895
+ });
896
+ markCloudActivity(); // Mark as active
897
+ }
898
+ else {
899
+ console.warn(`☁️ [Commands] context_sync failed for ${agent}: ${syncResult.error}`);
900
+ await cloudPost(`/api/hosts/${state.hostId}/commands/${cmd.id}/ack`, {
901
+ action: 'fail',
902
+ error: syncResult.error,
903
+ });
904
+ }
905
+ }
906
+ async function cloudGet(path) {
907
+ if (!config)
908
+ return { success: false, error: 'Not configured' };
909
+ try {
910
+ const url = `${config.cloudUrl}${path}`;
911
+ const headers = {};
912
+ if (state.credential) {
913
+ headers['Authorization'] = `Bearer ${state.credential}`;
914
+ }
915
+ else {
916
+ headers['Authorization'] = `Bearer ${config.token}`;
917
+ }
918
+ const response = await fetch(url, { method: 'GET', headers });
919
+ if (!response.ok) {
920
+ const errBody = await response.json().catch(() => ({}));
921
+ return { success: false, error: errBody.error || `HTTP ${response.status}` };
922
+ }
923
+ const payload = await response.json();
924
+ return { success: true, data: payload };
925
+ }
926
+ catch (err) {
927
+ return { success: false, error: err?.message || 'Request failed' };
928
+ }
929
+ }
930
+ async function cloudPost(path, body) {
931
+ if (!config)
932
+ return { success: false, error: 'Not configured' };
933
+ try {
934
+ const url = `${config.cloudUrl}${path}`;
935
+ const headers = {
936
+ 'Content-Type': 'application/json',
937
+ };
938
+ // Use credential if registered, otherwise join token for enrollment
939
+ if (state.credential) {
940
+ headers['Authorization'] = `Bearer ${state.credential}`;
941
+ }
942
+ else {
943
+ headers['Authorization'] = `Bearer ${config.token}`;
944
+ }
945
+ const response = await fetch(url, {
946
+ method: 'POST',
947
+ headers,
948
+ body: JSON.stringify(body),
949
+ });
950
+ if (!response.ok) {
951
+ const errBody = await response.json().catch(() => ({}));
952
+ return { success: false, error: errBody.error || `HTTP ${response.status}` };
953
+ }
954
+ const payload = await response.json();
955
+ return { success: true, data: payload };
956
+ }
957
+ catch (err) {
958
+ // Don't increment errors here — callers handle error counting
959
+ return { success: false, error: err?.message || 'Request failed' };
960
+ }
961
+ }
962
+ //# sourceMappingURL=cloud.js.map