@useorgx/openclaw-plugin 0.7.18 → 0.7.23

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 (161) hide show
  1. package/dashboard/dist/assets/9gFmK3Kr.js +1 -0
  2. package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
  3. package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
  4. package/dashboard/dist/assets/{DS79hzMu.js → BrMXbzQ-.js} +2 -2
  5. package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
  6. package/dashboard/dist/assets/BrMXbzQ-.js.gz +0 -0
  7. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  8. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  9. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  10. package/dashboard/dist/assets/C1u2SGin.css +1 -0
  11. package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
  12. package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
  13. package/dashboard/dist/assets/{467jKHFJ.js → CGJiHCIx.js} +1 -1
  14. package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
  15. package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
  16. package/dashboard/dist/assets/CSd4rSuU.js +212 -0
  17. package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
  18. package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
  19. package/dashboard/dist/assets/{5Ihga-4X.js → CZXS5i_5.js} +1 -1
  20. package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
  21. package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
  22. package/dashboard/dist/assets/{a6qcPiWt.js → CbVWL74-.js} +1 -1
  23. package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
  24. package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
  25. package/dashboard/dist/assets/{qDJ6rqcs.js → D-FuHfT8.js} +1 -1
  26. package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
  27. package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
  28. package/dashboard/dist/assets/{BcJmNILk.js → D0PN5_vY.js} +1 -1
  29. package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
  30. package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
  31. package/dashboard/dist/assets/DDCPrZRt.js +1 -0
  32. package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
  33. package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
  34. package/dashboard/dist/assets/{B71dt9yu.js → DNQ-iFO2.js} +1 -1
  35. package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
  36. package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
  37. package/dashboard/dist/assets/{PVi0vr9a.js → DhPuHPK7.js} +1 -1
  38. package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
  39. package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
  40. package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
  41. package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
  42. package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
  43. package/dashboard/dist/assets/LOFrVoPD.js +1 -0
  44. package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
  45. package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
  46. package/dashboard/dist/assets/OlLPtzdz.js +1 -0
  47. package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
  48. package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
  49. package/dashboard/dist/assets/{sdoPH_Z1.js → RN4M9u9W.js} +2 -2
  50. package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
  51. package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
  52. package/dashboard/dist/assets/VCHu272d.js +1 -0
  53. package/dashboard/dist/assets/VCHu272d.js.br +0 -0
  54. package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
  55. package/dashboard/dist/assets/m2smti3F.js +1 -0
  56. package/dashboard/dist/assets/m2smti3F.js.br +0 -0
  57. package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
  58. package/dashboard/dist/assets/{C3_j_W9V.js → nra1yvJX.js} +1 -1
  59. package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
  60. package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
  61. package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
  62. package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
  63. package/dashboard/dist/assets/qLX6NZ-J.js.gz +0 -0
  64. package/dashboard/dist/index.html +2 -2
  65. package/dashboard/dist/index.html.br +0 -0
  66. package/dashboard/dist/index.html.gz +0 -0
  67. package/dist/agent-run-store.js +162 -24
  68. package/dist/cli/orgx.d.ts +3 -0
  69. package/dist/config/resolution.d.ts +7 -0
  70. package/dist/config/resolution.js +13 -5
  71. package/dist/contracts/onboarding-state.d.ts +2 -0
  72. package/dist/contracts/onboarding-state.js +23 -0
  73. package/dist/contracts/shared-types.d.ts +17 -0
  74. package/dist/http/helpers/auto-continue-engine.d.ts +62 -0
  75. package/dist/http/helpers/auto-continue-engine.js +329 -53
  76. package/dist/http/helpers/autopilot-runtime.js +5 -1
  77. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  78. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  79. package/dist/http/helpers/decision-mapper.js +19 -2
  80. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  81. package/dist/http/helpers/mission-control.d.ts +1 -0
  82. package/dist/http/helpers/mission-control.js +5 -2
  83. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  84. package/dist/http/helpers/slice-run-projections.js +198 -10
  85. package/dist/http/helpers/triage-mapper.js +220 -6
  86. package/dist/http/index.d.ts +1 -0
  87. package/dist/http/index.js +94 -46
  88. package/dist/http/router.js +64 -9
  89. package/dist/http/routes/live-legacy.d.ts +19 -2
  90. package/dist/http/routes/live-legacy.js +110 -27
  91. package/dist/http/routes/live-snapshot.d.ts +16 -2
  92. package/dist/http/routes/live-snapshot.js +169 -25
  93. package/dist/http/routes/mission-control-actions.js +28 -0
  94. package/dist/http/routes/mission-control-read.d.ts +18 -0
  95. package/dist/http/routes/mission-control-read.js +130 -218
  96. package/dist/http/routes/onboarding.d.ts +1 -0
  97. package/dist/http/routes/onboarding.js +17 -0
  98. package/dist/index.d.ts +5 -0
  99. package/dist/index.js +199 -123
  100. package/dist/outbox.d.ts +0 -2
  101. package/dist/outbox.js +268 -150
  102. package/dist/reporting/rollups.js +18 -11
  103. package/dist/runtime-instance-store.js +212 -58
  104. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  105. package/dist/stores/materialized-snapshot-store.js +91 -0
  106. package/dist/stores/sqlite-state.d.ts +6 -0
  107. package/dist/stores/sqlite-state.js +179 -0
  108. package/package.json +6 -1
  109. package/dashboard/dist/assets/467jKHFJ.js.br +0 -0
  110. package/dashboard/dist/assets/467jKHFJ.js.gz +0 -0
  111. package/dashboard/dist/assets/5Ihga-4X.js.br +0 -0
  112. package/dashboard/dist/assets/5Ihga-4X.js.gz +0 -0
  113. package/dashboard/dist/assets/B71dt9yu.js.br +0 -0
  114. package/dashboard/dist/assets/B71dt9yu.js.gz +0 -0
  115. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  116. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  117. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  118. package/dashboard/dist/assets/BEnI6kNR.js +0 -1
  119. package/dashboard/dist/assets/BEnI6kNR.js.br +0 -0
  120. package/dashboard/dist/assets/BEnI6kNR.js.gz +0 -0
  121. package/dashboard/dist/assets/BcJmNILk.js.br +0 -0
  122. package/dashboard/dist/assets/BcJmNILk.js.gz +0 -0
  123. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  124. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  125. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  126. package/dashboard/dist/assets/C-XuWXGi.js +0 -1
  127. package/dashboard/dist/assets/C-XuWXGi.js.br +0 -0
  128. package/dashboard/dist/assets/C-XuWXGi.js.gz +0 -0
  129. package/dashboard/dist/assets/C3_j_W9V.js.br +0 -0
  130. package/dashboard/dist/assets/C3_j_W9V.js.gz +0 -0
  131. package/dashboard/dist/assets/C9-UYhBb.js +0 -1
  132. package/dashboard/dist/assets/C9-UYhBb.js.br +0 -0
  133. package/dashboard/dist/assets/C9-UYhBb.js.gz +0 -0
  134. package/dashboard/dist/assets/C9yV06GS.js +0 -1
  135. package/dashboard/dist/assets/C9yV06GS.js.br +0 -0
  136. package/dashboard/dist/assets/C9yV06GS.js.gz +0 -0
  137. package/dashboard/dist/assets/CReugbyT.js +0 -1
  138. package/dashboard/dist/assets/CReugbyT.js.br +0 -0
  139. package/dashboard/dist/assets/CReugbyT.js.gz +0 -0
  140. package/dashboard/dist/assets/CSDhTbKy.js +0 -1
  141. package/dashboard/dist/assets/CSDhTbKy.js.br +0 -0
  142. package/dashboard/dist/assets/CSDhTbKy.js.gz +0 -0
  143. package/dashboard/dist/assets/CfMS9yIf.js +0 -1
  144. package/dashboard/dist/assets/CfMS9yIf.js.br +0 -0
  145. package/dashboard/dist/assets/CfMS9yIf.js.gz +0 -0
  146. package/dashboard/dist/assets/D2Kqcmv9.js +0 -212
  147. package/dashboard/dist/assets/D2Kqcmv9.js.br +0 -0
  148. package/dashboard/dist/assets/D2Kqcmv9.js.gz +0 -0
  149. package/dashboard/dist/assets/DS79hzMu.js.br +0 -0
  150. package/dashboard/dist/assets/DS79hzMu.js.gz +0 -0
  151. package/dashboard/dist/assets/PVi0vr9a.js.br +0 -0
  152. package/dashboard/dist/assets/PVi0vr9a.js.gz +0 -0
  153. package/dashboard/dist/assets/RZkbqlJk.css +0 -1
  154. package/dashboard/dist/assets/RZkbqlJk.css.br +0 -0
  155. package/dashboard/dist/assets/RZkbqlJk.css.gz +0 -0
  156. package/dashboard/dist/assets/a6qcPiWt.js.br +0 -0
  157. package/dashboard/dist/assets/a6qcPiWt.js.gz +0 -0
  158. package/dashboard/dist/assets/qDJ6rqcs.js.br +0 -0
  159. package/dashboard/dist/assets/qDJ6rqcs.js.gz +0 -0
  160. package/dashboard/dist/assets/sdoPH_Z1.js.br +0 -0
  161. package/dashboard/dist/assets/sdoPH_Z1.js.gz +0 -0
@@ -1,10 +1,12 @@
1
1
  import { existsSync, readFileSync, writeFileSync, } from "node:fs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
4
- import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
4
+ import { backupCorruptFileSync } from "./fs-utils.js";
5
5
  import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
6
+ import { getStateDb, readStateMeta, writeStateMeta, } from "./stores/sqlite-state.js";
6
7
  const MAX_INSTANCES = 600;
7
8
  export const DEFAULT_RUNTIME_HEARTBEAT_TIMEOUT_MS = 90_000;
9
+ const RUNTIME_IMPORT_META_KEY = "runtime_instances_imported_v1";
8
10
  function runtimeDir() {
9
11
  return getOrgxPluginConfigDir();
10
12
  }
@@ -19,8 +21,7 @@ function ensureRuntimeDir() {
19
21
  }
20
22
  function writeHookTokenFile(token) {
21
23
  ensureRuntimeDir();
22
- const file = hookTokenFile();
23
- writeFileSync(file, `${token}\n`, { encoding: "utf8", mode: 0o600 });
24
+ writeFileSync(hookTokenFile(), `${token}\n`, { encoding: "utf8", mode: 0o600 });
24
25
  }
25
26
  function normalizeNullableString(value) {
26
27
  if (typeof value !== "string")
@@ -174,7 +175,7 @@ function normalizeRecord(input) {
174
175
  updatedAt: input.updatedAt,
175
176
  };
176
177
  }
177
- export function readRuntimeInstances() {
178
+ function legacyReadRuntimeInstances() {
178
179
  const file = runtimeFile();
179
180
  try {
180
181
  if (!existsSync(file)) {
@@ -200,24 +201,171 @@ export function readRuntimeInstances() {
200
201
  return { updatedAt: new Date().toISOString(), instances: {} };
201
202
  }
202
203
  }
203
- function pruneStore(store) {
204
- const values = Object.values(store.instances);
205
- if (values.length <= MAX_INSTANCES)
204
+ function rowToRecord(row) {
205
+ return normalizeRecord({
206
+ id: row.id,
207
+ sourceClient: normalizeSourceClient(row.source_client),
208
+ displayName: row.display_name,
209
+ providerLogo: normalizeProviderLogo(row.provider_logo, normalizeSourceClient(row.source_client)),
210
+ state: normalizeState(row.state),
211
+ event: normalizeHookEvent(row.event),
212
+ runId: row.run_id,
213
+ correlationId: row.correlation_id,
214
+ initiativeId: row.initiative_id,
215
+ workstreamId: row.workstream_id,
216
+ taskId: row.task_id,
217
+ agentId: row.agent_id,
218
+ agentName: row.agent_name,
219
+ phase: row.phase,
220
+ progressPct: typeof row.progress_pct === "number" ? row.progress_pct : null,
221
+ currentTask: row.current_task,
222
+ lastHeartbeatAt: row.last_heartbeat_at,
223
+ lastEventAt: row.last_event_at,
224
+ lastMessage: row.last_message,
225
+ metadata: typeof row.metadata_json === "string"
226
+ ? normalizeObject(parseJsonSafe(row.metadata_json))
227
+ : null,
228
+ createdAt: row.created_at,
229
+ updatedAt: row.updated_at,
230
+ });
231
+ }
232
+ function writeRuntimeRecord(record) {
233
+ const normalized = normalizeRecord(record);
234
+ getStateDb()
235
+ .prepare(`INSERT INTO runtime_instances (
236
+ id,
237
+ source_client,
238
+ display_name,
239
+ provider_logo,
240
+ state,
241
+ event,
242
+ run_id,
243
+ correlation_id,
244
+ initiative_id,
245
+ workstream_id,
246
+ task_id,
247
+ agent_id,
248
+ agent_name,
249
+ phase,
250
+ progress_pct,
251
+ current_task,
252
+ last_heartbeat_at,
253
+ last_event_at,
254
+ last_message,
255
+ metadata_json,
256
+ created_at,
257
+ updated_at
258
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
259
+ ON CONFLICT(id) DO UPDATE SET
260
+ source_client = excluded.source_client,
261
+ display_name = excluded.display_name,
262
+ provider_logo = excluded.provider_logo,
263
+ state = excluded.state,
264
+ event = excluded.event,
265
+ run_id = excluded.run_id,
266
+ correlation_id = excluded.correlation_id,
267
+ initiative_id = excluded.initiative_id,
268
+ workstream_id = excluded.workstream_id,
269
+ task_id = excluded.task_id,
270
+ agent_id = excluded.agent_id,
271
+ agent_name = excluded.agent_name,
272
+ phase = excluded.phase,
273
+ progress_pct = excluded.progress_pct,
274
+ current_task = excluded.current_task,
275
+ last_heartbeat_at = excluded.last_heartbeat_at,
276
+ last_event_at = excluded.last_event_at,
277
+ last_message = excluded.last_message,
278
+ metadata_json = excluded.metadata_json,
279
+ created_at = excluded.created_at,
280
+ updated_at = excluded.updated_at`)
281
+ .run(normalized.id, normalized.sourceClient, normalized.displayName, normalized.providerLogo, normalized.state, normalized.event, normalized.runId, normalized.correlationId, normalized.initiativeId, normalized.workstreamId, normalized.taskId, normalized.agentId, normalized.agentName, normalized.phase, normalized.progressPct, normalized.currentTask, normalized.lastHeartbeatAt, normalized.lastEventAt, normalized.lastMessage, normalized.metadata ? JSON.stringify(normalized.metadata) : null, normalized.createdAt, normalized.updatedAt);
282
+ }
283
+ function pruneRuntimeStore() {
284
+ getStateDb()
285
+ .prepare(`DELETE FROM runtime_instances
286
+ WHERE id NOT IN (
287
+ SELECT id
288
+ FROM runtime_instances
289
+ ORDER BY last_event_at DESC, updated_at DESC
290
+ LIMIT ?
291
+ )`)
292
+ .run(MAX_INSTANCES);
293
+ }
294
+ function readRuntimeRows(limit) {
295
+ ensureRuntimeStoreMigrated();
296
+ const max = Math.max(1, limit ?? MAX_INSTANCES);
297
+ return getStateDb()
298
+ .prepare(`SELECT
299
+ id,
300
+ source_client,
301
+ display_name,
302
+ provider_logo,
303
+ state,
304
+ event,
305
+ run_id,
306
+ correlation_id,
307
+ initiative_id,
308
+ workstream_id,
309
+ task_id,
310
+ agent_id,
311
+ agent_name,
312
+ phase,
313
+ progress_pct,
314
+ current_task,
315
+ last_heartbeat_at,
316
+ last_event_at,
317
+ last_message,
318
+ metadata_json,
319
+ created_at,
320
+ updated_at
321
+ FROM runtime_instances
322
+ ORDER BY last_event_at DESC, updated_at DESC
323
+ LIMIT ?`)
324
+ .all(max);
325
+ }
326
+ function ensureRuntimeStoreMigrated() {
327
+ const migrated = readStateMeta(RUNTIME_IMPORT_META_KEY);
328
+ if (migrated)
329
+ return;
330
+ const db = getStateDb();
331
+ const countRow = db
332
+ .prepare("SELECT COUNT(*) AS count FROM runtime_instances")
333
+ .get();
334
+ if ((countRow?.count ?? 0) > 0) {
335
+ writeStateMeta(RUNTIME_IMPORT_META_KEY, true);
206
336
  return;
207
- values.sort((a, b) => Date.parse(b.lastEventAt) - Date.parse(a.lastEventAt));
208
- const keep = new Set(values.slice(0, MAX_INSTANCES).map((record) => record.id));
209
- for (const key of Object.keys(store.instances)) {
210
- if (!keep.has(key)) {
211
- delete store.instances[key];
212
- }
213
337
  }
338
+ const legacy = legacyReadRuntimeInstances();
339
+ const records = Object.values(legacy.instances)
340
+ .map((record) => normalizeRecord(record))
341
+ .filter((record) => Boolean(record.id));
342
+ const transaction = db.transaction((items) => {
343
+ for (const item of items) {
344
+ writeRuntimeRecord(item);
345
+ }
346
+ pruneRuntimeStore();
347
+ writeStateMeta(RUNTIME_IMPORT_META_KEY, true);
348
+ });
349
+ transaction(records);
214
350
  }
215
- function writeRuntimeInstances(next) {
216
- ensureRuntimeDir();
217
- const file = runtimeFile();
218
- writeJsonFileAtomicSync(file, next, 0o600);
351
+ export function readRuntimeInstances() {
352
+ const rows = readRuntimeRows(MAX_INSTANCES);
353
+ const instances = {};
354
+ let updatedAt = new Date(0).toISOString();
355
+ for (const row of rows) {
356
+ const record = rowToRecord(row);
357
+ instances[record.id] = record;
358
+ if (Date.parse(record.updatedAt) > Date.parse(updatedAt)) {
359
+ updatedAt = record.updatedAt;
360
+ }
361
+ }
362
+ return {
363
+ updatedAt: rows.length > 0 ? updatedAt : new Date().toISOString(),
364
+ instances,
365
+ };
219
366
  }
220
367
  export function upsertRuntimeInstanceFromHook(payload) {
368
+ ensureRuntimeStoreMigrated();
221
369
  const sourceClient = normalizeSourceClient(payload.source_client);
222
370
  const event = normalizeHookEvent(payload.event);
223
371
  const nowIso = new Date().toISOString();
@@ -240,8 +388,34 @@ export function upsertRuntimeInstanceFromHook(payload) {
240
388
  agentId,
241
389
  initiativeId,
242
390
  });
243
- const store = readRuntimeInstances();
244
- const existing = store.instances[id] ? normalizeRecord(store.instances[id]) : null;
391
+ const existingRow = getStateDb()
392
+ .prepare(`SELECT
393
+ id,
394
+ source_client,
395
+ display_name,
396
+ provider_logo,
397
+ state,
398
+ event,
399
+ run_id,
400
+ correlation_id,
401
+ initiative_id,
402
+ workstream_id,
403
+ task_id,
404
+ agent_id,
405
+ agent_name,
406
+ phase,
407
+ progress_pct,
408
+ current_task,
409
+ last_heartbeat_at,
410
+ last_event_at,
411
+ last_message,
412
+ metadata_json,
413
+ created_at,
414
+ updated_at
415
+ FROM runtime_instances
416
+ WHERE id = ?`)
417
+ .get(id);
418
+ const existing = existingRow ? rowToRecord(existingRow) : null;
245
419
  let state = existing?.state ?? "active";
246
420
  if (event === "session_stop")
247
421
  state = "stopped";
@@ -279,56 +453,36 @@ export function upsertRuntimeInstanceFromHook(payload) {
279
453
  createdAt: existing?.createdAt ?? eventAt,
280
454
  updatedAt: nowIso,
281
455
  };
282
- store.instances[id] = record;
283
- store.updatedAt = nowIso;
284
- pruneStore(store);
285
- writeRuntimeInstances(store);
456
+ const transaction = getStateDb().transaction((item) => {
457
+ writeRuntimeRecord(item);
458
+ pruneRuntimeStore();
459
+ });
460
+ transaction(record);
286
461
  return record;
287
462
  }
288
463
  export function applyRuntimeInstanceStaleness(options) {
464
+ ensureRuntimeStoreMigrated();
289
465
  const timeoutMs = Math.max(10_000, options?.timeoutMs ?? DEFAULT_RUNTIME_HEARTBEAT_TIMEOUT_MS);
290
466
  const nowMs = options?.nowMs ?? Date.now();
291
- const store = readRuntimeInstances();
292
- let changed = false;
293
- for (const [id, rawRecord] of Object.entries(store.instances)) {
294
- const record = normalizeRecord(rawRecord);
295
- if (record.state !== "active") {
296
- if (rawRecord !== record) {
297
- store.instances[id] = record;
298
- changed = true;
299
- }
300
- continue;
301
- }
302
- const heartbeatAt = record.lastHeartbeatAt ?? record.lastEventAt;
303
- const heartbeatEpoch = Date.parse(heartbeatAt);
304
- if (!Number.isFinite(heartbeatEpoch))
305
- continue;
306
- if (nowMs - heartbeatEpoch <= timeoutMs)
307
- continue;
308
- store.instances[id] = {
309
- ...record,
310
- state: "stale",
311
- updatedAt: new Date(nowMs).toISOString(),
312
- };
313
- changed = true;
314
- }
315
- if (changed) {
316
- store.updatedAt = new Date(nowMs).toISOString();
317
- writeRuntimeInstances(store);
318
- }
319
- return store;
467
+ const cutoffIso = new Date(nowMs - timeoutMs).toISOString();
468
+ const updatedAt = new Date(nowMs).toISOString();
469
+ getStateDb()
470
+ .prepare(`UPDATE runtime_instances
471
+ SET state = 'stale',
472
+ updated_at = ?
473
+ WHERE state = 'active'
474
+ AND COALESCE(last_heartbeat_at, last_event_at) < ?`)
475
+ .run(updatedAt, cutoffIso);
476
+ return readRuntimeInstances();
320
477
  }
321
478
  export function listRuntimeInstances(options) {
322
479
  const timeoutMs = options?.timeoutMs ?? DEFAULT_RUNTIME_HEARTBEAT_TIMEOUT_MS;
323
480
  const nowMs = options?.nowMs ?? Date.now();
324
- const store = applyRuntimeInstanceStaleness({ timeoutMs, nowMs });
325
- const limit = Math.max(1, options?.limit ?? MAX_INSTANCES);
326
- return Object.values(store.instances)
327
- .map((record) => normalizeRecord(record))
328
- .sort((a, b) => Date.parse(b.lastEventAt) - Date.parse(a.lastEventAt))
329
- .slice(0, limit);
481
+ void applyRuntimeInstanceStaleness({ timeoutMs, nowMs });
482
+ return readRuntimeRows(options?.limit ?? MAX_INSTANCES).map(rowToRecord);
330
483
  }
331
484
  export function clearRuntimeInstances() {
485
+ getStateDb().prepare("DELETE FROM runtime_instances").run();
332
486
  clearStoreFileSync(runtimeFile());
333
487
  }
334
488
  export function resolveRuntimeHookToken() {
@@ -0,0 +1,18 @@
1
+ export type MaterializedSnapshotEntry = {
2
+ cacheKey: string;
3
+ generation: number;
4
+ expiresAt: number;
5
+ updatedAt: string;
6
+ payload: Record<string, unknown>;
7
+ };
8
+ export declare function readMaterializedSnapshot(cacheKey: string, input?: {
9
+ allowStale?: boolean;
10
+ generation?: number;
11
+ nowMs?: number;
12
+ }): Record<string, unknown> | null;
13
+ export declare function writeMaterializedSnapshot(cacheKey: string, payload: Record<string, unknown>, input: {
14
+ generation: number;
15
+ ttlMs: number;
16
+ nowMs?: number;
17
+ }): void;
18
+ export declare function clearMaterializedSnapshotMemory(): void;
@@ -0,0 +1,91 @@
1
+ import { parseJsonSafe } from "./json-store.js";
2
+ import { getStateDb } from "./sqlite-state.js";
3
+ const MEMORY_CACHE_MAX = 160;
4
+ const memoryCache = new Map();
5
+ function setMemoryEntry(entry) {
6
+ memoryCache.set(entry.cacheKey, entry);
7
+ if (memoryCache.size <= MEMORY_CACHE_MAX)
8
+ return;
9
+ const oldestKey = memoryCache.keys().next().value;
10
+ if (oldestKey)
11
+ memoryCache.delete(oldestKey);
12
+ }
13
+ function rowToEntry(row) {
14
+ if (!row)
15
+ return null;
16
+ const payload = parseJsonSafe(row.payload_json);
17
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
18
+ return null;
19
+ return {
20
+ cacheKey: row.cache_key,
21
+ generation: Number(row.generation) || 0,
22
+ expiresAt: Number(row.expires_at) || 0,
23
+ updatedAt: row.updated_at,
24
+ payload,
25
+ };
26
+ }
27
+ export function readMaterializedSnapshot(cacheKey, input) {
28
+ const normalizedKey = cacheKey.trim();
29
+ if (!normalizedKey)
30
+ return null;
31
+ const allowStale = Boolean(input?.allowStale);
32
+ const generation = input?.generation ?? 0;
33
+ const nowMs = input?.nowMs ?? Date.now();
34
+ const cached = memoryCache.get(normalizedKey) ?? null;
35
+ if (cached) {
36
+ if (allowStale ||
37
+ (cached.generation === generation && cached.expiresAt > nowMs)) {
38
+ return cached.payload;
39
+ }
40
+ memoryCache.delete(normalizedKey);
41
+ }
42
+ const row = getStateDb()
43
+ .prepare(`SELECT cache_key, generation, expires_at, updated_at, payload_json
44
+ FROM materialized_snapshots
45
+ WHERE cache_key = ?`)
46
+ .get(normalizedKey);
47
+ const entry = rowToEntry(row);
48
+ if (!entry)
49
+ return null;
50
+ if (!allowStale && (entry.generation !== generation || entry.expiresAt <= nowMs)) {
51
+ return null;
52
+ }
53
+ setMemoryEntry(entry);
54
+ return entry.payload;
55
+ }
56
+ export function writeMaterializedSnapshot(cacheKey, payload, input) {
57
+ const normalizedKey = cacheKey.trim();
58
+ if (!normalizedKey)
59
+ return;
60
+ const nowMs = input.nowMs ?? Date.now();
61
+ const updatedAt = new Date(nowMs).toISOString();
62
+ const expiresAt = nowMs + Math.max(250, input.ttlMs);
63
+ const entry = {
64
+ cacheKey: normalizedKey,
65
+ generation: input.generation,
66
+ expiresAt,
67
+ updatedAt,
68
+ payload,
69
+ };
70
+ getStateDb()
71
+ .prepare(`INSERT INTO materialized_snapshots (
72
+ cache_key,
73
+ generation,
74
+ expires_at,
75
+ updated_at,
76
+ payload_json
77
+ ) VALUES (?, ?, ?, ?, ?)
78
+ ON CONFLICT(cache_key) DO UPDATE SET
79
+ generation = excluded.generation,
80
+ expires_at = excluded.expires_at,
81
+ updated_at = excluded.updated_at,
82
+ payload_json = excluded.payload_json`)
83
+ .run(normalizedKey, entry.generation, entry.expiresAt, entry.updatedAt, JSON.stringify(payload));
84
+ getStateDb()
85
+ .prepare("DELETE FROM materialized_snapshots WHERE expires_at <= ?")
86
+ .run(nowMs - 1);
87
+ setMemoryEntry(entry);
88
+ }
89
+ export function clearMaterializedSnapshotMemory() {
90
+ memoryCache.clear();
91
+ }
@@ -0,0 +1,6 @@
1
+ import Database from "better-sqlite3";
2
+ export declare function closeStateDb(): void;
3
+ export declare function getStateDb(): Database.Database;
4
+ export declare function readStateMeta<T>(key: string): T | null;
5
+ export declare function writeStateMeta(key: string, value: unknown): void;
6
+ export declare function deleteStateMeta(key: string): void;
@@ -0,0 +1,179 @@
1
+ import Database from "better-sqlite3";
2
+ import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "../paths.js";
3
+ import { ensureStoreDirSync, parseJsonSafe } from "./json-store.js";
4
+ const STATE_DB_FILENAME = "orgx-state.sqlite";
5
+ const USER_VERSION = 1;
6
+ let dbInstance = null;
7
+ let dbInstancePath = "";
8
+ let stateDbHooksRegistered = false;
9
+ function stateDbPath() {
10
+ return getOrgxPluginConfigPath(STATE_DB_FILENAME);
11
+ }
12
+ function ensureStateDbDir() {
13
+ ensureStoreDirSync(getOrgxPluginConfigDir());
14
+ }
15
+ function initializeDatabase(db) {
16
+ db.pragma("journal_mode = WAL");
17
+ db.pragma("synchronous = NORMAL");
18
+ db.pragma("busy_timeout = 5000");
19
+ const currentVersion = Number(db.pragma("user_version", { simple: true }) ?? 0);
20
+ if (currentVersion >= USER_VERSION) {
21
+ return;
22
+ }
23
+ db.exec(`
24
+ CREATE TABLE IF NOT EXISTS kv_meta (
25
+ key TEXT PRIMARY KEY,
26
+ value_json TEXT NOT NULL,
27
+ updated_at TEXT NOT NULL
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS runtime_instances (
31
+ id TEXT PRIMARY KEY,
32
+ source_client TEXT NOT NULL,
33
+ display_name TEXT NOT NULL,
34
+ provider_logo TEXT NOT NULL,
35
+ state TEXT NOT NULL,
36
+ event TEXT NOT NULL,
37
+ run_id TEXT,
38
+ correlation_id TEXT,
39
+ initiative_id TEXT,
40
+ workstream_id TEXT,
41
+ task_id TEXT,
42
+ agent_id TEXT,
43
+ agent_name TEXT,
44
+ phase TEXT,
45
+ progress_pct INTEGER,
46
+ current_task TEXT,
47
+ last_heartbeat_at TEXT,
48
+ last_event_at TEXT NOT NULL,
49
+ last_message TEXT,
50
+ metadata_json TEXT,
51
+ created_at TEXT NOT NULL,
52
+ updated_at TEXT NOT NULL
53
+ );
54
+ CREATE INDEX IF NOT EXISTS idx_runtime_instances_last_event
55
+ ON runtime_instances(last_event_at DESC);
56
+
57
+ CREATE TABLE IF NOT EXISTS agent_runs (
58
+ run_id TEXT PRIMARY KEY,
59
+ agent_id TEXT NOT NULL,
60
+ pid INTEGER,
61
+ message TEXT,
62
+ provider TEXT,
63
+ model TEXT,
64
+ initiative_id TEXT,
65
+ initiative_title TEXT,
66
+ workstream_id TEXT,
67
+ task_id TEXT,
68
+ started_at TEXT NOT NULL,
69
+ stopped_at TEXT,
70
+ status TEXT NOT NULL,
71
+ updated_at TEXT NOT NULL
72
+ );
73
+ CREATE INDEX IF NOT EXISTS idx_agent_runs_started_at
74
+ ON agent_runs(started_at DESC);
75
+
76
+ CREATE TABLE IF NOT EXISTS outbox_events (
77
+ event_id TEXT PRIMARY KEY,
78
+ queue_id TEXT NOT NULL,
79
+ event_type TEXT NOT NULL,
80
+ timestamp TEXT NOT NULL,
81
+ payload_json TEXT NOT NULL,
82
+ activity_item_json TEXT NOT NULL,
83
+ replay_failures INTEGER NOT NULL DEFAULT 0,
84
+ last_replay_error TEXT,
85
+ last_replay_at TEXT,
86
+ updated_at TEXT NOT NULL
87
+ );
88
+ CREATE INDEX IF NOT EXISTS idx_outbox_queue_timestamp
89
+ ON outbox_events(queue_id, timestamp ASC, event_id ASC);
90
+ CREATE INDEX IF NOT EXISTS idx_outbox_timestamp
91
+ ON outbox_events(timestamp DESC, event_id DESC);
92
+
93
+ CREATE TABLE IF NOT EXISTS materialized_snapshots (
94
+ cache_key TEXT PRIMARY KEY,
95
+ generation INTEGER NOT NULL,
96
+ expires_at INTEGER NOT NULL,
97
+ updated_at TEXT NOT NULL,
98
+ payload_json TEXT NOT NULL
99
+ );
100
+ CREATE INDEX IF NOT EXISTS idx_materialized_snapshots_expires_at
101
+ ON materialized_snapshots(expires_at ASC);
102
+ `);
103
+ db.pragma(`user_version = ${USER_VERSION}`);
104
+ }
105
+ export function closeStateDb() {
106
+ if (!dbInstance)
107
+ return;
108
+ try {
109
+ dbInstance.pragma("optimize");
110
+ }
111
+ catch {
112
+ // best effort
113
+ }
114
+ try {
115
+ dbInstance.close();
116
+ }
117
+ catch {
118
+ // best effort
119
+ }
120
+ dbInstance = null;
121
+ dbInstancePath = "";
122
+ }
123
+ function ensureStateDbProcessHooks() {
124
+ if (stateDbHooksRegistered)
125
+ return;
126
+ stateDbHooksRegistered = true;
127
+ const shutdown = () => {
128
+ closeStateDb();
129
+ };
130
+ process.once("beforeExit", shutdown);
131
+ process.once("exit", shutdown);
132
+ }
133
+ export function getStateDb() {
134
+ const nextPath = stateDbPath();
135
+ if (dbInstance && dbInstancePath === nextPath)
136
+ return dbInstance;
137
+ if (dbInstance && dbInstancePath !== nextPath) {
138
+ closeStateDb();
139
+ }
140
+ ensureStateDbDir();
141
+ const db = new Database(nextPath);
142
+ initializeDatabase(db);
143
+ dbInstance = db;
144
+ dbInstancePath = nextPath;
145
+ ensureStateDbProcessHooks();
146
+ return db;
147
+ }
148
+ export function readStateMeta(key) {
149
+ const normalizedKey = key.trim();
150
+ if (!normalizedKey)
151
+ return null;
152
+ const row = getStateDb()
153
+ .prepare("SELECT value_json FROM kv_meta WHERE key = ?")
154
+ .get(normalizedKey);
155
+ if (!row || typeof row.value_json !== "string")
156
+ return null;
157
+ return parseJsonSafe(row.value_json);
158
+ }
159
+ export function writeStateMeta(key, value) {
160
+ const normalizedKey = key.trim();
161
+ if (!normalizedKey)
162
+ return;
163
+ const nowIso = new Date().toISOString();
164
+ getStateDb()
165
+ .prepare(`INSERT INTO kv_meta (key, value_json, updated_at)
166
+ VALUES (?, ?, ?)
167
+ ON CONFLICT(key) DO UPDATE SET
168
+ value_json = excluded.value_json,
169
+ updated_at = excluded.updated_at`)
170
+ .run(normalizedKey, JSON.stringify(value ?? null), nowIso);
171
+ }
172
+ export function deleteStateMeta(key) {
173
+ const normalizedKey = key.trim();
174
+ if (!normalizedKey)
175
+ return;
176
+ getStateDb()
177
+ .prepare("DELETE FROM kv_meta WHERE key = ?")
178
+ .run(normalizedKey);
179
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useorgx/openclaw-plugin",
3
- "version": "0.7.18",
3
+ "version": "0.7.23",
4
4
  "description": "OrgX plugin for OpenClaw — agent orchestration, quality gates, model routing, and live dashboard",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,6 +54,7 @@
54
54
  "verify:conduit-mcp": "node ./scripts/verify-conduit-mcp.mjs",
55
55
  "verify:repo-hygiene": "node ./scripts/verify-repo-hygiene.mjs",
56
56
  "dev:main": "node ./scripts/dev-main-sync.mjs",
57
+ "dev:live": "node ./scripts/live-dev-serve.mjs",
57
58
  "e2e:auto-continue": "node ./scripts/e2e-auto-continue.mjs",
58
59
  "e2e:agent-suite": "npm run build:core && node ./scripts/e2e-agent-suite-kickoff-3x.mjs",
59
60
  "demo:record": "node ./scripts/record-demo.mjs",
@@ -113,8 +114,12 @@
113
114
  }
114
115
  },
115
116
  "devDependencies": {
117
+ "@types/better-sqlite3": "^7.6.13",
116
118
  "@types/node": "^20.19.30",
117
119
  "playwright-core": "^1.58.2",
118
120
  "typescript": "^5.9.3"
121
+ },
122
+ "dependencies": {
123
+ "better-sqlite3": "^11.10.0"
119
124
  }
120
125
  }
@@ -1 +0,0 @@
1
- import{j as s}from"./Dj2k1r16.js";function n({metrics:a,className:l}){return s.jsx("div",{className:`flex items-center gap-12 ${l??""}`,children:a.map(e=>s.jsxs("div",{children:[s.jsx("p",{className:"text-[10px] font-semibold uppercase tracking-widest text-muted",children:e.label}),s.jsxs("p",{className:"mt-1 text-2xl font-light",style:{color:typeof e.value=="number"&&e.value===0||e.value==="0"?"rgba(255,255,255,0.2)":e.color??"rgba(242,247,255,0.78)",fontVariantNumeric:"tabular-nums"},children:[e.value,e.suffix&&s.jsx("span",{className:"ml-0.5 text-sm font-normal text-muted",children:e.suffix})]})]},e.label))})}export{n as M};