@useorgx/openclaw-plugin 0.7.20 → 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.
- package/dashboard/dist/assets/9gFmK3Kr.js +1 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.br +0 -0
- package/dashboard/dist/assets/9gFmK3Kr.js.gz +0 -0
- package/dashboard/dist/assets/{BoDhb8_y.js → BrMXbzQ-.js} +2 -2
- package/dashboard/dist/assets/BrMXbzQ-.js.br +0 -0
- package/dashboard/dist/assets/BrMXbzQ-.js.gz +0 -0
- package/dashboard/dist/assets/By0MIBj_.js +1 -0
- package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
- package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
- package/dashboard/dist/assets/C1u2SGin.css +1 -0
- package/dashboard/dist/assets/C1u2SGin.css.br +0 -0
- package/dashboard/dist/assets/C1u2SGin.css.gz +0 -0
- package/dashboard/dist/assets/{DAr4MfFk.js → CGJiHCIx.js} +1 -1
- package/dashboard/dist/assets/CGJiHCIx.js.br +0 -0
- package/dashboard/dist/assets/CGJiHCIx.js.gz +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js +212 -0
- package/dashboard/dist/assets/CSd4rSuU.js.br +0 -0
- package/dashboard/dist/assets/CSd4rSuU.js.gz +0 -0
- package/dashboard/dist/assets/{DibzNd0I.js → CZXS5i_5.js} +1 -1
- package/dashboard/dist/assets/CZXS5i_5.js.br +0 -0
- package/dashboard/dist/assets/CZXS5i_5.js.gz +0 -0
- package/dashboard/dist/assets/{wa4jJQK9.js → CbVWL74-.js} +1 -1
- package/dashboard/dist/assets/CbVWL74-.js.br +0 -0
- package/dashboard/dist/assets/CbVWL74-.js.gz +0 -0
- package/dashboard/dist/assets/{Dm0CfDGr.js → D-FuHfT8.js} +1 -1
- package/dashboard/dist/assets/D-FuHfT8.js.br +0 -0
- package/dashboard/dist/assets/D-FuHfT8.js.gz +0 -0
- package/dashboard/dist/assets/{DXVs61e1.js → D0PN5_vY.js} +1 -1
- package/dashboard/dist/assets/D0PN5_vY.js.br +0 -0
- package/dashboard/dist/assets/D0PN5_vY.js.gz +0 -0
- package/dashboard/dist/assets/{_zpQCpjm.js → DDCPrZRt.js} +1 -1
- package/dashboard/dist/assets/DDCPrZRt.js.br +0 -0
- package/dashboard/dist/assets/DDCPrZRt.js.gz +0 -0
- package/dashboard/dist/assets/{BYb6DARX.js → DNQ-iFO2.js} +1 -1
- package/dashboard/dist/assets/DNQ-iFO2.js.br +0 -0
- package/dashboard/dist/assets/DNQ-iFO2.js.gz +0 -0
- package/dashboard/dist/assets/{BGY6oI8h.js → DhPuHPK7.js} +1 -1
- package/dashboard/dist/assets/DhPuHPK7.js.br +0 -0
- package/dashboard/dist/assets/DhPuHPK7.js.gz +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js +1 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.br +0 -0
- package/dashboard/dist/assets/Dhz7qPtn.js.gz +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js +1 -0
- package/dashboard/dist/assets/LOFrVoPD.js.br +0 -0
- package/dashboard/dist/assets/LOFrVoPD.js.gz +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js +1 -0
- package/dashboard/dist/assets/OlLPtzdz.js.br +0 -0
- package/dashboard/dist/assets/OlLPtzdz.js.gz +0 -0
- package/dashboard/dist/assets/{B014hrCe.js → RN4M9u9W.js} +2 -2
- package/dashboard/dist/assets/RN4M9u9W.js.br +0 -0
- package/dashboard/dist/assets/RN4M9u9W.js.gz +0 -0
- package/dashboard/dist/assets/VCHu272d.js +1 -0
- package/dashboard/dist/assets/VCHu272d.js.br +0 -0
- package/dashboard/dist/assets/VCHu272d.js.gz +0 -0
- package/dashboard/dist/assets/m2smti3F.js +1 -0
- package/dashboard/dist/assets/m2smti3F.js.br +0 -0
- package/dashboard/dist/assets/m2smti3F.js.gz +0 -0
- package/dashboard/dist/assets/{CV0sWMbv.js → nra1yvJX.js} +1 -1
- package/dashboard/dist/assets/nra1yvJX.js.br +0 -0
- package/dashboard/dist/assets/nra1yvJX.js.gz +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js +1 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.br +0 -0
- package/dashboard/dist/assets/qLX6NZ-J.js.gz +0 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/agent-run-store.js +162 -24
- package/dist/cli/orgx.d.ts +3 -0
- package/dist/config/resolution.d.ts +7 -0
- package/dist/config/resolution.js +13 -5
- package/dist/contracts/onboarding-state.d.ts +2 -0
- package/dist/contracts/onboarding-state.js +23 -0
- package/dist/contracts/shared-types.d.ts +17 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
- package/dist/http/helpers/auto-continue-engine.js +233 -53
- package/dist/http/helpers/autopilot-runtime.js +5 -1
- package/dist/http/helpers/autopilot-slice-utils.js +25 -1
- package/dist/http/helpers/decision-mapper.d.ts +1 -0
- package/dist/http/helpers/decision-mapper.js +19 -2
- package/dist/http/helpers/dispatch-lifecycle.js +3 -0
- package/dist/http/helpers/mission-control.d.ts +1 -0
- package/dist/http/helpers/mission-control.js +5 -2
- package/dist/http/helpers/slice-run-projections.d.ts +27 -0
- package/dist/http/helpers/slice-run-projections.js +198 -10
- package/dist/http/helpers/triage-mapper.js +220 -6
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +92 -45
- package/dist/http/router.js +64 -9
- package/dist/http/routes/live-legacy.d.ts +19 -2
- package/dist/http/routes/live-legacy.js +110 -27
- package/dist/http/routes/live-snapshot.d.ts +16 -2
- package/dist/http/routes/live-snapshot.js +169 -25
- package/dist/http/routes/mission-control-actions.js +28 -0
- package/dist/http/routes/mission-control-read.d.ts +4 -0
- package/dist/http/routes/mission-control-read.js +67 -219
- package/dist/http/routes/onboarding.d.ts +1 -0
- package/dist/http/routes/onboarding.js +17 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +199 -123
- package/dist/outbox.d.ts +0 -2
- package/dist/outbox.js +259 -148
- package/dist/reporting/rollups.js +18 -11
- package/dist/runtime-instance-store.js +212 -58
- package/dist/stores/materialized-snapshot-store.d.ts +18 -0
- package/dist/stores/materialized-snapshot-store.js +91 -0
- package/dist/stores/sqlite-state.d.ts +6 -0
- package/dist/stores/sqlite-state.js +179 -0
- package/package.json +5 -1
- package/dashboard/dist/assets/B014hrCe.js.br +0 -0
- package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
- package/dashboard/dist/assets/BCudUvwg.js +0 -1
- package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
- package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
- package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
- package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
- package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
- package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js +0 -1
- package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
- package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
- package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
- package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
- package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
- package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
- package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
- package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js +0 -1
- package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
- package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
- package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
- package/dashboard/dist/assets/CaAkScfa.js +0 -1
- package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
- package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
- package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
- package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
- package/dashboard/dist/assets/D2G51wQm.js +0 -1
- package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
- package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
- package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
- package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
- package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
- package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
- package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js +0 -1
- package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
- package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
- package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
- package/dashboard/dist/assets/wa4jJQK9.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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
204
|
-
|
|
205
|
-
|
|
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
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
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
|
|
244
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
325
|
-
|
|
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.
|
|
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",
|
|
@@ -114,8 +114,12 @@
|
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
117
118
|
"@types/node": "^20.19.30",
|
|
118
119
|
"playwright-core": "^1.58.2",
|
|
119
120
|
"typescript": "^5.9.3"
|
|
121
|
+
},
|
|
122
|
+
"dependencies": {
|
|
123
|
+
"better-sqlite3": "^11.10.0"
|
|
120
124
|
}
|
|
121
125
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -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};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|