@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.
- package/README.md +94 -122
- package/dashboard/dist/assets/0RUEVzJa.js +1 -0
- package/dashboard/dist/assets/0RUEVzJa.js.br +0 -0
- package/dashboard/dist/assets/0RUEVzJa.js.gz +0 -0
- package/dashboard/dist/assets/3TtV4moZ.js +1 -0
- package/dashboard/dist/assets/3TtV4moZ.js.br +0 -0
- package/dashboard/dist/assets/3TtV4moZ.js.gz +0 -0
- package/dashboard/dist/assets/3VwNyxUf.js +1 -0
- package/dashboard/dist/assets/3VwNyxUf.js.br +0 -0
- package/dashboard/dist/assets/3VwNyxUf.js.gz +0 -0
- package/dashboard/dist/assets/{DpuQm1oF.js → 7DhYqBrM.js} +2 -2
- package/dashboard/dist/assets/7DhYqBrM.js.br +0 -0
- package/dashboard/dist/assets/7DhYqBrM.js.gz +0 -0
- package/dashboard/dist/assets/{tcEHYcbW.js → BCudUvwg.js} +1 -1
- package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
- package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
- package/dashboard/dist/assets/BV0BcV1u.js +53 -0
- package/dashboard/dist/assets/BV0BcV1u.js.br +0 -0
- package/dashboard/dist/assets/BV0BcV1u.js.gz +0 -0
- package/dashboard/dist/assets/BVvffj0x.js +1 -0
- package/dashboard/dist/assets/BVvffj0x.js.br +0 -0
- package/dashboard/dist/assets/BVvffj0x.js.gz +0 -0
- package/dashboard/dist/assets/BiOgVMED.js +1 -0
- package/dashboard/dist/assets/BiOgVMED.js.br +0 -0
- package/dashboard/dist/assets/BiOgVMED.js.gz +0 -0
- package/dashboard/dist/assets/BjK42gtU.js +1 -0
- package/dashboard/dist/assets/BjK42gtU.js.br +0 -0
- package/dashboard/dist/assets/BjK42gtU.js.gz +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js +1 -0
- package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
- package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
- package/dashboard/dist/assets/C91KLKit.js +1 -0
- package/dashboard/dist/assets/C91KLKit.js.br +0 -0
- package/dashboard/dist/assets/C91KLKit.js.gz +0 -0
- package/dashboard/dist/assets/{CnitK1MX.js → C9fvfXmS.js} +1 -1
- package/dashboard/dist/assets/C9fvfXmS.js.br +0 -0
- package/dashboard/dist/assets/C9fvfXmS.js.gz +0 -0
- package/dashboard/dist/assets/CFZ4Swr5.js +1 -0
- package/dashboard/dist/assets/CFZ4Swr5.js.br +0 -0
- package/dashboard/dist/assets/CFZ4Swr5.js.gz +0 -0
- package/dashboard/dist/assets/{77gGFBt6.js → CGj8kRhg.js} +1 -1
- package/dashboard/dist/assets/CGj8kRhg.js.br +0 -0
- package/dashboard/dist/assets/CGj8kRhg.js.gz +0 -0
- package/dashboard/dist/assets/CJjEAGFN.js +1 -0
- package/dashboard/dist/assets/CJjEAGFN.js.br +0 -0
- package/dashboard/dist/assets/CJjEAGFN.js.gz +0 -0
- package/dashboard/dist/assets/CKrH5fYO.js +1 -0
- package/dashboard/dist/assets/CKrH5fYO.js.br +0 -0
- package/dashboard/dist/assets/CKrH5fYO.js.gz +0 -0
- package/dashboard/dist/assets/CMTTPXch.js +1 -0
- package/dashboard/dist/assets/CMTTPXch.js.br +0 -0
- package/dashboard/dist/assets/CMTTPXch.js.gz +0 -0
- package/dashboard/dist/assets/CSlBSRyv.js +1 -0
- package/dashboard/dist/assets/CSlBSRyv.js.br +0 -0
- package/dashboard/dist/assets/CSlBSRyv.js.gz +0 -0
- package/dashboard/dist/assets/CnPC783_.js +1 -0
- package/dashboard/dist/assets/CnPC783_.js.br +0 -0
- package/dashboard/dist/assets/CnPC783_.js.gz +0 -0
- package/dashboard/dist/assets/Ctw95IkC.js +1 -0
- package/dashboard/dist/assets/Ctw95IkC.js.br +0 -0
- package/dashboard/dist/assets/Ctw95IkC.js.gz +0 -0
- package/dashboard/dist/assets/DHz-aQPw.js +1 -0
- package/dashboard/dist/assets/DHz-aQPw.js.br +0 -0
- package/dashboard/dist/assets/DHz-aQPw.js.gz +0 -0
- package/dashboard/dist/assets/DNX2foSJ.css +1 -0
- package/dashboard/dist/assets/DNX2foSJ.css.br +0 -0
- package/dashboard/dist/assets/DNX2foSJ.css.gz +0 -0
- package/dashboard/dist/assets/Dj2k1r16.js +8 -0
- package/dashboard/dist/assets/Dj2k1r16.js.br +0 -0
- package/dashboard/dist/assets/Dj2k1r16.js.gz +0 -0
- package/dashboard/dist/assets/DxUw4FMR.js +212 -0
- package/dashboard/dist/assets/DxUw4FMR.js.br +0 -0
- package/dashboard/dist/assets/DxUw4FMR.js.gz +0 -0
- package/dashboard/dist/assets/T2NFtzAv.js +1 -0
- package/dashboard/dist/assets/T2NFtzAv.js.br +0 -0
- package/dashboard/dist/assets/T2NFtzAv.js.gz +0 -0
- package/dashboard/dist/assets/cX2e-TLi.js +1 -0
- package/dashboard/dist/assets/cX2e-TLi.js.br +0 -0
- package/dashboard/dist/assets/cX2e-TLi.js.gz +0 -0
- package/dashboard/dist/assets/eeHXe_OQ.js +9 -0
- package/dashboard/dist/assets/eeHXe_OQ.js.br +0 -0
- package/dashboard/dist/assets/eeHXe_OQ.js.gz +0 -0
- package/dashboard/dist/assets/{DxKG5zy8.js → gZr_xKlA.js} +2 -2
- package/dashboard/dist/assets/gZr_xKlA.js.br +0 -0
- package/dashboard/dist/assets/gZr_xKlA.js.gz +0 -0
- package/dashboard/dist/brand/control-tower.png +0 -0
- package/dashboard/dist/brand/design-codex.png +0 -0
- package/dashboard/dist/brand/engineering-autopilot.png +0 -0
- package/dashboard/dist/brand/launch-captain.png +0 -0
- package/dashboard/dist/brand/orgx-logo.png +0 -0
- package/dashboard/dist/brand/pipeline-intelligence.png +0 -0
- package/dashboard/dist/brand/product-orchestrator.png +0 -0
- package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
- package/dashboard/dist/index.html +8 -6
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/hash-utils.d.ts +1 -0
- package/dist/hash-utils.js +4 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +36 -0
- package/dist/http/helpers/auto-continue-engine.js +198 -75
- package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
- package/dist/http/helpers/autopilot-runtime.js +31 -3
- package/dist/http/helpers/autopilot-slice-utils.d.ts +10 -0
- package/dist/http/helpers/autopilot-slice-utils.js +158 -54
- package/dist/http/helpers/hash-utils.d.ts +1 -1
- package/dist/http/helpers/hash-utils.js +1 -1
- package/dist/http/helpers/humanize-slice-failure.d.ts +35 -0
- package/dist/http/helpers/humanize-slice-failure.js +137 -0
- package/dist/http/helpers/mission-control.d.ts +1 -0
- package/dist/http/helpers/mission-control.js +73 -7
- package/dist/http/helpers/queue-constants.d.ts +37 -0
- package/dist/http/helpers/queue-constants.js +34 -0
- package/dist/http/helpers/slice-experience-v2.js +2 -5
- package/dist/http/helpers/slice-run-projections.js +2 -5
- package/dist/http/helpers/workspace-scope.js +4 -3
- package/dist/http/index.js +166 -63
- package/dist/http/routes/chat.js +1 -21
- package/dist/http/routes/live-misc.js +9 -2
- package/dist/http/routes/live-snapshot.js +14 -27
- package/dist/http/routes/mission-control-actions.js +7 -18
- package/dist/http/routes/mission-control-read.d.ts +1 -0
- package/dist/http/routes/mission-control-read.js +14 -56
- package/dist/index.d.ts +8 -1
- package/dist/index.js +21 -1
- package/dist/lib/type-coercion.d.ts +10 -0
- package/dist/lib/type-coercion.js +82 -0
- package/dist/mcp-http-handler.js +14 -2
- package/dist/openclaw.plugin.json +1 -1
- package/dist/services/experiment-randomization.js +9 -2
- package/dist/tools/core-tools.d.ts +27 -0
- package/dist/tools/core-tools.js +89 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -2
- package/dashboard/dist/assets/77gGFBt6.js.br +0 -0
- package/dashboard/dist/assets/77gGFBt6.js.gz +0 -0
- package/dashboard/dist/assets/BBpTN_SR.js +0 -1
- package/dashboard/dist/assets/BBpTN_SR.js.br +0 -0
- package/dashboard/dist/assets/BBpTN_SR.js.gz +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js +0 -53
- package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
- package/dashboard/dist/assets/BTAEErUY.js +0 -1
- package/dashboard/dist/assets/BTAEErUY.js.br +0 -0
- package/dashboard/dist/assets/BTAEErUY.js.gz +0 -0
- package/dashboard/dist/assets/BVShoyjA.js +0 -1
- package/dashboard/dist/assets/BVShoyjA.js.br +0 -0
- package/dashboard/dist/assets/BVShoyjA.js.gz +0 -0
- package/dashboard/dist/assets/BgcAY5rE.js +0 -1
- package/dashboard/dist/assets/BgcAY5rE.js.br +0 -0
- package/dashboard/dist/assets/BgcAY5rE.js.gz +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js +0 -1
- package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
- package/dashboard/dist/assets/C-PAoJF-.js +0 -1
- package/dashboard/dist/assets/C-PAoJF-.js.br +0 -0
- package/dashboard/dist/assets/C-PAoJF-.js.gz +0 -0
- package/dashboard/dist/assets/C0nA-iUG.js +0 -1
- package/dashboard/dist/assets/C0nA-iUG.js.br +0 -0
- package/dashboard/dist/assets/C0nA-iUG.js.gz +0 -0
- package/dashboard/dist/assets/C6GO-FKy.js +0 -1
- package/dashboard/dist/assets/C6GO-FKy.js.br +0 -0
- package/dashboard/dist/assets/C6GO-FKy.js.gz +0 -0
- package/dashboard/dist/assets/CFwPph5U.js +0 -1
- package/dashboard/dist/assets/CFwPph5U.js.br +0 -0
- package/dashboard/dist/assets/CFwPph5U.js.gz +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js +0 -1
- package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
- package/dashboard/dist/assets/CPjsbbgZ.js +0 -212
- package/dashboard/dist/assets/CPjsbbgZ.js.br +0 -0
- package/dashboard/dist/assets/CPjsbbgZ.js.gz +0 -0
- package/dashboard/dist/assets/CSr2ZnTV.js +0 -1
- package/dashboard/dist/assets/CSr2ZnTV.js.br +0 -0
- package/dashboard/dist/assets/CSr2ZnTV.js.gz +0 -0
- package/dashboard/dist/assets/CgQDT6yL.js +0 -1
- package/dashboard/dist/assets/CgQDT6yL.js.br +0 -0
- package/dashboard/dist/assets/CgQDT6yL.js.gz +0 -0
- package/dashboard/dist/assets/CnitK1MX.js.br +0 -0
- package/dashboard/dist/assets/CnitK1MX.js.gz +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js +0 -9
- package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
- package/dashboard/dist/assets/D7DHFX0D.js +0 -1
- package/dashboard/dist/assets/D7DHFX0D.js.br +0 -0
- package/dashboard/dist/assets/D7DHFX0D.js.gz +0 -0
- package/dashboard/dist/assets/DEip7uko.js +0 -1
- package/dashboard/dist/assets/DEip7uko.js.br +0 -0
- package/dashboard/dist/assets/DEip7uko.js.gz +0 -0
- package/dashboard/dist/assets/DHUSLc01.css +0 -1
- package/dashboard/dist/assets/DHUSLc01.css.br +0 -0
- package/dashboard/dist/assets/DHUSLc01.css.gz +0 -0
- package/dashboard/dist/assets/DOFL9l8s.js +0 -1
- package/dashboard/dist/assets/DOFL9l8s.js.br +0 -0
- package/dashboard/dist/assets/DOFL9l8s.js.gz +0 -0
- package/dashboard/dist/assets/DpuQm1oF.js.br +0 -0
- package/dashboard/dist/assets/DpuQm1oF.js.gz +0 -0
- package/dashboard/dist/assets/DxKG5zy8.js.br +0 -0
- package/dashboard/dist/assets/DxKG5zy8.js.gz +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js +0 -8
- package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
- package/dashboard/dist/assets/tcEHYcbW.js.br +0 -0
- 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
|
-
|
|
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
|
|
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
|
-
:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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];
|