@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.
Files changed (165) hide show
  1. package/dashboard/dist/assets/B6VftyY6.js +1 -0
  2. package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
  3. package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
  4. package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
  5. package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
  6. package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
  7. package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
  8. package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
  9. package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
  10. package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
  11. package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
  12. package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
  13. package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
  14. package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
  15. package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
  16. package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
  17. package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
  18. package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
  19. package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
  20. package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
  21. package/dashboard/dist/assets/BvFcH_Iy.js.gz +0 -0
  22. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  23. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  24. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  25. package/dashboard/dist/assets/C0i7ABUU.js +212 -0
  26. package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
  27. package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
  28. package/dashboard/dist/assets/CFB0MM7j.js +1 -0
  29. package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
  30. package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
  31. package/dashboard/dist/assets/CQSRb1yu.js +1 -0
  32. package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
  33. package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
  34. package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
  35. package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
  36. package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
  37. package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
  38. package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
  39. package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
  40. package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
  41. package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
  42. package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
  43. package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
  44. package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
  45. package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
  46. package/dashboard/dist/assets/DF2PMTwT.js +1 -0
  47. package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
  48. package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
  49. package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
  50. package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
  51. package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
  52. package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
  53. package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
  54. package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
  55. package/dashboard/dist/assets/DlEa8PI0.js +1 -0
  56. package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
  57. package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
  58. package/dashboard/dist/assets/M4QxcXjh.js +1 -0
  59. package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
  60. package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
  61. package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
  62. package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
  63. package/dashboard/dist/assets/MrW1ixGx.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/activity-store.js +68 -8
  68. package/dist/agent-run-store.js +162 -24
  69. package/dist/cli/orgx.d.ts +3 -0
  70. package/dist/config/resolution.d.ts +7 -0
  71. package/dist/config/resolution.js +13 -5
  72. package/dist/contracts/onboarding-state.d.ts +2 -0
  73. package/dist/contracts/onboarding-state.js +23 -0
  74. package/dist/contracts/shared-types.d.ts +45 -0
  75. package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
  76. package/dist/http/helpers/auto-continue-engine.js +468 -85
  77. package/dist/http/helpers/autopilot-runtime.js +5 -1
  78. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  79. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  80. package/dist/http/helpers/decision-mapper.js +19 -2
  81. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  82. package/dist/http/helpers/mission-control.d.ts +1 -0
  83. package/dist/http/helpers/mission-control.js +5 -2
  84. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  85. package/dist/http/helpers/slice-run-projections.js +198 -10
  86. package/dist/http/helpers/triage-mapper.js +499 -6
  87. package/dist/http/helpers/value-utils.d.ts +1 -0
  88. package/dist/http/helpers/value-utils.js +17 -0
  89. package/dist/http/index.d.ts +1 -0
  90. package/dist/http/index.js +179 -46
  91. package/dist/http/router.js +64 -9
  92. package/dist/http/routes/live-legacy.d.ts +19 -2
  93. package/dist/http/routes/live-legacy.js +110 -27
  94. package/dist/http/routes/live-snapshot.d.ts +16 -2
  95. package/dist/http/routes/live-snapshot.js +169 -25
  96. package/dist/http/routes/live-triage.js +6 -1
  97. package/dist/http/routes/mission-control-actions.d.ts +9 -0
  98. package/dist/http/routes/mission-control-actions.js +185 -7
  99. package/dist/http/routes/mission-control-read.d.ts +13 -0
  100. package/dist/http/routes/mission-control-read.js +100 -219
  101. package/dist/http/routes/onboarding.d.ts +1 -0
  102. package/dist/http/routes/onboarding.js +17 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +199 -123
  105. package/dist/outbox.d.ts +0 -2
  106. package/dist/outbox.js +259 -148
  107. package/dist/reporting/rollups.js +18 -11
  108. package/dist/runtime-instance-store.js +212 -58
  109. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  110. package/dist/stores/materialized-snapshot-store.js +91 -0
  111. package/dist/stores/sqlite-state.d.ts +6 -0
  112. package/dist/stores/sqlite-state.js +330 -0
  113. package/package.json +5 -1
  114. package/dashboard/dist/assets/B014hrCe.js.br +0 -0
  115. package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
  116. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  117. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  118. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  119. package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
  120. package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
  121. package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
  122. package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
  123. package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
  124. package/dashboard/dist/assets/BUvcp_7V.js +0 -1
  125. package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
  126. package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
  127. package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
  128. package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
  129. package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
  130. package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
  131. package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
  132. package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
  133. package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
  134. package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
  135. package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
  136. package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
  137. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  138. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  139. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  140. package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
  141. package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
  142. package/dashboard/dist/assets/CaAkScfa.js +0 -1
  143. package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
  144. package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
  145. package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
  146. package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
  147. package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
  148. package/dashboard/dist/assets/D2G51wQm.js +0 -1
  149. package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
  150. package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
  151. package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
  152. package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
  153. package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
  154. package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
  155. package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
  156. package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
  157. package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
  158. package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
  159. package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
  160. package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
  161. package/dashboard/dist/assets/uNGpYMSH.js +0 -1
  162. package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
  163. package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
  164. package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
  165. package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
@@ -41,6 +41,7 @@ import { listRuntimeInstances, resolveRuntimeHookToken, upsertRuntimeInstanceFro
41
41
  import { parseJsonSafe } from "../json-utils.js";
42
42
  import { readSkillPackState, refreshSkillPackState, rollbackSkillPackPolicy, updateSkillPackPolicy, } from "../skill-pack-state.js";
43
43
  import { posthogCapture } from "../telemetry/posthog.js";
44
+ import { clearMaterializedSnapshotMemory, readMaterializedSnapshot, writeMaterializedSnapshot, } from "../stores/materialized-snapshot-store.js";
44
45
  import { createRouter } from "./router.js";
45
46
  import { summarizeActivityHeadline } from "./helpers/activity-headline.js";
46
47
  import { createAutoContinueEngine, } from "./helpers/auto-continue-engine.js";
@@ -55,7 +56,7 @@ import { configureOpenClawProviderRouting, fetchBillingStatusSafe, isPidAlive, l
55
56
  import { fetchKickoffContextSafe, renderKickoffMessage } from "./helpers/kickoff-context.js";
56
57
  import { createDispatchLifecycle } from "./helpers/dispatch-lifecycle.js";
57
58
  import { createRuntimeSseHub } from "./helpers/runtime-sse.js";
58
- import { parseBooleanQuery, parsePositiveInt, pickHeaderString, pickNumber, pickString, } from "./helpers/value-utils.js";
59
+ import { parseBooleanQuery, pickBoolean, parsePositiveInt, pickHeaderString, pickNumber, pickString, } from "./helpers/value-utils.js";
59
60
  import { registerAgentControlRoutes } from "./routes/agent-control.js";
60
61
  import { registerAgentSuiteRoutes } from "./routes/agent-suite.js";
61
62
  import { registerAgentsCatalogRoutes } from "./routes/agents-catalog.js";
@@ -271,7 +272,6 @@ async function mapWithConcurrency(items, concurrency, mapper) {
271
272
  const ACTIVITY_WARM_THROTTLE_MS = 30_000;
272
273
  const activityWarmByKey = new Map();
273
274
  const SNAPSHOT_RESPONSE_CACHE_TTL_MS = 800;
274
- const SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES = 16;
275
275
  const SNAPSHOT_ACTIVITY_PERSIST_MIN_INTERVAL_MS = 15_000;
276
276
  const SNAPSHOT_ACTIVITY_FINGERPRINT_DEPTH = 8;
277
277
  const NEXT_UP_QUEUE_CACHE_TTL_MS = readPositiveIntEnv("ORGX_NEXT_UP_QUEUE_CACHE_TTL_MS", 30_000, { min: 250, max: 120_000 });
@@ -292,7 +292,6 @@ const LIVE_WORKSPACE_INITIATIVE_STATUSES = [
292
292
  let lastSnapshotActivityPersistAt = 0;
293
293
  let lastSnapshotActivityFingerprint = "";
294
294
  let snapshotCacheGeneration = 0;
295
- const snapshotResponseCache = new Map();
296
295
  const ACTIVITY_DECISION_EVENT_HINTS = new Set([
297
296
  "decision_buffered",
298
297
  "auto_continue_spawn_guard_blocked",
@@ -435,39 +434,24 @@ function snapshotActivityFingerprint(items) {
435
434
  .join(";");
436
435
  return `${items.length}:${sample}`;
437
436
  }
438
- function readSnapshotResponseCache(key) {
439
- const entry = snapshotResponseCache.get(key);
440
- if (!entry)
441
- return null;
442
- if (entry.generation !== snapshotCacheGeneration || entry.expiresAt <= Date.now()) {
443
- snapshotResponseCache.delete(key);
444
- return null;
445
- }
446
- return entry.payload;
437
+ function getSnapshotCacheGeneration() {
438
+ return snapshotCacheGeneration;
439
+ }
440
+ function readSnapshotResponseCache(key, options) {
441
+ return readMaterializedSnapshot(key, {
442
+ allowStale: options?.allowStale,
443
+ generation: snapshotCacheGeneration,
444
+ });
447
445
  }
448
446
  function writeSnapshotResponseCache(key, payload) {
449
- const now = Date.now();
450
- snapshotResponseCache.set(key, {
451
- expiresAt: now + SNAPSHOT_RESPONSE_CACHE_TTL_MS,
447
+ writeMaterializedSnapshot(key, payload, {
452
448
  generation: snapshotCacheGeneration,
453
- payload,
449
+ ttlMs: SNAPSHOT_RESPONSE_CACHE_TTL_MS,
454
450
  });
455
- if (snapshotResponseCache.size <= SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES)
456
- return;
457
- for (const [cachedKey, entry] of snapshotResponseCache.entries()) {
458
- if (entry.expiresAt <= now)
459
- snapshotResponseCache.delete(cachedKey);
460
- }
461
- while (snapshotResponseCache.size > SNAPSHOT_RESPONSE_CACHE_MAX_ENTRIES) {
462
- const oldestKey = snapshotResponseCache.keys().next().value;
463
- if (!oldestKey)
464
- break;
465
- snapshotResponseCache.delete(oldestKey);
466
- }
467
451
  }
468
452
  function clearSnapshotResponseCache() {
469
453
  snapshotCacheGeneration += 1;
470
- snapshotResponseCache.clear();
454
+ clearMaterializedSnapshotMemory();
471
455
  }
472
456
  function isUserScopedApiKey(apiKey) {
473
457
  return apiKey.trim().toLowerCase().startsWith("oxk_");
@@ -1751,9 +1735,36 @@ async function parseJsonRequest(req) {
1751
1735
  }
1752
1736
  return parseJsonBody(streamed);
1753
1737
  }
1754
- // =============================================================================
1755
- // Factory
1756
- // =============================================================================
1738
+ let activeHttpRuntimeLifecycle = null;
1739
+ function createHttpRuntimeLifecycle(input) {
1740
+ let nextUpPrewarmTimer = null;
1741
+ let autoContinueTimer = null;
1742
+ const stop = () => {
1743
+ if (nextUpPrewarmTimer) {
1744
+ clearTimeout(nextUpPrewarmTimer);
1745
+ nextUpPrewarmTimer = null;
1746
+ }
1747
+ if (autoContinueTimer) {
1748
+ clearInterval(autoContinueTimer);
1749
+ autoContinueTimer = null;
1750
+ }
1751
+ };
1752
+ return {
1753
+ start() {
1754
+ stop();
1755
+ nextUpPrewarmTimer = setTimeout(() => {
1756
+ nextUpPrewarmTimer = null;
1757
+ input.prewarmNextUpQueue();
1758
+ }, 75);
1759
+ nextUpPrewarmTimer.unref?.();
1760
+ autoContinueTimer = setInterval(() => {
1761
+ void input.tickAllAutoContinue();
1762
+ }, input.autoContinueTickMs);
1763
+ autoContinueTimer.unref?.();
1764
+ },
1765
+ stop,
1766
+ };
1767
+ }
1757
1768
  export function createHttpHandler(config, client, getSnapshot, onboarding, diagnostics, adapters) {
1758
1769
  const dashboardEnabled = config.dashboardEnabled ??
1759
1770
  true;
@@ -2400,6 +2411,30 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2400
2411
  ? entry.blockers[0] ??
2401
2412
  (statusValues.includes("failed") ? "Latest run failed" : "Workstream blocked")
2402
2413
  : null,
2414
+ canStartNow: queueState === QueueState.QUEUED || queueState === QueueState.IDLE,
2415
+ startReasonCode: queueState === QueueState.RUNNING
2416
+ ? "already_running"
2417
+ : hasBlocked
2418
+ ? "blocked"
2419
+ : queueState === QueueState.QUEUED || queueState === QueueState.IDLE
2420
+ ? "dispatchable"
2421
+ : "not_startable",
2422
+ startReasonLabel: hasBlocked
2423
+ ? entry.blockers[0] ??
2424
+ (statusValues.includes("failed") ? "Latest run failed." : "Workstream blocked.")
2425
+ : queueState === QueueState.RUNNING
2426
+ ? "Already running."
2427
+ : "Ready to start this workstream.",
2428
+ dispatchableTask: queueState === QueueState.QUEUED || queueState === QueueState.IDLE
2429
+ ? {
2430
+ id: entry.latest.id ?? `${entry.initiativeId}:${entry.workstreamId}`,
2431
+ title: (entry.latest.lastEventSummary ?? "").trim() ||
2432
+ (entry.latest.title ?? "").trim() ||
2433
+ entry.workstreamTitle,
2434
+ scope: "workstream",
2435
+ milestoneId: null,
2436
+ }
2437
+ : null,
2403
2438
  isPinned: pinnedRankByKey.has(pinKey),
2404
2439
  pinnedRank: pinnedRankByKey.get(pinKey) ?? null,
2405
2440
  autoContinue: null,
@@ -2492,6 +2527,14 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2492
2527
  const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
2493
2528
  const workstreamNodes = graph.nodes.filter((node) => node.type === "workstream");
2494
2529
  const runningWorkstreams = new Set();
2530
+ const initiativeRun = autoContinueRuns.get(initiativeId) ?? null;
2531
+ const initiativeActiveRunIds = Array.isArray(initiativeRun?.activeSliceRunIds)
2532
+ ? initiativeRun.activeSliceRunIds
2533
+ .filter((id) => typeof id === "string" && id.trim().length > 0)
2534
+ .map((id) => id.trim())
2535
+ : typeof initiativeRun?.activeRunId === "string" && initiativeRun.activeRunId.trim().length > 0
2536
+ ? [initiativeRun.activeRunId.trim()]
2537
+ : [];
2495
2538
  const taskIsReady = (task) => task.dependencyIds.every((depId) => {
2496
2539
  const dependency = nodeById.get(depId);
2497
2540
  return dependency ? isDoneStatus(dependency.status) : true;
@@ -2692,6 +2735,36 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2692
2735
  if (isSuppressed(initiativeId, workstream.id) && queueState !== QueueState.RUNNING) {
2693
2736
  continue;
2694
2737
  }
2738
+ const dispatchableTask = preferredReadyTask ?? readyTask ?? null;
2739
+ const initiativeHasConcurrentRun = initiativeActiveRunIds.length > 0 &&
2740
+ laneState !== LaneState.RUNNING &&
2741
+ !(autoContinueRun && autoContinueRun.status === RunStatus.RUNNING);
2742
+ const canStartNow = Boolean(dispatchableTask) &&
2743
+ queueState !== QueueState.RUNNING &&
2744
+ queueState !== QueueState.BLOCKED &&
2745
+ !initiativeHasConcurrentRun;
2746
+ const startReasonCode = canStartNow
2747
+ ? "dispatchable"
2748
+ : queueState === QueueState.RUNNING
2749
+ ? "already_running"
2750
+ : initiativeHasConcurrentRun
2751
+ ? "initiative_run_active"
2752
+ : queueState === QueueState.BLOCKED
2753
+ ? "blocked"
2754
+ : !dispatchableTask
2755
+ ? "no_dispatchable_task"
2756
+ : "not_startable";
2757
+ const startReasonLabel = canStartNow
2758
+ ? `Ready to start ${dispatchableTask?.title ?? "this workstream"}.`
2759
+ : initiativeHasConcurrentRun
2760
+ ? "Autopilot is already running for this initiative."
2761
+ : queueState === QueueState.RUNNING
2762
+ ? "Already running."
2763
+ : blockReason
2764
+ ? blockReason
2765
+ : dispatchableTask
2766
+ ? "This workstream is not ready to start."
2767
+ : "No dispatchable task is available right now.";
2695
2768
  runningWorkstreams.add(workstream.id);
2696
2769
  const assignedRunnerAgents = [];
2697
2770
  const assignedRunnerSeen = new Set();
@@ -2752,6 +2825,17 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2752
2825
  runnerSource,
2753
2826
  queueState,
2754
2827
  blockReason,
2828
+ canStartNow,
2829
+ startReasonCode,
2830
+ startReasonLabel,
2831
+ dispatchableTask: dispatchableTask
2832
+ ? {
2833
+ id: dispatchableTask.id,
2834
+ title: dispatchableTask.title,
2835
+ scope: defaultScope,
2836
+ milestoneId: dispatchableTask.milestoneId ?? null,
2837
+ }
2838
+ : null,
2755
2839
  isPinned: Boolean(pin),
2756
2840
  pinnedRank: pin ? (pinnedRankByKey.get(pinKey) ?? null) : null,
2757
2841
  sliceScope: defaultScope,
@@ -2859,6 +2943,12 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2859
2943
  blockReason: queueState === QueueState.BLOCKED
2860
2944
  ? lane?.blockedReason ?? "Blocked"
2861
2945
  : null,
2946
+ canStartNow: false,
2947
+ startReasonCode: queueState === QueueState.RUNNING ? "already_running" : "initiative_run_active",
2948
+ startReasonLabel: queueState === QueueState.RUNNING
2949
+ ? "Already running."
2950
+ : "Autopilot is already running for this initiative.",
2951
+ dispatchableTask: null,
2862
2952
  isPinned: Boolean(pinnedByKey.get(`${initiativeId}:${workstream.id}`)),
2863
2953
  pinnedRank: pinnedRankByKey.get(`${initiativeId}:${workstream.id}`) ?? null,
2864
2954
  sliceScope,
@@ -2962,12 +3052,14 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
2962
3052
  // best effort prewarm only
2963
3053
  });
2964
3054
  };
2965
- const nextUpPrewarmTimer = setTimeout(prewarmNextUpQueue, 75);
2966
- nextUpPrewarmTimer.unref?.();
2967
- const autoContinueTimer = setInterval(() => {
2968
- void tickAllAutoContinue();
2969
- }, AUTO_CONTINUE_TICK_MS);
2970
- autoContinueTimer.unref?.();
3055
+ activeHttpRuntimeLifecycle?.stop();
3056
+ const runtimeLifecycle = createHttpRuntimeLifecycle({
3057
+ prewarmNextUpQueue,
3058
+ tickAllAutoContinue,
3059
+ autoContinueTickMs: AUTO_CONTINUE_TICK_MS,
3060
+ });
3061
+ runtimeLifecycle.start();
3062
+ activeHttpRuntimeLifecycle = runtimeLifecycle;
2971
3063
  const apiRouter = createRouter();
2972
3064
  registerOnboardingRoutes(apiRouter, {
2973
3065
  onboarding,
@@ -3511,6 +3603,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3511
3603
  outboxReadAllItems: () => outboxAdapter.readAllItems(),
3512
3604
  toLocalLiveActivity,
3513
3605
  loadLocalTurnDetail,
3606
+ summarizeActivityHeadline,
3514
3607
  sendJson,
3515
3608
  safeErrorMessage,
3516
3609
  sendHtml,
@@ -3539,6 +3632,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3539
3632
  parsePositiveInt,
3540
3633
  readSnapshotResponseCache,
3541
3634
  writeSnapshotResponseCache,
3635
+ getSnapshotCacheGeneration,
3542
3636
  safeErrorMessage,
3543
3637
  readAgentContexts,
3544
3638
  getScopedAgentIds,
@@ -3596,6 +3690,8 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3596
3690
  listChatThreads: ({ commandCenterId, initiativeId, limit, offset }) => listChatThreads({ commandCenterId, initiativeId, limit, offset }),
3597
3691
  getCanonicalAutopilotState,
3598
3692
  sendJson,
3693
+ securityHeaders: SECURITY_HEADERS,
3694
+ corsHeaders: CORS_HEADERS,
3599
3695
  });
3600
3696
  registerRuntimeHookRoutes(apiRouter, {
3601
3697
  parseJsonRequest,
@@ -3679,12 +3775,18 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3679
3775
  const keys = [...scopedKeys, ...fallbackKeys];
3680
3776
  const seen = new Set();
3681
3777
  const mapped = [];
3682
- const deriveFailureType = (eventNameRaw, actionTypeRaw) => {
3778
+ const deriveFailureType = (eventNameRaw, actionTypeRaw, reasonRaw, blockingRaw) => {
3683
3779
  const eventName = (eventNameRaw ?? "").trim().toLowerCase();
3684
3780
  const actionType = (actionTypeRaw ?? "").trim().toLowerCase();
3685
- const signature = `${eventName} ${actionType}`;
3781
+ const reason = (reasonRaw ?? "").trim().toLowerCase();
3782
+ const signature = `${eventName} ${actionType} ${reason}`;
3686
3783
  if (!signature.trim())
3687
3784
  return null;
3785
+ if (signature.includes("question_asked") ||
3786
+ signature.includes("review_item_created") ||
3787
+ signature.includes("decision_requested")) {
3788
+ return blockingRaw === false ? "review_required" : "decision_required";
3789
+ }
3688
3790
  if (signature.includes("status_updates_buffered"))
3689
3791
  return "status_updates_buffered";
3690
3792
  if (signature.includes("question_answer_failed"))
@@ -3707,6 +3809,18 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3707
3809
  return "budget_exhausted";
3708
3810
  if (signature.includes("stale_blocked_workstream"))
3709
3811
  return "stale_blocked_workstream";
3812
+ if (signature.includes("credit") ||
3813
+ signature.includes("insufficient_quota") ||
3814
+ signature.includes("insufficient credit") ||
3815
+ signature.includes("payment required")) {
3816
+ return "budget_exhausted";
3817
+ }
3818
+ if (signature.includes("run_failed") ||
3819
+ signature.includes("autopilot_slice_result") ||
3820
+ signature.includes("autopilot_slice_finished") ||
3821
+ signature.includes("failed")) {
3822
+ return "worker_exit_no_output";
3823
+ }
3710
3824
  return null;
3711
3825
  };
3712
3826
  try {
@@ -3724,7 +3838,22 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3724
3838
  const metadataRecord = activityRecord.metadata && typeof activityRecord.metadata === "object"
3725
3839
  ? activityRecord.metadata
3726
3840
  : {};
3727
- const failureType = deriveFailureType(pickString(metadataRecord, ["event", "event_name"]), pickString(metadataRecord, ["action_type", "actionType"]));
3841
+ const resultRecord = metadataRecord.result && typeof metadataRecord.result === "object"
3842
+ ? metadataRecord.result
3843
+ : null;
3844
+ const blockerRecord = metadataRecord.blocker && typeof metadataRecord.blocker === "object"
3845
+ ? metadataRecord.blocker
3846
+ : resultRecord && resultRecord.blocker && typeof resultRecord.blocker === "object"
3847
+ ? resultRecord.blocker
3848
+ : null;
3849
+ const reasonText = pickString(blockerRecord ?? {}, ["description", "summary"]) ??
3850
+ pickString(resultRecord ?? {}, ["error", "reason", "blocked_reason", "blockedReason", "summary"]) ??
3851
+ pickString(metadataRecord, ["error", "reason", "message", "blocked_reason", "blockedReason"]) ??
3852
+ pickString(activityRecord, ["description", "summary", "title"]);
3853
+ const blockingSignal = pickBoolean(metadataRecord, ["blocking"]) ??
3854
+ pickBoolean(resultRecord, ["blocking"]);
3855
+ const failureType = deriveFailureType(pickString(metadataRecord, ["event", "event_name"]), pickString(metadataRecord, ["action_type", "actionType"]) ??
3856
+ pickString(activityRecord, ["type"]), reasonText, blockingSignal);
3728
3857
  if (!failureType)
3729
3858
  continue;
3730
3859
  const runId = pickString(metadataRecord, ["run_id", "source_run_id"]) ?? pickString(activityRecord, ["runId"]);
@@ -3743,9 +3872,9 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3743
3872
  mapped.push({
3744
3873
  id: dedupeId,
3745
3874
  failureType,
3746
- reason: pickString(metadataRecord, ["error", "reason", "message"]) ??
3747
- pickString(activityRecord, ["description", "summary", "title"]),
3748
- provider: pickString(metadataRecord, ["provider"]),
3875
+ reason: reasonText,
3876
+ provider: pickString(metadataRecord, ["provider"]) ??
3877
+ pickString(blockerRecord ?? {}, ["provider"]),
3749
3878
  initiativeId,
3750
3879
  initiativeTitle: pickString(metadataRecord, ["initiative_title"]) ??
3751
3880
  pickString(activityRecord, ["initiativeTitle"]),
@@ -3759,8 +3888,12 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
3759
3888
  domain: pickString(metadataRecord, ["domain", "executor_domain"]),
3760
3889
  sourceSystem: pickString(metadataRecord, ["source_system", "source"]) ?? "openclaw",
3761
3890
  runId,
3762
- logPath: pickString(metadataRecord, ["log_path"]),
3763
- outputPath: pickString(metadataRecord, ["output_path"]),
3891
+ logPath: pickString(metadataRecord, ["log_path"]) ??
3892
+ pickString(resultRecord ?? {}, ["log_path"]) ??
3893
+ pickString(blockerRecord ?? {}, ["log_path"]),
3894
+ outputPath: pickString(metadataRecord, ["output_path"]) ??
3895
+ pickString(resultRecord ?? {}, ["output_path"]) ??
3896
+ pickString(blockerRecord ?? {}, ["output_path"]),
3764
3897
  metadata: metadataRecord,
3765
3898
  timestamp: timestamp ?? undefined,
3766
3899
  });
@@ -1,20 +1,75 @@
1
- function isPatternMatch(pattern, path) {
2
- if (pattern.endsWith("/*")) {
3
- return path.startsWith(pattern.slice(0, -1));
1
+ function normalizePrefixBase(pattern) {
2
+ return pattern.endsWith("/*") ? pattern.slice(0, -1) : null;
3
+ }
4
+ function getOrCreateBucket(map, key) {
5
+ const existing = map.get(key);
6
+ if (existing)
7
+ return existing;
8
+ const created = [];
9
+ map.set(key, created);
10
+ return created;
11
+ }
12
+ function getOrCreateMethodBuckets(map, method) {
13
+ const existing = map.get(method);
14
+ if (existing)
15
+ return existing;
16
+ const created = new Map();
17
+ map.set(method, created);
18
+ return created;
19
+ }
20
+ function collectPathPrefixBases(path) {
21
+ const bases = new Set();
22
+ let slashIndex = path.indexOf("/");
23
+ while (slashIndex !== -1) {
24
+ bases.add(path.slice(0, slashIndex + 1));
25
+ slashIndex = path.indexOf("/", slashIndex + 1);
4
26
  }
5
- return pattern === path;
27
+ bases.add(`${path}/`);
28
+ return Array.from(bases);
6
29
  }
7
30
  export function createRouter() {
8
31
  const entries = [];
32
+ const exactRoutes = new Map();
33
+ const prefixRoutes = new Map();
9
34
  function add(method, pattern, handler, description) {
10
- entries.push({ method, pattern, handler, description });
35
+ const route = {
36
+ method,
37
+ pattern,
38
+ handler,
39
+ description,
40
+ order: entries.length,
41
+ prefixBase: normalizePrefixBase(pattern),
42
+ };
43
+ entries.push(route);
44
+ if (route.prefixBase) {
45
+ getOrCreateBucket(getOrCreateMethodBuckets(prefixRoutes, method), route.prefixBase).push(route);
46
+ return;
47
+ }
48
+ getOrCreateBucket(getOrCreateMethodBuckets(exactRoutes, method), pattern).push(route);
49
+ }
50
+ function pickEarlierRoute(current, candidate) {
51
+ if (!current)
52
+ return candidate;
53
+ return candidate.order < current.order ? candidate : current;
54
+ }
55
+ function matchFromBuckets(routeBuckets, method, key, current) {
56
+ const methodBuckets = routeBuckets.get(method);
57
+ const wildcardBuckets = routeBuckets.get("*");
58
+ for (const candidate of methodBuckets?.get(key) ?? []) {
59
+ current = pickEarlierRoute(current, candidate);
60
+ }
61
+ for (const candidate of wildcardBuckets?.get(key) ?? []) {
62
+ current = pickEarlierRoute(current, candidate);
63
+ }
64
+ return current;
11
65
  }
12
66
  function match(method, path) {
13
67
  const normalizedMethod = method.toUpperCase();
14
- return entries.find((route) => {
15
- const methodMatches = route.method === "*" || route.method === normalizedMethod;
16
- return methodMatches && isPatternMatch(route.pattern, path);
17
- });
68
+ let matched = matchFromBuckets(exactRoutes, normalizedMethod, path, undefined);
69
+ for (const base of collectPathPrefixBases(path)) {
70
+ matched = matchFromBuckets(prefixRoutes, normalizedMethod, base, matched);
71
+ }
72
+ return matched;
18
73
  }
19
74
  function routes() {
20
75
  return entries;
@@ -13,6 +13,8 @@ type LocalLiveActivity = {
13
13
  };
14
14
  type LiveActivityPage = {
15
15
  activities: LiveActivityItem[];
16
+ total?: number;
17
+ storeUpdatedAt?: string;
16
18
  cursor?: string | null;
17
19
  nextCursor?: string | null;
18
20
  prevCursor?: string | null;
@@ -34,7 +36,7 @@ type RouteResLike = {
34
36
  on?: (event: string, listener: () => void) => void;
35
37
  once?: (event: string, listener: () => void) => void;
36
38
  };
37
- type RegisterLiveLegacyRoutesDeps<TRes extends RouteResLike> = {
39
+ type RegisterLiveLegacyRoutesDeps<TReq extends RouteReqLike, TRes extends RouteResLike> = {
38
40
  getLiveSessions: (input: {
39
41
  initiative: string | null;
40
42
  projectId: string | null;
@@ -82,6 +84,15 @@ type RegisterLiveLegacyRoutesDeps<TRes extends RouteResLike> = {
82
84
  sessionKey: string | null;
83
85
  runId: string | null;
84
86
  }) => Promise<Record<string, unknown> | null>;
87
+ summarizeActivityHeadline: (input: {
88
+ text: string;
89
+ title: string | null;
90
+ type: string | null;
91
+ }) => Promise<{
92
+ headline: string;
93
+ source: string;
94
+ model: string | null;
95
+ }>;
85
96
  sendJson: (res: TRes, status: number, payload: unknown) => void;
86
97
  safeErrorMessage: (err: unknown) => string;
87
98
  sendHtml: (res: TRes, status: number, html: string) => void;
@@ -112,6 +123,12 @@ type RegisterLiveLegacyRoutesDeps<TRes extends RouteResLike> = {
112
123
  };
113
124
  isUserScopedApiKey: (apiKey: string) => boolean;
114
125
  streamIdleTimeoutMs: number;
126
+ renderLiveStreamV2?: (input: {
127
+ path: string;
128
+ query: URLSearchParams;
129
+ req: TReq;
130
+ res: TRes;
131
+ }) => Promise<void>;
115
132
  };
116
- export declare function registerLiveLegacyRoutes<TReq extends RouteReqLike, TRes extends RouteResLike>(router: Router<Record<string, never>, TReq, TRes>, deps: RegisterLiveLegacyRoutesDeps<TRes>): void;
133
+ export declare function registerLiveLegacyRoutes<TReq extends RouteReqLike, TRes extends RouteResLike>(router: Router<Record<string, never>, TReq, TRes>, deps: RegisterLiveLegacyRoutesDeps<TReq, TRes>): void;
117
134
  export {};