@useorgx/openclaw-plugin 0.4.8 → 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 (284) 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 +38 -26
  88. package/dist/agent-context-store.js +84 -42
  89. package/dist/agent-run-store.js +49 -28
  90. package/dist/agent-suite.d.ts +9 -0
  91. package/dist/agent-suite.js +150 -17
  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/auth/flows.d.ts +47 -0
  97. package/dist/auth/flows.js +169 -0
  98. package/dist/auth-store.js +6 -26
  99. package/dist/byok-store.js +5 -19
  100. package/dist/chat-store.d.ts +157 -0
  101. package/dist/chat-store.js +586 -0
  102. package/dist/cli/orgx.d.ts +66 -0
  103. package/dist/cli/orgx.js +102 -0
  104. package/dist/config/refresh.d.ts +32 -0
  105. package/dist/config/refresh.js +55 -0
  106. package/dist/config/resolution.d.ts +37 -0
  107. package/dist/config/resolution.js +178 -0
  108. package/dist/contracts/client.d.ts +43 -3
  109. package/dist/contracts/client.js +159 -30
  110. package/dist/contracts/retro-schema.d.ts +81 -0
  111. package/dist/contracts/retro-schema.js +80 -0
  112. package/dist/contracts/shared-types.d.ts +306 -0
  113. package/dist/contracts/shared-types.js +179 -0
  114. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  115. package/dist/contracts/skill-pack-schema.js +180 -0
  116. package/dist/contracts/types.d.ts +224 -132
  117. package/dist/contracts/types.js +5 -0
  118. package/dist/entities/auto-assignment.d.ts +36 -0
  119. package/dist/entities/auto-assignment.js +141 -0
  120. package/dist/entity-comment-store.js +5 -25
  121. package/dist/event-sanitization.d.ts +11 -0
  122. package/dist/event-sanitization.js +113 -0
  123. package/dist/fs-utils.js +13 -1
  124. package/dist/gateway-watchdog.d.ts +5 -0
  125. package/dist/gateway-watchdog.js +50 -0
  126. package/dist/hash-utils.d.ts +2 -0
  127. package/dist/hash-utils.js +12 -0
  128. package/dist/hooks/post-reporting-event.mjs +1 -5
  129. package/dist/http/helpers/activity-headline.d.ts +10 -0
  130. package/dist/http/helpers/activity-headline.js +73 -0
  131. package/dist/http/helpers/artifact-fallback.d.ts +13 -0
  132. package/dist/http/helpers/artifact-fallback.js +148 -0
  133. package/dist/http/helpers/auto-continue-engine.d.ts +486 -0
  134. package/dist/http/helpers/auto-continue-engine.js +3563 -0
  135. package/dist/http/helpers/autopilot-operations.d.ts +176 -0
  136. package/dist/http/helpers/autopilot-operations.js +554 -0
  137. package/dist/http/helpers/autopilot-runtime.d.ts +43 -0
  138. package/dist/http/helpers/autopilot-runtime.js +607 -0
  139. package/dist/http/helpers/autopilot-slice-utils.d.ts +56 -0
  140. package/dist/http/helpers/autopilot-slice-utils.js +899 -0
  141. package/dist/http/helpers/decision-mapper.d.ts +52 -0
  142. package/dist/http/helpers/decision-mapper.js +260 -0
  143. package/dist/http/helpers/dispatch-lifecycle.d.ts +119 -0
  144. package/dist/http/helpers/dispatch-lifecycle.js +809 -0
  145. package/dist/http/helpers/hash-utils.d.ts +1 -0
  146. package/dist/http/helpers/hash-utils.js +1 -0
  147. package/dist/http/helpers/kickoff-context.d.ts +12 -0
  148. package/dist/http/helpers/kickoff-context.js +228 -0
  149. package/dist/http/helpers/llm-client.d.ts +47 -0
  150. package/dist/http/helpers/llm-client.js +256 -0
  151. package/dist/http/helpers/mission-control.d.ts +193 -0
  152. package/dist/http/helpers/mission-control.js +1383 -0
  153. package/dist/http/helpers/openclaw-cli.d.ts +37 -0
  154. package/dist/http/helpers/openclaw-cli.js +283 -0
  155. package/dist/http/helpers/runtime-sse.d.ts +20 -0
  156. package/dist/http/helpers/runtime-sse.js +110 -0
  157. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  158. package/dist/http/helpers/sentinel-catalog.js +193 -0
  159. package/dist/http/helpers/session-classification.d.ts +9 -0
  160. package/dist/http/helpers/session-classification.js +564 -0
  161. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  162. package/dist/http/helpers/slice-experience-v2.js +677 -0
  163. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  164. package/dist/http/helpers/slice-run-projections.js +860 -0
  165. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  166. package/dist/http/helpers/triage-mapper.js +549 -0
  167. package/dist/http/helpers/value-utils.d.ts +6 -0
  168. package/dist/http/helpers/value-utils.js +72 -0
  169. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  170. package/dist/http/helpers/workspace-scope.js +170 -0
  171. package/dist/http/index.d.ts +88 -0
  172. package/dist/http/index.js +3610 -0
  173. package/dist/http/router.d.ts +23 -0
  174. package/dist/http/router.js +23 -0
  175. package/dist/http/routes/agent-control.d.ts +79 -0
  176. package/dist/http/routes/agent-control.js +684 -0
  177. package/dist/http/routes/agent-suite.d.ts +38 -0
  178. package/dist/http/routes/agent-suite.js +397 -0
  179. package/dist/http/routes/agents-catalog.d.ts +40 -0
  180. package/dist/http/routes/agents-catalog.js +128 -0
  181. package/dist/http/routes/billing.d.ts +23 -0
  182. package/dist/http/routes/billing.js +55 -0
  183. package/dist/http/routes/chat.d.ts +19 -0
  184. package/dist/http/routes/chat.js +522 -0
  185. package/dist/http/routes/debug.d.ts +14 -0
  186. package/dist/http/routes/debug.js +21 -0
  187. package/dist/http/routes/decision-actions.d.ts +20 -0
  188. package/dist/http/routes/decision-actions.js +103 -0
  189. package/dist/http/routes/delegation.d.ts +19 -0
  190. package/dist/http/routes/delegation.js +32 -0
  191. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  192. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  193. package/dist/http/routes/entities.d.ts +63 -0
  194. package/dist/http/routes/entities.js +440 -0
  195. package/dist/http/routes/entity-dynamic.d.ts +25 -0
  196. package/dist/http/routes/entity-dynamic.js +191 -0
  197. package/dist/http/routes/health.d.ts +22 -0
  198. package/dist/http/routes/health.js +49 -0
  199. package/dist/http/routes/live-legacy.d.ts +115 -0
  200. package/dist/http/routes/live-legacy.js +112 -0
  201. package/dist/http/routes/live-misc.d.ts +81 -0
  202. package/dist/http/routes/live-misc.js +426 -0
  203. package/dist/http/routes/live-snapshot.d.ts +136 -0
  204. package/dist/http/routes/live-snapshot.js +916 -0
  205. package/dist/http/routes/live-terminal.d.ts +11 -0
  206. package/dist/http/routes/live-terminal.js +261 -0
  207. package/dist/http/routes/live-triage.d.ts +61 -0
  208. package/dist/http/routes/live-triage.js +248 -0
  209. package/dist/http/routes/mission-control-actions.d.ts +131 -0
  210. package/dist/http/routes/mission-control-actions.js +1791 -0
  211. package/dist/http/routes/mission-control-read.d.ts +73 -0
  212. package/dist/http/routes/mission-control-read.js +1640 -0
  213. package/dist/http/routes/onboarding.d.ts +34 -0
  214. package/dist/http/routes/onboarding.js +101 -0
  215. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  216. package/dist/http/routes/realtime-orchestrator.js +74 -0
  217. package/dist/http/routes/run-control.d.ts +27 -0
  218. package/dist/http/routes/run-control.js +96 -0
  219. package/dist/http/routes/runtime-hooks.d.ts +69 -0
  220. package/dist/http/routes/runtime-hooks.js +437 -0
  221. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  222. package/dist/http/routes/sentinels-catalog.js +24 -0
  223. package/dist/http/routes/settings-byok.d.ts +23 -0
  224. package/dist/http/routes/settings-byok.js +163 -0
  225. package/dist/http/routes/summary.d.ts +18 -0
  226. package/dist/http/routes/summary.js +49 -0
  227. package/dist/http/routes/usage.d.ts +24 -0
  228. package/dist/http/routes/usage.js +362 -0
  229. package/dist/http/routes/work-artifacts.d.ts +9 -0
  230. package/dist/http/routes/work-artifacts.js +55 -0
  231. package/dist/http/shared-state.d.ts +16 -0
  232. package/dist/http/shared-state.js +1 -0
  233. package/dist/http-handler.d.ts +1 -88
  234. package/dist/http-handler.js +1 -10605
  235. package/dist/index.js +287 -2284
  236. package/dist/json-utils.d.ts +1 -0
  237. package/dist/json-utils.js +8 -0
  238. package/dist/local-openclaw.js +29 -6
  239. package/dist/mcp-client-setup.js +3 -3
  240. package/dist/mcp-http-handler.js +33 -59
  241. package/dist/next-up-queue-store.d.ts +16 -1
  242. package/dist/next-up-queue-store.js +93 -25
  243. package/dist/outbox.d.ts +5 -0
  244. package/dist/outbox.js +113 -9
  245. package/dist/paths.js +24 -5
  246. package/dist/reporting/rollups.d.ts +53 -0
  247. package/dist/reporting/rollups.js +148 -0
  248. package/dist/retro/domain-templates.d.ts +45 -0
  249. package/dist/retro/domain-templates.js +297 -0
  250. package/dist/retro/quality-rubric.d.ts +33 -0
  251. package/dist/retro/quality-rubric.js +213 -0
  252. package/dist/runtime-cleanup.d.ts +18 -0
  253. package/dist/runtime-cleanup.js +87 -0
  254. package/dist/runtime-instance-store.js +5 -31
  255. package/dist/services/background.d.ts +34 -0
  256. package/dist/services/background.js +45 -0
  257. package/dist/services/experiment-randomization.d.ts +21 -0
  258. package/dist/services/experiment-randomization.js +63 -0
  259. package/dist/services/instrumentation.d.ts +29 -0
  260. package/dist/services/instrumentation.js +136 -0
  261. package/dist/skill-pack-state.d.ts +36 -5
  262. package/dist/skill-pack-state.js +273 -29
  263. package/dist/snapshot-store.js +5 -25
  264. package/dist/stores/json-store.d.ts +11 -0
  265. package/dist/stores/json-store.js +42 -0
  266. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  267. package/dist/sync/local-agent-telemetry.js +128 -0
  268. package/dist/sync/outbox-replay.d.ts +55 -0
  269. package/dist/sync/outbox-replay.js +621 -0
  270. package/dist/team-context-store.d.ts +23 -0
  271. package/dist/team-context-store.js +116 -0
  272. package/dist/telemetry/posthog.js +4 -2
  273. package/dist/tools/core-tools.d.ts +72 -0
  274. package/dist/tools/core-tools.js +2270 -0
  275. package/dist/types.d.ts +2 -0
  276. package/dist/types.js +2 -0
  277. package/dist/worker-supervisor.js +23 -0
  278. package/package.json +14 -4
  279. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  280. package/dashboard/dist/assets/BNeJ0kpF.js +0 -1
  281. package/dashboard/dist/assets/BzkiMPmM.js +0 -215
  282. package/dashboard/dist/assets/CUV9IHHi.js +0 -1
  283. package/dashboard/dist/assets/Ie7d9Iq2.css +0 -1
  284. 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,261 @@
1
+ import { exec } from "node:child_process";
2
+ import { closeSync, existsSync, openSync, readSync, statSync } 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
+ const DEFAULT_TAIL_LINES = 120;
10
+ const MAX_TAIL_LINES = 400;
11
+ const MAX_TAIL_BYTES = 256 * 1024;
12
+ function pickString(input, keys) {
13
+ for (const key of keys) {
14
+ const value = input[key];
15
+ if (typeof value !== "string")
16
+ continue;
17
+ const trimmed = value.trim();
18
+ if (trimmed.length > 0)
19
+ return trimmed;
20
+ }
21
+ return null;
22
+ }
23
+ function resolveLogsDir() {
24
+ return resolve(getOrgxPluginConfigDir(), "autopilot-logs");
25
+ }
26
+ export function hasParentTraversalSegment(rawPath) {
27
+ return rawPath.split(/[\\/]+/).some((segment) => segment === "..");
28
+ }
29
+ export function resolveSafeLogPath(logsDir, rawPath) {
30
+ if (rawPath.includes("\0"))
31
+ return null;
32
+ const isAbsolute = rawPath.startsWith("/") || rawPath.startsWith("\\");
33
+ if (!isAbsolute && hasParentTraversalSegment(rawPath))
34
+ return null;
35
+ const candidate = isAbsolute ? resolve(rawPath) : resolve(logsDir, rawPath);
36
+ const base = logsDir.endsWith(sep) ? logsDir : `${logsDir}${sep}`;
37
+ if (!candidate.startsWith(base))
38
+ return null;
39
+ return existsSync(candidate) ? candidate : null;
40
+ }
41
+ function resolveLogPathFromIds(logsDir, ids) {
42
+ for (const rawId of ids) {
43
+ const id = rawId.trim();
44
+ if (!isSafeLogId(id))
45
+ continue;
46
+ const candidates = [join(logsDir, id), join(logsDir, `${id}.log`), join(logsDir, `${id}.output.json`)];
47
+ for (const candidate of candidates) {
48
+ if (existsSync(candidate))
49
+ return candidate;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ function isSafeLogId(input) {
55
+ if (input.length === 0 || input.length > 128)
56
+ return false;
57
+ if (input === "." || input === ".." || input.includes(".."))
58
+ return false;
59
+ return /^[A-Za-z0-9._-]+$/.test(input);
60
+ }
61
+ function openPathInTerminal(targetPath) {
62
+ return new Promise((resolvePromise, rejectPromise) => {
63
+ const os = platform();
64
+ const pathArg = escapeShellSingleQuotedArg(targetPath);
65
+ const tailCmd = `tail -f ${pathArg}`;
66
+ const tailCmdArg = escapeShellSingleQuotedArg(tailCmd);
67
+ let cmd;
68
+ if (os === "darwin") {
69
+ cmd = `osascript -e 'tell application "Terminal" to do script ${JSON.stringify(tailCmd)}'`;
70
+ }
71
+ else if (os === "linux") {
72
+ cmd = `gnome-terminal -- bash -lc ${tailCmdArg} 2>/dev/null || xterm -e bash -lc ${tailCmdArg}`;
73
+ }
74
+ else {
75
+ rejectPromise(new Error(`Terminal open not supported on ${os}`));
76
+ return;
77
+ }
78
+ exec(cmd, (err) => {
79
+ if (err)
80
+ rejectPromise(err);
81
+ else
82
+ resolvePromise();
83
+ });
84
+ });
85
+ }
86
+ function openPathInEditor(targetPath) {
87
+ return new Promise((resolvePromise, rejectPromise) => {
88
+ const pathArg = escapeShellSingleQuotedArg(targetPath);
89
+ const os = platform();
90
+ const cmd = os === "darwin"
91
+ ? `cursor ${pathArg} 2>/dev/null || code ${pathArg} 2>/dev/null || open ${pathArg} 2>/dev/null`
92
+ : os === "linux"
93
+ ? `cursor ${pathArg} 2>/dev/null || code ${pathArg} 2>/dev/null || xdg-open ${pathArg} 2>/dev/null`
94
+ : "";
95
+ if (!cmd) {
96
+ rejectPromise(new Error(`Editor open not supported on ${os}`));
97
+ return;
98
+ }
99
+ exec(cmd, (err) => {
100
+ if (err)
101
+ rejectPromise(err);
102
+ else
103
+ resolvePromise();
104
+ });
105
+ });
106
+ }
107
+ function resolveTargetPath(payload) {
108
+ const logsDir = resolveLogsDir();
109
+ const explicitPath = pickString(payload, [
110
+ "logPath",
111
+ "log_path",
112
+ "path",
113
+ "sessionPath",
114
+ "session_path",
115
+ ]);
116
+ if (explicitPath) {
117
+ const resolved = resolveSafeLogPath(logsDir, explicitPath);
118
+ if (resolved)
119
+ return resolved;
120
+ }
121
+ const ids = [
122
+ pickString(payload, ["sliceRunId", "slice_run_id"]),
123
+ pickString(payload, ["runId", "run_id"]),
124
+ pickString(payload, ["sessionId", "session_id"]),
125
+ ].filter((value) => Boolean(value));
126
+ if (ids.length > 0) {
127
+ return resolveLogPathFromIds(logsDir, ids);
128
+ }
129
+ return null;
130
+ }
131
+ function parseTailLines(raw) {
132
+ if (!raw)
133
+ return DEFAULT_TAIL_LINES;
134
+ const parsed = Number(raw);
135
+ if (!Number.isFinite(parsed))
136
+ return DEFAULT_TAIL_LINES;
137
+ const normalized = Math.floor(parsed);
138
+ if (normalized <= 0)
139
+ return DEFAULT_TAIL_LINES;
140
+ return Math.min(MAX_TAIL_LINES, normalized);
141
+ }
142
+ function readLogTailPreview(path, lineLimit) {
143
+ const stats = statSync(path);
144
+ if (!stats.isFile()) {
145
+ throw new Error("Tail target is not a file.");
146
+ }
147
+ const totalBytes = Number.isFinite(stats.size) ? Math.max(0, stats.size) : 0;
148
+ const offsetBytes = Math.max(0, totalBytes - MAX_TAIL_BYTES);
149
+ const readLength = Math.max(0, totalBytes - offsetBytes);
150
+ if (readLength === 0) {
151
+ return {
152
+ text: "",
153
+ lineCount: 0,
154
+ truncated: false,
155
+ totalBytes,
156
+ offsetBytes,
157
+ updatedAt: stats.mtime.toISOString(),
158
+ };
159
+ }
160
+ const fd = openSync(path, "r");
161
+ try {
162
+ const buffer = Buffer.allocUnsafe(readLength);
163
+ let bytesRead = 0;
164
+ while (bytesRead < readLength) {
165
+ const chunk = readSync(fd, buffer, bytesRead, readLength - bytesRead, offsetBytes + bytesRead);
166
+ if (chunk <= 0)
167
+ break;
168
+ bytesRead += chunk;
169
+ }
170
+ const normalizedText = buffer
171
+ .subarray(0, Math.max(0, bytesRead))
172
+ .toString("utf8")
173
+ .replaceAll("\r\n", "\n")
174
+ .replaceAll("\r", "\n");
175
+ const allLines = normalizedText.split("\n");
176
+ if (allLines.length > 0 && allLines[allLines.length - 1] === "") {
177
+ allLines.pop();
178
+ }
179
+ const tailLines = allLines.slice(-lineLimit);
180
+ const truncated = offsetBytes > 0 || allLines.length > tailLines.length;
181
+ return {
182
+ text: tailLines.join("\n"),
183
+ lineCount: tailLines.length,
184
+ truncated,
185
+ totalBytes,
186
+ offsetBytes,
187
+ updatedAt: stats.mtime.toISOString(),
188
+ };
189
+ }
190
+ finally {
191
+ closeSync(fd);
192
+ }
193
+ }
194
+ export function registerLiveTerminalRoutes(router, deps) {
195
+ router.add("GET", "live/terminal/tail", ({ query, res }) => {
196
+ try {
197
+ const payload = {
198
+ path: query.get("path"),
199
+ logPath: query.get("logPath"),
200
+ log_path: query.get("log_path"),
201
+ sliceRunId: query.get("sliceRunId"),
202
+ slice_run_id: query.get("slice_run_id"),
203
+ runId: query.get("runId"),
204
+ run_id: query.get("run_id"),
205
+ sessionId: query.get("sessionId"),
206
+ session_id: query.get("session_id"),
207
+ };
208
+ const targetPath = resolveTargetPath(payload);
209
+ if (!targetPath) {
210
+ deps.sendJson(res, 404, {
211
+ error: "Tail target not found. Provide runId, sliceRunId, sessionId, or logPath/path.",
212
+ });
213
+ return;
214
+ }
215
+ const lineLimit = parseTailLines(query.get("lines") ?? query.get("line_count"));
216
+ const preview = readLogTailPreview(targetPath, lineLimit);
217
+ deps.sendJson(res, 200, {
218
+ ok: true,
219
+ path: targetPath,
220
+ lines_requested: lineLimit,
221
+ line_count: preview.lineCount,
222
+ truncated: preview.truncated,
223
+ bytes: preview.totalBytes,
224
+ offset_bytes: preview.offsetBytes,
225
+ updated_at: preview.updatedAt,
226
+ text: preview.text,
227
+ });
228
+ }
229
+ catch (err) {
230
+ deps.sendJson(res, 500, { error: deps.safeErrorMessage(err) });
231
+ }
232
+ }, "Read a safe tail preview for run/session logs");
233
+ router.add("*", "live/terminal/tail", ({ res }) => {
234
+ deps.sendJson(res, 405, { error: "Use GET /orgx/api/live/terminal/tail" });
235
+ }, "Reject unsupported methods for live/terminal/tail");
236
+ router.add("POST", "live/terminal/open", async ({ req, res }) => {
237
+ try {
238
+ const payload = await deps.parseJsonRequest(req);
239
+ const targetPath = resolveTargetPath(payload);
240
+ if (!targetPath) {
241
+ deps.sendJson(res, 404, {
242
+ error: "Terminal target not found. Provide runId, sliceRunId, sessionId, or logPath.",
243
+ });
244
+ return;
245
+ }
246
+ try {
247
+ await openPathInTerminal(targetPath);
248
+ }
249
+ catch {
250
+ await openPathInEditor(targetPath);
251
+ }
252
+ deps.sendJson(res, 200, { ok: true, path: targetPath });
253
+ }
254
+ catch (err) {
255
+ deps.sendJson(res, 500, { error: deps.safeErrorMessage(err) });
256
+ }
257
+ }, "Open run/session logs in terminal or editor");
258
+ router.add("*", "live/terminal/open", ({ res }) => {
259
+ deps.sendJson(res, 405, { error: "Use POST /orgx/api/live/terminal/open" });
260
+ }, "Reject unsupported methods for live/terminal/open");
261
+ }
@@ -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,248 @@
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
+ // Noise reduction query params
16
+ const noiseThreshold = (query.get("noise_threshold") ?? "medium");
17
+ const dedupWindowStr = query.get("dedup_window");
18
+ const dedupWindowMs = dedupWindowStr != null
19
+ ? Math.max(0, parseInt(dedupWindowStr, 10) || 60000)
20
+ : 60000;
21
+ const degraded = [];
22
+ // 1. Map existing decisions to triage items
23
+ let decisionItems = [];
24
+ try {
25
+ const decisions = deps.getDecisions(workspaceId);
26
+ decisionItems = decisions
27
+ .filter((d) => d.status === "pending")
28
+ .map(mapDecisionToTriageItem);
29
+ }
30
+ catch {
31
+ degraded.push("decisions");
32
+ }
33
+ // 2. Map blocker events to triage items
34
+ let blockerItems = [];
35
+ try {
36
+ const blockerEvents = deps.getBlockerEvents(workspaceId);
37
+ blockerItems = await Promise.all(blockerEvents.map((event) => mapFailureToTriageItem(event)));
38
+ }
39
+ catch {
40
+ degraded.push("blockers");
41
+ }
42
+ // 3. Merge and deduplicate
43
+ let allItems = deduplicateTriageItems([...decisionItems, ...blockerItems]);
44
+ // 4. Filter by status
45
+ if (statusFilter !== "all") {
46
+ allItems = allItems.filter((item) => item.status === statusFilter);
47
+ }
48
+ // 5. Apply noise threshold — suppress low-severity items based on threshold
49
+ if (noiseThreshold === "high") {
50
+ // Only show critical and high severity
51
+ allItems = allItems.filter((item) => item.severity === "critical" || item.severity === "high");
52
+ }
53
+ else if (noiseThreshold === "medium") {
54
+ // Suppress low-severity routine items (review_required with low severity)
55
+ allItems = allItems.filter((item) => {
56
+ if (item.severity === "low" &&
57
+ item.kind === "review_required") {
58
+ return false;
59
+ }
60
+ return true;
61
+ });
62
+ }
63
+ // noiseThreshold === 'low' — show everything (no filtering)
64
+ // 6. Dedup by title within window — group items with the same title
65
+ // that occurred within dedupWindowMs of each other, keeping the most recent.
66
+ if (dedupWindowMs > 0) {
67
+ const seen = new Map();
68
+ for (const item of allItems) {
69
+ const key = item.title.trim().toLowerCase();
70
+ const ts = new Date(item.lastSeenAt).getTime();
71
+ const existing = seen.get(key);
72
+ if (!existing) {
73
+ seen.set(key, { item, ts, count: 1 });
74
+ continue;
75
+ }
76
+ if (Math.abs(existing.ts - ts) <= dedupWindowMs) {
77
+ existing.count += 1;
78
+ // Keep the more recent item
79
+ if (ts > existing.ts) {
80
+ existing.item = item;
81
+ existing.ts = ts;
82
+ }
83
+ }
84
+ else {
85
+ // Outside window — keep as separate under a unique key
86
+ seen.set(`${key}::${item.id}`, { item, ts, count: 1 });
87
+ }
88
+ }
89
+ allItems = Array.from(seen.values()).map((entry) => {
90
+ // Encode occurrence count so clients can show "N similar" badge
91
+ const merged = { ...entry.item };
92
+ if (entry.count > 1) {
93
+ merged.occurrenceCount = Math.max(merged.occurrenceCount, entry.count);
94
+ }
95
+ return merged;
96
+ });
97
+ }
98
+ // 7. Sort: critical first, then by impact, then recency
99
+ allItems.sort((a, b) => {
100
+ const severityOrder = {
101
+ critical: 0,
102
+ high: 1,
103
+ medium: 2,
104
+ low: 3,
105
+ };
106
+ const sevDiff = (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3);
107
+ if (sevDiff !== 0)
108
+ return sevDiff;
109
+ const impactA = a.impact.initiativeCount +
110
+ a.impact.workstreamCount +
111
+ a.impact.downstreamBlockedCount;
112
+ const impactB = b.impact.initiativeCount +
113
+ b.impact.workstreamCount +
114
+ b.impact.downstreamBlockedCount;
115
+ if (impactB !== impactA)
116
+ return impactB - impactA;
117
+ return (new Date(b.lastSeenAt).getTime() - new Date(a.lastSeenAt).getTime());
118
+ });
119
+ const total = allItems.length;
120
+ const items = allItems.slice(0, limit);
121
+ const response = {
122
+ ok: true,
123
+ items,
124
+ total,
125
+ generatedAt: new Date().toISOString(),
126
+ ...(degraded.length > 0 ? { degraded } : {}),
127
+ };
128
+ deps.sendJson(res, 200, response);
129
+ }, "List triage items (merged decisions + blockers)");
130
+ // ─── POST /live/triage/:id/action ─────────────────────────────────
131
+ router.add("POST", "live/triage/action", async ({ req, res, query }) => {
132
+ const itemId = query.get("id");
133
+ if (!itemId) {
134
+ deps.sendJson(res, 400, { ok: false, error: "Missing triage item id" });
135
+ return;
136
+ }
137
+ let body;
138
+ try {
139
+ body = await deps.parseJsonRequest(req);
140
+ }
141
+ catch {
142
+ deps.sendJson(res, 400, { ok: false, error: "Invalid JSON body" });
143
+ return;
144
+ }
145
+ const action = typeof body.action === "string" ? body.action : null;
146
+ if (!action) {
147
+ deps.sendJson(res, 400, { ok: false, error: "Missing action field" });
148
+ return;
149
+ }
150
+ const note = typeof body.note === "string" ? body.note : null;
151
+ const optionIdRaw = typeof body.option_id === "string"
152
+ ? body.option_id
153
+ : typeof body.optionId === "string"
154
+ ? body.optionId
155
+ : null;
156
+ const optionId = typeof optionIdRaw === "string" ? optionIdRaw : null;
157
+ const snoozeDurationMinutes = typeof body.snoozeDurationMinutes === "number"
158
+ ? body.snoozeDurationMinutes
159
+ : null;
160
+ const sideEffects = [];
161
+ let itemStatus = "open";
162
+ let continuationPlan = null;
163
+ // Route action based on item type
164
+ if (itemId.startsWith("triage-decision-")) {
165
+ const decisionId = itemId.replace("triage-decision-", "");
166
+ if (action === "approve" || action === "reject") {
167
+ const result = await deps.resolveDecisionAction(decisionId, action, note, optionId);
168
+ if (!result.ok) {
169
+ deps.sendJson(res, 500, {
170
+ ok: false,
171
+ error: result.error ?? "Decision action failed",
172
+ });
173
+ return;
174
+ }
175
+ if (typeof deps.emitDecisionResolvedActivity === "function") {
176
+ try {
177
+ await deps.emitDecisionResolvedActivity({
178
+ ids: [decisionId],
179
+ action,
180
+ note,
181
+ optionId,
182
+ });
183
+ }
184
+ catch {
185
+ // best effort
186
+ }
187
+ }
188
+ itemStatus = "resolved";
189
+ sideEffects.push(action === "approve"
190
+ ? "Decision approved; agent will continue."
191
+ : "Decision rejected; agent paused.");
192
+ continuationPlan =
193
+ action === "approve"
194
+ ? "Agent will resume with approved direction."
195
+ : null;
196
+ }
197
+ else if (action === "snooze" && deps.snoozeTriage) {
198
+ await deps.snoozeTriage(itemId, snoozeDurationMinutes ?? 60);
199
+ itemStatus = "snoozed";
200
+ sideEffects.push(`Snoozed for ${snoozeDurationMinutes ?? 60} minutes.`);
201
+ }
202
+ else if (action === "dismiss" && deps.dismissTriage) {
203
+ await deps.dismissTriage(itemId, note ?? undefined);
204
+ itemStatus = "dismissed";
205
+ sideEffects.push("Dismissed. Will not re-raise until root cause changes.");
206
+ }
207
+ else {
208
+ deps.sendJson(res, 400, {
209
+ ok: false,
210
+ error: `Unsupported action: ${action}`,
211
+ });
212
+ return;
213
+ }
214
+ }
215
+ else {
216
+ // Non-decision triage items
217
+ if (action === "snooze" && deps.snoozeTriage) {
218
+ await deps.snoozeTriage(itemId, snoozeDurationMinutes ?? 60);
219
+ itemStatus = "snoozed";
220
+ sideEffects.push(`Snoozed for ${snoozeDurationMinutes ?? 60} minutes.`);
221
+ }
222
+ else if (action === "dismiss" && deps.dismissTriage) {
223
+ await deps.dismissTriage(itemId, note ?? undefined);
224
+ itemStatus = "dismissed";
225
+ sideEffects.push("Dismissed.");
226
+ }
227
+ else if (action === "retry") {
228
+ itemStatus = "open";
229
+ sideEffects.push("Retry queued.");
230
+ continuationPlan = "Will re-attempt the failed operation.";
231
+ }
232
+ else {
233
+ deps.sendJson(res, 400, {
234
+ ok: false,
235
+ error: `Unsupported action: ${action} for item ${itemId}`,
236
+ });
237
+ return;
238
+ }
239
+ }
240
+ const response = {
241
+ ok: true,
242
+ itemStatus: itemStatus,
243
+ continuationPlan,
244
+ sideEffects,
245
+ };
246
+ deps.sendJson(res, 200, response);
247
+ }, "Perform action on a triage item");
248
+ }