@useorgx/openclaw-plugin 0.4.9 → 0.7.0

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 (222) hide show
  1. package/README.md +35 -0
  2. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  3. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  4. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  5. package/dashboard/dist/assets/BXWDRGm-.js +1 -0
  6. package/dashboard/dist/assets/BXWDRGm-.js.br +0 -0
  7. package/dashboard/dist/assets/BXWDRGm-.js.gz +0 -0
  8. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  9. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  10. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  11. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  12. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  13. package/dashboard/dist/assets/CE38zU4U.js +1 -0
  14. package/dashboard/dist/assets/CE38zU4U.js.br +0 -0
  15. package/dashboard/dist/assets/CE38zU4U.js.gz +0 -0
  16. package/dashboard/dist/assets/CFGKRAzG.js +1 -0
  17. package/dashboard/dist/assets/CFGKRAzG.js.br +0 -0
  18. package/dashboard/dist/assets/CFGKRAzG.js.gz +0 -0
  19. package/dashboard/dist/assets/CGGR2GZh.js +1 -0
  20. package/dashboard/dist/assets/CGGR2GZh.js.br +0 -0
  21. package/dashboard/dist/assets/CGGR2GZh.js.gz +0 -0
  22. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  23. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  24. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  25. package/dashboard/dist/assets/CPFiTmlw.js +8 -0
  26. package/dashboard/dist/assets/CPFiTmlw.js.br +0 -0
  27. package/dashboard/dist/assets/CPFiTmlw.js.gz +0 -0
  28. package/dashboard/dist/assets/CZZTvkQZ.js +1 -0
  29. package/dashboard/dist/assets/CZZTvkQZ.js.br +0 -0
  30. package/dashboard/dist/assets/CZZTvkQZ.js.gz +0 -0
  31. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  32. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  33. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  34. package/dashboard/dist/assets/D-bf6hEI.js +213 -0
  35. package/dashboard/dist/assets/D-bf6hEI.js.br +0 -0
  36. package/dashboard/dist/assets/D-bf6hEI.js.gz +0 -0
  37. package/dashboard/dist/assets/DG6y9wJI.js +2 -0
  38. package/dashboard/dist/assets/DG6y9wJI.js.br +0 -0
  39. package/dashboard/dist/assets/DG6y9wJI.js.gz +0 -0
  40. package/dashboard/dist/assets/DNxKz-GV.js +1 -0
  41. package/dashboard/dist/assets/DNxKz-GV.js.br +0 -0
  42. package/dashboard/dist/assets/DNxKz-GV.js.gz +0 -0
  43. package/dashboard/dist/assets/DW_rKUic.js +11 -0
  44. package/dashboard/dist/assets/DW_rKUic.js.br +0 -0
  45. package/dashboard/dist/assets/DW_rKUic.js.gz +0 -0
  46. package/dashboard/dist/assets/DbNoijHm.js +1 -0
  47. package/dashboard/dist/assets/DbNoijHm.js.br +0 -0
  48. package/dashboard/dist/assets/DbNoijHm.js.gz +0 -0
  49. package/dashboard/dist/assets/DjcdE6jC.js +2 -0
  50. package/dashboard/dist/assets/DjcdE6jC.js.br +0 -0
  51. package/dashboard/dist/assets/DjcdE6jC.js.gz +0 -0
  52. package/dashboard/dist/assets/FZYuCDnt.js +1 -0
  53. package/dashboard/dist/assets/FZYuCDnt.js.br +0 -0
  54. package/dashboard/dist/assets/FZYuCDnt.js.gz +0 -0
  55. package/dashboard/dist/assets/PAUiij_z.js +1 -0
  56. package/dashboard/dist/assets/PAUiij_z.js.br +0 -0
  57. package/dashboard/dist/assets/PAUiij_z.js.gz +0 -0
  58. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  59. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  60. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  61. package/dashboard/dist/assets/h5biQs2I.css +1 -0
  62. package/dashboard/dist/assets/h5biQs2I.css.br +0 -0
  63. package/dashboard/dist/assets/h5biQs2I.css.gz +0 -0
  64. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  65. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  66. package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
  67. package/dashboard/dist/assets/nByHNHoW.js +1 -0
  68. package/dashboard/dist/assets/nByHNHoW.js.br +0 -0
  69. package/dashboard/dist/assets/nByHNHoW.js.gz +0 -0
  70. package/dashboard/dist/assets/qm8xLgv-.css +1 -0
  71. package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
  72. package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
  73. package/dashboard/dist/assets/tS9mbYZi.js +1 -0
  74. package/dashboard/dist/assets/tS9mbYZi.js.br +0 -0
  75. package/dashboard/dist/assets/tS9mbYZi.js.gz +0 -0
  76. package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
  77. package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
  78. package/dashboard/dist/brand/openai-mark.svg.br +0 -0
  79. package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
  80. package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
  81. package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
  82. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  83. package/dashboard/dist/index.html +7 -5
  84. package/dashboard/dist/index.html.br +0 -0
  85. package/dashboard/dist/index.html.gz +0 -0
  86. package/dist/activity-actor-fields.js +26 -4
  87. package/dist/activity-store.js +34 -8
  88. package/dist/agent-context-store.js +79 -17
  89. package/dist/agent-run-store.js +44 -3
  90. package/dist/agent-suite.d.ts +9 -0
  91. package/dist/agent-suite.js +149 -9
  92. package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
  93. package/dist/artifacts/artifact-domain-schemas.js +357 -0
  94. package/dist/artifacts/register-artifact.d.ts +4 -3
  95. package/dist/artifacts/register-artifact.js +170 -57
  96. package/dist/chat-store.d.ts +157 -0
  97. package/dist/chat-store.js +586 -0
  98. package/dist/cli/orgx.js +11 -0
  99. package/dist/contracts/client.d.ts +43 -3
  100. package/dist/contracts/client.js +159 -30
  101. package/dist/contracts/retro-schema.d.ts +81 -0
  102. package/dist/contracts/retro-schema.js +80 -0
  103. package/dist/contracts/shared-types.d.ts +159 -0
  104. package/dist/contracts/shared-types.js +177 -1
  105. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  106. package/dist/contracts/skill-pack-schema.js +180 -0
  107. package/dist/contracts/types.d.ts +227 -2
  108. package/dist/entities/auto-assignment.js +43 -17
  109. package/dist/event-sanitization.d.ts +11 -0
  110. package/dist/event-sanitization.js +113 -0
  111. package/dist/fs-utils.js +13 -1
  112. package/dist/gateway-watchdog.d.ts +5 -0
  113. package/dist/gateway-watchdog.js +50 -0
  114. package/dist/hooks/post-reporting-event.mjs +1 -5
  115. package/dist/http/helpers/activity-headline.js +13 -132
  116. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  117. package/dist/http/helpers/auto-continue-engine.js +2531 -186
  118. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  119. package/dist/http/helpers/autopilot-operations.js +182 -31
  120. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  121. package/dist/http/helpers/autopilot-runtime.js +308 -20
  122. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  123. package/dist/http/helpers/autopilot-slice-utils.js +516 -93
  124. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  125. package/dist/http/helpers/decision-mapper.js +223 -7
  126. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  127. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  128. package/dist/http/helpers/kickoff-context.js +74 -0
  129. package/dist/http/helpers/llm-client.d.ts +47 -0
  130. package/dist/http/helpers/llm-client.js +256 -0
  131. package/dist/http/helpers/mission-control.d.ts +102 -3
  132. package/dist/http/helpers/mission-control.js +498 -9
  133. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  134. package/dist/http/helpers/sentinel-catalog.js +193 -0
  135. package/dist/http/helpers/session-classification.d.ts +9 -0
  136. package/dist/http/helpers/session-classification.js +564 -0
  137. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  138. package/dist/http/helpers/slice-experience-v2.js +677 -0
  139. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  140. package/dist/http/helpers/slice-run-projections.js +860 -0
  141. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  142. package/dist/http/helpers/triage-mapper.js +549 -0
  143. package/dist/http/helpers/value-utils.js +7 -2
  144. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  145. package/dist/http/helpers/workspace-scope.js +170 -0
  146. package/dist/http/index.js +1354 -97
  147. package/dist/http/routes/agent-suite.d.ts +9 -0
  148. package/dist/http/routes/agent-suite.js +207 -8
  149. package/dist/http/routes/agents-catalog.js +64 -19
  150. package/dist/http/routes/chat.d.ts +19 -0
  151. package/dist/http/routes/chat.js +522 -0
  152. package/dist/http/routes/decision-actions.d.ts +8 -1
  153. package/dist/http/routes/decision-actions.js +42 -5
  154. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  155. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  156. package/dist/http/routes/entities.d.ts +16 -0
  157. package/dist/http/routes/entities.js +294 -6
  158. package/dist/http/routes/live-legacy.d.ts +5 -0
  159. package/dist/http/routes/live-legacy.js +23 -509
  160. package/dist/http/routes/live-misc.d.ts +12 -0
  161. package/dist/http/routes/live-misc.js +251 -31
  162. package/dist/http/routes/live-snapshot.d.ts +48 -2
  163. package/dist/http/routes/live-snapshot.js +638 -19
  164. package/dist/http/routes/live-terminal.d.ts +11 -0
  165. package/dist/http/routes/live-terminal.js +261 -0
  166. package/dist/http/routes/live-triage.d.ts +61 -0
  167. package/dist/http/routes/live-triage.js +248 -0
  168. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  169. package/dist/http/routes/mission-control-actions.js +1334 -84
  170. package/dist/http/routes/mission-control-read.d.ts +48 -3
  171. package/dist/http/routes/mission-control-read.js +1593 -20
  172. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  173. package/dist/http/routes/realtime-orchestrator.js +74 -0
  174. package/dist/http/routes/run-control.d.ts +5 -2
  175. package/dist/http/routes/run-control.js +10 -0
  176. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  177. package/dist/http/routes/sentinels-catalog.js +24 -0
  178. package/dist/http/routes/summary.js +10 -3
  179. package/dist/http/routes/usage.d.ts +24 -0
  180. package/dist/http/routes/usage.js +362 -0
  181. package/dist/http/routes/work-artifacts.js +28 -9
  182. package/dist/index.js +165 -27
  183. package/dist/local-openclaw.js +29 -6
  184. package/dist/mcp-client-setup.js +3 -3
  185. package/dist/mcp-http-handler.js +33 -59
  186. package/dist/next-up-queue-store.d.ts +16 -1
  187. package/dist/next-up-queue-store.js +89 -7
  188. package/dist/outbox.d.ts +5 -0
  189. package/dist/outbox.js +113 -9
  190. package/dist/paths.js +24 -5
  191. package/dist/reporting/rollups.d.ts +53 -0
  192. package/dist/reporting/rollups.js +148 -0
  193. package/dist/retro/domain-templates.d.ts +45 -0
  194. package/dist/retro/domain-templates.js +297 -0
  195. package/dist/retro/quality-rubric.d.ts +33 -0
  196. package/dist/retro/quality-rubric.js +213 -0
  197. package/dist/runtime-cleanup.d.ts +18 -0
  198. package/dist/runtime-cleanup.js +87 -0
  199. package/dist/services/background.d.ts +11 -0
  200. package/dist/services/background.js +22 -0
  201. package/dist/services/experiment-randomization.d.ts +21 -0
  202. package/dist/services/experiment-randomization.js +63 -0
  203. package/dist/skill-pack-state.d.ts +36 -5
  204. package/dist/skill-pack-state.js +273 -29
  205. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  206. package/dist/sync/local-agent-telemetry.js +128 -0
  207. package/dist/sync/outbox-replay.js +131 -24
  208. package/dist/team-context-store.d.ts +23 -0
  209. package/dist/team-context-store.js +116 -0
  210. package/dist/telemetry/posthog.js +4 -2
  211. package/dist/tools/core-tools.d.ts +10 -14
  212. package/dist/tools/core-tools.js +1289 -24
  213. package/dist/types.d.ts +2 -0
  214. package/dist/types.js +2 -0
  215. package/dist/worker-supervisor.js +23 -0
  216. package/package.json +14 -4
  217. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  218. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  219. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  220. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  221. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  222. package/dashboard/dist/assets/sAhvFnpk.js +0 -4
@@ -0,0 +1,10 @@
1
+ import type { Router } from "../router.js";
2
+ type JsonRecord = Record<string, unknown>;
3
+ type RegisterRealtimeOrchestratorRoutesDeps<TReq, TRes> = {
4
+ parseJsonRequest: (req: TReq) => Promise<JsonRecord>;
5
+ rawRequest: (method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", path: string, body?: unknown) => Promise<unknown>;
6
+ sendJson: (res: TRes, status: number, payload: unknown) => void;
7
+ safeErrorMessage: (err: unknown) => string;
8
+ };
9
+ export declare function registerRealtimeOrchestratorRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: RegisterRealtimeOrchestratorRoutesDeps<TReq, TRes>): void;
10
+ export {};
@@ -0,0 +1,74 @@
1
+ function parseStatusCodeFromError(message) {
2
+ const normalized = message.trim();
3
+ const match = normalized.match(/^(\d{3})\b/);
4
+ if (!match)
5
+ return 500;
6
+ const value = Number(match[1]);
7
+ if (!Number.isFinite(value))
8
+ return 500;
9
+ if (value < 400 || value > 599)
10
+ return 500;
11
+ return value;
12
+ }
13
+ export function registerRealtimeOrchestratorRoutes(router, deps) {
14
+ router.add("POST", "realtime/session", async ({ req, res }) => {
15
+ try {
16
+ const payload = await deps.parseJsonRequest(req);
17
+ const upstream = await deps.rawRequest("POST", "/api/client/orchestrator/realtime/session", payload);
18
+ deps.sendJson(res, 200, upstream);
19
+ }
20
+ catch (err) {
21
+ const message = deps.safeErrorMessage(err);
22
+ deps.sendJson(res, parseStatusCodeFromError(message), { ok: false, error: message });
23
+ }
24
+ }, "Create an ephemeral GPT realtime session for orchestrator voice control");
25
+ router.add("POST", "orchestrator/commands/preview", async ({ req, res }) => {
26
+ try {
27
+ const payload = await deps.parseJsonRequest(req);
28
+ const upstream = await deps.rawRequest("POST", "/api/client/orchestrator/commands/preview", payload);
29
+ deps.sendJson(res, 200, upstream);
30
+ }
31
+ catch (err) {
32
+ const message = deps.safeErrorMessage(err);
33
+ deps.sendJson(res, parseStatusCodeFromError(message), { ok: false, error: message });
34
+ }
35
+ }, "Preview inferred orchestrator actions from natural language input");
36
+ router.add("POST", "orchestrator/commands/apply", async ({ req, res }) => {
37
+ try {
38
+ const payload = await deps.parseJsonRequest(req);
39
+ const upstream = await deps.rawRequest("POST", "/api/client/orchestrator/commands/apply", payload);
40
+ deps.sendJson(res, 200, upstream);
41
+ }
42
+ catch (err) {
43
+ const message = deps.safeErrorMessage(err);
44
+ deps.sendJson(res, parseStatusCodeFromError(message), { ok: false, error: message });
45
+ }
46
+ }, "Apply confirmed orchestrator actions");
47
+ router.add("GET", "orchestrator/commands/*", async ({ path, res }) => {
48
+ const match = path.match(/^orchestrator\/commands\/([^/]+)$/);
49
+ if (!match) {
50
+ deps.sendJson(res, 404, { ok: false, error: "Unknown API endpoint" });
51
+ return;
52
+ }
53
+ let commandId = "";
54
+ try {
55
+ commandId = decodeURIComponent(match[1] ?? "").trim();
56
+ }
57
+ catch {
58
+ deps.sendJson(res, 400, { ok: false, error: "invalid command id encoding" });
59
+ return;
60
+ }
61
+ if (!commandId) {
62
+ deps.sendJson(res, 400, { ok: false, error: "command id is required" });
63
+ return;
64
+ }
65
+ try {
66
+ const upstream = await deps.rawRequest("GET", `/api/client/orchestrator/commands/${encodeURIComponent(commandId)}`);
67
+ deps.sendJson(res, 200, upstream);
68
+ }
69
+ catch (err) {
70
+ const message = deps.safeErrorMessage(err);
71
+ deps.sendJson(res, parseStatusCodeFromError(message), { ok: false, error: message });
72
+ }
73
+ }, "Read orchestrator command status");
74
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Router } from "../router.js";
2
2
  type JsonRecord = Record<string, unknown>;
3
- type RunAction = "pause" | "resume" | "cancel" | "rollback";
3
+ type RunAction = "pause" | "resume" | "cancel" | "rollback" | "complete";
4
4
  type RegisterRunControlRoutesDeps<TReq, TRes> = {
5
5
  parseJsonRequest: (req: TReq) => Promise<JsonRecord>;
6
6
  pickString: (input: Record<string, unknown>, keys: string[]) => string | null;
@@ -13,10 +13,13 @@ type RegisterRunControlRoutesDeps<TReq, TRes> = {
13
13
  checkpointId: string;
14
14
  reason?: string;
15
15
  }) => Promise<unknown>;
16
- runAction: (runId: string, action: RunAction, input: {
16
+ runAction: (runId: string, action: Exclude<RunAction, "complete">, input: {
17
17
  checkpointId?: string;
18
18
  reason?: string;
19
19
  }) => Promise<unknown>;
20
+ markRunCompleted: (runId: string, input: {
21
+ reason?: string;
22
+ }) => Promise<unknown>;
20
23
  sendJson: (res: TRes, status: number, payload: unknown) => void;
21
24
  safeErrorMessage: (err: unknown) => string;
22
25
  };
@@ -70,6 +70,13 @@ export function registerRunControlRoutes(router, deps) {
70
70
  const payload = await deps.parseJsonRequest(req);
71
71
  const checkpointId = deps.pickString(payload, ["checkpointId", "checkpoint_id"]);
72
72
  const reason = deps.pickString(payload, ["reason"]);
73
+ if (action === "complete") {
74
+ const data = await deps.markRunCompleted(runId, {
75
+ reason: reason ?? undefined,
76
+ });
77
+ deps.sendJson(res, 200, data);
78
+ return;
79
+ }
73
80
  const data = await deps.runAction(runId, action, {
74
81
  checkpointId: checkpointId ?? undefined,
75
82
  reason: reason ?? undefined,
@@ -77,6 +84,9 @@ export function registerRunControlRoutes(router, deps) {
77
84
  deps.sendJson(res, 200, data);
78
85
  }
79
86
  catch (err) {
87
+ const actionLabel = runActionMatch ? runActionMatch[2] : "unknown";
88
+ const runLabel = runActionMatch ? runActionMatch[1] : "unknown";
89
+ console.error(`[run-control] ${actionLabel} failed for run ${runLabel}:`, err);
80
90
  deps.sendJson(res, 500, { error: deps.safeErrorMessage(err) });
81
91
  }
82
92
  return;
@@ -0,0 +1,7 @@
1
+ import type { Router } from "../router.js";
2
+ type SentinelsCatalogDeps<TRes> = {
3
+ sendJson: (res: TRes, status: number, payload: unknown) => void;
4
+ safeErrorMessage: (err: unknown) => string;
5
+ };
6
+ export declare function registerSentinelsCatalogRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: SentinelsCatalogDeps<TRes>): void;
7
+ export {};
@@ -0,0 +1,24 @@
1
+ import { listBuiltInSentinels } from "../helpers/sentinel-catalog.js";
2
+ export function registerSentinelsCatalogRoutes(router, deps) {
3
+ async function handle(res, domain) {
4
+ try {
5
+ const sentinels = listBuiltInSentinels({ domain });
6
+ deps.sendJson(res, 200, {
7
+ generatedAt: new Date().toISOString(),
8
+ domain: domain ?? null,
9
+ sentinels,
10
+ });
11
+ }
12
+ catch (err) {
13
+ deps.sendJson(res, 500, {
14
+ error: deps.safeErrorMessage(err),
15
+ });
16
+ }
17
+ }
18
+ router.add("GET", "sentinels/catalog", async ({ query, res }) => {
19
+ return handle(res, query?.get("domain") ?? undefined);
20
+ }, "Sentinel catalog");
21
+ router.add("HEAD", "sentinels/catalog", async ({ query, res }) => {
22
+ return handle(res, query?.get("domain") ?? undefined);
23
+ }, "Sentinel catalog (HEAD)");
24
+ }
@@ -1,4 +1,11 @@
1
1
  export function registerSummaryRoutes(router, deps) {
2
+ const sendDeprecated = (res, endpoint, replacement) => {
3
+ deps.sendJson(res, 410, {
4
+ error: `${endpoint} is deprecated`,
5
+ replacement,
6
+ required_scope: "workspace_id",
7
+ });
8
+ };
2
9
  router.add("HEAD", "status", async ({ res }) => {
3
10
  let snapshot = deps.getSnapshot();
4
11
  if (!snapshot) {
@@ -28,13 +35,13 @@ export function registerSummaryRoutes(router, deps) {
28
35
  deps.sendJson(res, 200, deps.formatStatus(snapshot));
29
36
  }, "Status snapshot");
30
37
  router.add("GET", "agents", ({ res }) => {
31
- deps.sendJson(res, 200, deps.formatAgents(deps.getSnapshot()));
38
+ sendDeprecated(res, "/orgx/api/agents", "/orgx/api/live/agents");
32
39
  }, "Agent summary");
33
40
  router.add("GET", "activity", ({ res }) => {
34
- deps.sendJson(res, 200, deps.formatActivity(deps.getSnapshot()));
41
+ sendDeprecated(res, "/orgx/api/activity", "/orgx/api/live/snapshot");
35
42
  }, "Activity summary");
36
43
  router.add("GET", "initiatives", ({ res }) => {
37
- deps.sendJson(res, 200, deps.formatInitiatives(deps.getSnapshot()));
44
+ sendDeprecated(res, "/orgx/api/initiatives", "/orgx/api/live/initiatives");
38
45
  }, "Initiatives summary");
39
46
  router.add("GET", "onboarding", async ({ res }) => {
40
47
  deps.sendJson(res, 200, await deps.getOnboardingState());
@@ -0,0 +1,24 @@
1
+ import type { LiveActivityItem, UsageControlPlaneSummary } from "../../types.js";
2
+ import type { Router } from "../router.js";
3
+ type UsageClientLike = {
4
+ getUsageControlPlaneSummary: () => Promise<UsageControlPlaneSummary>;
5
+ };
6
+ type UsageRoutesDeps<TRes> = {
7
+ client: UsageClientLike;
8
+ listActivityPage: (input: {
9
+ limit: number;
10
+ runId?: string | null;
11
+ since?: string | null;
12
+ until?: string | null;
13
+ cursor?: string | null;
14
+ }) => {
15
+ activities: LiveActivityItem[];
16
+ nextCursor: string | null;
17
+ total: number;
18
+ };
19
+ sendJson: (res: TRes, status: number, payload: unknown) => void;
20
+ safeErrorMessage: (err: unknown) => string;
21
+ now?: () => Date;
22
+ };
23
+ export declare function registerUsageRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: UsageRoutesDeps<TRes>): void;
24
+ export {};
@@ -0,0 +1,362 @@
1
+ const DAY_MS = 24 * 60 * 60_000;
2
+ const MAX_ACTIVITY_PAGES = 12;
3
+ const PAGE_LIMIT = 500;
4
+ function clampInt(value, min, max) {
5
+ if (!Number.isFinite(value))
6
+ return min;
7
+ const rounded = Math.floor(value);
8
+ if (rounded < min)
9
+ return min;
10
+ if (rounded > max)
11
+ return max;
12
+ return rounded;
13
+ }
14
+ function toEpoch(value) {
15
+ if (!value)
16
+ return 0;
17
+ const parsed = Date.parse(value);
18
+ return Number.isFinite(parsed) ? parsed : 0;
19
+ }
20
+ function toNumber(value) {
21
+ if (typeof value === "number" && Number.isFinite(value))
22
+ return value;
23
+ if (typeof value === "string") {
24
+ const parsed = Number(value);
25
+ if (Number.isFinite(parsed))
26
+ return parsed;
27
+ }
28
+ return null;
29
+ }
30
+ function normalizeText(value) {
31
+ if (typeof value !== "string")
32
+ return null;
33
+ const trimmed = value.trim();
34
+ return trimmed.length > 0 ? trimmed : null;
35
+ }
36
+ function asRecord(value) {
37
+ if (!value || typeof value !== "object" || Array.isArray(value))
38
+ return null;
39
+ return value;
40
+ }
41
+ function pickMetadataNumber(metadata, keys) {
42
+ if (!metadata)
43
+ return null;
44
+ for (const key of keys) {
45
+ const parsed = toNumber(metadata[key]);
46
+ if (parsed !== null)
47
+ return parsed;
48
+ }
49
+ return null;
50
+ }
51
+ function pickMetadataString(metadata, keys) {
52
+ if (!metadata)
53
+ return null;
54
+ for (const key of keys) {
55
+ const normalized = normalizeText(metadata[key]);
56
+ if (normalized)
57
+ return normalized;
58
+ }
59
+ return null;
60
+ }
61
+ function roundInt(value) {
62
+ if (!Number.isFinite(value))
63
+ return 0;
64
+ return Math.max(0, Math.round(value));
65
+ }
66
+ function addToBucket(map, key, runRef, tokens, minutes, costCents) {
67
+ const normalizedKey = key.trim() || "unknown";
68
+ const bucket = map.get(normalizedKey) ??
69
+ {
70
+ runs: new Set(),
71
+ tokens: 0,
72
+ minutes: 0,
73
+ costCents: 0,
74
+ };
75
+ bucket.runs.add(runRef);
76
+ bucket.tokens += tokens;
77
+ bucket.minutes += minutes;
78
+ bucket.costCents += costCents;
79
+ map.set(normalizedKey, bucket);
80
+ }
81
+ function mapToBreakdownBuckets(map, labelTransform) {
82
+ return Array.from(map.entries())
83
+ .map(([key, value]) => ({
84
+ key,
85
+ label: labelTransform ? labelTransform(key) : key,
86
+ runs: value.runs.size,
87
+ tokens: roundInt(value.tokens),
88
+ minutes: roundInt(value.minutes),
89
+ costCents: roundInt(value.costCents),
90
+ }))
91
+ .sort((a, b) => {
92
+ if (b.runs !== a.runs)
93
+ return b.runs - a.runs;
94
+ return b.tokens - a.tokens;
95
+ });
96
+ }
97
+ function startOfMonthUtc(now) {
98
+ return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
99
+ }
100
+ function startOfNextMonthUtc(now) {
101
+ return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
102
+ }
103
+ function capitalizeLabel(input) {
104
+ const normalized = input.trim();
105
+ if (!normalized)
106
+ return "Unknown";
107
+ return normalized
108
+ .split(/[\s_-]+/g)
109
+ .map((part) => part.length > 0 ? `${part[0].toUpperCase()}${part.slice(1).toLowerCase()}` : part)
110
+ .join(" ");
111
+ }
112
+ function buildLocalSummary(input) {
113
+ const periodStartIso = input.periodStart.toISOString();
114
+ const periodEndIso = input.periodEnd.toISOString();
115
+ const nowEpoch = input.now.getTime();
116
+ const startEpoch = input.periodStart.getTime();
117
+ const endEpoch = input.periodEnd.getTime();
118
+ const daysTotal = Math.max(1, Math.round((endEpoch - startEpoch) / DAY_MS));
119
+ const elapsedWindow = Math.max(0, nowEpoch - startEpoch);
120
+ const daysElapsed = clampInt(Math.floor(elapsedWindow / DAY_MS) + 1, 1, daysTotal);
121
+ const daysRemaining = Math.max(0, daysTotal - daysElapsed);
122
+ const runIds = new Set();
123
+ let totalTokens = 0;
124
+ let totalMinutes = 0;
125
+ let totalCostCents = 0;
126
+ let usedFallbackMinutes = false;
127
+ const sourceClientBuckets = new Map();
128
+ const providerBuckets = new Map();
129
+ const modelBuckets = new Map();
130
+ const executionTargetBuckets = new Map();
131
+ for (const item of input.activities) {
132
+ const timestampEpoch = toEpoch(item.timestamp);
133
+ if (!timestampEpoch || timestampEpoch < startEpoch || timestampEpoch >= endEpoch)
134
+ continue;
135
+ const metadata = asRecord(item.metadata);
136
+ const runId = normalizeText(item.runId) ??
137
+ pickMetadataString(metadata, ["run_id", "runId", "correlation_id", "correlationId"]) ??
138
+ item.id;
139
+ runIds.add(runId);
140
+ const rawTokens = pickMetadataNumber(metadata, [
141
+ "tokens_used",
142
+ "tokensUsed",
143
+ "total_tokens",
144
+ "totalTokens",
145
+ "auto_continue_tokens_used",
146
+ ]) ?? 0;
147
+ const rawMinutes = pickMetadataNumber(metadata, [
148
+ "duration_minutes",
149
+ "durationMinutes",
150
+ "elapsed_minutes",
151
+ "elapsedMinutes",
152
+ "minutes",
153
+ ]) ??
154
+ (() => {
155
+ const durationMs = pickMetadataNumber(metadata, ["duration_ms", "durationMs", "elapsed_ms"]);
156
+ return durationMs !== null ? durationMs / 60_000 : null;
157
+ })();
158
+ const minutes = rawMinutes !== null ? Math.max(0, rawMinutes) : 0;
159
+ if (rawMinutes === null)
160
+ usedFallbackMinutes = true;
161
+ const rawCostCents = pickMetadataNumber(metadata, ["cost_cents", "costCents"]) ??
162
+ (() => {
163
+ const costUsd = pickMetadataNumber(metadata, ["cost_usd", "costUsd"]);
164
+ return costUsd !== null ? costUsd * 100 : null;
165
+ })() ??
166
+ 0;
167
+ const tokens = Math.max(0, rawTokens);
168
+ const costCents = Math.max(0, rawCostCents);
169
+ totalTokens += tokens;
170
+ totalMinutes += minutes;
171
+ totalCostCents += costCents;
172
+ const sourceClient = pickMetadataString(metadata, ["source_client", "sourceClient", "runtime_source", "runtimeSource"]) ??
173
+ normalizeText(item.runtimeClient) ??
174
+ "unknown";
175
+ const provider = pickMetadataString(metadata, ["provider", "runtime_provider", "runtimeProvider"]) ??
176
+ normalizeText(item.runtimeProvider) ??
177
+ "unknown";
178
+ const model = pickMetadataString(metadata, ["model", "model_id", "modelId"]) ?? "unknown";
179
+ const executionTarget = pickMetadataString(metadata, ["execution_target", "executionTarget", "executor"]) ??
180
+ "unknown";
181
+ addToBucket(sourceClientBuckets, sourceClient, runId, tokens, minutes, costCents);
182
+ addToBucket(providerBuckets, provider, runId, tokens, minutes, costCents);
183
+ addToBucket(modelBuckets, model, runId, tokens, minutes, costCents);
184
+ addToBucket(executionTargetBuckets, executionTarget, runId, tokens, minutes, costCents);
185
+ }
186
+ if (usedFallbackMinutes && runIds.size > 0 && totalMinutes === 0) {
187
+ totalMinutes = runIds.size * 4;
188
+ input.warnings.push("Agent minutes are estimated from run volume because duration telemetry was unavailable.");
189
+ }
190
+ const scale = daysElapsed > 0 ? daysTotal / daysElapsed : 1;
191
+ const predictedRuns = roundInt(runIds.size * scale);
192
+ const predictedMinutes = roundInt(totalMinutes * scale);
193
+ const predictedTokens = roundInt(totalTokens * scale);
194
+ const predictedCostCents = roundInt(totalCostCents * scale);
195
+ const confidence = Math.max(0.4, Math.min(0.95, daysElapsed / Math.max(daysTotal, 1)));
196
+ return {
197
+ generatedAt: new Date().toISOString(),
198
+ period: {
199
+ start: periodStartIso,
200
+ end: periodEndIso,
201
+ daysTotal,
202
+ daysElapsed,
203
+ daysRemaining,
204
+ },
205
+ plan: {
206
+ id: "local_estimate",
207
+ name: "Local Runtime Estimate",
208
+ allowsOverage: true,
209
+ includedBudgetCents: 0,
210
+ overageBudgetCents: 0,
211
+ agentRunsLimit: 0,
212
+ agentMinutesLimit: 0,
213
+ scaffoldsLimit: 0,
214
+ },
215
+ actual: {
216
+ agentRuns: runIds.size,
217
+ agentMinutes: roundInt(totalMinutes),
218
+ tokens: roundInt(totalTokens),
219
+ costCents: roundInt(totalCostCents),
220
+ scaffoldsUsed: 0,
221
+ scaffoldsRemaining: 0,
222
+ },
223
+ predicted: {
224
+ agentRuns: predictedRuns,
225
+ agentMinutes: predictedMinutes,
226
+ tokens: predictedTokens,
227
+ costCents: predictedCostCents,
228
+ confidence: Number(confidence.toFixed(2)),
229
+ method: "local_linear_projection",
230
+ remainingAgentRuns: Math.max(0, predictedRuns - runIds.size),
231
+ remainingAgentMinutes: Math.max(0, predictedMinutes - roundInt(totalMinutes)),
232
+ remainingTokens: Math.max(0, predictedTokens - roundInt(totalTokens)),
233
+ remainingCostCents: Math.max(0, predictedCostCents - roundInt(totalCostCents)),
234
+ },
235
+ utilization: {
236
+ runsPct: null,
237
+ minutesPct: null,
238
+ budgetPct: null,
239
+ },
240
+ headroom: {
241
+ agentRunsRemaining: 0,
242
+ agentMinutesRemaining: 0,
243
+ budgetRemainingCents: 0,
244
+ },
245
+ risk: "safe",
246
+ breakdown: {
247
+ sourceClient: mapToBreakdownBuckets(sourceClientBuckets, capitalizeLabel),
248
+ provider: mapToBreakdownBuckets(providerBuckets, capitalizeLabel),
249
+ model: mapToBreakdownBuckets(modelBuckets, (key) => key),
250
+ executionTarget: mapToBreakdownBuckets(executionTargetBuckets, capitalizeLabel),
251
+ },
252
+ velocity: {
253
+ windowDays: daysElapsed,
254
+ dailyAvgRuns: Number((runIds.size / Math.max(daysElapsed, 1)).toFixed(2)),
255
+ dailyAvgMinutes: Number((totalMinutes / Math.max(daysElapsed, 1)).toFixed(2)),
256
+ dailyAvgTokens: Number((totalTokens / Math.max(daysElapsed, 1)).toFixed(2)),
257
+ dailyAvgCostCents: Number((totalCostCents / Math.max(daysElapsed, 1)).toFixed(2)),
258
+ },
259
+ };
260
+ }
261
+ function collectLocalActivities(deps, input) {
262
+ const merged = [];
263
+ let cursor = null;
264
+ for (let page = 0; page < MAX_ACTIVITY_PAGES; page += 1) {
265
+ const result = deps.listActivityPage({
266
+ limit: PAGE_LIMIT,
267
+ since: input.sinceIso,
268
+ until: input.untilIso,
269
+ cursor,
270
+ });
271
+ if (Array.isArray(result.activities) && result.activities.length > 0) {
272
+ merged.push(...result.activities);
273
+ }
274
+ if (!result.nextCursor || result.nextCursor === cursor)
275
+ break;
276
+ cursor = result.nextCursor;
277
+ }
278
+ return merged;
279
+ }
280
+ async function resolveUsageSummary(deps) {
281
+ try {
282
+ const summary = await deps.client.getUsageControlPlaneSummary();
283
+ return {
284
+ summary,
285
+ source: "cloud",
286
+ warnings: [],
287
+ };
288
+ }
289
+ catch (err) {
290
+ const warnings = [
291
+ `Cloud usage endpoint unavailable (${deps.safeErrorMessage(err)}). Showing local estimate.`,
292
+ ];
293
+ const now = deps.now ? deps.now() : new Date();
294
+ const periodStart = startOfMonthUtc(now);
295
+ const periodEnd = startOfNextMonthUtc(now);
296
+ const activities = collectLocalActivities(deps, {
297
+ sinceIso: periodStart.toISOString(),
298
+ untilIso: periodEnd.toISOString(),
299
+ });
300
+ const summary = buildLocalSummary({
301
+ activities,
302
+ periodStart,
303
+ periodEnd,
304
+ now,
305
+ warnings,
306
+ });
307
+ return {
308
+ summary,
309
+ source: "local_estimate",
310
+ warnings,
311
+ };
312
+ }
313
+ }
314
+ export function registerUsageRoutes(router, deps) {
315
+ router.add("GET", "usage/control-plane/summary", async ({ res }) => {
316
+ const resolved = await resolveUsageSummary(deps);
317
+ deps.sendJson(res, 200, {
318
+ ...resolved.summary,
319
+ source: resolved.source,
320
+ warnings: resolved.warnings,
321
+ });
322
+ }, "Usage control-plane summary");
323
+ router.add("GET", "usage/unified", async ({ res }) => {
324
+ const resolved = await resolveUsageSummary(deps);
325
+ deps.sendJson(res, 200, {
326
+ generatedAt: resolved.summary.generatedAt,
327
+ period: resolved.summary.period,
328
+ plan: resolved.summary.plan,
329
+ actual: resolved.summary.actual,
330
+ predicted: resolved.summary.predicted,
331
+ headroom: resolved.summary.headroom,
332
+ utilization: resolved.summary.utilization,
333
+ risk: resolved.summary.risk,
334
+ breakdown: resolved.summary.breakdown,
335
+ velocity: resolved.summary.velocity,
336
+ source: resolved.source,
337
+ warnings: resolved.warnings,
338
+ });
339
+ }, "Usage unified summary");
340
+ router.add("GET", "usage/forecast", async ({ res }) => {
341
+ const resolved = await resolveUsageSummary(deps);
342
+ deps.sendJson(res, 200, {
343
+ generatedAt: resolved.summary.generatedAt,
344
+ period: resolved.summary.period,
345
+ predicted: resolved.summary.predicted,
346
+ risk: resolved.summary.risk,
347
+ headroom: resolved.summary.headroom,
348
+ utilization: resolved.summary.utilization,
349
+ source: resolved.source,
350
+ warnings: resolved.warnings,
351
+ });
352
+ }, "Usage forecast summary");
353
+ router.add("*", "usage/control-plane/summary", ({ res }) => {
354
+ deps.sendJson(res, 405, { ok: false, error: "Method not allowed" });
355
+ }, "Reject unsupported methods for usage/control-plane/summary");
356
+ router.add("*", "usage/unified", ({ res }) => {
357
+ deps.sendJson(res, 405, { ok: false, error: "Method not allowed" });
358
+ }, "Reject unsupported methods for usage/unified");
359
+ router.add("*", "usage/forecast", ({ res }) => {
360
+ deps.sendJson(res, 405, { ok: false, error: "Method not allowed" });
361
+ }, "Reject unsupported methods for usage/forecast");
362
+ }
@@ -1,13 +1,24 @@
1
1
  export function registerWorkArtifactsRoutes(router, deps) {
2
2
  router.add("GET", "work-artifacts/by-entity", async ({ query, res }) => {
3
+ const qs = query.toString();
3
4
  try {
4
- const qs = query.toString();
5
- const path = `/api/work-artifacts/by-entity${qs ? `?${qs}` : ""}`;
5
+ const path = `/api/client/artifacts/by-entity${qs ? `?${qs}` : ""}`;
6
6
  const data = await deps.rawRequest("GET", path);
7
7
  deps.sendJson(res, 200, data);
8
8
  }
9
9
  catch (err) {
10
- deps.sendJson(res, 502, { error: deps.safeErrorMessage(err) });
10
+ const warning = deps.safeErrorMessage(err);
11
+ try {
12
+ const fallbackPath = `/api/work-artifacts/by-entity${qs ? `?${qs}` : ""}`;
13
+ const fallback = await deps.rawRequest("GET", fallbackPath);
14
+ deps.sendJson(res, 200, fallback);
15
+ }
16
+ catch (fallbackErr) {
17
+ deps.sendJson(res, 502, {
18
+ error: deps.safeErrorMessage(fallbackErr),
19
+ warning,
20
+ });
21
+ }
11
22
  }
12
23
  }, "Work artifacts by entity");
13
24
  router.add("GET", "artifacts/*", async ({ path, res }) => {
@@ -18,18 +29,26 @@ export function registerWorkArtifactsRoutes(router, deps) {
18
29
  }
19
30
  const artifactId = decodeURIComponent(artifactDetailMatch[1]);
20
31
  try {
21
- const upstreamPath = `/api/artifacts/${encodeURIComponent(artifactId)}`;
32
+ const upstreamPath = `/api/client/artifacts/${encodeURIComponent(artifactId)}`;
22
33
  const data = await deps.rawRequest("GET", upstreamPath);
23
34
  deps.sendJson(res, 200, data);
24
35
  }
25
36
  catch (err) {
26
37
  const warning = deps.safeErrorMessage(err);
27
- const fallback = deps.buildLocalArtifactDetailFallback(artifactId, warning);
28
- if (fallback) {
29
- deps.sendJson(res, 200, fallback);
38
+ try {
39
+ const legacyPath = `/api/artifacts/${encodeURIComponent(artifactId)}`;
40
+ const legacyData = await deps.rawRequest("GET", legacyPath);
41
+ deps.sendJson(res, 200, legacyData);
30
42
  }
31
- else {
32
- deps.sendJson(res, 502, { error: warning });
43
+ catch (legacyErr) {
44
+ const legacyWarning = `${warning}; legacy route failed: ${deps.safeErrorMessage(legacyErr)}`;
45
+ const fallback = deps.buildLocalArtifactDetailFallback(artifactId, legacyWarning);
46
+ if (fallback) {
47
+ deps.sendJson(res, 200, fallback);
48
+ }
49
+ else {
50
+ deps.sendJson(res, 502, { error: legacyWarning });
51
+ }
33
52
  }
34
53
  }
35
54
  }, "Artifact detail");