@useorgx/openclaw-plugin 0.7.20 → 0.7.24
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/B6VftyY6.js +1 -0
- package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
- package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
- package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
- package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
- package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
- package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
- package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
- package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
- package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
- package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
- package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
- package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
- package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
- package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
- package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
- package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
- package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
- package/dashboard/dist/assets/BvFcH_Iy.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/C0i7ABUU.js +212 -0
- package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
- package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js +1 -0
- package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
- package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js +1 -0
- package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
- package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
- package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
- package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
- package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
- package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
- package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
- package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
- package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
- package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
- package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
- package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js +1 -0
- package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
- package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
- package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
- package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
- package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
- package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
- package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
- package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js +1 -0
- package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
- package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js +1 -0
- package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
- package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
- package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
- package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
- package/dashboard/dist/assets/MrW1ixGx.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/activity-store.js +68 -8
- 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 +45 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
- package/dist/http/helpers/auto-continue-engine.js +468 -85
- 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 +499 -6
- package/dist/http/helpers/value-utils.d.ts +1 -0
- package/dist/http/helpers/value-utils.js +17 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.js +179 -46
- 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/live-triage.js +6 -1
- package/dist/http/routes/mission-control-actions.d.ts +9 -0
- package/dist/http/routes/mission-control-actions.js +185 -7
- package/dist/http/routes/mission-control-read.d.ts +13 -0
- package/dist/http/routes/mission-control-read.js +100 -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 +330 -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 type 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;
|