@useorgx/openclaw-plugin 0.4.9 → 0.7.2

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 (224) hide show
  1. package/README.md +77 -11
  2. package/dashboard/dist/assets/6mILZQ2a.js +1 -0
  3. package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
  4. package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
  5. package/dashboard/dist/assets/8dksYiq4.js +2 -0
  6. package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
  7. package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
  8. package/dashboard/dist/assets/B5zYRHc3.js +1 -0
  9. package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
  10. package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
  11. package/dashboard/dist/assets/B6wPWJ35.js +1 -0
  12. package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
  13. package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -0
  14. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  15. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  16. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  17. package/dashboard/dist/assets/BWEwjt1W.js +1 -0
  18. package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
  19. package/dashboard/dist/assets/BWEwjt1W.js.gz +0 -0
  20. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  21. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  22. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  23. package/dashboard/dist/assets/BzRbDCAD.css +1 -0
  24. package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
  25. package/dashboard/dist/assets/BzRbDCAD.css.gz +0 -0
  26. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  27. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  28. package/dashboard/dist/assets/C8uM3AX8.js +1 -0
  29. package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
  30. package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
  31. package/dashboard/dist/assets/C9jy61eu.js +212 -0
  32. package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
  33. package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
  34. package/dashboard/dist/assets/CC63EwFD.js +1 -0
  35. package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
  36. package/dashboard/dist/assets/CC63EwFD.js.gz +0 -0
  37. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  38. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  39. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  40. package/dashboard/dist/assets/CZaT3ob_.js +1 -0
  41. package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
  42. package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
  43. package/dashboard/dist/assets/CgaottFX.js +1 -0
  44. package/dashboard/dist/assets/CgaottFX.js.br +0 -0
  45. package/dashboard/dist/assets/CgaottFX.js.gz +0 -0
  46. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  47. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  48. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  49. package/dashboard/dist/assets/CzCxAZlW.js +1 -0
  50. package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
  51. package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
  52. package/dashboard/dist/assets/D3iMTYEj.js +1 -0
  53. package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
  54. package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
  55. package/dashboard/dist/assets/D8JNX8kq.js +2 -0
  56. package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
  57. package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
  58. package/dashboard/dist/assets/DnA8dpj6.js +1 -0
  59. package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
  60. package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
  61. package/dashboard/dist/assets/IUexzymk.js +1 -0
  62. package/dashboard/dist/assets/IUexzymk.js.br +0 -0
  63. package/dashboard/dist/assets/IUexzymk.js.gz +0 -0
  64. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  65. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  66. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  67. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  68. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  69. package/dashboard/dist/assets/ic2FaMnh.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/rttbDbEx.js +1 -0
  74. package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
  75. package/dashboard/dist/assets/rttbDbEx.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/practice-exercise-schema.d.ts +216 -0
  102. package/dist/contracts/practice-exercise-schema.js +314 -0
  103. package/dist/contracts/retro-schema.d.ts +81 -0
  104. package/dist/contracts/retro-schema.js +80 -0
  105. package/dist/contracts/shared-types.d.ts +159 -0
  106. package/dist/contracts/shared-types.js +199 -1
  107. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  108. package/dist/contracts/skill-pack-schema.js +180 -0
  109. package/dist/contracts/types.d.ts +247 -2
  110. package/dist/entities/auto-assignment.js +43 -17
  111. package/dist/event-sanitization.d.ts +11 -0
  112. package/dist/event-sanitization.js +113 -0
  113. package/dist/gateway-watchdog.d.ts +5 -0
  114. package/dist/gateway-watchdog.js +50 -0
  115. package/dist/hooks/post-reporting-event.mjs +1 -5
  116. package/dist/http/helpers/activity-headline.js +13 -132
  117. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  118. package/dist/http/helpers/auto-continue-engine.js +3145 -186
  119. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  120. package/dist/http/helpers/autopilot-operations.js +182 -31
  121. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  122. package/dist/http/helpers/autopilot-runtime.js +328 -25
  123. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  124. package/dist/http/helpers/autopilot-slice-utils.js +514 -93
  125. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  126. package/dist/http/helpers/decision-mapper.js +223 -7
  127. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  128. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  129. package/dist/http/helpers/kickoff-context.js +104 -0
  130. package/dist/http/helpers/llm-client.d.ts +47 -0
  131. package/dist/http/helpers/llm-client.js +256 -0
  132. package/dist/http/helpers/mission-control.d.ts +102 -3
  133. package/dist/http/helpers/mission-control.js +498 -9
  134. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  135. package/dist/http/helpers/sentinel-catalog.js +193 -0
  136. package/dist/http/helpers/session-classification.d.ts +9 -0
  137. package/dist/http/helpers/session-classification.js +564 -0
  138. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  139. package/dist/http/helpers/slice-experience-v2.js +677 -0
  140. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  141. package/dist/http/helpers/slice-run-projections.js +877 -0
  142. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  143. package/dist/http/helpers/triage-mapper.js +549 -0
  144. package/dist/http/helpers/value-utils.js +7 -2
  145. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  146. package/dist/http/helpers/workspace-scope.js +170 -0
  147. package/dist/http/index.js +1420 -105
  148. package/dist/http/routes/agent-suite.d.ts +9 -0
  149. package/dist/http/routes/agent-suite.js +294 -8
  150. package/dist/http/routes/agents-catalog.js +64 -19
  151. package/dist/http/routes/chat.d.ts +19 -0
  152. package/dist/http/routes/chat.js +522 -0
  153. package/dist/http/routes/decision-actions.d.ts +8 -1
  154. package/dist/http/routes/decision-actions.js +42 -5
  155. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  156. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  157. package/dist/http/routes/entities.d.ts +16 -0
  158. package/dist/http/routes/entities.js +232 -6
  159. package/dist/http/routes/live-legacy.d.ts +5 -0
  160. package/dist/http/routes/live-legacy.js +23 -509
  161. package/dist/http/routes/live-misc.d.ts +12 -0
  162. package/dist/http/routes/live-misc.js +251 -31
  163. package/dist/http/routes/live-snapshot.d.ts +49 -2
  164. package/dist/http/routes/live-snapshot.js +653 -23
  165. package/dist/http/routes/live-terminal.d.ts +11 -0
  166. package/dist/http/routes/live-terminal.js +154 -0
  167. package/dist/http/routes/live-triage.d.ts +61 -0
  168. package/dist/http/routes/live-triage.js +192 -0
  169. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  170. package/dist/http/routes/mission-control-actions.js +1246 -84
  171. package/dist/http/routes/mission-control-read.d.ts +48 -3
  172. package/dist/http/routes/mission-control-read.js +1658 -20
  173. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  174. package/dist/http/routes/realtime-orchestrator.js +74 -0
  175. package/dist/http/routes/run-control.d.ts +5 -2
  176. package/dist/http/routes/run-control.js +10 -0
  177. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  178. package/dist/http/routes/sentinels-catalog.js +24 -0
  179. package/dist/http/routes/summary.js +10 -3
  180. package/dist/http/routes/usage.d.ts +24 -0
  181. package/dist/http/routes/usage.js +362 -0
  182. package/dist/http/routes/work-artifacts.js +28 -9
  183. package/dist/index.js +165 -27
  184. package/dist/local-openclaw.js +29 -6
  185. package/dist/mcp-client-setup.js +3 -3
  186. package/dist/mcp-http-handler.d.ts +3 -0
  187. package/dist/mcp-http-handler.js +34 -60
  188. package/dist/next-up-queue-store.d.ts +16 -1
  189. package/dist/next-up-queue-store.js +89 -7
  190. package/dist/outbox.d.ts +5 -0
  191. package/dist/outbox.js +113 -9
  192. package/dist/paths.js +36 -5
  193. package/dist/reporting/rollups.d.ts +41 -0
  194. package/dist/reporting/rollups.js +113 -0
  195. package/dist/retro/domain-templates.d.ts +45 -0
  196. package/dist/retro/domain-templates.js +297 -0
  197. package/dist/retro/quality-rubric.d.ts +33 -0
  198. package/dist/retro/quality-rubric.js +213 -0
  199. package/dist/runtime-cleanup.d.ts +18 -0
  200. package/dist/runtime-cleanup.js +87 -0
  201. package/dist/services/background.d.ts +11 -0
  202. package/dist/services/background.js +22 -0
  203. package/dist/services/experiment-randomization.d.ts +21 -0
  204. package/dist/services/experiment-randomization.js +63 -0
  205. package/dist/skill-pack-state.d.ts +36 -5
  206. package/dist/skill-pack-state.js +273 -29
  207. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  208. package/dist/sync/local-agent-telemetry.js +128 -0
  209. package/dist/sync/outbox-replay.js +131 -24
  210. package/dist/team-context-store.d.ts +23 -0
  211. package/dist/team-context-store.js +116 -0
  212. package/dist/telemetry/posthog.js +4 -2
  213. package/dist/tools/core-tools.d.ts +10 -14
  214. package/dist/tools/core-tools.js +1289 -24
  215. package/dist/types.d.ts +2 -0
  216. package/dist/types.js +2 -0
  217. package/dist/worker-supervisor.js +23 -0
  218. package/package.json +20 -6
  219. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  220. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  221. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  222. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  223. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  224. package/dashboard/dist/assets/sAhvFnpk.js +0 -4
@@ -0,0 +1,11 @@
1
+ import type { Router } from "../router.js";
2
+ type RegisterLiveTerminalRoutesDeps<TReq, TRes> = {
3
+ parseJsonRequest: (req: TReq) => Promise<Record<string, unknown>>;
4
+ sendJson: (res: TRes, status: number, payload: unknown) => void;
5
+ safeErrorMessage: (err: unknown) => string;
6
+ };
7
+ export declare function escapeShellSingleQuotedArg(value: string): string;
8
+ export declare function hasParentTraversalSegment(rawPath: string): boolean;
9
+ export declare function resolveSafeLogPath(logsDir: string, rawPath: string): string | null;
10
+ export declare function registerLiveTerminalRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: RegisterLiveTerminalRoutesDeps<TReq, TRes>): void;
11
+ export {};
@@ -0,0 +1,154 @@
1
+ import { exec } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { platform } from "node:os";
4
+ import { join, resolve, sep } from "node:path";
5
+ import { getOrgxPluginConfigDir } from "../../paths.js";
6
+ export function escapeShellSingleQuotedArg(value) {
7
+ return `'${value.replaceAll("'", "'\\''")}'`;
8
+ }
9
+ function pickString(input, keys) {
10
+ for (const key of keys) {
11
+ const value = input[key];
12
+ if (typeof value !== "string")
13
+ continue;
14
+ const trimmed = value.trim();
15
+ if (trimmed.length > 0)
16
+ return trimmed;
17
+ }
18
+ return null;
19
+ }
20
+ function resolveLogsDir() {
21
+ return resolve(getOrgxPluginConfigDir(), "autopilot-logs");
22
+ }
23
+ export function hasParentTraversalSegment(rawPath) {
24
+ return rawPath.split(/[\\/]+/).some((segment) => segment === "..");
25
+ }
26
+ export function resolveSafeLogPath(logsDir, rawPath) {
27
+ if (rawPath.includes("\0"))
28
+ return null;
29
+ const isAbsolute = rawPath.startsWith("/") || rawPath.startsWith("\\");
30
+ if (!isAbsolute && hasParentTraversalSegment(rawPath))
31
+ return null;
32
+ const candidate = isAbsolute ? resolve(rawPath) : resolve(logsDir, rawPath);
33
+ const base = logsDir.endsWith(sep) ? logsDir : `${logsDir}${sep}`;
34
+ if (!candidate.startsWith(base))
35
+ return null;
36
+ return existsSync(candidate) ? candidate : null;
37
+ }
38
+ function resolveLogPathFromIds(logsDir, ids) {
39
+ for (const rawId of ids) {
40
+ const id = rawId.trim();
41
+ if (!isSafeLogId(id))
42
+ continue;
43
+ const candidates = [join(logsDir, id), join(logsDir, `${id}.log`), join(logsDir, `${id}.output.json`)];
44
+ for (const candidate of candidates) {
45
+ if (existsSync(candidate))
46
+ return candidate;
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+ function isSafeLogId(input) {
52
+ if (input.length === 0 || input.length > 128)
53
+ return false;
54
+ if (input === "." || input === ".." || input.includes(".."))
55
+ return false;
56
+ return /^[A-Za-z0-9._-]+$/.test(input);
57
+ }
58
+ function openPathInTerminal(targetPath) {
59
+ return new Promise((resolvePromise, rejectPromise) => {
60
+ const os = platform();
61
+ const pathArg = escapeShellSingleQuotedArg(targetPath);
62
+ const tailCmd = `tail -f ${pathArg}`;
63
+ const tailCmdArg = escapeShellSingleQuotedArg(tailCmd);
64
+ let cmd;
65
+ if (os === "darwin") {
66
+ cmd = `osascript -e 'tell application "Terminal" to do script ${JSON.stringify(tailCmd)}'`;
67
+ }
68
+ else if (os === "linux") {
69
+ cmd = `gnome-terminal -- bash -lc ${tailCmdArg} 2>/dev/null || xterm -e bash -lc ${tailCmdArg}`;
70
+ }
71
+ else {
72
+ rejectPromise(new Error(`Terminal open not supported on ${os}`));
73
+ return;
74
+ }
75
+ exec(cmd, (err) => {
76
+ if (err)
77
+ rejectPromise(err);
78
+ else
79
+ resolvePromise();
80
+ });
81
+ });
82
+ }
83
+ function openPathInEditor(targetPath) {
84
+ return new Promise((resolvePromise, rejectPromise) => {
85
+ const pathArg = escapeShellSingleQuotedArg(targetPath);
86
+ const os = platform();
87
+ const cmd = os === "darwin"
88
+ ? `cursor ${pathArg} 2>/dev/null || code ${pathArg} 2>/dev/null || open ${pathArg} 2>/dev/null`
89
+ : os === "linux"
90
+ ? `cursor ${pathArg} 2>/dev/null || code ${pathArg} 2>/dev/null || xdg-open ${pathArg} 2>/dev/null`
91
+ : "";
92
+ if (!cmd) {
93
+ rejectPromise(new Error(`Editor open not supported on ${os}`));
94
+ return;
95
+ }
96
+ exec(cmd, (err) => {
97
+ if (err)
98
+ rejectPromise(err);
99
+ else
100
+ resolvePromise();
101
+ });
102
+ });
103
+ }
104
+ function resolveTargetPath(payload) {
105
+ const logsDir = resolveLogsDir();
106
+ const explicitPath = pickString(payload, [
107
+ "logPath",
108
+ "log_path",
109
+ "path",
110
+ "sessionPath",
111
+ "session_path",
112
+ ]);
113
+ if (explicitPath) {
114
+ const resolved = resolveSafeLogPath(logsDir, explicitPath);
115
+ if (resolved)
116
+ return resolved;
117
+ }
118
+ const ids = [
119
+ pickString(payload, ["sliceRunId", "slice_run_id"]),
120
+ pickString(payload, ["runId", "run_id"]),
121
+ pickString(payload, ["sessionId", "session_id"]),
122
+ ].filter((value) => Boolean(value));
123
+ if (ids.length > 0) {
124
+ return resolveLogPathFromIds(logsDir, ids);
125
+ }
126
+ return null;
127
+ }
128
+ export function registerLiveTerminalRoutes(router, deps) {
129
+ router.add("POST", "live/terminal/open", async ({ req, res }) => {
130
+ try {
131
+ const payload = await deps.parseJsonRequest(req);
132
+ const targetPath = resolveTargetPath(payload);
133
+ if (!targetPath) {
134
+ deps.sendJson(res, 404, {
135
+ error: "Terminal target not found. Provide runId, sliceRunId, sessionId, or logPath.",
136
+ });
137
+ return;
138
+ }
139
+ try {
140
+ await openPathInTerminal(targetPath);
141
+ }
142
+ catch {
143
+ await openPathInEditor(targetPath);
144
+ }
145
+ deps.sendJson(res, 200, { ok: true, path: targetPath });
146
+ }
147
+ catch (err) {
148
+ deps.sendJson(res, 500, { error: deps.safeErrorMessage(err) });
149
+ }
150
+ }, "Open run/session logs in terminal or editor");
151
+ router.add("*", "live/terminal/open", ({ res }) => {
152
+ deps.sendJson(res, 405, { error: "Use POST /orgx/api/live/terminal/open" });
153
+ }, "Reject unsupported methods for live/terminal/open");
154
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Triage queue API routes.
3
+ *
4
+ * GET /live/triage – list open triage items (merged decisions + blockers)
5
+ * POST /live/triage/:id/action – act on a triage item
6
+ */
7
+ import type { LiveDecision } from "../../contracts/shared-types.js";
8
+ interface Router<TState, TReq, TRes> {
9
+ add(method: string, path: string, handler: (ctx: {
10
+ req: TReq;
11
+ res: TRes;
12
+ path: string;
13
+ query: URLSearchParams;
14
+ body: unknown;
15
+ state: TState;
16
+ }) => Promise<void>, description?: string): void;
17
+ }
18
+ export interface RegisterLiveTriageRoutesDeps<TReq, TRes> {
19
+ parseJsonRequest: (req: TReq) => Promise<Record<string, unknown>>;
20
+ sendJson: (res: TRes, status: number, body: unknown) => void;
21
+ getDecisions: (workspaceId?: string | null) => LiveDecision[];
22
+ getBlockerEvents: (workspaceId?: string | null) => Array<{
23
+ id: string;
24
+ failureType: string;
25
+ reason?: string | null;
26
+ provider?: string | null;
27
+ initiativeId?: string | null;
28
+ initiativeTitle?: string | null;
29
+ workstreamId?: string | null;
30
+ workstreamTitle?: string | null;
31
+ taskId?: string | null;
32
+ taskTitle?: string | null;
33
+ agentId?: string | null;
34
+ domain?: string | null;
35
+ sourceSystem?: string | null;
36
+ runId?: string | null;
37
+ logPath?: string | null;
38
+ outputPath?: string | null;
39
+ metadata?: Record<string, unknown>;
40
+ timestamp?: string;
41
+ }>;
42
+ resolveDecisionAction: (decisionId: string, action: string, note?: string | null, optionId?: string | null) => Promise<{
43
+ ok: boolean;
44
+ error?: string;
45
+ }>;
46
+ emitDecisionResolvedActivity?: (input: {
47
+ ids: string[];
48
+ action: "approve" | "reject";
49
+ note?: string | null;
50
+ optionId?: string | null;
51
+ initiativeId?: string | null;
52
+ }) => Promise<void>;
53
+ snoozeTriage?: (itemId: string, durationMinutes: number) => Promise<{
54
+ ok: boolean;
55
+ }>;
56
+ dismissTriage?: (itemId: string, note?: string) => Promise<{
57
+ ok: boolean;
58
+ }>;
59
+ }
60
+ export declare function registerLiveTriageRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: RegisterLiveTriageRoutesDeps<TReq, TRes>): void;
61
+ export {};
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Triage queue API routes.
3
+ *
4
+ * GET /live/triage – list open triage items (merged decisions + blockers)
5
+ * POST /live/triage/:id/action – act on a triage item
6
+ */
7
+ import { mapDecisionToTriageItem, mapFailureToTriageItem, deduplicateTriageItems, } from "../helpers/triage-mapper.js";
8
+ export function registerLiveTriageRoutes(router, deps) {
9
+ // ─── GET /live/triage ─────────────────────────────────────────────
10
+ router.add("GET", "live/triage", async ({ res, query }) => {
11
+ const workspaceId = query.get("workspace_id") || null;
12
+ const statusFilter = query.get("status") || "open";
13
+ const limitStr = query.get("limit");
14
+ const limit = limitStr ? Math.min(Math.max(1, parseInt(limitStr, 10) || 50), 200) : 50;
15
+ const degraded = [];
16
+ // 1. Map existing decisions to triage items
17
+ let decisionItems = [];
18
+ try {
19
+ const decisions = deps.getDecisions(workspaceId);
20
+ decisionItems = decisions
21
+ .filter((d) => d.status === "pending")
22
+ .map(mapDecisionToTriageItem);
23
+ }
24
+ catch {
25
+ degraded.push("decisions");
26
+ }
27
+ // 2. Map blocker events to triage items
28
+ let blockerItems = [];
29
+ try {
30
+ const blockerEvents = deps.getBlockerEvents(workspaceId);
31
+ blockerItems = await Promise.all(blockerEvents.map((event) => mapFailureToTriageItem(event)));
32
+ }
33
+ catch {
34
+ degraded.push("blockers");
35
+ }
36
+ // 3. Merge and deduplicate
37
+ let allItems = deduplicateTriageItems([...decisionItems, ...blockerItems]);
38
+ // 4. Filter by status
39
+ if (statusFilter !== "all") {
40
+ allItems = allItems.filter((item) => item.status === statusFilter);
41
+ }
42
+ // 5. Sort: critical first, then by impact, then recency
43
+ allItems.sort((a, b) => {
44
+ const severityOrder = {
45
+ critical: 0,
46
+ high: 1,
47
+ medium: 2,
48
+ low: 3,
49
+ };
50
+ const sevDiff = (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3);
51
+ if (sevDiff !== 0)
52
+ return sevDiff;
53
+ const impactA = a.impact.initiativeCount +
54
+ a.impact.workstreamCount +
55
+ a.impact.downstreamBlockedCount;
56
+ const impactB = b.impact.initiativeCount +
57
+ b.impact.workstreamCount +
58
+ b.impact.downstreamBlockedCount;
59
+ if (impactB !== impactA)
60
+ return impactB - impactA;
61
+ return (new Date(b.lastSeenAt).getTime() - new Date(a.lastSeenAt).getTime());
62
+ });
63
+ const total = allItems.length;
64
+ const items = allItems.slice(0, limit);
65
+ const response = {
66
+ ok: true,
67
+ items,
68
+ total,
69
+ generatedAt: new Date().toISOString(),
70
+ ...(degraded.length > 0 ? { degraded } : {}),
71
+ };
72
+ deps.sendJson(res, 200, response);
73
+ }, "List triage items (merged decisions + blockers)");
74
+ // ─── POST /live/triage/:id/action ─────────────────────────────────
75
+ router.add("POST", "live/triage/action", async ({ req, res, query }) => {
76
+ const itemId = query.get("id");
77
+ if (!itemId) {
78
+ deps.sendJson(res, 400, { ok: false, error: "Missing triage item id" });
79
+ return;
80
+ }
81
+ let body;
82
+ try {
83
+ body = await deps.parseJsonRequest(req);
84
+ }
85
+ catch {
86
+ deps.sendJson(res, 400, { ok: false, error: "Invalid JSON body" });
87
+ return;
88
+ }
89
+ const action = typeof body.action === "string" ? body.action : null;
90
+ if (!action) {
91
+ deps.sendJson(res, 400, { ok: false, error: "Missing action field" });
92
+ return;
93
+ }
94
+ const note = typeof body.note === "string" ? body.note : null;
95
+ const optionIdRaw = typeof body.option_id === "string"
96
+ ? body.option_id
97
+ : typeof body.optionId === "string"
98
+ ? body.optionId
99
+ : null;
100
+ const optionId = typeof optionIdRaw === "string" ? optionIdRaw : null;
101
+ const snoozeDurationMinutes = typeof body.snoozeDurationMinutes === "number"
102
+ ? body.snoozeDurationMinutes
103
+ : null;
104
+ const sideEffects = [];
105
+ let itemStatus = "open";
106
+ let continuationPlan = null;
107
+ // Route action based on item type
108
+ if (itemId.startsWith("triage-decision-")) {
109
+ const decisionId = itemId.replace("triage-decision-", "");
110
+ if (action === "approve" || action === "reject") {
111
+ const result = await deps.resolveDecisionAction(decisionId, action, note, optionId);
112
+ if (!result.ok) {
113
+ deps.sendJson(res, 500, {
114
+ ok: false,
115
+ error: result.error ?? "Decision action failed",
116
+ });
117
+ return;
118
+ }
119
+ if (typeof deps.emitDecisionResolvedActivity === "function") {
120
+ try {
121
+ await deps.emitDecisionResolvedActivity({
122
+ ids: [decisionId],
123
+ action,
124
+ note,
125
+ optionId,
126
+ });
127
+ }
128
+ catch {
129
+ // best effort
130
+ }
131
+ }
132
+ itemStatus = "resolved";
133
+ sideEffects.push(action === "approve"
134
+ ? "Decision approved; agent will continue."
135
+ : "Decision rejected; agent paused.");
136
+ continuationPlan =
137
+ action === "approve"
138
+ ? "Agent will resume with approved direction."
139
+ : null;
140
+ }
141
+ else if (action === "snooze" && deps.snoozeTriage) {
142
+ await deps.snoozeTriage(itemId, snoozeDurationMinutes ?? 60);
143
+ itemStatus = "snoozed";
144
+ sideEffects.push(`Snoozed for ${snoozeDurationMinutes ?? 60} minutes.`);
145
+ }
146
+ else if (action === "dismiss" && deps.dismissTriage) {
147
+ await deps.dismissTriage(itemId, note ?? undefined);
148
+ itemStatus = "dismissed";
149
+ sideEffects.push("Dismissed. Will not re-raise until root cause changes.");
150
+ }
151
+ else {
152
+ deps.sendJson(res, 400, {
153
+ ok: false,
154
+ error: `Unsupported action: ${action}`,
155
+ });
156
+ return;
157
+ }
158
+ }
159
+ else {
160
+ // Non-decision triage items
161
+ if (action === "snooze" && deps.snoozeTriage) {
162
+ await deps.snoozeTriage(itemId, snoozeDurationMinutes ?? 60);
163
+ itemStatus = "snoozed";
164
+ sideEffects.push(`Snoozed for ${snoozeDurationMinutes ?? 60} minutes.`);
165
+ }
166
+ else if (action === "dismiss" && deps.dismissTriage) {
167
+ await deps.dismissTriage(itemId, note ?? undefined);
168
+ itemStatus = "dismissed";
169
+ sideEffects.push("Dismissed.");
170
+ }
171
+ else if (action === "retry") {
172
+ itemStatus = "open";
173
+ sideEffects.push("Retry queued.");
174
+ continuationPlan = "Will re-attempt the failed operation.";
175
+ }
176
+ else {
177
+ deps.sendJson(res, 400, {
178
+ ok: false,
179
+ error: `Unsupported action: ${action} for item ${itemId}`,
180
+ });
181
+ return;
182
+ }
183
+ }
184
+ const response = {
185
+ ok: true,
186
+ itemStatus: itemStatus,
187
+ continuationPlan,
188
+ sideEffects,
189
+ };
190
+ deps.sendJson(res, 200, response);
191
+ }, "Perform action on a triage item");
192
+ }
@@ -9,7 +9,9 @@ type AutoContinueRunRecord = Record<string, any> & {
9
9
  };
10
10
  type NextUpQueue = {
11
11
  items: Array<{
12
+ initiativeId: string;
12
13
  workstreamId: string;
14
+ queueState: "queued" | "running" | "blocked" | "idle";
13
15
  runnerAgentId?: string | null;
14
16
  runnerAgentName?: string | null;
15
17
  runnerSource?: string | null;
@@ -17,6 +19,23 @@ type NextUpQueue = {
17
19
  workstreamTitle?: string | null;
18
20
  nextTaskId?: string | null;
19
21
  nextTaskTitle?: string | null;
22
+ sliceScope?: "task" | "milestone" | "workstream" | null;
23
+ sliceTaskIds?: string[];
24
+ sliceTaskCount?: number | null;
25
+ sliceMilestoneId?: string | null;
26
+ executionPolicy?: {
27
+ domain?: string;
28
+ requiredSkills?: string[];
29
+ profile?: string | null;
30
+ sliceScopePreference?: "adaptive" | "task" | "milestone" | "workstream" | null;
31
+ maxSliceTasks?: number | null;
32
+ maxParallelAgents?: number | null;
33
+ dependencyMode?: "strict" | "relaxed" | null;
34
+ } | null;
35
+ autoContinue?: {
36
+ status?: string | null;
37
+ stopReason?: string | null;
38
+ } | null;
20
39
  }>;
21
40
  degraded: string[];
22
41
  };
@@ -29,7 +48,7 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
29
48
  dedupeStrings: (values: string[]) => string[];
30
49
  resolveAgentDisplayName: (agentId: string, fallbackName: string | null) => Promise<string | null>;
31
50
  buildNextUpQueue: (input: {
32
- initiativeId: string;
51
+ initiativeId?: string | null;
33
52
  }) => Promise<NextUpQueue>;
34
53
  startAutoContinueRun: (input: any) => Promise<AutoContinueRunRecord>;
35
54
  autoContinueRuns: Map<string, any>;
@@ -49,6 +68,24 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
49
68
  stopAutoContinueRun: (input: any) => Promise<void>;
50
69
  updateInitiativeAutoContinueState: (input: any) => Promise<void>;
51
70
  tickAllAutoContinue: () => Promise<void>;
71
+ scheduleAutoFixForWorkstream: (input: {
72
+ initiativeId: string;
73
+ workstreamId: string;
74
+ runId?: string | null;
75
+ event?: string | null;
76
+ requestedByAgentId?: string | null;
77
+ requestedByAgentName?: string | null;
78
+ graceMs?: number | null;
79
+ }) => Promise<{
80
+ requestId: string;
81
+ initiativeId: string;
82
+ workstreamId: string;
83
+ runId: string | null;
84
+ sourceEvent: string | null;
85
+ graceMs: number;
86
+ scheduledAt: string;
87
+ dueAt: string;
88
+ }>;
52
89
  upsertNextUpQueuePin: (input: {
53
90
  initiativeId: string;
54
91
  workstreamId: string;
@@ -65,6 +102,13 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
65
102
  pins: unknown[];
66
103
  updatedAt: string;
67
104
  };
105
+ suppressNextUpQueueItem: (input: {
106
+ initiativeId: string;
107
+ workstreamId: string;
108
+ }) => {
109
+ suppressions: unknown[];
110
+ updatedAt: string;
111
+ };
68
112
  setNextUpQueuePinOrder: (input: {
69
113
  order: Array<{
70
114
  initiativeId: string;
@@ -74,8 +118,12 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
74
118
  pins: unknown[];
75
119
  updatedAt: string;
76
120
  };
121
+ clearNextUpQueueCache: (initiativeId?: string | null) => void;
77
122
  resolveAutoAssignments: (input: any) => Promise<unknown>;
123
+ buildMissionControlGraph: (initiativeId: string) => Promise<unknown>;
124
+ applyLocalInitiativeOverrideToGraph: (graph: unknown) => unknown;
78
125
  client: any;
126
+ rawRequest?: (requestMethod: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", requestPath: string, body?: unknown) => Promise<unknown>;
79
127
  sendJson: (res: TRes, status: number, payload: unknown) => void;
80
128
  safeErrorMessage: (err: unknown) => string;
81
129
  };