@useorgx/openclaw-plugin 0.7.8 → 0.7.15

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 (203) hide show
  1. package/README.md +94 -122
  2. package/dashboard/dist/assets/0RUEVzJa.js +1 -0
  3. package/dashboard/dist/assets/0RUEVzJa.js.br +0 -0
  4. package/dashboard/dist/assets/0RUEVzJa.js.gz +0 -0
  5. package/dashboard/dist/assets/3TtV4moZ.js +1 -0
  6. package/dashboard/dist/assets/3TtV4moZ.js.br +0 -0
  7. package/dashboard/dist/assets/3TtV4moZ.js.gz +0 -0
  8. package/dashboard/dist/assets/3VwNyxUf.js +1 -0
  9. package/dashboard/dist/assets/3VwNyxUf.js.br +0 -0
  10. package/dashboard/dist/assets/3VwNyxUf.js.gz +0 -0
  11. package/dashboard/dist/assets/{DpuQm1oF.js → 7DhYqBrM.js} +2 -2
  12. package/dashboard/dist/assets/7DhYqBrM.js.br +0 -0
  13. package/dashboard/dist/assets/7DhYqBrM.js.gz +0 -0
  14. package/dashboard/dist/assets/{tcEHYcbW.js → BCudUvwg.js} +1 -1
  15. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  16. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  17. package/dashboard/dist/assets/BV0BcV1u.js +53 -0
  18. package/dashboard/dist/assets/BV0BcV1u.js.br +0 -0
  19. package/dashboard/dist/assets/BV0BcV1u.js.gz +0 -0
  20. package/dashboard/dist/assets/BVvffj0x.js +1 -0
  21. package/dashboard/dist/assets/BVvffj0x.js.br +0 -0
  22. package/dashboard/dist/assets/BVvffj0x.js.gz +0 -0
  23. package/dashboard/dist/assets/BiOgVMED.js +1 -0
  24. package/dashboard/dist/assets/BiOgVMED.js.br +0 -0
  25. package/dashboard/dist/assets/BiOgVMED.js.gz +0 -0
  26. package/dashboard/dist/assets/BjK42gtU.js +1 -0
  27. package/dashboard/dist/assets/BjK42gtU.js.br +0 -0
  28. package/dashboard/dist/assets/BjK42gtU.js.gz +0 -0
  29. package/dashboard/dist/assets/C-MOJWHs.js +1 -0
  30. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  31. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  32. package/dashboard/dist/assets/C91KLKit.js +1 -0
  33. package/dashboard/dist/assets/C91KLKit.js.br +0 -0
  34. package/dashboard/dist/assets/C91KLKit.js.gz +0 -0
  35. package/dashboard/dist/assets/{CnitK1MX.js → C9fvfXmS.js} +1 -1
  36. package/dashboard/dist/assets/C9fvfXmS.js.br +0 -0
  37. package/dashboard/dist/assets/C9fvfXmS.js.gz +0 -0
  38. package/dashboard/dist/assets/CFZ4Swr5.js +1 -0
  39. package/dashboard/dist/assets/CFZ4Swr5.js.br +0 -0
  40. package/dashboard/dist/assets/CFZ4Swr5.js.gz +0 -0
  41. package/dashboard/dist/assets/{77gGFBt6.js → CGj8kRhg.js} +1 -1
  42. package/dashboard/dist/assets/CGj8kRhg.js.br +0 -0
  43. package/dashboard/dist/assets/CGj8kRhg.js.gz +0 -0
  44. package/dashboard/dist/assets/CJjEAGFN.js +1 -0
  45. package/dashboard/dist/assets/CJjEAGFN.js.br +0 -0
  46. package/dashboard/dist/assets/CJjEAGFN.js.gz +0 -0
  47. package/dashboard/dist/assets/CKrH5fYO.js +1 -0
  48. package/dashboard/dist/assets/CKrH5fYO.js.br +0 -0
  49. package/dashboard/dist/assets/CKrH5fYO.js.gz +0 -0
  50. package/dashboard/dist/assets/CMTTPXch.js +1 -0
  51. package/dashboard/dist/assets/CMTTPXch.js.br +0 -0
  52. package/dashboard/dist/assets/CMTTPXch.js.gz +0 -0
  53. package/dashboard/dist/assets/CSlBSRyv.js +1 -0
  54. package/dashboard/dist/assets/CSlBSRyv.js.br +0 -0
  55. package/dashboard/dist/assets/CSlBSRyv.js.gz +0 -0
  56. package/dashboard/dist/assets/CnPC783_.js +1 -0
  57. package/dashboard/dist/assets/CnPC783_.js.br +0 -0
  58. package/dashboard/dist/assets/CnPC783_.js.gz +0 -0
  59. package/dashboard/dist/assets/Ctw95IkC.js +1 -0
  60. package/dashboard/dist/assets/Ctw95IkC.js.br +0 -0
  61. package/dashboard/dist/assets/Ctw95IkC.js.gz +0 -0
  62. package/dashboard/dist/assets/DHz-aQPw.js +1 -0
  63. package/dashboard/dist/assets/DHz-aQPw.js.br +0 -0
  64. package/dashboard/dist/assets/DHz-aQPw.js.gz +0 -0
  65. package/dashboard/dist/assets/DNX2foSJ.css +1 -0
  66. package/dashboard/dist/assets/DNX2foSJ.css.br +0 -0
  67. package/dashboard/dist/assets/DNX2foSJ.css.gz +0 -0
  68. package/dashboard/dist/assets/Dj2k1r16.js +8 -0
  69. package/dashboard/dist/assets/Dj2k1r16.js.br +0 -0
  70. package/dashboard/dist/assets/Dj2k1r16.js.gz +0 -0
  71. package/dashboard/dist/assets/DxUw4FMR.js +212 -0
  72. package/dashboard/dist/assets/DxUw4FMR.js.br +0 -0
  73. package/dashboard/dist/assets/DxUw4FMR.js.gz +0 -0
  74. package/dashboard/dist/assets/T2NFtzAv.js +1 -0
  75. package/dashboard/dist/assets/T2NFtzAv.js.br +0 -0
  76. package/dashboard/dist/assets/T2NFtzAv.js.gz +0 -0
  77. package/dashboard/dist/assets/cX2e-TLi.js +1 -0
  78. package/dashboard/dist/assets/cX2e-TLi.js.br +0 -0
  79. package/dashboard/dist/assets/cX2e-TLi.js.gz +0 -0
  80. package/dashboard/dist/assets/eeHXe_OQ.js +9 -0
  81. package/dashboard/dist/assets/eeHXe_OQ.js.br +0 -0
  82. package/dashboard/dist/assets/eeHXe_OQ.js.gz +0 -0
  83. package/dashboard/dist/assets/{DxKG5zy8.js → gZr_xKlA.js} +2 -2
  84. package/dashboard/dist/assets/gZr_xKlA.js.br +0 -0
  85. package/dashboard/dist/assets/gZr_xKlA.js.gz +0 -0
  86. package/dashboard/dist/brand/control-tower.png +0 -0
  87. package/dashboard/dist/brand/design-codex.png +0 -0
  88. package/dashboard/dist/brand/engineering-autopilot.png +0 -0
  89. package/dashboard/dist/brand/launch-captain.png +0 -0
  90. package/dashboard/dist/brand/orgx-logo.png +0 -0
  91. package/dashboard/dist/brand/pipeline-intelligence.png +0 -0
  92. package/dashboard/dist/brand/product-orchestrator.png +0 -0
  93. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  94. package/dashboard/dist/index.html +8 -6
  95. package/dashboard/dist/index.html.br +0 -0
  96. package/dashboard/dist/index.html.gz +0 -0
  97. package/dist/hash-utils.d.ts +1 -0
  98. package/dist/hash-utils.js +4 -0
  99. package/dist/http/helpers/auto-continue-engine.d.ts +36 -0
  100. package/dist/http/helpers/auto-continue-engine.js +198 -75
  101. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  102. package/dist/http/helpers/autopilot-runtime.js +31 -3
  103. package/dist/http/helpers/autopilot-slice-utils.d.ts +10 -0
  104. package/dist/http/helpers/autopilot-slice-utils.js +158 -54
  105. package/dist/http/helpers/hash-utils.d.ts +1 -1
  106. package/dist/http/helpers/hash-utils.js +1 -1
  107. package/dist/http/helpers/humanize-slice-failure.d.ts +35 -0
  108. package/dist/http/helpers/humanize-slice-failure.js +137 -0
  109. package/dist/http/helpers/mission-control.d.ts +1 -0
  110. package/dist/http/helpers/mission-control.js +73 -7
  111. package/dist/http/helpers/queue-constants.d.ts +37 -0
  112. package/dist/http/helpers/queue-constants.js +34 -0
  113. package/dist/http/helpers/slice-experience-v2.js +2 -5
  114. package/dist/http/helpers/slice-run-projections.js +2 -5
  115. package/dist/http/helpers/workspace-scope.js +4 -3
  116. package/dist/http/index.js +166 -63
  117. package/dist/http/routes/chat.js +1 -21
  118. package/dist/http/routes/live-misc.js +9 -2
  119. package/dist/http/routes/live-snapshot.js +14 -27
  120. package/dist/http/routes/mission-control-actions.js +7 -18
  121. package/dist/http/routes/mission-control-read.d.ts +1 -0
  122. package/dist/http/routes/mission-control-read.js +14 -56
  123. package/dist/index.d.ts +8 -1
  124. package/dist/index.js +21 -1
  125. package/dist/lib/type-coercion.d.ts +10 -0
  126. package/dist/lib/type-coercion.js +82 -0
  127. package/dist/mcp-http-handler.js +14 -2
  128. package/dist/openclaw.plugin.json +1 -1
  129. package/dist/services/experiment-randomization.js +9 -2
  130. package/dist/tools/core-tools.d.ts +27 -0
  131. package/dist/tools/core-tools.js +89 -0
  132. package/openclaw.plugin.json +1 -1
  133. package/package.json +3 -2
  134. package/dashboard/dist/assets/77gGFBt6.js.br +0 -0
  135. package/dashboard/dist/assets/77gGFBt6.js.gz +0 -0
  136. package/dashboard/dist/assets/BBpTN_SR.js +0 -1
  137. package/dashboard/dist/assets/BBpTN_SR.js.br +0 -0
  138. package/dashboard/dist/assets/BBpTN_SR.js.gz +0 -0
  139. package/dashboard/dist/assets/BJgZIVUQ.js +0 -53
  140. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  141. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  142. package/dashboard/dist/assets/BTAEErUY.js +0 -1
  143. package/dashboard/dist/assets/BTAEErUY.js.br +0 -0
  144. package/dashboard/dist/assets/BTAEErUY.js.gz +0 -0
  145. package/dashboard/dist/assets/BVShoyjA.js +0 -1
  146. package/dashboard/dist/assets/BVShoyjA.js.br +0 -0
  147. package/dashboard/dist/assets/BVShoyjA.js.gz +0 -0
  148. package/dashboard/dist/assets/BgcAY5rE.js +0 -1
  149. package/dashboard/dist/assets/BgcAY5rE.js.br +0 -0
  150. package/dashboard/dist/assets/BgcAY5rE.js.gz +0 -0
  151. package/dashboard/dist/assets/C-KIc3Wc.js +0 -1
  152. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  153. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  154. package/dashboard/dist/assets/C-PAoJF-.js +0 -1
  155. package/dashboard/dist/assets/C-PAoJF-.js.br +0 -0
  156. package/dashboard/dist/assets/C-PAoJF-.js.gz +0 -0
  157. package/dashboard/dist/assets/C0nA-iUG.js +0 -1
  158. package/dashboard/dist/assets/C0nA-iUG.js.br +0 -0
  159. package/dashboard/dist/assets/C0nA-iUG.js.gz +0 -0
  160. package/dashboard/dist/assets/C6GO-FKy.js +0 -1
  161. package/dashboard/dist/assets/C6GO-FKy.js.br +0 -0
  162. package/dashboard/dist/assets/C6GO-FKy.js.gz +0 -0
  163. package/dashboard/dist/assets/CFwPph5U.js +0 -1
  164. package/dashboard/dist/assets/CFwPph5U.js.br +0 -0
  165. package/dashboard/dist/assets/CFwPph5U.js.gz +0 -0
  166. package/dashboard/dist/assets/CL_wXqR7.js +0 -1
  167. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  168. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  169. package/dashboard/dist/assets/CPjsbbgZ.js +0 -212
  170. package/dashboard/dist/assets/CPjsbbgZ.js.br +0 -0
  171. package/dashboard/dist/assets/CPjsbbgZ.js.gz +0 -0
  172. package/dashboard/dist/assets/CSr2ZnTV.js +0 -1
  173. package/dashboard/dist/assets/CSr2ZnTV.js.br +0 -0
  174. package/dashboard/dist/assets/CSr2ZnTV.js.gz +0 -0
  175. package/dashboard/dist/assets/CgQDT6yL.js +0 -1
  176. package/dashboard/dist/assets/CgQDT6yL.js.br +0 -0
  177. package/dashboard/dist/assets/CgQDT6yL.js.gz +0 -0
  178. package/dashboard/dist/assets/CnitK1MX.js.br +0 -0
  179. package/dashboard/dist/assets/CnitK1MX.js.gz +0 -0
  180. package/dashboard/dist/assets/CxQ08qFN.js +0 -9
  181. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  182. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  183. package/dashboard/dist/assets/D7DHFX0D.js +0 -1
  184. package/dashboard/dist/assets/D7DHFX0D.js.br +0 -0
  185. package/dashboard/dist/assets/D7DHFX0D.js.gz +0 -0
  186. package/dashboard/dist/assets/DEip7uko.js +0 -1
  187. package/dashboard/dist/assets/DEip7uko.js.br +0 -0
  188. package/dashboard/dist/assets/DEip7uko.js.gz +0 -0
  189. package/dashboard/dist/assets/DHUSLc01.css +0 -1
  190. package/dashboard/dist/assets/DHUSLc01.css.br +0 -0
  191. package/dashboard/dist/assets/DHUSLc01.css.gz +0 -0
  192. package/dashboard/dist/assets/DOFL9l8s.js +0 -1
  193. package/dashboard/dist/assets/DOFL9l8s.js.br +0 -0
  194. package/dashboard/dist/assets/DOFL9l8s.js.gz +0 -0
  195. package/dashboard/dist/assets/DpuQm1oF.js.br +0 -0
  196. package/dashboard/dist/assets/DpuQm1oF.js.gz +0 -0
  197. package/dashboard/dist/assets/DxKG5zy8.js.br +0 -0
  198. package/dashboard/dist/assets/DxKG5zy8.js.gz +0 -0
  199. package/dashboard/dist/assets/cNrhgGc1.js +0 -8
  200. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  201. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  202. package/dashboard/dist/assets/tcEHYcbW.js.br +0 -0
  203. package/dashboard/dist/assets/tcEHYcbW.js.gz +0 -0
@@ -190,6 +190,12 @@ export function createAutopilotRuntime(deps) {
190
190
  return false;
191
191
  }
192
192
  }
193
+ function sessionResumeEnabled() {
194
+ const raw = (process.env.ORGX_AUTOPILOT_SESSION_RESUME ?? "").trim().toLowerCase();
195
+ if (!raw)
196
+ return false;
197
+ return !(raw === "0" || raw === "false" || raw === "no" || raw === "off");
198
+ }
193
199
  function spawnCodexSliceWorker(input) {
194
200
  ensurePrivateDirForFile(input.logPath);
195
201
  ensurePrivateDirForFile(input.outputPath);
@@ -335,8 +341,15 @@ export function createAutopilotRuntime(deps) {
335
341
  claudeExtraArgs.push("--print");
336
342
  if (!hasOutputFormat)
337
343
  claudeExtraArgs.push("--output-format", "json");
338
- if (!hasNoSessionPersistence)
344
+ // Session resume: when resumeSessionId is provided, use --resume and skip --no-session-persistence.
345
+ // When feature is enabled but no resume, omit --no-session-persistence to persist for future resume.
346
+ const resumeId = typeof input.resumeSessionId === "string" ? input.resumeSessionId.trim() : "";
347
+ if (resumeId) {
348
+ claudeExtraArgs.push("--resume", resumeId);
349
+ }
350
+ else if (!sessionResumeEnabled() && !hasNoSessionPersistence) {
339
351
  claudeExtraArgs.push("--no-session-persistence");
352
+ }
340
353
  if (!hasPermissionMode)
341
354
  claudeExtraArgs.push("--permission-mode", "bypassPermissions");
342
355
  if (!hasDangerousSkipPermissions && !hasAllowDangerousSkipPermissions) {
@@ -469,10 +482,25 @@ export function createAutopilotRuntime(deps) {
469
482
  }
470
483
  const codexInfo = deps.resolveCodexBinInfo();
471
484
  const codexBin = codexInfo.bin;
472
- const rawArgs = (process.env.ORGX_CODEX_ARGS ?? "").trim();
485
+ const codexResumeId = typeof input.resumeSessionId === "string" ? input.resumeSessionId.trim() : "";
486
+ // Session resume: use "resume <id>" subcommand instead of "exec --ephemeral"
487
+ // When feature enabled but no resume ID: omit --ephemeral to persist for future resume
488
+ let rawArgs;
489
+ let defaultArgs;
490
+ if (codexResumeId) {
491
+ rawArgs = "";
492
+ defaultArgs = ["resume", codexResumeId, "--full-auto", "--skip-git-repo-check"];
493
+ }
494
+ else {
495
+ rawArgs = (process.env.ORGX_CODEX_ARGS ?? "").trim();
496
+ const featureEnabled = sessionResumeEnabled();
497
+ defaultArgs = featureEnabled
498
+ ? ["exec", "--full-auto", "--skip-git-repo-check"]
499
+ : ["exec", "--ephemeral", "--full-auto", "--skip-git-repo-check"];
500
+ }
473
501
  const normalizedArgs = normalizeCodexArgs(rawArgs.length > 0
474
502
  ? rawArgs.split(/\s+/).filter(Boolean)
475
- : ["exec", "--ephemeral", "--full-auto", "--skip-git-repo-check"]);
503
+ : defaultArgs);
476
504
  const args = hasExplicitCodexSubcommand(normalizedArgs)
477
505
  ? normalizedArgs
478
506
  : ["exec", ...normalizedArgs];
@@ -2,6 +2,16 @@ export declare function ensureAutopilotSliceSchemaPath(schemaFilename: string):
2
2
  export declare function parseSliceResult<T extends object>(raw: string): T | null;
3
3
  export declare function readSliceOutputFile(pathname: string): string | null;
4
4
  export declare function readFileTailSafe(pathname: string, maxChars?: number): string;
5
+ /**
6
+ * Extract a CLI session ID from structured output JSON (Claude/Codex envelope).
7
+ * Looks for `session_id`, `sessionId`, or `conversation_id` fields.
8
+ */
9
+ export declare function extractSessionIdFromOutput(raw: string, _sourceClient?: string): string | null;
10
+ /**
11
+ * Extract a CLI session ID from worker log text.
12
+ * Matches patterns emitted by Claude Code and Codex CLIs.
13
+ */
14
+ export declare function extractSessionIdFromLog(logContent: string, _sourceClient?: string): string | null;
5
15
  export declare function fileUpdatedAtEpochMs(pathname: string, fallbackEpochMs: number): number;
6
16
  export type CodexBinInfo = {
7
17
  bin: string;
@@ -159,7 +159,57 @@ export function ensureAutopilotSliceSchemaPath(schemaFilename) {
159
159
  }
160
160
  export function parseSliceResult(raw) {
161
161
  const allowedStatuses = new Set(["completed", "blocked", "needs_decision", "error"]);
162
+ const normalizeStatusValue = (value) => {
163
+ if (typeof value !== "string")
164
+ return "";
165
+ const normalized = value.trim().toLowerCase();
166
+ return allowedStatuses.has(normalized) ? normalized : "";
167
+ };
162
168
  const stripUtf8Bom = (text) => text.replace(/^\uFEFF/, "");
169
+ const extractTopLevelObjects = (text) => {
170
+ let inString = false;
171
+ let escaped = false;
172
+ let depth = 0;
173
+ let start = -1;
174
+ const objects = [];
175
+ for (let i = 0; i < text.length; i += 1) {
176
+ const ch = text[i];
177
+ if (inString) {
178
+ if (escaped) {
179
+ escaped = false;
180
+ continue;
181
+ }
182
+ if (ch === "\\") {
183
+ escaped = true;
184
+ continue;
185
+ }
186
+ if (ch === "\"") {
187
+ inString = false;
188
+ }
189
+ continue;
190
+ }
191
+ if (ch === "\"") {
192
+ inString = true;
193
+ continue;
194
+ }
195
+ if (ch === "{") {
196
+ if (depth === 0)
197
+ start = i;
198
+ depth += 1;
199
+ continue;
200
+ }
201
+ if (ch === "}") {
202
+ if (depth <= 0)
203
+ continue;
204
+ depth -= 1;
205
+ if (depth === 0 && start >= 0) {
206
+ objects.push(text.slice(start, i + 1));
207
+ start = -1;
208
+ }
209
+ }
210
+ }
211
+ return objects;
212
+ };
163
213
  const extractMarkdownJsonFences = (text) => {
164
214
  const matches = text.matchAll(/```(?:json)?\s*([\s\S]*?)\s*```/gi);
165
215
  const fences = [];
@@ -192,13 +242,20 @@ export function parseSliceResult(raw) {
192
242
  return normalizeSliceResult(parsedInner);
193
243
  }
194
244
  }
245
+ const objectCandidates = extractTopLevelObjects(normalized);
246
+ for (let i = objectCandidates.length - 1; i >= 0; i -= 1) {
247
+ const parsedObject = parseJsonSafe(stripUtf8Bom(objectCandidates[i]));
248
+ if (parsedObject && typeof parsedObject === "object" && isLikelySliceResult(parsedObject)) {
249
+ return normalizeSliceResult(parsedObject);
250
+ }
251
+ }
195
252
  return null;
196
253
  };
197
254
  const isLikelySliceResult = (value) => {
198
255
  if (!value || typeof value !== "object")
199
256
  return false;
200
257
  const record = value;
201
- const status = typeof record.status === "string" ? record.status : "";
258
+ const status = normalizeStatusValue(record.status);
202
259
  const workstreamId = typeof record.workstream_id === "string" ? record.workstream_id : "";
203
260
  const summary = typeof record.summary === "string" ? record.summary : "";
204
261
  return (allowedStatuses.has(status) &&
@@ -207,10 +264,13 @@ export function parseSliceResult(raw) {
207
264
  };
208
265
  const normalizeSliceResult = (value) => {
209
266
  const record = value;
210
- const status = typeof record.status === "string" ? record.status : "";
267
+ const status = normalizeStatusValue(record.status);
211
268
  const decisions = record.decisions_needed;
212
269
  let changed = false;
213
- let nextRecord = record;
270
+ let nextRecord = status ? { ...record, status } : record;
271
+ if (status && record.status !== status) {
272
+ changed = true;
273
+ }
214
274
  if (Array.isArray(decisions)) {
215
275
  const normalized = decisions.map((decision) => {
216
276
  if (!decision || typeof decision !== "object")
@@ -275,7 +335,11 @@ export function parseSliceResult(raw) {
275
335
  const record = value;
276
336
  const parseEmbeddedText = (candidate) => {
277
337
  if (typeof candidate === "string") {
278
- return parseSliceJsonText(candidate);
338
+ const direct = parseSliceJsonText(candidate);
339
+ if (direct)
340
+ return direct;
341
+ // Some envelopes embed worker logs/prose with a trailing JSON object.
342
+ return parseSliceResult(candidate);
279
343
  }
280
344
  if (Array.isArray(candidate)) {
281
345
  for (let i = candidate.length - 1; i >= 0; i -= 1) {
@@ -288,12 +352,6 @@ export function parseSliceResult(raw) {
288
352
  if (!candidate || typeof candidate !== "object")
289
353
  return null;
290
354
  const candidateRecord = candidate;
291
- if (typeof candidateRecord.value === "string") {
292
- return parseSliceJsonText(candidateRecord.value);
293
- }
294
- if (typeof candidateRecord.text === "string") {
295
- return parseSliceJsonText(candidateRecord.text);
296
- }
297
355
  const fromValue = parseEmbeddedText(candidateRecord.value);
298
356
  if (fromValue)
299
357
  return fromValue;
@@ -392,50 +450,6 @@ export function parseSliceResult(raw) {
392
450
  if (directTextParsed && typeof directTextParsed === "object")
393
451
  return directTextParsed;
394
452
  // Tolerant parse: extract the last complete top-level JSON object from mixed logs.
395
- const extractTopLevelObjects = (text) => {
396
- let inString = false;
397
- let escaped = false;
398
- let depth = 0;
399
- let start = -1;
400
- const objects = [];
401
- for (let i = 0; i < text.length; i += 1) {
402
- const ch = text[i];
403
- if (inString) {
404
- if (escaped) {
405
- escaped = false;
406
- continue;
407
- }
408
- if (ch === "\\") {
409
- escaped = true;
410
- continue;
411
- }
412
- if (ch === "\"") {
413
- inString = false;
414
- }
415
- continue;
416
- }
417
- if (ch === "\"") {
418
- inString = true;
419
- continue;
420
- }
421
- if (ch === "{") {
422
- if (depth === 0)
423
- start = i;
424
- depth += 1;
425
- continue;
426
- }
427
- if (ch === "}") {
428
- if (depth <= 0)
429
- continue;
430
- depth -= 1;
431
- if (depth === 0 && start >= 0) {
432
- objects.push(text.slice(start, i + 1));
433
- start = -1;
434
- }
435
- }
436
- }
437
- return objects;
438
- };
439
453
  const candidates = extractTopLevelObjects(trimmed);
440
454
  for (let i = candidates.length - 1; i >= 0; i -= 1) {
441
455
  const candidate = candidates[i];
@@ -470,6 +484,96 @@ export function readFileTailSafe(pathname, maxChars = 64_000) {
470
484
  return "";
471
485
  }
472
486
  }
487
+ // ---------------------------------------------------------------------------
488
+ // Session ID extraction (for session resume support)
489
+ // ---------------------------------------------------------------------------
490
+ const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
491
+ /**
492
+ * Extract a CLI session ID from structured output JSON (Claude/Codex envelope).
493
+ * Looks for `session_id`, `sessionId`, or `conversation_id` fields.
494
+ */
495
+ export function extractSessionIdFromOutput(raw, _sourceClient) {
496
+ if (!raw || typeof raw !== "string")
497
+ return null;
498
+ const extractUuid = (value) => {
499
+ const match = value.trim().match(UUID_RE);
500
+ return match?.[0] ?? null;
501
+ };
502
+ const findSessionId = (candidate) => {
503
+ if (!candidate)
504
+ return null;
505
+ if (typeof candidate === "string") {
506
+ const parsedCandidate = parseJsonSafe(candidate.trim());
507
+ if (parsedCandidate)
508
+ return findSessionId(parsedCandidate);
509
+ return null;
510
+ }
511
+ if (Array.isArray(candidate)) {
512
+ for (const item of candidate) {
513
+ const found = findSessionId(item);
514
+ if (found)
515
+ return found;
516
+ }
517
+ return null;
518
+ }
519
+ if (typeof candidate !== "object")
520
+ return null;
521
+ const record = candidate;
522
+ for (const key of ["session_id", "sessionId", "conversation_id"]) {
523
+ const value = record[key];
524
+ if (typeof value === "string") {
525
+ const uuid = extractUuid(value);
526
+ if (uuid)
527
+ return uuid;
528
+ }
529
+ }
530
+ return (findSessionId(record.value) ??
531
+ findSessionId(record.text) ??
532
+ findSessionId(record.content) ??
533
+ findSessionId(record.output_text) ??
534
+ null);
535
+ };
536
+ const parsed = parseJsonSafe(raw.trim());
537
+ if (parsed && typeof parsed === "object") {
538
+ const found = findSessionId([
539
+ parsed,
540
+ parsed.result,
541
+ parsed.structured_output,
542
+ parsed.final_output,
543
+ parsed.output_text,
544
+ parsed.output,
545
+ ]);
546
+ if (found) {
547
+ return found;
548
+ }
549
+ }
550
+ // Fallback: scan raw text for session_id: <uuid> pattern
551
+ const inline = raw.match(/session_id\s*[:=]\s*"?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"?/i);
552
+ if (inline && typeof inline[1] === "string")
553
+ return inline[1];
554
+ return null;
555
+ }
556
+ /**
557
+ * Extract a CLI session ID from worker log text.
558
+ * Matches patterns emitted by Claude Code and Codex CLIs.
559
+ */
560
+ export function extractSessionIdFromLog(logContent, _sourceClient) {
561
+ if (!logContent || typeof logContent !== "string")
562
+ return null;
563
+ // Claude Code: "Resume this session with: claude --resume <uuid>"
564
+ const claudeResume = logContent.match(/claude\s+--resume\s+([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
565
+ if (claudeResume && typeof claudeResume[1] === "string")
566
+ return claudeResume[1];
567
+ // Codex: "codex resume <uuid>"
568
+ const codexResume = logContent.match(/codex\s+resume\s+([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
569
+ if (codexResume && typeof codexResume[1] === "string")
570
+ return codexResume[1];
571
+ // Generic: "Session: <uuid>", "session_id: <uuid>", "saving session <uuid>"
572
+ const generic = logContent.match(/(?:Session|session_id|saving\s+session)\s*[:=]?\s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
573
+ if (generic && typeof generic[1] === "string")
574
+ return generic[1];
575
+ return null;
576
+ }
473
577
  export function fileUpdatedAtEpochMs(pathname, fallbackEpochMs) {
474
578
  try {
475
579
  const st = statSync(pathname);
@@ -1 +1 @@
1
- export { idempotencyKey, stableHash } from "../../hash-utils.js";
1
+ export { deterministicActivityId, idempotencyKey, stableHash } from "../../hash-utils.js";
@@ -1 +1 @@
1
- export { idempotencyKey, stableHash } from "../../hash-utils.js";
1
+ export { deterministicActivityId, idempotencyKey, stableHash } from "../../hash-utils.js";
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Translates raw auto-continue engine error strings into human-readable
3
+ * decision context suitable for operator display.
4
+ *
5
+ * Used at decision creation time to enrich the `summary` field and
6
+ * generate structured options when the engine produces terse diagnostics.
7
+ */
8
+ export interface HumanizedSliceFailure {
9
+ /** One-line human headline, e.g. "Agent work stopped unexpectedly" */
10
+ headline: string;
11
+ /** Multi-sentence explanation for operators */
12
+ explanation: string;
13
+ /** Parsed structured data extracted from the raw string */
14
+ structuredDetails: {
15
+ exitCode?: string;
16
+ signal?: string;
17
+ elapsedMs?: string;
18
+ idleMs?: string;
19
+ server?: string;
20
+ reason?: string;
21
+ };
22
+ /** Severity for UI theming */
23
+ severity: "critical" | "warning" | "info";
24
+ }
25
+ /**
26
+ * Translate a raw auto-continue error/context string into a human-friendly
27
+ * decision description. Falls back gracefully for unrecognised patterns.
28
+ */
29
+ export declare function humanizeSliceFailure(raw: string): HumanizedSliceFailure;
30
+ /**
31
+ * Generate a human-friendly summary string from a raw error, suitable for
32
+ * the `summary` field when creating decisions. Combines the headline and
33
+ * explanation into a concise paragraph.
34
+ */
35
+ export declare function humanizeSliceFailureSummary(raw: string): string;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Translates raw auto-continue engine error strings into human-readable
3
+ * decision context suitable for operator display.
4
+ *
5
+ * Used at decision creation time to enrich the `summary` field and
6
+ * generate structured options when the engine produces terse diagnostics.
7
+ */
8
+ const PATTERNS = [
9
+ {
10
+ test: /Worker exited without structured output.*?code=(\S+?),\s*signal=(\S+?)\)/i,
11
+ headline: "Agent work stopped unexpectedly",
12
+ explain: (_raw, m) => {
13
+ const code = m[1] === "null" ? "none" : m[1];
14
+ const signal = m[2] === "null" ? "none" : m[2];
15
+ const parts = [
16
+ "The agent process exited before producing results.",
17
+ ];
18
+ if (signal !== "none" && signal !== "null") {
19
+ parts.push(`It was terminated by signal ${signal}, which usually means the worker was stopped externally or ran out of resources.`);
20
+ }
21
+ else {
22
+ parts.push("This usually means the worker crashed or was terminated before completing.");
23
+ }
24
+ parts.push(`Exit code: ${code}. Signal: ${signal}.`);
25
+ return parts.join(" ");
26
+ },
27
+ severity: "critical",
28
+ extractDetails: (_raw, m) => ({
29
+ exitCode: m[1] === "null" ? undefined : m[1],
30
+ signal: m[2] === "null" ? undefined : m[2],
31
+ }),
32
+ },
33
+ {
34
+ test: /MCP handshake failed(?:\s+for\s+(\S+))?/i,
35
+ headline: "Agent couldn't connect to tools",
36
+ explain: (_raw, m) => {
37
+ const server = m[1] ? ` (${m[1]})` : "";
38
+ return `The agent failed to establish a connection with its tool server${server}. This typically means the MCP server is unreachable, misconfigured, or took too long to respond. Retrying often resolves transient connection issues.`;
39
+ },
40
+ severity: "critical",
41
+ extractDetails: (_raw, m) => ({
42
+ server: m[1] || undefined,
43
+ }),
44
+ },
45
+ {
46
+ test: /(?:Slice|Autopilot slice) timed out after (\d+)/i,
47
+ headline: "Agent ran out of time",
48
+ explain: (_raw, m) => {
49
+ const ms = parseInt(m[1], 10);
50
+ const mins = Math.round(ms / 60_000);
51
+ return `The agent exceeded its ${mins > 0 ? `${mins}-minute` : `${ms}ms`} time limit without completing. This can happen when the task is too large for a single work slice or when the agent is waiting on a slow external resource. Consider breaking the work into smaller steps or increasing the time budget.`;
52
+ },
53
+ severity: "warning",
54
+ extractDetails: (_raw, m) => ({
55
+ elapsedMs: m[1],
56
+ }),
57
+ },
58
+ {
59
+ test: /(?:Slice|Autopilot slice) stalled.*?(?:no progress for (\d+))?/i,
60
+ headline: "Agent stopped making progress",
61
+ explain: (_raw, m) => {
62
+ const mins = m[1] ? Math.round(parseInt(m[1], 10) / 60_000) : null;
63
+ const duration = mins ? ` for ${mins} minute${mins !== 1 ? "s" : ""}` : "";
64
+ return `The agent stopped producing output${duration}. This can indicate it's stuck in a loop, waiting on an unresponsive resource, or unable to proceed with the current approach. Reviewing the session logs may reveal the specific bottleneck.`;
65
+ },
66
+ severity: "warning",
67
+ extractDetails: (_raw, m) => ({
68
+ idleMs: m[1] || undefined,
69
+ }),
70
+ },
71
+ {
72
+ test: /blocked.*?(?:needs|requires?) intervention/i,
73
+ headline: "Agent needs your help to continue",
74
+ explain: () => "The agent reached a point where it cannot proceed without human guidance. This may be a question about requirements, a permission needed, or an ambiguity that needs resolution.",
75
+ severity: "warning",
76
+ },
77
+ {
78
+ test: /blocked.*?without.*?(?:blocking )?decision payload/i,
79
+ headline: "Agent paused without clear reason",
80
+ explain: () => "The agent reported it was blocked but did not specify what decision is needed. Review the session logs for context about what the agent was working on when it paused.",
81
+ severity: "warning",
82
+ },
83
+ {
84
+ test: /code=(\d+)/i,
85
+ headline: "Agent encountered an error",
86
+ explain: (_raw, m) => `The agent process exited with error code ${m[1]}. This indicates the agent hit an unexpected condition during execution. Reviewing the session logs will show what operation failed.`,
87
+ severity: "critical",
88
+ extractDetails: (_raw, m) => ({
89
+ exitCode: m[1],
90
+ }),
91
+ },
92
+ {
93
+ test: /completed.*?(?:without|no) (?:verifiable )?(?:outcomes?|artifacts?|status updates?)/i,
94
+ headline: "Agent finished but produced nothing",
95
+ explain: () => "The agent reported completion but did not produce any artifacts, status updates, or measurable outcomes. This may mean the work was done informally (e.g., analysis without a written output) or the agent couldn't find actionable work.",
96
+ severity: "info",
97
+ },
98
+ {
99
+ test: /Spawn guard denied/i,
100
+ headline: "Agent dispatch was blocked by safety check",
101
+ explain: (_raw) => "The system's safety checks prevented this agent from starting. This is typically due to capacity limits, domain restrictions, or quality gate requirements that haven't been met.",
102
+ severity: "warning",
103
+ },
104
+ ];
105
+ /**
106
+ * Translate a raw auto-continue error/context string into a human-friendly
107
+ * decision description. Falls back gracefully for unrecognised patterns.
108
+ */
109
+ export function humanizeSliceFailure(raw) {
110
+ for (const pattern of PATTERNS) {
111
+ const match = raw.match(pattern.test);
112
+ if (match) {
113
+ return {
114
+ headline: pattern.headline,
115
+ explanation: pattern.explain(raw, match),
116
+ structuredDetails: pattern.extractDetails?.(raw, match) ?? {},
117
+ severity: pattern.severity,
118
+ };
119
+ }
120
+ }
121
+ // Fallback for unrecognised patterns
122
+ return {
123
+ headline: "Agent work needs attention",
124
+ explanation: raw,
125
+ structuredDetails: {},
126
+ severity: "warning",
127
+ };
128
+ }
129
+ /**
130
+ * Generate a human-friendly summary string from a raw error, suitable for
131
+ * the `summary` field when creating decisions. Combines the headline and
132
+ * explanation into a concise paragraph.
133
+ */
134
+ export function humanizeSliceFailureSummary(raw) {
135
+ const h = humanizeSliceFailure(raw);
136
+ return `${h.headline}. ${h.explanation}`;
137
+ }
@@ -71,6 +71,7 @@ export interface MissionControlExecutionPolicy {
71
71
  export declare const SLICE_SCOPE_MAX_TASKS: Record<SliceScope, number>;
72
72
  export declare const SLICE_SCOPE_TIMEOUT_MULTIPLIER: Record<SliceScope, number>;
73
73
  export declare const ORGX_SKILL_BY_DOMAIN: Record<string, string>;
74
+ export declare function safeErrorMessage(err: unknown): string;
74
75
  interface BudgetEnvBounds {
75
76
  min?: number;
76
77
  max?: number;
@@ -19,11 +19,77 @@ export const ORGX_SKILL_BY_DOMAIN = {
19
19
  design: "orgx-design-agent",
20
20
  orchestration: "orgx-orchestrator-agent",
21
21
  };
22
- function safeErrorMessage(err) {
23
- if (err instanceof Error)
24
- return err.message;
25
- if (typeof err === "string")
26
- return err;
22
+ export function safeErrorMessage(err) {
23
+ const raw = err instanceof Error
24
+ ? err.message
25
+ : typeof err === "string"
26
+ ? err
27
+ : err && typeof err === "object" && "message" in err && typeof err.message === "string"
28
+ ? (err.message ?? "")
29
+ : "";
30
+ const parseStructuredMessage = (value) => {
31
+ const trimmed = value.trim();
32
+ if (!trimmed)
33
+ return null;
34
+ const parseObjectMessage = (parsed) => {
35
+ if (!parsed || typeof parsed !== "object")
36
+ return null;
37
+ const root = parsed;
38
+ const nested = root.error && typeof root.error === "object" ? root.error : null;
39
+ const envelope = nested ?? root;
40
+ return ((typeof envelope.message === "string" && envelope.message.trim()) ||
41
+ (typeof envelope.detail === "string" && envelope.detail.trim()) ||
42
+ (!nested && typeof root.error === "string" && root.error.trim()) ||
43
+ null);
44
+ };
45
+ try {
46
+ const parsed = JSON.parse(trimmed);
47
+ const direct = parseObjectMessage(parsed);
48
+ if (direct)
49
+ return direct;
50
+ }
51
+ catch {
52
+ // fall through and attempt extraction of embedded JSON blocks
53
+ }
54
+ const firstBrace = trimmed.indexOf("{");
55
+ const lastBrace = trimmed.lastIndexOf("}");
56
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
57
+ const candidate = trimmed.slice(firstBrace, lastBrace + 1);
58
+ try {
59
+ const parsed = JSON.parse(candidate);
60
+ return parseObjectMessage(parsed);
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ }
66
+ return null;
67
+ };
68
+ const stripStructuredNoise = (value) => value
69
+ .replace(/"requestId"\s*:\s*"[^"]*"/gi, "")
70
+ .replace(/"timestamp"\s*:\s*"[^"]*"/gi, "")
71
+ .replace(/"docsUrl"\s*:\s*"[^"]*"/gi, "")
72
+ .replace(/\brequest[_\s-]?id[:=]\s*[\w-]+/gi, "")
73
+ .replace(/\btimestamp[:=]\s*\S+/gi, "")
74
+ .replace(/\bdocsUrl[:=]\s*\S+/gi, "")
75
+ .replace(/[{}]/g, " ")
76
+ .replace(/\s{2,}/g, " ")
77
+ .trim();
78
+ const normalizedMessage = parseStructuredMessage(raw) ?? raw;
79
+ const sanitized = stripStructuredNoise(normalizedMessage);
80
+ const normalized = sanitized.toLowerCase();
81
+ if (normalized.length > 0) {
82
+ if (normalized.includes("relation does not exist")) {
83
+ return sanitized;
84
+ }
85
+ if (normalized.includes("internal_error") || normalized.includes("internal server error")) {
86
+ return "temporary server issue";
87
+ }
88
+ if (normalized.includes("failed to list decision") || normalized.includes("failed to load decision")) {
89
+ return "decision data temporarily unavailable";
90
+ }
91
+ return sanitized;
92
+ }
27
93
  return "Unexpected error";
28
94
  }
29
95
  function toNullableBoolean(value) {
@@ -642,10 +708,10 @@ export async function listEntitiesSafe(client, type, filters) {
642
708
  }
643
709
  }
644
710
  export async function buildMissionControlGraph(client, initiativeId, options) {
711
+ const degraded = [];
645
712
  if (!UUID_RE.test(initiativeId)) {
646
- throw new Error(`buildMissionControlGraph: initiativeId must be a UUID, got "${initiativeId}"`);
713
+ degraded.push(`initiative id "${initiativeId}" is non-UUID; using compatibility graph lookup`);
647
714
  }
648
- const degraded = [];
649
715
  const preloadedInitiative = options?.initiativeEntity ?? null;
650
716
  const [initiativeResult, workstreamResult, milestoneResult, taskResult] = await Promise.all([
651
717
  preloadedInitiative
@@ -0,0 +1,37 @@
1
+ /** Queue state for next-up items (workstream-level). */
2
+ export declare const QueueState: {
3
+ readonly QUEUED: "queued";
4
+ readonly RUNNING: "running";
5
+ readonly BLOCKED: "blocked";
6
+ readonly IDLE: "idle";
7
+ /** Used only in the API normalization layer (mission-control-read.ts). */
8
+ readonly COMPLETED: "completed";
9
+ };
10
+ /** Core queue states used by the queue builder (excludes "completed"). */
11
+ export type CoreQueueState = "queued" | "running" | "blocked" | "idle";
12
+ /** Extended queue state including API-only values. */
13
+ export type QueueStateValue = (typeof QueueState)[keyof typeof QueueState];
14
+ /** Auto-continue lane state (per-workstream within a run). */
15
+ export declare const LaneState: {
16
+ readonly IDLE: "idle";
17
+ readonly RUNNING: "running";
18
+ readonly BLOCKED: "blocked";
19
+ readonly WAITING_DEPENDENCY: "waiting_dependency";
20
+ readonly RATE_LIMITED: "rate_limited";
21
+ readonly COMPLETED: "completed";
22
+ };
23
+ export type LaneStateValue = (typeof LaneState)[keyof typeof LaneState];
24
+ /** Auto-continue run status. */
25
+ export declare const RunStatus: {
26
+ readonly RUNNING: "running";
27
+ readonly STOPPING: "stopping";
28
+ readonly STOPPED: "stopped";
29
+ };
30
+ export type RunStatusValue = (typeof RunStatus)[keyof typeof RunStatus];
31
+ /** Runner source — how the agent was assigned. */
32
+ export declare const RunnerSource: {
33
+ readonly ASSIGNED: "assigned";
34
+ readonly INFERRED: "inferred";
35
+ readonly FALLBACK: "fallback";
36
+ };
37
+ export type RunnerSourceValue = (typeof RunnerSource)[keyof typeof RunnerSource];