@useorgx/openclaw-plugin 0.4.9 → 0.7.2

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 (224) hide show
  1. package/README.md +77 -11
  2. package/dashboard/dist/assets/6mILZQ2a.js +1 -0
  3. package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
  4. package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
  5. package/dashboard/dist/assets/8dksYiq4.js +2 -0
  6. package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
  7. package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
  8. package/dashboard/dist/assets/B5zYRHc3.js +1 -0
  9. package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
  10. package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
  11. package/dashboard/dist/assets/B6wPWJ35.js +1 -0
  12. package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
  13. package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -0
  14. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  15. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  16. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  17. package/dashboard/dist/assets/BWEwjt1W.js +1 -0
  18. package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
  19. package/dashboard/dist/assets/BWEwjt1W.js.gz +0 -0
  20. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  21. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  22. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  23. package/dashboard/dist/assets/BzRbDCAD.css +1 -0
  24. package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
  25. package/dashboard/dist/assets/BzRbDCAD.css.gz +0 -0
  26. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  27. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  28. package/dashboard/dist/assets/C8uM3AX8.js +1 -0
  29. package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
  30. package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
  31. package/dashboard/dist/assets/C9jy61eu.js +212 -0
  32. package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
  33. package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
  34. package/dashboard/dist/assets/CC63EwFD.js +1 -0
  35. package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
  36. package/dashboard/dist/assets/CC63EwFD.js.gz +0 -0
  37. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  38. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  39. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  40. package/dashboard/dist/assets/CZaT3ob_.js +1 -0
  41. package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
  42. package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
  43. package/dashboard/dist/assets/CgaottFX.js +1 -0
  44. package/dashboard/dist/assets/CgaottFX.js.br +0 -0
  45. package/dashboard/dist/assets/CgaottFX.js.gz +0 -0
  46. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  47. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  48. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  49. package/dashboard/dist/assets/CzCxAZlW.js +1 -0
  50. package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
  51. package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
  52. package/dashboard/dist/assets/D3iMTYEj.js +1 -0
  53. package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
  54. package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
  55. package/dashboard/dist/assets/D8JNX8kq.js +2 -0
  56. package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
  57. package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
  58. package/dashboard/dist/assets/DnA8dpj6.js +1 -0
  59. package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
  60. package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
  61. package/dashboard/dist/assets/IUexzymk.js +1 -0
  62. package/dashboard/dist/assets/IUexzymk.js.br +0 -0
  63. package/dashboard/dist/assets/IUexzymk.js.gz +0 -0
  64. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  65. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  66. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  67. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  68. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  69. package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
  70. package/dashboard/dist/assets/qm8xLgv-.css +1 -0
  71. package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
  72. package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
  73. package/dashboard/dist/assets/rttbDbEx.js +1 -0
  74. package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
  75. package/dashboard/dist/assets/rttbDbEx.js.gz +0 -0
  76. package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
  77. package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
  78. package/dashboard/dist/brand/openai-mark.svg.br +0 -0
  79. package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
  80. package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
  81. package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
  82. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  83. package/dashboard/dist/index.html +7 -5
  84. package/dashboard/dist/index.html.br +0 -0
  85. package/dashboard/dist/index.html.gz +0 -0
  86. package/dist/activity-actor-fields.js +26 -4
  87. package/dist/activity-store.js +34 -8
  88. package/dist/agent-context-store.js +79 -17
  89. package/dist/agent-run-store.js +44 -3
  90. package/dist/agent-suite.d.ts +9 -0
  91. package/dist/agent-suite.js +149 -9
  92. package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
  93. package/dist/artifacts/artifact-domain-schemas.js +357 -0
  94. package/dist/artifacts/register-artifact.d.ts +4 -3
  95. package/dist/artifacts/register-artifact.js +170 -57
  96. package/dist/chat-store.d.ts +157 -0
  97. package/dist/chat-store.js +586 -0
  98. package/dist/cli/orgx.js +11 -0
  99. package/dist/contracts/client.d.ts +43 -3
  100. package/dist/contracts/client.js +159 -30
  101. package/dist/contracts/practice-exercise-schema.d.ts +216 -0
  102. package/dist/contracts/practice-exercise-schema.js +314 -0
  103. package/dist/contracts/retro-schema.d.ts +81 -0
  104. package/dist/contracts/retro-schema.js +80 -0
  105. package/dist/contracts/shared-types.d.ts +159 -0
  106. package/dist/contracts/shared-types.js +199 -1
  107. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  108. package/dist/contracts/skill-pack-schema.js +180 -0
  109. package/dist/contracts/types.d.ts +247 -2
  110. package/dist/entities/auto-assignment.js +43 -17
  111. package/dist/event-sanitization.d.ts +11 -0
  112. package/dist/event-sanitization.js +113 -0
  113. package/dist/gateway-watchdog.d.ts +5 -0
  114. package/dist/gateway-watchdog.js +50 -0
  115. package/dist/hooks/post-reporting-event.mjs +1 -5
  116. package/dist/http/helpers/activity-headline.js +13 -132
  117. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  118. package/dist/http/helpers/auto-continue-engine.js +3145 -186
  119. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  120. package/dist/http/helpers/autopilot-operations.js +182 -31
  121. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  122. package/dist/http/helpers/autopilot-runtime.js +328 -25
  123. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  124. package/dist/http/helpers/autopilot-slice-utils.js +514 -93
  125. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  126. package/dist/http/helpers/decision-mapper.js +223 -7
  127. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  128. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  129. package/dist/http/helpers/kickoff-context.js +104 -0
  130. package/dist/http/helpers/llm-client.d.ts +47 -0
  131. package/dist/http/helpers/llm-client.js +256 -0
  132. package/dist/http/helpers/mission-control.d.ts +102 -3
  133. package/dist/http/helpers/mission-control.js +498 -9
  134. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  135. package/dist/http/helpers/sentinel-catalog.js +193 -0
  136. package/dist/http/helpers/session-classification.d.ts +9 -0
  137. package/dist/http/helpers/session-classification.js +564 -0
  138. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  139. package/dist/http/helpers/slice-experience-v2.js +677 -0
  140. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  141. package/dist/http/helpers/slice-run-projections.js +877 -0
  142. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  143. package/dist/http/helpers/triage-mapper.js +549 -0
  144. package/dist/http/helpers/value-utils.js +7 -2
  145. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  146. package/dist/http/helpers/workspace-scope.js +170 -0
  147. package/dist/http/index.js +1420 -105
  148. package/dist/http/routes/agent-suite.d.ts +9 -0
  149. package/dist/http/routes/agent-suite.js +294 -8
  150. package/dist/http/routes/agents-catalog.js +64 -19
  151. package/dist/http/routes/chat.d.ts +19 -0
  152. package/dist/http/routes/chat.js +522 -0
  153. package/dist/http/routes/decision-actions.d.ts +8 -1
  154. package/dist/http/routes/decision-actions.js +42 -5
  155. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  156. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  157. package/dist/http/routes/entities.d.ts +16 -0
  158. package/dist/http/routes/entities.js +232 -6
  159. package/dist/http/routes/live-legacy.d.ts +5 -0
  160. package/dist/http/routes/live-legacy.js +23 -509
  161. package/dist/http/routes/live-misc.d.ts +12 -0
  162. package/dist/http/routes/live-misc.js +251 -31
  163. package/dist/http/routes/live-snapshot.d.ts +49 -2
  164. package/dist/http/routes/live-snapshot.js +653 -23
  165. package/dist/http/routes/live-terminal.d.ts +11 -0
  166. package/dist/http/routes/live-terminal.js +154 -0
  167. package/dist/http/routes/live-triage.d.ts +61 -0
  168. package/dist/http/routes/live-triage.js +192 -0
  169. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  170. package/dist/http/routes/mission-control-actions.js +1246 -84
  171. package/dist/http/routes/mission-control-read.d.ts +48 -3
  172. package/dist/http/routes/mission-control-read.js +1658 -20
  173. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  174. package/dist/http/routes/realtime-orchestrator.js +74 -0
  175. package/dist/http/routes/run-control.d.ts +5 -2
  176. package/dist/http/routes/run-control.js +10 -0
  177. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  178. package/dist/http/routes/sentinels-catalog.js +24 -0
  179. package/dist/http/routes/summary.js +10 -3
  180. package/dist/http/routes/usage.d.ts +24 -0
  181. package/dist/http/routes/usage.js +362 -0
  182. package/dist/http/routes/work-artifacts.js +28 -9
  183. package/dist/index.js +165 -27
  184. package/dist/local-openclaw.js +29 -6
  185. package/dist/mcp-client-setup.js +3 -3
  186. package/dist/mcp-http-handler.d.ts +3 -0
  187. package/dist/mcp-http-handler.js +34 -60
  188. package/dist/next-up-queue-store.d.ts +16 -1
  189. package/dist/next-up-queue-store.js +89 -7
  190. package/dist/outbox.d.ts +5 -0
  191. package/dist/outbox.js +113 -9
  192. package/dist/paths.js +36 -5
  193. package/dist/reporting/rollups.d.ts +41 -0
  194. package/dist/reporting/rollups.js +113 -0
  195. package/dist/retro/domain-templates.d.ts +45 -0
  196. package/dist/retro/domain-templates.js +297 -0
  197. package/dist/retro/quality-rubric.d.ts +33 -0
  198. package/dist/retro/quality-rubric.js +213 -0
  199. package/dist/runtime-cleanup.d.ts +18 -0
  200. package/dist/runtime-cleanup.js +87 -0
  201. package/dist/services/background.d.ts +11 -0
  202. package/dist/services/background.js +22 -0
  203. package/dist/services/experiment-randomization.d.ts +21 -0
  204. package/dist/services/experiment-randomization.js +63 -0
  205. package/dist/skill-pack-state.d.ts +36 -5
  206. package/dist/skill-pack-state.js +273 -29
  207. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  208. package/dist/sync/local-agent-telemetry.js +128 -0
  209. package/dist/sync/outbox-replay.js +131 -24
  210. package/dist/team-context-store.d.ts +23 -0
  211. package/dist/team-context-store.js +116 -0
  212. package/dist/telemetry/posthog.js +4 -2
  213. package/dist/tools/core-tools.d.ts +10 -14
  214. package/dist/tools/core-tools.js +1289 -24
  215. package/dist/types.d.ts +2 -0
  216. package/dist/types.js +2 -0
  217. package/dist/worker-supervisor.js +23 -0
  218. package/package.json +20 -6
  219. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  220. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  221. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  222. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  223. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  224. package/dashboard/dist/assets/sAhvFnpk.js +0 -4
@@ -0,0 +1,586 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { randomUUID } from "node:crypto";
3
+ import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
4
+ import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
5
+ import { ensureStoreDirSync, parseJsonSafe } from "./stores/json-store.js";
6
+ const STORE_VERSION = 1;
7
+ const STORE_FILENAME = "chat-store.json";
8
+ const MAX_THREADS = 400;
9
+ const MAX_MESSAGES_PER_THREAD = 200;
10
+ const MAX_LAUNCHES_PER_THREAD = 120;
11
+ function storeDir() {
12
+ return getOrgxPluginConfigDir();
13
+ }
14
+ function storePath() {
15
+ return getOrgxPluginConfigPath(STORE_FILENAME);
16
+ }
17
+ function toEpoch(value) {
18
+ if (!value)
19
+ return 0;
20
+ const parsed = Date.parse(value);
21
+ return Number.isFinite(parsed) ? parsed : 0;
22
+ }
23
+ function normalizeString(value) {
24
+ if (typeof value !== "string")
25
+ return null;
26
+ const trimmed = value.trim();
27
+ return trimmed.length > 0 ? trimmed : null;
28
+ }
29
+ function dedupeStrings(values) {
30
+ if (!Array.isArray(values))
31
+ return [];
32
+ const next = [];
33
+ const seen = new Set();
34
+ for (const value of values) {
35
+ if (typeof value !== "string")
36
+ continue;
37
+ const trimmed = value.trim();
38
+ if (!trimmed || seen.has(trimmed))
39
+ continue;
40
+ seen.add(trimmed);
41
+ next.push(trimmed);
42
+ }
43
+ return next;
44
+ }
45
+ function summarizeBody(body) {
46
+ const compact = body.replace(/\s+/g, " ").trim();
47
+ if (compact.length <= 140)
48
+ return compact;
49
+ return `${compact.slice(0, 137)}...`;
50
+ }
51
+ function titleFromBody(body) {
52
+ const compact = body.replace(/\s+/g, " ").trim();
53
+ if (compact.length <= 64)
54
+ return compact || "New thread";
55
+ return `${compact.slice(0, 61)}...`;
56
+ }
57
+ function threadStatusFromLaunch(status) {
58
+ if (status === "queued")
59
+ return "queued";
60
+ if (status === "running")
61
+ return "running";
62
+ if (status === "blocked")
63
+ return "blocked";
64
+ if (status === "failed")
65
+ return "failed";
66
+ if (status === "completed")
67
+ return "completed";
68
+ return "message_only";
69
+ }
70
+ function normalizeAttachment(threadId, value) {
71
+ const name = normalizeString(value.name);
72
+ if (!name)
73
+ return null;
74
+ const now = new Date().toISOString();
75
+ const sizeBytes = typeof value.sizeBytes === "number" && Number.isFinite(value.sizeBytes) && value.sizeBytes >= 0
76
+ ? Math.floor(value.sizeBytes)
77
+ : null;
78
+ const mimeType = normalizeString(value.mimeType);
79
+ const status = value.status === "preparing" ||
80
+ value.status === "indexing" ||
81
+ value.status === "ready" ||
82
+ value.status === "failed"
83
+ ? value.status
84
+ : "ready";
85
+ const error = normalizeString(value.error);
86
+ const createdAt = normalizeString(value.createdAt) ?? now;
87
+ const updatedAt = normalizeString(value.updatedAt) ?? now;
88
+ const id = normalizeString(value.id) ?? `att_${randomUUID()}`;
89
+ void threadId;
90
+ return {
91
+ id,
92
+ name,
93
+ mimeType,
94
+ sizeBytes,
95
+ status,
96
+ error,
97
+ masked: value.masked === true,
98
+ createdAt,
99
+ updatedAt,
100
+ };
101
+ }
102
+ function normalizeMessage(threadId, value) {
103
+ const body = normalizeString(value.body);
104
+ if (!body)
105
+ return null;
106
+ const now = new Date().toISOString();
107
+ const role = value.role === "agent" || value.role === "system" ? value.role : "user";
108
+ const attachmentsInput = Array.isArray(value.attachments) ? value.attachments : [];
109
+ const attachments = attachmentsInput
110
+ .map((entry) => normalizeAttachment(threadId, (entry ?? {})))
111
+ .filter((entry) => Boolean(entry));
112
+ return {
113
+ id: normalizeString(value.id) ?? `msg_${randomUUID()}`,
114
+ threadId,
115
+ role,
116
+ body,
117
+ senderId: normalizeString(value.senderId),
118
+ senderName: normalizeString(value.senderName),
119
+ createdAt: normalizeString(value.createdAt) ?? now,
120
+ updatedAt: normalizeString(value.updatedAt) ?? now,
121
+ attachments,
122
+ metadata: value.metadata && typeof value.metadata === "object" && !Array.isArray(value.metadata)
123
+ ? value.metadata
124
+ : {},
125
+ };
126
+ }
127
+ function normalizeLaunch(threadId, value) {
128
+ const messageId = normalizeString(value.messageId);
129
+ if (!messageId)
130
+ return null;
131
+ const now = new Date().toISOString();
132
+ const executionMode = value.executionMode === "cloud" || value.executionMode === "hybrid"
133
+ ? value.executionMode
134
+ : "local_queue";
135
+ const status = value.status === "queued" ||
136
+ value.status === "running" ||
137
+ value.status === "blocked" ||
138
+ value.status === "completed" ||
139
+ value.status === "failed" ||
140
+ value.status === "requested"
141
+ ? value.status
142
+ : "requested";
143
+ return {
144
+ id: normalizeString(value.id) ?? `launch_${randomUUID()}`,
145
+ threadId,
146
+ messageId,
147
+ assigneeId: normalizeString(value.assigneeId),
148
+ assigneeName: normalizeString(value.assigneeName),
149
+ watcherIds: dedupeStrings(value.watcherIds),
150
+ watcherNames: dedupeStrings(value.watcherNames),
151
+ executionMode,
152
+ provider: normalizeString(value.provider),
153
+ runId: normalizeString(value.runId),
154
+ status,
155
+ blockedReason: normalizeString(value.blockedReason),
156
+ warnings: dedupeStrings(value.warnings),
157
+ requestedAt: normalizeString(value.requestedAt) ?? now,
158
+ updatedAt: normalizeString(value.updatedAt) ?? now,
159
+ metadata: value.metadata && typeof value.metadata === "object" && !Array.isArray(value.metadata)
160
+ ? value.metadata
161
+ : {},
162
+ };
163
+ }
164
+ function normalizeThread(value) {
165
+ const id = normalizeString(value.id);
166
+ if (!id)
167
+ return null;
168
+ const now = new Date().toISOString();
169
+ const messagesInput = Array.isArray(value.messages) ? value.messages : [];
170
+ const launchesInput = Array.isArray(value.launches) ? value.launches : [];
171
+ const messages = messagesInput
172
+ .map((entry) => normalizeMessage(id, entry ?? {}))
173
+ .filter((entry) => Boolean(entry))
174
+ .sort((a, b) => toEpoch(a.createdAt) - toEpoch(b.createdAt))
175
+ .slice(-MAX_MESSAGES_PER_THREAD);
176
+ const launches = launchesInput
177
+ .map((entry) => normalizeLaunch(id, entry ?? {}))
178
+ .filter((entry) => Boolean(entry))
179
+ .sort((a, b) => toEpoch(b.requestedAt) - toEpoch(a.requestedAt))
180
+ .slice(0, MAX_LAUNCHES_PER_THREAD);
181
+ const latestMessage = messages.length > 0 ? messages[messages.length - 1] : null;
182
+ const latestLaunch = launches.length > 0 ? launches[0] : null;
183
+ const lastMessageAt = normalizeString(value.lastMessageAt) ?? latestMessage?.createdAt ?? null;
184
+ const lastLaunchAt = normalizeString(value.lastLaunchAt) ?? latestLaunch?.requestedAt ?? null;
185
+ const lastActivityAt = normalizeString(value.lastActivityAt) ??
186
+ (toEpoch(lastLaunchAt) > toEpoch(lastMessageAt) ? lastLaunchAt : lastMessageAt) ??
187
+ now;
188
+ const title = normalizeString(value.title) ?? titleFromBody(latestMessage?.body ?? "");
189
+ const summary = normalizeString(value.summary);
190
+ const status = value.status === "queued" ||
191
+ value.status === "running" ||
192
+ value.status === "blocked" ||
193
+ value.status === "completed" ||
194
+ value.status === "failed"
195
+ ? value.status
196
+ : latestLaunch
197
+ ? threadStatusFromLaunch(latestLaunch.status)
198
+ : "message_only";
199
+ return {
200
+ id,
201
+ commandCenterId: normalizeString(value.commandCenterId),
202
+ initiativeId: normalizeString(value.initiativeId),
203
+ initiativeTitle: normalizeString(value.initiativeTitle),
204
+ workstreamId: normalizeString(value.workstreamId),
205
+ taskId: normalizeString(value.taskId),
206
+ title,
207
+ summary,
208
+ status,
209
+ assigneeId: normalizeString(value.assigneeId) ?? latestLaunch?.assigneeId ?? null,
210
+ assigneeName: normalizeString(value.assigneeName) ?? latestLaunch?.assigneeName ?? null,
211
+ watcherIds: dedupeStrings(value.watcherIds),
212
+ watcherNames: dedupeStrings(value.watcherNames),
213
+ messageCount: typeof value.messageCount === "number" && Number.isFinite(value.messageCount)
214
+ ? Math.max(messages.length, Math.floor(value.messageCount))
215
+ : messages.length,
216
+ launchCount: typeof value.launchCount === "number" && Number.isFinite(value.launchCount)
217
+ ? Math.max(launches.length, Math.floor(value.launchCount))
218
+ : launches.length,
219
+ lastMessageAt,
220
+ lastLaunchAt,
221
+ lastActivityAt,
222
+ lastSnippet: normalizeString(value.lastSnippet) ?? summarizeBody(latestMessage?.body ?? ""),
223
+ createdAt: normalizeString(value.createdAt) ?? now,
224
+ updatedAt: normalizeString(value.updatedAt) ?? now,
225
+ messages,
226
+ launches,
227
+ metadata: value.metadata && typeof value.metadata === "object" && !Array.isArray(value.metadata)
228
+ ? value.metadata
229
+ : {},
230
+ };
231
+ }
232
+ function ensureDir() {
233
+ ensureStoreDirSync(storeDir());
234
+ }
235
+ function readPersistedStore() {
236
+ ensureDir();
237
+ const file = storePath();
238
+ if (!existsSync(file)) {
239
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), threads: [] };
240
+ }
241
+ try {
242
+ const raw = readFileSync(file, "utf8");
243
+ const parsed = parseJsonSafe(raw);
244
+ if (!parsed || parsed.version !== STORE_VERSION || !Array.isArray(parsed.threads)) {
245
+ backupCorruptFileSync(file);
246
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), threads: [] };
247
+ }
248
+ const threads = parsed.threads
249
+ .map((entry) => normalizeThread(entry ?? {}))
250
+ .filter((entry) => Boolean(entry))
251
+ .sort((a, b) => toEpoch(b.lastActivityAt) - toEpoch(a.lastActivityAt))
252
+ .slice(0, MAX_THREADS);
253
+ return {
254
+ version: STORE_VERSION,
255
+ updatedAt: normalizeString(parsed.updatedAt) ?? new Date().toISOString(),
256
+ threads,
257
+ };
258
+ }
259
+ catch {
260
+ return { version: STORE_VERSION, updatedAt: new Date().toISOString(), threads: [] };
261
+ }
262
+ }
263
+ function writePersistedStore(store) {
264
+ ensureDir();
265
+ const normalizedThreads = store.threads
266
+ .map((entry) => normalizeThread(entry))
267
+ .filter((entry) => Boolean(entry))
268
+ .sort((a, b) => toEpoch(b.lastActivityAt) - toEpoch(a.lastActivityAt))
269
+ .slice(0, MAX_THREADS);
270
+ writeJsonFileAtomicSync(storePath(), {
271
+ version: STORE_VERSION,
272
+ updatedAt: normalizeString(store.updatedAt) ?? new Date().toISOString(),
273
+ threads: normalizedThreads,
274
+ }, 0o600);
275
+ }
276
+ function toSummary(thread) {
277
+ return {
278
+ ...thread,
279
+ latestMessage: thread.messages.length > 0 ? thread.messages[thread.messages.length - 1] : null,
280
+ latestLaunch: thread.launches.length > 0 ? thread.launches[0] : null,
281
+ };
282
+ }
283
+ export function listChatThreads(input) {
284
+ const store = readPersistedStore();
285
+ const commandCenterId = normalizeString(input?.commandCenterId);
286
+ const initiativeId = normalizeString(input?.initiativeId);
287
+ const query = normalizeString(input?.query)?.toLowerCase() ?? null;
288
+ const status = normalizeString(input?.status)?.toLowerCase() ?? null;
289
+ const limit = Math.max(1, Math.min(200, Math.floor(input?.limit ?? 60)));
290
+ const offset = Math.max(0, Math.floor(input?.offset ?? 0));
291
+ const filtered = store.threads.filter((thread) => {
292
+ if (commandCenterId && thread.commandCenterId !== commandCenterId)
293
+ return false;
294
+ if (initiativeId && thread.initiativeId !== initiativeId)
295
+ return false;
296
+ if (status && thread.status.toLowerCase() !== status)
297
+ return false;
298
+ if (!query)
299
+ return true;
300
+ const haystack = [
301
+ thread.title,
302
+ thread.summary ?? "",
303
+ thread.lastSnippet ?? "",
304
+ thread.assigneeName ?? "",
305
+ thread.initiativeTitle ?? "",
306
+ ...thread.watcherNames,
307
+ ]
308
+ .join(" ")
309
+ .toLowerCase();
310
+ return haystack.includes(query);
311
+ });
312
+ return {
313
+ threads: filtered.slice(offset, offset + limit).map(toSummary),
314
+ total: filtered.length,
315
+ updatedAt: store.updatedAt,
316
+ };
317
+ }
318
+ export function getChatThread(threadId) {
319
+ const id = normalizeString(threadId);
320
+ if (!id)
321
+ return null;
322
+ const store = readPersistedStore();
323
+ return store.threads.find((thread) => thread.id === id) ?? null;
324
+ }
325
+ export function sendChatMessage(input) {
326
+ const body = normalizeString(input.body);
327
+ if (!body) {
328
+ throw new Error("message body is required");
329
+ }
330
+ const role = input.role === "agent" || input.role === "system" ? input.role : "user";
331
+ const now = new Date().toISOString();
332
+ const store = readPersistedStore();
333
+ let thread = null;
334
+ const threadId = normalizeString(input.threadId);
335
+ if (threadId) {
336
+ thread = store.threads.find((entry) => entry.id === threadId) ?? null;
337
+ }
338
+ const createdThread = !thread;
339
+ if (!thread) {
340
+ const id = `thread_${randomUUID()}`;
341
+ thread = {
342
+ id,
343
+ commandCenterId: normalizeString(input.commandCenterId),
344
+ initiativeId: normalizeString(input.initiativeId),
345
+ initiativeTitle: normalizeString(input.initiativeTitle),
346
+ workstreamId: normalizeString(input.workstreamId),
347
+ taskId: normalizeString(input.taskId),
348
+ title: normalizeString(input.title) ?? titleFromBody(body),
349
+ summary: summarizeBody(body),
350
+ status: "message_only",
351
+ assigneeId: normalizeString(input.assigneeId),
352
+ assigneeName: normalizeString(input.assigneeName),
353
+ watcherIds: dedupeStrings(input.watcherIds),
354
+ watcherNames: dedupeStrings(input.watcherNames),
355
+ messageCount: 0,
356
+ launchCount: 0,
357
+ lastMessageAt: null,
358
+ lastLaunchAt: null,
359
+ lastActivityAt: now,
360
+ lastSnippet: null,
361
+ createdAt: now,
362
+ updatedAt: now,
363
+ messages: [],
364
+ launches: [],
365
+ metadata: input.metadata && typeof input.metadata === "object" ? input.metadata : {},
366
+ };
367
+ store.threads.unshift(thread);
368
+ }
369
+ const message = normalizeMessage(thread.id, {
370
+ id: `msg_${randomUUID()}`,
371
+ threadId: thread.id,
372
+ role,
373
+ body,
374
+ senderId: normalizeString(input.senderId),
375
+ senderName: normalizeString(input.senderName),
376
+ createdAt: now,
377
+ updatedAt: now,
378
+ attachments: Array.isArray(input.attachments) ? input.attachments : [],
379
+ metadata: input.metadata && typeof input.metadata === "object" ? input.metadata : {},
380
+ });
381
+ if (!message) {
382
+ throw new Error("failed to normalize chat message");
383
+ }
384
+ thread.messages.push(message);
385
+ if (thread.messages.length > MAX_MESSAGES_PER_THREAD) {
386
+ thread.messages = thread.messages.slice(-MAX_MESSAGES_PER_THREAD);
387
+ }
388
+ thread.messageCount = Math.max(thread.messageCount + 1, thread.messages.length);
389
+ thread.lastMessageAt = now;
390
+ thread.lastActivityAt = now;
391
+ if (role === "user") {
392
+ thread.lastSnippet = summarizeBody(body);
393
+ thread.summary = summarizeBody(body);
394
+ thread.status = "message_only";
395
+ }
396
+ else if (!thread.lastSnippet) {
397
+ thread.lastSnippet = summarizeBody(body);
398
+ }
399
+ thread.updatedAt = now;
400
+ thread.assigneeId = normalizeString(input.assigneeId) ?? thread.assigneeId;
401
+ thread.assigneeName = normalizeString(input.assigneeName) ?? thread.assigneeName;
402
+ thread.watcherIds = dedupeStrings([...(thread.watcherIds ?? []), ...(input.watcherIds ?? [])]);
403
+ thread.watcherNames = dedupeStrings([...(thread.watcherNames ?? []), ...(input.watcherNames ?? [])]);
404
+ if (role === "user" && (!thread.title || thread.title.trim().length === 0)) {
405
+ thread.title = titleFromBody(body);
406
+ }
407
+ if (!thread.commandCenterId) {
408
+ thread.commandCenterId = normalizeString(input.commandCenterId);
409
+ }
410
+ if (!thread.initiativeId) {
411
+ thread.initiativeId = normalizeString(input.initiativeId);
412
+ thread.initiativeTitle = normalizeString(input.initiativeTitle);
413
+ }
414
+ if (!thread.workstreamId) {
415
+ thread.workstreamId = normalizeString(input.workstreamId);
416
+ }
417
+ if (!thread.taskId) {
418
+ thread.taskId = normalizeString(input.taskId);
419
+ }
420
+ store.updatedAt = now;
421
+ writePersistedStore(store);
422
+ return {
423
+ thread,
424
+ message,
425
+ createdThread,
426
+ updatedAt: store.updatedAt,
427
+ };
428
+ }
429
+ export function recordChatLaunch(input) {
430
+ const threadId = normalizeString(input.threadId);
431
+ const messageId = normalizeString(input.messageId);
432
+ if (!threadId)
433
+ throw new Error("threadId is required");
434
+ if (!messageId)
435
+ throw new Error("messageId is required");
436
+ const now = new Date().toISOString();
437
+ const store = readPersistedStore();
438
+ const thread = store.threads.find((entry) => entry.id === threadId);
439
+ if (!thread)
440
+ throw new Error("thread not found");
441
+ const messageExists = thread.messages.some((message) => message.id === messageId);
442
+ if (!messageExists)
443
+ throw new Error("message not found on thread");
444
+ const launch = normalizeLaunch(threadId, {
445
+ id: `launch_${randomUUID()}`,
446
+ threadId,
447
+ messageId,
448
+ assigneeId: normalizeString(input.assigneeId),
449
+ assigneeName: normalizeString(input.assigneeName),
450
+ watcherIds: input.watcherIds ?? [],
451
+ watcherNames: input.watcherNames ?? [],
452
+ executionMode: input.executionMode ?? "local_queue",
453
+ provider: normalizeString(input.provider),
454
+ runId: normalizeString(input.runId),
455
+ status: input.status ?? (normalizeString(input.runId) ? "queued" : "requested"),
456
+ blockedReason: normalizeString(input.blockedReason),
457
+ warnings: input.warnings ?? [],
458
+ requestedAt: now,
459
+ updatedAt: now,
460
+ metadata: input.metadata ?? {},
461
+ });
462
+ if (!launch)
463
+ throw new Error("failed to create launch attempt");
464
+ thread.launches.unshift(launch);
465
+ if (thread.launches.length > MAX_LAUNCHES_PER_THREAD) {
466
+ thread.launches = thread.launches.slice(0, MAX_LAUNCHES_PER_THREAD);
467
+ }
468
+ thread.launchCount = Math.max(thread.launchCount + 1, thread.launches.length);
469
+ thread.lastLaunchAt = now;
470
+ thread.lastActivityAt = now;
471
+ thread.updatedAt = now;
472
+ thread.assigneeId = launch.assigneeId ?? thread.assigneeId;
473
+ thread.assigneeName = launch.assigneeName ?? thread.assigneeName;
474
+ thread.watcherIds = dedupeStrings([...(thread.watcherIds ?? []), ...launch.watcherIds]);
475
+ thread.watcherNames = dedupeStrings([...(thread.watcherNames ?? []), ...launch.watcherNames]);
476
+ thread.status = threadStatusFromLaunch(launch.status);
477
+ const baseSnippet = launch.blockedReason
478
+ ? `Launch blocked: ${launch.blockedReason}`
479
+ : launch.status === "queued"
480
+ ? "Queued locally. Run starts when a worker is available."
481
+ : launch.status === "running"
482
+ ? "Run is active."
483
+ : launch.status === "completed"
484
+ ? "Launch completed."
485
+ : launch.status === "failed"
486
+ ? "Launch failed."
487
+ : "Launch requested.";
488
+ thread.lastSnippet = baseSnippet;
489
+ store.updatedAt = now;
490
+ writePersistedStore(store);
491
+ return {
492
+ thread,
493
+ launch,
494
+ updatedAt: store.updatedAt,
495
+ };
496
+ }
497
+ export function updateChatLaunchStatus(input) {
498
+ const threadId = normalizeString(input.threadId);
499
+ const launchId = normalizeString(input.launchId);
500
+ if (!threadId)
501
+ throw new Error("threadId is required");
502
+ if (!launchId)
503
+ throw new Error("launchId is required");
504
+ const now = new Date().toISOString();
505
+ const store = readPersistedStore();
506
+ const thread = store.threads.find((entry) => entry.id === threadId);
507
+ if (!thread)
508
+ throw new Error("thread not found");
509
+ const launch = thread.launches.find((entry) => entry.id === launchId);
510
+ if (!launch)
511
+ throw new Error("launch not found");
512
+ launch.status = input.status;
513
+ launch.updatedAt = now;
514
+ launch.runId = normalizeString(input.runId) ?? launch.runId;
515
+ launch.blockedReason = normalizeString(input.blockedReason) ?? launch.blockedReason;
516
+ launch.warnings = dedupeStrings(input.warnings ?? launch.warnings);
517
+ thread.status = threadStatusFromLaunch(launch.status);
518
+ thread.lastActivityAt = now;
519
+ thread.lastLaunchAt = now;
520
+ thread.updatedAt = now;
521
+ thread.lastSnippet = launch.blockedReason
522
+ ? `Launch blocked: ${launch.blockedReason}`
523
+ : launch.status === "running"
524
+ ? "Run is active."
525
+ : launch.status === "completed"
526
+ ? "Launch completed."
527
+ : launch.status === "failed"
528
+ ? "Launch failed."
529
+ : thread.lastSnippet;
530
+ store.updatedAt = now;
531
+ writePersistedStore(store);
532
+ return { thread, launch, updatedAt: store.updatedAt };
533
+ }
534
+ export function linkChatThreadScope(input) {
535
+ const threadId = normalizeString(input.threadId);
536
+ if (!threadId)
537
+ throw new Error("threadId is required");
538
+ const now = new Date().toISOString();
539
+ const store = readPersistedStore();
540
+ const thread = store.threads.find((entry) => entry.id === threadId);
541
+ if (!thread)
542
+ throw new Error("thread not found");
543
+ const previousInitiative = thread.initiativeTitle ?? thread.initiativeId ?? "Unscoped";
544
+ const nextInitiativeId = normalizeString(input.initiativeId);
545
+ const nextInitiativeTitle = normalizeString(input.initiativeTitle);
546
+ thread.commandCenterId = normalizeString(input.commandCenterId) ?? thread.commandCenterId;
547
+ thread.initiativeId = nextInitiativeId;
548
+ thread.initiativeTitle = nextInitiativeTitle;
549
+ thread.workstreamId = normalizeString(input.workstreamId);
550
+ thread.taskId = normalizeString(input.taskId);
551
+ thread.updatedAt = now;
552
+ thread.lastActivityAt = now;
553
+ const currentLabel = nextInitiativeTitle ?? nextInitiativeId ?? "Unscoped";
554
+ const eventBody = previousInitiative === currentLabel
555
+ ? `Linked to ${currentLabel}.`
556
+ : `Scope updated: ${previousInitiative} -> ${currentLabel}.`;
557
+ const eventMessage = normalizeMessage(thread.id, {
558
+ id: `msg_${randomUUID()}`,
559
+ threadId: thread.id,
560
+ role: "system",
561
+ body: eventBody,
562
+ senderId: "orgx_system",
563
+ senderName: "OrgX",
564
+ createdAt: now,
565
+ updatedAt: now,
566
+ attachments: [],
567
+ metadata: {
568
+ event: "thread_scope_linked",
569
+ previousInitiative,
570
+ currentInitiative: currentLabel,
571
+ },
572
+ });
573
+ if (!eventMessage)
574
+ throw new Error("failed to create scope event message");
575
+ thread.messages.push(eventMessage);
576
+ if (thread.messages.length > MAX_MESSAGES_PER_THREAD) {
577
+ thread.messages = thread.messages.slice(-MAX_MESSAGES_PER_THREAD);
578
+ }
579
+ thread.messageCount = Math.max(thread.messageCount + 1, thread.messages.length);
580
+ thread.lastMessageAt = now;
581
+ thread.lastSnippet = eventBody;
582
+ thread.summary = summarizeBody(eventBody);
583
+ store.updatedAt = now;
584
+ writePersistedStore(store);
585
+ return { thread, eventMessage, updatedAt: store.updatedAt };
586
+ }
package/dist/cli/orgx.js CHANGED
@@ -19,14 +19,25 @@ export function registerOrgxCli(deps) {
19
19
  .description("Trigger manual memory sync")
20
20
  .option("--memory <text>", "Memory to push")
21
21
  .option("--daily-log <text>", "Daily log to push")
22
+ .option("--agents-json <json>", "JSON array of local agent states to include (id,name,domain,status)")
22
23
  .action(async (opts = {}) => {
23
24
  try {
25
+ let agents;
26
+ if (typeof opts.agentsJson === "string" && opts.agentsJson.trim().length > 0) {
27
+ const parsed = JSON.parse(opts.agentsJson);
28
+ if (!Array.isArray(parsed)) {
29
+ throw new Error("--agents-json must be a JSON array");
30
+ }
31
+ agents = parsed;
32
+ }
24
33
  const resp = await deps.client.syncMemory({
25
34
  memory: opts.memory,
26
35
  dailyLog: opts.dailyLog,
36
+ agents,
27
37
  });
28
38
  console.log("Sync complete:");
29
39
  console.log(` Initiatives: ${resp.initiatives?.length ?? 0}`);
40
+ console.log(` Agents: ${resp.agents?.length ?? 0}`);
30
41
  console.log(` Active tasks: ${resp.activeTasks?.length ?? 0}`);
31
42
  console.log(` Pending decisions: ${resp.pendingDecisions?.length ?? 0}`);
32
43
  }