@useorgx/openclaw-plugin 0.7.20 → 0.7.24

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 (165) hide show
  1. package/dashboard/dist/assets/B6VftyY6.js +1 -0
  2. package/dashboard/dist/assets/B6VftyY6.js.br +0 -0
  3. package/dashboard/dist/assets/B6VftyY6.js.gz +0 -0
  4. package/dashboard/dist/assets/{Dm0CfDGr.js → BANQdlC4.js} +1 -1
  5. package/dashboard/dist/assets/BANQdlC4.js.br +0 -0
  6. package/dashboard/dist/assets/BANQdlC4.js.gz +0 -0
  7. package/dashboard/dist/assets/{_zpQCpjm.js → BPL4CL3c.js} +1 -1
  8. package/dashboard/dist/assets/BPL4CL3c.js.br +0 -0
  9. package/dashboard/dist/assets/BPL4CL3c.js.gz +0 -0
  10. package/dashboard/dist/assets/{DXVs61e1.js → BZCkOZ20.js} +1 -1
  11. package/dashboard/dist/assets/BZCkOZ20.js.br +0 -0
  12. package/dashboard/dist/assets/BZCkOZ20.js.gz +0 -0
  13. package/dashboard/dist/assets/{BYb6DARX.js → B_LdOJUa.js} +1 -1
  14. package/dashboard/dist/assets/B_LdOJUa.js.br +0 -0
  15. package/dashboard/dist/assets/B_LdOJUa.js.gz +0 -0
  16. package/dashboard/dist/assets/Bfp-wdwb.css +1 -0
  17. package/dashboard/dist/assets/Bfp-wdwb.css.br +0 -0
  18. package/dashboard/dist/assets/Bfp-wdwb.css.gz +0 -0
  19. package/dashboard/dist/assets/{DibzNd0I.js → BvFcH_Iy.js} +1 -1
  20. package/dashboard/dist/assets/BvFcH_Iy.js.br +0 -0
  21. package/dashboard/dist/assets/BvFcH_Iy.js.gz +0 -0
  22. package/dashboard/dist/assets/By0MIBj_.js +1 -0
  23. package/dashboard/dist/assets/By0MIBj_.js.br +0 -0
  24. package/dashboard/dist/assets/By0MIBj_.js.gz +0 -0
  25. package/dashboard/dist/assets/C0i7ABUU.js +212 -0
  26. package/dashboard/dist/assets/C0i7ABUU.js.br +0 -0
  27. package/dashboard/dist/assets/C0i7ABUU.js.gz +0 -0
  28. package/dashboard/dist/assets/CFB0MM7j.js +1 -0
  29. package/dashboard/dist/assets/CFB0MM7j.js.br +0 -0
  30. package/dashboard/dist/assets/CFB0MM7j.js.gz +0 -0
  31. package/dashboard/dist/assets/CQSRb1yu.js +1 -0
  32. package/dashboard/dist/assets/CQSRb1yu.js.br +0 -0
  33. package/dashboard/dist/assets/CQSRb1yu.js.gz +0 -0
  34. package/dashboard/dist/assets/{wa4jJQK9.js → CUoQoSm-.js} +1 -1
  35. package/dashboard/dist/assets/CUoQoSm-.js.br +0 -0
  36. package/dashboard/dist/assets/CUoQoSm-.js.gz +0 -0
  37. package/dashboard/dist/assets/Ckd1R1iE.js +1 -0
  38. package/dashboard/dist/assets/Ckd1R1iE.js.br +0 -0
  39. package/dashboard/dist/assets/Ckd1R1iE.js.gz +0 -0
  40. package/dashboard/dist/assets/{BGY6oI8h.js → CqRNb2EL.js} +1 -1
  41. package/dashboard/dist/assets/CqRNb2EL.js.br +0 -0
  42. package/dashboard/dist/assets/CqRNb2EL.js.gz +0 -0
  43. package/dashboard/dist/assets/{DAr4MfFk.js → DClUc9rw.js} +1 -1
  44. package/dashboard/dist/assets/DClUc9rw.js.br +0 -0
  45. package/dashboard/dist/assets/DClUc9rw.js.gz +0 -0
  46. package/dashboard/dist/assets/DF2PMTwT.js +1 -0
  47. package/dashboard/dist/assets/DF2PMTwT.js.br +0 -0
  48. package/dashboard/dist/assets/DF2PMTwT.js.gz +0 -0
  49. package/dashboard/dist/assets/{B014hrCe.js → DJYl7gyA.js} +2 -2
  50. package/dashboard/dist/assets/DJYl7gyA.js.br +0 -0
  51. package/dashboard/dist/assets/DJYl7gyA.js.gz +0 -0
  52. package/dashboard/dist/assets/{BoDhb8_y.js → DZtNMX0t.js} +2 -2
  53. package/dashboard/dist/assets/DZtNMX0t.js.br +0 -0
  54. package/dashboard/dist/assets/DZtNMX0t.js.gz +0 -0
  55. package/dashboard/dist/assets/DlEa8PI0.js +1 -0
  56. package/dashboard/dist/assets/DlEa8PI0.js.br +0 -0
  57. package/dashboard/dist/assets/DlEa8PI0.js.gz +0 -0
  58. package/dashboard/dist/assets/M4QxcXjh.js +1 -0
  59. package/dashboard/dist/assets/M4QxcXjh.js.br +0 -0
  60. package/dashboard/dist/assets/M4QxcXjh.js.gz +0 -0
  61. package/dashboard/dist/assets/{CV0sWMbv.js → MrW1ixGx.js} +1 -1
  62. package/dashboard/dist/assets/MrW1ixGx.js.br +0 -0
  63. package/dashboard/dist/assets/MrW1ixGx.js.gz +0 -0
  64. package/dashboard/dist/index.html +2 -2
  65. package/dashboard/dist/index.html.br +0 -0
  66. package/dashboard/dist/index.html.gz +0 -0
  67. package/dist/activity-store.js +68 -8
  68. package/dist/agent-run-store.js +162 -24
  69. package/dist/cli/orgx.d.ts +3 -0
  70. package/dist/config/resolution.d.ts +7 -0
  71. package/dist/config/resolution.js +13 -5
  72. package/dist/contracts/onboarding-state.d.ts +2 -0
  73. package/dist/contracts/onboarding-state.js +23 -0
  74. package/dist/contracts/shared-types.d.ts +45 -0
  75. package/dist/http/helpers/auto-continue-engine.d.ts +23 -0
  76. package/dist/http/helpers/auto-continue-engine.js +468 -85
  77. package/dist/http/helpers/autopilot-runtime.js +5 -1
  78. package/dist/http/helpers/autopilot-slice-utils.js +25 -1
  79. package/dist/http/helpers/decision-mapper.d.ts +1 -0
  80. package/dist/http/helpers/decision-mapper.js +19 -2
  81. package/dist/http/helpers/dispatch-lifecycle.js +3 -0
  82. package/dist/http/helpers/mission-control.d.ts +1 -0
  83. package/dist/http/helpers/mission-control.js +5 -2
  84. package/dist/http/helpers/slice-run-projections.d.ts +27 -0
  85. package/dist/http/helpers/slice-run-projections.js +198 -10
  86. package/dist/http/helpers/triage-mapper.js +499 -6
  87. package/dist/http/helpers/value-utils.d.ts +1 -0
  88. package/dist/http/helpers/value-utils.js +17 -0
  89. package/dist/http/index.d.ts +1 -0
  90. package/dist/http/index.js +179 -46
  91. package/dist/http/router.js +64 -9
  92. package/dist/http/routes/live-legacy.d.ts +19 -2
  93. package/dist/http/routes/live-legacy.js +110 -27
  94. package/dist/http/routes/live-snapshot.d.ts +16 -2
  95. package/dist/http/routes/live-snapshot.js +169 -25
  96. package/dist/http/routes/live-triage.js +6 -1
  97. package/dist/http/routes/mission-control-actions.d.ts +9 -0
  98. package/dist/http/routes/mission-control-actions.js +185 -7
  99. package/dist/http/routes/mission-control-read.d.ts +13 -0
  100. package/dist/http/routes/mission-control-read.js +100 -219
  101. package/dist/http/routes/onboarding.d.ts +1 -0
  102. package/dist/http/routes/onboarding.js +17 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +199 -123
  105. package/dist/outbox.d.ts +0 -2
  106. package/dist/outbox.js +259 -148
  107. package/dist/reporting/rollups.js +18 -11
  108. package/dist/runtime-instance-store.js +212 -58
  109. package/dist/stores/materialized-snapshot-store.d.ts +18 -0
  110. package/dist/stores/materialized-snapshot-store.js +91 -0
  111. package/dist/stores/sqlite-state.d.ts +6 -0
  112. package/dist/stores/sqlite-state.js +330 -0
  113. package/package.json +5 -1
  114. package/dashboard/dist/assets/B014hrCe.js.br +0 -0
  115. package/dashboard/dist/assets/B014hrCe.js.gz +0 -0
  116. package/dashboard/dist/assets/BCudUvwg.js +0 -1
  117. package/dashboard/dist/assets/BCudUvwg.js.br +0 -0
  118. package/dashboard/dist/assets/BCudUvwg.js.gz +0 -0
  119. package/dashboard/dist/assets/BGY6oI8h.js.br +0 -0
  120. package/dashboard/dist/assets/BGY6oI8h.js.gz +0 -0
  121. package/dashboard/dist/assets/BJI1Iy5v.css +0 -1
  122. package/dashboard/dist/assets/BJI1Iy5v.css.br +0 -0
  123. package/dashboard/dist/assets/BJI1Iy5v.css.gz +0 -0
  124. package/dashboard/dist/assets/BUvcp_7V.js +0 -1
  125. package/dashboard/dist/assets/BUvcp_7V.js.br +0 -0
  126. package/dashboard/dist/assets/BUvcp_7V.js.gz +0 -0
  127. package/dashboard/dist/assets/BV2Tf8S2.js +0 -212
  128. package/dashboard/dist/assets/BV2Tf8S2.js.br +0 -0
  129. package/dashboard/dist/assets/BV2Tf8S2.js.gz +0 -0
  130. package/dashboard/dist/assets/BYb6DARX.js.br +0 -0
  131. package/dashboard/dist/assets/BYb6DARX.js.gz +0 -0
  132. package/dashboard/dist/assets/BoDhb8_y.js.br +0 -0
  133. package/dashboard/dist/assets/BoDhb8_y.js.gz +0 -0
  134. package/dashboard/dist/assets/Bqk_l0k6.js +0 -1
  135. package/dashboard/dist/assets/Bqk_l0k6.js.br +0 -0
  136. package/dashboard/dist/assets/Bqk_l0k6.js.gz +0 -0
  137. package/dashboard/dist/assets/C-MOJWHs.js +0 -1
  138. package/dashboard/dist/assets/C-MOJWHs.js.br +0 -0
  139. package/dashboard/dist/assets/C-MOJWHs.js.gz +0 -0
  140. package/dashboard/dist/assets/CV0sWMbv.js.br +0 -0
  141. package/dashboard/dist/assets/CV0sWMbv.js.gz +0 -0
  142. package/dashboard/dist/assets/CaAkScfa.js +0 -1
  143. package/dashboard/dist/assets/CaAkScfa.js.br +0 -0
  144. package/dashboard/dist/assets/CaAkScfa.js.gz +0 -0
  145. package/dashboard/dist/assets/Ck5KlsPN.js +0 -1
  146. package/dashboard/dist/assets/Ck5KlsPN.js.br +0 -0
  147. package/dashboard/dist/assets/Ck5KlsPN.js.gz +0 -0
  148. package/dashboard/dist/assets/D2G51wQm.js +0 -1
  149. package/dashboard/dist/assets/D2G51wQm.js.br +0 -0
  150. package/dashboard/dist/assets/D2G51wQm.js.gz +0 -0
  151. package/dashboard/dist/assets/DAr4MfFk.js.br +0 -0
  152. package/dashboard/dist/assets/DAr4MfFk.js.gz +0 -0
  153. package/dashboard/dist/assets/DXVs61e1.js.br +0 -0
  154. package/dashboard/dist/assets/DXVs61e1.js.gz +0 -0
  155. package/dashboard/dist/assets/DibzNd0I.js.br +0 -0
  156. package/dashboard/dist/assets/DibzNd0I.js.gz +0 -0
  157. package/dashboard/dist/assets/Dm0CfDGr.js.br +0 -0
  158. package/dashboard/dist/assets/Dm0CfDGr.js.gz +0 -0
  159. package/dashboard/dist/assets/_zpQCpjm.js.br +0 -0
  160. package/dashboard/dist/assets/_zpQCpjm.js.gz +0 -0
  161. package/dashboard/dist/assets/uNGpYMSH.js +0 -1
  162. package/dashboard/dist/assets/uNGpYMSH.js.br +0 -0
  163. package/dashboard/dist/assets/uNGpYMSH.js.gz +0 -0
  164. package/dashboard/dist/assets/wa4jJQK9.js.br +0 -0
  165. package/dashboard/dist/assets/wa4jJQK9.js.gz +0 -0
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { readdir, stat, unlink } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
- import { normalizeActivityActionPhase, normalizeActivityActionType, } from "../../contracts/shared-types.js";
6
+ import { normalizeActivityActionPhase, normalizeActivityActionType, normalizeDecisionActionType, } from "../../contracts/shared-types.js";
7
7
  import { upsertAgentContext, upsertRunContext } from "../../agent-context-store.js";
8
8
  import { appendTeamCompletion } from "../../team-context-store.js";
9
9
  import { readOpenClawGatewayPort, readOpenClawSettingsSnapshot, } from "../../openclaw-settings.js";
@@ -11,7 +11,7 @@ import { resolveRuntimeHookToken, } from "../../runtime-instance-store.js";
11
11
  import { detectMcpHandshakeFailure, shouldKillWorker } from "../../worker-supervisor.js";
12
12
  import { humanizeSliceFailure, humanizeSliceFailureSummary } from "./humanize-slice-failure.js";
13
13
  import { getOrgxPluginConfigDir } from "../../paths.js";
14
- import { buildMissionControlGraph, DEFAULT_TOKEN_BUDGET_ASSUMPTIONS, dedupeStrings, detectBehaviorConfigDrift, deriveBehaviorAutomationLevel, deriveBehaviorConfigContext, deriveExecutionPolicy, evaluateScopeCompletion, isDispatchableWorkstreamStatus, isDoneStatus, isTodoStatus, readBudgetEnvNumber, selectSliceTasksByScope, SLICE_SCOPE_TIMEOUT_MULTIPLIER, spawnGuardIsRateLimited, summarizeSpawnGuardBlockReason, } from "./mission-control.js";
14
+ import { buildMissionControlGraph, DEFAULT_TOKEN_BUDGET_ASSUMPTIONS, dedupeStrings, detectBehaviorConfigDrift, deriveBehaviorAutomationLevel, deriveBehaviorConfigContext, deriveInitiativeLifecycleStatus, deriveExecutionPolicy, evaluateScopeCompletion, isDispatchableWorkstreamStatus, isDoneStatus, isTodoStatus, readBudgetEnvNumber, selectSliceTasksByScope, SLICE_SCOPE_TIMEOUT_MULTIPLIER, spawnGuardIsRateLimited, summarizeSpawnGuardBlockReason, } from "./mission-control.js";
15
15
  import { createAutopilotRuntime } from "./autopilot-runtime.js";
16
16
  import { buildScopeDirective, buildSliceOutputInstructions, buildWorkstreamSlicePrompt, createCodexBinResolver, ensureAutopilotSliceSchemaPath, extractSessionIdFromLog, extractSessionIdFromOutput, fileUpdatedAtEpochMs, parseSliceResult, readFileTailSafe, readSliceOutputFile, } from "./autopilot-slice-utils.js";
17
17
  import { pickString } from "./value-utils.js";
@@ -28,7 +28,18 @@ function resolveAutopilotDefaultCwd(filename) {
28
28
  }
29
29
  return homedir();
30
30
  }
31
+ function captureAutopilotWorkerEnv() {
32
+ return {
33
+ ORGX_AUTOPILOT_CWD: (process.env.ORGX_AUTOPILOT_CWD ?? "").trim() || undefined,
34
+ ORGX_AUTOPILOT_EXECUTOR: (process.env.ORGX_AUTOPILOT_EXECUTOR ?? "").trim() || undefined,
35
+ ORGX_AUTOPILOT_WORKER_KIND: (process.env.ORGX_AUTOPILOT_WORKER_KIND ?? "").trim() || undefined,
36
+ ORGX_AUTOPILOT_MOCK_SCENARIO: (process.env.ORGX_AUTOPILOT_MOCK_SCENARIO ?? "").trim() || undefined,
37
+ ORGX_AUTOPILOT_MOCK_SLEEP_MS: (process.env.ORGX_AUTOPILOT_MOCK_SLEEP_MS ?? "").trim() || undefined,
38
+ ORGX_AUTOPILOT_SESSION_RESUME: (process.env.ORGX_AUTOPILOT_SESSION_RESUME ?? "").trim() || undefined,
39
+ };
40
+ }
31
41
  export function createAutoContinueEngine(deps) {
42
+ const defaultWorkerEnvOverrides = captureAutopilotWorkerEnv();
32
43
  const { client, safeErrorMessage, pidAlive, stopProcess, resolveOrgxAgentForDomain, checkSpawnGuardSafe, syncParentRollupsForTask, emitActivitySafe, requestDecisionSafe, registerArtifactSafe, applyAgentStatusUpdatesSafe, upsertRuntimeInstanceFromHook, broadcastRuntimeSse, clearSnapshotResponseCache, resolveByokEnvOverrides, } = deps;
33
44
  const randomUUID = deps.randomUUID ?? randomUuidFn;
34
45
  const fetchKickoffContextSafeFn = deps.fetchKickoffContextSafe ?? null;
@@ -319,10 +330,7 @@ export function createAutoContinueEngine(deps) {
319
330
  event: "question_timeout_started",
320
331
  action_type: normalizeActivityActionType("question_timeout_started"),
321
332
  action_phase: normalizeActivityActionPhase("review"),
322
- initiative_id: pending.initiativeId,
323
- workstream_id: pending.workstreamId,
324
- source_run_id: pending.sourceRunId,
325
- source_client: pending.sourceClient,
333
+ ...(pending.eventMetadata ?? {}),
326
334
  decision_ids: pending.decisionIds,
327
335
  decision_count: pending.decisionIds.length,
328
336
  decision_action: pending.action,
@@ -367,6 +375,166 @@ export function createAutoContinueEngine(deps) {
367
375
  }, delaySeconds * 1_000);
368
376
  pending.timer.unref?.();
369
377
  };
378
+ const pickMetadataString = (record, keys) => {
379
+ if (!record)
380
+ return null;
381
+ for (const key of keys) {
382
+ const value = record[key];
383
+ if (typeof value !== "string")
384
+ continue;
385
+ const trimmed = value.trim();
386
+ if (trimmed.length > 0)
387
+ return trimmed;
388
+ }
389
+ return null;
390
+ };
391
+ const pickMetadataStringArray = (record, keys) => {
392
+ if (!record)
393
+ return [];
394
+ for (const key of keys) {
395
+ const raw = record[key];
396
+ if (!Array.isArray(raw))
397
+ continue;
398
+ const values = raw
399
+ .filter((entry) => typeof entry === "string")
400
+ .map((entry) => entry.trim())
401
+ .filter(Boolean);
402
+ if (values.length > 0)
403
+ return values;
404
+ }
405
+ return [];
406
+ };
407
+ const normalizeQueuedDecisionOptions = (value, recommendedAction) => {
408
+ if (!Array.isArray(value))
409
+ return [];
410
+ const normalized = [];
411
+ const seen = new Set();
412
+ const recommendedLower = recommendedAction?.trim().toLowerCase() ?? null;
413
+ for (const rawOption of value) {
414
+ if (typeof rawOption === "string") {
415
+ const label = rawOption.trim();
416
+ if (!label)
417
+ continue;
418
+ const key = label.toLowerCase();
419
+ if (seen.has(key))
420
+ continue;
421
+ seen.add(key);
422
+ normalized.push({
423
+ label,
424
+ recommended: recommendedLower !== null && label.toLowerCase() === recommendedLower,
425
+ });
426
+ continue;
427
+ }
428
+ if (!rawOption || typeof rawOption !== "object" || Array.isArray(rawOption))
429
+ continue;
430
+ const optionRecord = rawOption;
431
+ const label = pickMetadataString(optionRecord, ["label", "title", "name"]) ??
432
+ pickMetadataString(optionRecord, ["action", "action_type", "actionType"]);
433
+ if (!label)
434
+ continue;
435
+ const id = pickMetadataString(optionRecord, ["id", "option_id", "optionId"]);
436
+ const description = pickMetadataString(optionRecord, ["description", "summary"]);
437
+ const consequences = pickMetadataString(optionRecord, ["consequences", "impact"]);
438
+ const actionType = pickMetadataString(optionRecord, ["action_type", "actionType", "action"]);
439
+ const impliedStatus = pickMetadataString(optionRecord, ["implied_status", "impliedStatus", "status"]);
440
+ const requiresNote = optionRecord.requires_note === true ||
441
+ optionRecord.requiresNote === true ||
442
+ optionRecord.note_required === true;
443
+ const recommended = optionRecord.recommended === true ||
444
+ optionRecord.is_recommended === true ||
445
+ optionRecord.isRecommended === true ||
446
+ (recommendedLower !== null && label.toLowerCase() === recommendedLower);
447
+ const key = `${(id ?? "").toLowerCase()}|${label.toLowerCase()}`;
448
+ if (seen.has(key))
449
+ continue;
450
+ seen.add(key);
451
+ normalized.push({
452
+ ...(id ? { id } : {}),
453
+ label,
454
+ ...(description ? { description } : {}),
455
+ ...(consequences ? { consequences } : {}),
456
+ ...(actionType ? { action_type: actionType } : {}),
457
+ ...(impliedStatus ? { implied_status: impliedStatus } : {}),
458
+ ...(requiresNote ? { requires_note: true } : {}),
459
+ ...(recommended ? { recommended: true } : {}),
460
+ });
461
+ }
462
+ return normalized.slice(0, 8);
463
+ };
464
+ const normalizeQueuedDecisionEvidence = (value) => {
465
+ if (!Array.isArray(value))
466
+ return [];
467
+ const normalized = [];
468
+ const seen = new Set();
469
+ for (const rawEvidence of value) {
470
+ if (!rawEvidence || typeof rawEvidence !== "object" || Array.isArray(rawEvidence))
471
+ continue;
472
+ const record = rawEvidence;
473
+ const title = pickMetadataString(record, ["title", "label", "name"]) ??
474
+ pickMetadataString(record, ["source_pointer", "sourcePointer", "source_url", "sourceUrl"]) ??
475
+ "Evidence";
476
+ const summary = pickMetadataString(record, ["summary", "description"]);
477
+ const sourceUrl = pickMetadataString(record, ["source_url", "sourceUrl", "url"]);
478
+ const sourcePointer = pickMetadataString(record, ["source_pointer", "sourcePointer", "path"]);
479
+ const evidenceType = pickMetadataString(record, ["evidence_type", "evidenceType", "type"]);
480
+ const confidenceRaw = record.confidence ?? record.confidence_score;
481
+ const confidence = typeof confidenceRaw === "number" && Number.isFinite(confidenceRaw)
482
+ ? Math.max(0, Math.min(1, confidenceRaw))
483
+ : null;
484
+ const key = `${title.toLowerCase()}|${sourceUrl ?? ""}|${sourcePointer ?? ""}`;
485
+ if (seen.has(key))
486
+ continue;
487
+ seen.add(key);
488
+ normalized.push({
489
+ title,
490
+ ...(summary ? { summary } : {}),
491
+ ...(sourceUrl ? { source_url: sourceUrl } : {}),
492
+ ...(sourcePointer ? { source_pointer: sourcePointer } : {}),
493
+ ...(evidenceType ? { evidence_type: evidenceType } : {}),
494
+ ...(confidence !== null ? { confidence } : {}),
495
+ });
496
+ }
497
+ return normalized.slice(0, 8);
498
+ };
499
+ const buildQuestionEventMetadata = (input) => {
500
+ const metadata = {
501
+ initiative_id: input.initiativeId,
502
+ workstream_id: input.workstreamId,
503
+ source_run_id: input.sourceRunId,
504
+ source_client: input.sourceClient,
505
+ decision_ids: input.decisionIds,
506
+ decision_count: input.decisionIds.length,
507
+ blocking: input.blocking,
508
+ decision_title: input.title,
509
+ decision_prompt: input.title,
510
+ question: input.title,
511
+ required_action: input.recommendedAction,
512
+ recommended_action: input.recommendedAction,
513
+ current_run_state: input.currentRunState,
514
+ impact_if_delayed: input.impactIfDelayed,
515
+ reason: input.reason,
516
+ decision_type: input.decisionType,
517
+ };
518
+ if (input.summary)
519
+ metadata.decision_summary = input.summary;
520
+ if (input.options.length > 0) {
521
+ metadata.decision_options = input.options;
522
+ metadata.decision_option_labels = input.options.map((option) => option.label);
523
+ }
524
+ if (input.evidenceRefs.length > 0)
525
+ metadata.evidence_refs = input.evidenceRefs;
526
+ if (input.scopeHierarchy.length > 0)
527
+ metadata.scope_hierarchy = input.scopeHierarchy;
528
+ if (input.initiativeTitle)
529
+ metadata.initiative_title = input.initiativeTitle;
530
+ if (input.workstreamTitle)
531
+ metadata.workstream_title = input.workstreamTitle;
532
+ if (input.taskTitle)
533
+ metadata.task_title = input.taskTitle;
534
+ if (input.nextActions.length > 0)
535
+ metadata.next_actions = input.nextActions;
536
+ return metadata;
537
+ };
370
538
  const scheduleQuestionAutoAnswer = async (input) => {
371
539
  const decisionIds = dedupeStrings(input.decisionIds
372
540
  .map((entry) => (entry ?? "").trim())
@@ -374,6 +542,28 @@ export function createAutoContinueEngine(deps) {
374
542
  if (decisionIds.length === 0)
375
543
  return;
376
544
  const policy = resolveQuestionPolicy(input.initiativeId, input.workstreamId);
545
+ const questionMetadata = buildQuestionEventMetadata({
546
+ initiativeId: input.initiativeId,
547
+ workstreamId: input.workstreamId,
548
+ sourceRunId: input.sourceRunId,
549
+ sourceClient: input.sourceClient,
550
+ decisionIds,
551
+ blocking: input.blocking,
552
+ title: input.title,
553
+ summary: input.summary,
554
+ decisionType: input.decisionType,
555
+ options: input.options,
556
+ recommendedAction: input.recommendedAction,
557
+ evidenceRefs: input.evidenceRefs,
558
+ scopeHierarchy: input.scopeHierarchy,
559
+ initiativeTitle: input.initiativeTitle,
560
+ workstreamTitle: input.workstreamTitle,
561
+ taskTitle: input.taskTitle,
562
+ nextActions: input.nextActions,
563
+ currentRunState: input.currentRunState,
564
+ impactIfDelayed: input.impactIfDelayed,
565
+ reason: input.reason,
566
+ });
377
567
  await emitActivitySafe({
378
568
  initiativeId: input.initiativeId,
379
569
  runId: input.sourceRunId,
@@ -391,13 +581,7 @@ export function createAutoContinueEngine(deps) {
391
581
  event: "question_asked",
392
582
  action_type: normalizeActivityActionType("question_asked"),
393
583
  action_phase: normalizeActivityActionPhase("review"),
394
- initiative_id: input.initiativeId,
395
- workstream_id: input.workstreamId,
396
- source_run_id: input.sourceRunId,
397
- source_client: input.sourceClient,
398
- decision_ids: decisionIds,
399
- decision_count: decisionIds.length,
400
- blocking: input.blocking,
584
+ ...questionMetadata,
401
585
  question_policy_mode: policy.mode,
402
586
  question_policy_version: policy.policyVersion,
403
587
  timeout_seconds_applied: policy.timeoutSeconds,
@@ -423,12 +607,7 @@ export function createAutoContinueEngine(deps) {
423
607
  event: "review_item_created",
424
608
  action_type: normalizeActivityActionType("review_item_created"),
425
609
  action_phase: normalizeActivityActionPhase("blocked"),
426
- initiative_id: input.initiativeId,
427
- workstream_id: input.workstreamId,
428
- source_run_id: input.sourceRunId,
429
- source_client: input.sourceClient,
430
- decision_ids: decisionIds,
431
- decision_count: decisionIds.length,
610
+ ...questionMetadata,
432
611
  blocking: true,
433
612
  reason: "blocking_question_requires_human",
434
613
  question_policy_mode: policy.mode,
@@ -452,11 +631,7 @@ export function createAutoContinueEngine(deps) {
452
631
  event: "review_item_created",
453
632
  action_type: normalizeActivityActionType("review_item_created"),
454
633
  action_phase: normalizeActivityActionPhase("review"),
455
- initiative_id: input.initiativeId,
456
- workstream_id: input.workstreamId,
457
- source_run_id: input.sourceRunId,
458
- source_client: input.sourceClient,
459
- decision_ids: decisionIds,
634
+ ...questionMetadata,
460
635
  reason: "policy_disabled",
461
636
  question_policy_mode: policy.mode,
462
637
  question_policy_version: policy.policyVersion,
@@ -476,6 +651,7 @@ export function createAutoContinueEngine(deps) {
476
651
  existing.policyVersion = policy.policyVersion;
477
652
  existing.timeoutSeconds = policy.timeoutSeconds;
478
653
  existing.dueAt = new Date(dueAtEpoch).toISOString();
654
+ existing.eventMetadata = questionMetadata;
479
655
  armQuestionAutoAnswerTimer(key, existing, policy.timeoutSeconds);
480
656
  await emitActivitySafe({
481
657
  initiativeId: input.initiativeId,
@@ -490,10 +666,7 @@ export function createAutoContinueEngine(deps) {
490
666
  event: "question_timeout_started",
491
667
  action_type: normalizeActivityActionType("question_timeout_started"),
492
668
  action_phase: normalizeActivityActionPhase("review"),
493
- initiative_id: input.initiativeId,
494
- workstream_id: input.workstreamId,
495
- source_run_id: input.sourceRunId,
496
- source_client: input.sourceClient,
669
+ ...questionMetadata,
497
670
  decision_ids: existing.decisionIds,
498
671
  decision_count: existing.decisionIds.length,
499
672
  decision_action: existing.action,
@@ -519,6 +692,7 @@ export function createAutoContinueEngine(deps) {
519
692
  dueAt: new Date(dueAtEpoch).toISOString(),
520
693
  timer: null,
521
694
  decisionIds,
695
+ eventMetadata: questionMetadata,
522
696
  };
523
697
  armQuestionAutoAnswerTimer(key, pending, policy.timeoutSeconds);
524
698
  pendingQuestionAutoAnswerByScope.set(key, pending);
@@ -535,12 +709,7 @@ export function createAutoContinueEngine(deps) {
535
709
  event: "question_timeout_started",
536
710
  action_type: normalizeActivityActionType("question_timeout_started"),
537
711
  action_phase: normalizeActivityActionPhase("review"),
538
- initiative_id: input.initiativeId,
539
- workstream_id: input.workstreamId,
540
- source_run_id: input.sourceRunId,
541
- source_client: input.sourceClient,
542
- decision_ids: decisionIds,
543
- decision_count: decisionIds.length,
712
+ ...questionMetadata,
544
713
  decision_action: policy.action,
545
714
  timeout_seconds_applied: policy.timeoutSeconds,
546
715
  question_policy_mode: policy.mode,
@@ -692,6 +861,34 @@ export function createAutoContinueEngine(deps) {
692
861
  inferredStreamId ??
693
862
  linkedSlice?.workstreamId ??
694
863
  null);
864
+ const initiativeTitle = pickMetadataString(metadataBase, ["initiative_title", "initiativeTitle"]) ??
865
+ pickMetadataString(sourceRefBase, ["initiative_title", "initiativeTitle"]) ??
866
+ null;
867
+ const workstreamTitle = pickMetadataString(metadataBase, ["workstream_title", "workstreamTitle"]) ??
868
+ pickMetadataString(sourceRefBase, ["workstream_title", "workstreamTitle"]) ??
869
+ linkedSlice?.workstreamTitle ??
870
+ null;
871
+ const taskTitle = pickMetadataString(metadataBase, ["task_title", "taskTitle", "dispatch_task_title"]) ??
872
+ null;
873
+ const recommendedAction = typeof normalizedInput.recommendedAction === "string" && normalizedInput.recommendedAction.trim().length > 0
874
+ ? normalizedInput.recommendedAction.trim()
875
+ : pickMetadataString(metadataBase, ["recommended_action", "recommendedAction"]);
876
+ const decisionOptions = normalizeQueuedDecisionOptions(normalizedInput.options ?? [], recommendedAction);
877
+ const decisionEvidenceRefs = normalizeQueuedDecisionEvidence(normalizedInput.evidenceRefs ?? []);
878
+ const scopeHierarchy = [
879
+ ...pickMetadataStringArray(metadataBase, ["scope_hierarchy", "scopeHierarchy"]),
880
+ ...pickMetadataStringArray(sourceRefBase, ["scope_hierarchy", "scopeHierarchy"]),
881
+ ...[initiativeTitle, workstreamTitle, taskTitle].filter((entry) => typeof entry === "string" && entry.trim().length > 0),
882
+ ].filter((entry, index, source) => source.indexOf(entry) === index);
883
+ const nextActions = [
884
+ ...pickMetadataStringArray(metadataBase, ["next_actions", "nextActions"]),
885
+ ...(recommendedAction ? [recommendedAction] : []),
886
+ ].filter((entry, index, source) => source.indexOf(entry) === index);
887
+ const currentRunState = pickMetadataString(metadataBase, ["current_run_state", "currentRunState", "runtime_state", "runtimeState", "parsed_status", "parsedStatus"]) ??
888
+ linkedSlice?.status ??
889
+ null;
890
+ const impactIfDelayed = pickMetadataString(metadataBase, ["impact_if_delayed", "impactIfDelayed"]) ??
891
+ null;
695
892
  const result = await requestDecisionSafe(normalizedInput);
696
893
  if (typeof result === "boolean") {
697
894
  return { queued: result, decisionIds: [] };
@@ -719,6 +916,23 @@ export function createAutoContinueEngine(deps) {
719
916
  sourceClient,
720
917
  decisionIds,
721
918
  blocking: Boolean(normalizedInput.blocking),
919
+ title: normalizedInput.title,
920
+ summary: typeof normalizedInput.summary === "string" && normalizedInput.summary.trim().length > 0
921
+ ? normalizedInput.summary.trim()
922
+ : null,
923
+ decisionType: typeof normalizedInput.decisionType === "string" && normalizedInput.decisionType.trim().length > 0
924
+ ? normalizedInput.decisionType.trim()
925
+ : null,
926
+ options: decisionOptions,
927
+ recommendedAction,
928
+ evidenceRefs: decisionEvidenceRefs,
929
+ scopeHierarchy,
930
+ initiativeTitle,
931
+ workstreamTitle,
932
+ taskTitle,
933
+ nextActions,
934
+ currentRunState,
935
+ impactIfDelayed,
722
936
  reason: typeof normalizedInput.conflictSource === "string"
723
937
  ? normalizedInput.conflictSource
724
938
  : null,
@@ -731,6 +945,35 @@ export function createAutoContinueEngine(deps) {
731
945
  }
732
946
  return { queued: false, decisionIds: [] };
733
947
  };
948
+ const defaultInterventionDecisionOptions = () => [
949
+ {
950
+ id: "retry_slice",
951
+ label: "Retry this workstream slice",
952
+ description: "Retry once with the latest context and logs.",
953
+ consequences: "Autopilot retries this workstream slice immediately.",
954
+ implied_status: "approved",
955
+ action_type: "retry",
956
+ requires_note: false,
957
+ },
958
+ {
959
+ id: "pause_and_investigate",
960
+ label: "Pause autopilot and investigate",
961
+ description: "Pause orchestration and capture operator notes for handoff.",
962
+ consequences: "Autopilot pauses and waits for new operator guidance.",
963
+ implied_status: "declined",
964
+ action_type: "pause",
965
+ requires_note: true,
966
+ },
967
+ {
968
+ id: "skip_for_now",
969
+ label: "Skip this workstream for now",
970
+ description: "Defer this lane and keep other workstreams moving.",
971
+ consequences: "This lane is deferred while the rest of the queue continues.",
972
+ implied_status: "declined",
973
+ action_type: "defer",
974
+ requires_note: true,
975
+ },
976
+ ];
734
977
  const __filename = deps.filename;
735
978
  const autoContinueRuns = new Map();
736
979
  /**
@@ -780,6 +1023,9 @@ export function createAutoContinueEngine(deps) {
780
1023
  const now = new Date().toISOString();
781
1024
  const run = {
782
1025
  initiativeId,
1026
+ workspaceId: typeof meta.workspace_id === "string" && meta.workspace_id.trim().length > 0
1027
+ ? meta.workspace_id.trim()
1028
+ : null,
783
1029
  agentId: "",
784
1030
  agentName: null,
785
1031
  includeVerification: Boolean(meta.auto_continue_include_verification),
@@ -817,6 +1063,10 @@ export function createAutoContinueEngine(deps) {
817
1063
  activeTaskTokenEstimate: typeof meta.auto_continue_active_task_token_estimate === "number"
818
1064
  ? meta.auto_continue_active_task_token_estimate
819
1065
  : null,
1066
+ workerEnvOverrides: null,
1067
+ lastInitiativeStatus: typeof meta.status === "string" && meta.status.trim().length > 0
1068
+ ? meta.status.trim()
1069
+ : null,
820
1070
  };
821
1071
  ensureRunInternals(run);
822
1072
  syncLegacyRunPointers(run);
@@ -1024,6 +1274,38 @@ export function createAutoContinueEngine(deps) {
1024
1274
  autoContinueSliceChildren.delete(id);
1025
1275
  autoContinueSliceLastHeartbeatMs.delete(id);
1026
1276
  };
1277
+ const stopActiveSliceProcesses = async (sliceRunIds) => {
1278
+ for (const rawRunId of sliceRunIds) {
1279
+ const sliceRunId = rawRunId.trim();
1280
+ if (!sliceRunId)
1281
+ continue;
1282
+ const child = autoContinueSliceChildren.get(sliceRunId) ?? null;
1283
+ try {
1284
+ if (child && child.exitCode === null && !child.killed) {
1285
+ child.kill("SIGTERM");
1286
+ }
1287
+ }
1288
+ catch {
1289
+ // best effort
1290
+ }
1291
+ const slice = autoContinueSliceRuns.get(sliceRunId) ?? null;
1292
+ const pid = slice?.pid ?? child?.pid ?? null;
1293
+ if (pid && pidAlive(pid)) {
1294
+ try {
1295
+ await stopProcess(pid);
1296
+ }
1297
+ catch {
1298
+ // best effort
1299
+ }
1300
+ }
1301
+ if (slice) {
1302
+ slice.pid = null;
1303
+ slice.updatedAt = new Date().toISOString();
1304
+ autoContinueSliceRuns.set(sliceRunId, slice);
1305
+ }
1306
+ clearAutoContinueSliceTransientState(sliceRunId);
1307
+ }
1308
+ };
1027
1309
  const AUTO_CONTINUE_SLICE_TIMEOUT_MS = readBudgetEnvNumber("ORGX_AUTOPILOT_SLICE_TIMEOUT_MS", 55 * 60_000,
1028
1310
  // Keep test runs fast; real-world defaults are still ~1h unless overridden.
1029
1311
  { min: 250, max: 6 * 60 * 60_000 });
@@ -1211,6 +1493,57 @@ export function createAutoContinueEngine(deps) {
1211
1493
  run.maxParallelSlices = normalizeMaxParallelSlices(run.maxParallelSlices, AUTO_CONTINUE_MAX_PARALLEL_DEFAULT);
1212
1494
  run.parallelMode = normalizeParallelMode(run.parallelMode);
1213
1495
  run.tokenBudget = normalizeTokenBudget(run.tokenBudget, defaultAutoContinueTokenBudget());
1496
+ if (!run.workerEnvOverrides || typeof run.workerEnvOverrides !== "object") {
1497
+ run.workerEnvOverrides = null;
1498
+ }
1499
+ run.workspaceId =
1500
+ typeof run.workspaceId === "string" && run.workspaceId.trim().length > 0
1501
+ ? run.workspaceId.trim()
1502
+ : null;
1503
+ run.lastInitiativeStatus =
1504
+ typeof run.lastInitiativeStatus === "string" && run.lastInitiativeStatus.trim().length > 0
1505
+ ? run.lastInitiativeStatus.trim()
1506
+ : null;
1507
+ };
1508
+ const laneStateToChildStatus = (laneState) => {
1509
+ if (laneState === LaneState.RUNNING)
1510
+ return "in_progress";
1511
+ if (laneState === LaneState.BLOCKED)
1512
+ return "blocked";
1513
+ if (laneState === LaneState.WAITING_DEPENDENCY || laneState === LaneState.RATE_LIMITED) {
1514
+ return "paused";
1515
+ }
1516
+ if (laneState === LaneState.COMPLETED)
1517
+ return "completed";
1518
+ return "todo";
1519
+ };
1520
+ const deriveInitiativeStatusFromRun = (run) => {
1521
+ ensureRunInternals(run);
1522
+ const childStatuses = Object.values(run.laneByWorkstreamId ?? {}).map((lane) => laneStateToChildStatus(lane.state));
1523
+ if (run.status === RunStatus.RUNNING || run.status === RunStatus.STOPPING) {
1524
+ return deriveInitiativeLifecycleStatus("active", childStatuses.length > 0 ? childStatuses : ["in_progress"]);
1525
+ }
1526
+ if (run.stopReason === "blocked" || run.stopReason === "error") {
1527
+ return "blocked";
1528
+ }
1529
+ if (run.stopReason === "completed") {
1530
+ const scopedRun = run.stopAfterSlice ||
1531
+ (Array.isArray(run.allowedWorkstreamIds) && run.allowedWorkstreamIds.length > 0);
1532
+ return scopedRun ? "paused" : "completed";
1533
+ }
1534
+ if (run.stopReason === "budget_exhausted" || run.stopReason === "stopped") {
1535
+ return "paused";
1536
+ }
1537
+ return childStatuses.length > 0
1538
+ ? deriveInitiativeLifecycleStatus("paused", childStatuses)
1539
+ : "paused";
1540
+ };
1541
+ const syncInitiativeLifecycleStatus = async (run) => {
1542
+ const nextStatus = deriveInitiativeStatusFromRun(run);
1543
+ if (run.lastInitiativeStatus === nextStatus)
1544
+ return;
1545
+ await client.updateEntity("initiative", run.initiativeId, { status: nextStatus });
1546
+ run.lastInitiativeStatus = nextStatus;
1214
1547
  };
1215
1548
  const recordLocalStatusOverrides = (input) => {
1216
1549
  const initiativeId = input.initiativeId.trim();
@@ -1485,6 +1818,7 @@ export function createAutoContinueEngine(deps) {
1485
1818
  updated_at: lane.updatedAt,
1486
1819
  }));
1487
1820
  const patch = {
1821
+ ...(input.run.workspaceId ? { workspace_id: input.run.workspaceId } : {}),
1488
1822
  auto_continue_enabled: input.run.status === RunStatus.RUNNING || input.run.status === RunStatus.STOPPING,
1489
1823
  auto_continue_status: input.run.status,
1490
1824
  auto_continue_stop_reason: input.run.stopReason,
@@ -1510,6 +1844,7 @@ export function createAutoContinueEngine(deps) {
1510
1844
  ...(input.run.lastError ? { auto_continue_last_error: input.run.lastError } : {}),
1511
1845
  };
1512
1846
  await updateInitiativeMetadata(input.initiativeId, patch);
1847
+ await syncInitiativeLifecycleStatus(input.run);
1513
1848
  }
1514
1849
  async function stopAutoContinueRun(input) {
1515
1850
  const decisionRequired = input.reason === "blocked" && input.decisionRequired === true;
@@ -1524,6 +1859,7 @@ export function createAutoContinueEngine(deps) {
1524
1859
  const now = new Date().toISOString();
1525
1860
  ensureRunInternals(input.run);
1526
1861
  const activeRunIds = listActiveSliceRunIds(input.run);
1862
+ await stopActiveSliceProcesses(activeRunIds);
1527
1863
  input.run.status = RunStatus.STOPPED;
1528
1864
  input.run.stopReason = input.reason;
1529
1865
  input.run.stoppedAt = now;
@@ -1553,18 +1889,6 @@ export function createAutoContinueEngine(deps) {
1553
1889
  for (const runId of activeRunIds) {
1554
1890
  clearAutoContinueSliceTransientState(runId);
1555
1891
  }
1556
- // Only pause the initiative on non-terminal stops (error, blocked, user-requested).
1557
- // Completed / budget-exhausted runs should not override the initiative status.
1558
- if (input.reason !== "completed" && input.reason !== "budget_exhausted") {
1559
- try {
1560
- await client.updateEntity("initiative", input.run.initiativeId, {
1561
- status: "paused",
1562
- });
1563
- }
1564
- catch {
1565
- // best effort
1566
- }
1567
- }
1568
1892
  try {
1569
1893
  await updateInitiativeAutoContinueState({
1570
1894
  initiativeId: input.run.initiativeId,
@@ -1685,7 +2009,7 @@ export function createAutoContinueEngine(deps) {
1685
2009
  old_state: LaneState.RUNNING,
1686
2010
  new_state: input.reason === "completed" || input.reason === "stopped" ? "idle" : input.reason === "blocked" ? "blocked" : input.reason === "error" ? "error" : "idle",
1687
2011
  reason: input.reason,
1688
- workspace_id: input.run.allowedWorkstreamIds?.[0] ?? null,
2012
+ workspace_id: input.run.workspaceId ?? null,
1689
2013
  },
1690
2014
  });
1691
2015
  }
@@ -1843,11 +2167,7 @@ export function createAutoContinueEngine(deps) {
1843
2167
  title: `Agent couldn't connect to tools: ${slice.workstreamTitle ?? slice.workstreamId}`,
1844
2168
  summary: humanizeSliceFailureSummary(`MCP handshake failed${mcpHandshake.server ? ` for ${mcpHandshake.server}` : ""}.`),
1845
2169
  urgency: "high",
1846
- options: [
1847
- "Retry this workstream slice",
1848
- "Pause autopilot and investigate",
1849
- "Skip this workstream for now",
1850
- ],
2170
+ options: defaultInterventionDecisionOptions(),
1851
2171
  blocking: true,
1852
2172
  decisionType: "autopilot_failure",
1853
2173
  workstreamId: slice.workstreamId,
@@ -1965,11 +2285,7 @@ export function createAutoContinueEngine(deps) {
1965
2285
  title: stallDecisionTitle,
1966
2286
  summary: humanizeSliceFailureSummary(slice.lastError ?? `Autopilot slice ${humanLabel}`),
1967
2287
  urgency: "high",
1968
- options: [
1969
- "Retry this workstream slice",
1970
- "Pause autopilot and investigate",
1971
- "Skip this workstream for now",
1972
- ],
2288
+ options: defaultInterventionDecisionOptions(),
1973
2289
  blocking: true,
1974
2290
  decisionType: "autopilot_failure",
1975
2291
  workstreamId: slice.workstreamId,
@@ -2067,6 +2383,68 @@ export function createAutoContinueEngine(deps) {
2067
2383
  }
2068
2384
  }
2069
2385
  const defaultDecisionBlocking = parsedStatus === "completed" ? false : true;
2386
+ const normalizeDecisionOptions = (value) => {
2387
+ if (!Array.isArray(value))
2388
+ return [];
2389
+ const normalized = [];
2390
+ for (const rawOption of value) {
2391
+ if (typeof rawOption === "string") {
2392
+ const label = rawOption.trim();
2393
+ if (label.length > 0)
2394
+ normalized.push(label);
2395
+ continue;
2396
+ }
2397
+ if (!rawOption || typeof rawOption !== "object" || Array.isArray(rawOption)) {
2398
+ continue;
2399
+ }
2400
+ const optionRecord = rawOption;
2401
+ const label = (typeof optionRecord.label === "string" && optionRecord.label.trim()) ||
2402
+ (typeof optionRecord.title === "string" && optionRecord.title.trim()) ||
2403
+ (typeof optionRecord.name === "string" && optionRecord.name.trim()) ||
2404
+ null;
2405
+ if (!label)
2406
+ continue;
2407
+ const normalizedRecord = { label };
2408
+ const id = (typeof optionRecord.id === "string" && optionRecord.id.trim()) ||
2409
+ (typeof optionRecord.option_id === "string" && optionRecord.option_id.trim()) ||
2410
+ null;
2411
+ if (id)
2412
+ normalizedRecord.id = id;
2413
+ const description = (typeof optionRecord.description === "string" && optionRecord.description.trim()) ||
2414
+ null;
2415
+ if (description)
2416
+ normalizedRecord.description = description;
2417
+ const consequences = (typeof optionRecord.consequences === "string" && optionRecord.consequences.trim()) ||
2418
+ (typeof optionRecord.impact === "string" && optionRecord.impact.trim()) ||
2419
+ null;
2420
+ if (consequences)
2421
+ normalizedRecord.consequences = consequences;
2422
+ const impliedStatusRaw = typeof optionRecord.implied_status === "string"
2423
+ ? optionRecord.implied_status
2424
+ : typeof optionRecord.status === "string"
2425
+ ? optionRecord.status
2426
+ : null;
2427
+ if (impliedStatusRaw) {
2428
+ const implied = impliedStatusRaw.trim().toLowerCase();
2429
+ if (implied === "approved" ||
2430
+ implied === "declined" ||
2431
+ implied === "cancelled" ||
2432
+ implied === "rejected") {
2433
+ normalizedRecord.implied_status = implied;
2434
+ }
2435
+ }
2436
+ const actionType = normalizeDecisionActionType(optionRecord.action_type ?? optionRecord.type ?? optionRecord.verb ?? optionRecord.action);
2437
+ if (actionType)
2438
+ normalizedRecord.action_type = actionType;
2439
+ if (optionRecord.requires_note === true ||
2440
+ optionRecord.requiresNote === true ||
2441
+ optionRecord.note_required === true) {
2442
+ normalizedRecord.requires_note = true;
2443
+ }
2444
+ normalized.push(normalizedRecord);
2445
+ }
2446
+ return normalized.slice(0, 8);
2447
+ };
2070
2448
  const allDecisions = Array.isArray(parsed?.decisions_needed)
2071
2449
  ? (parsed?.decisions_needed ?? [])
2072
2450
  .filter((item) => Boolean(item && typeof item.question === "string" && item.question.trim()))
@@ -2210,9 +2588,7 @@ export function createAutoContinueEngine(deps) {
2210
2588
  title: normalizedQuestion,
2211
2589
  summary: decision.summary ?? parsed?.summary ?? null,
2212
2590
  urgency: decision.urgency ?? "high",
2213
- options: Array.isArray(decision.options)
2214
- ? decision.options.filter((opt) => typeof opt === "string" && opt.trim())
2215
- : [],
2591
+ options: normalizeDecisionOptions(decision.options),
2216
2592
  blocking: isBlocking,
2217
2593
  decisionType: isBlocking
2218
2594
  ? "autopilot_blocking_decision"
@@ -2606,11 +2982,7 @@ export function createAutoContinueEngine(deps) {
2606
2982
  title: fallbackDecisionTitle,
2607
2983
  summary: fallbackDecisionSummary,
2608
2984
  urgency: "high",
2609
- options: [
2610
- "Retry this workstream slice",
2611
- "Pause autopilot and investigate",
2612
- "Skip this workstream for now",
2613
- ],
2985
+ options: defaultInterventionDecisionOptions(),
2614
2986
  blocking: true,
2615
2987
  decisionType: looksLikeNoOutcome
2616
2988
  ? "autopilot_completed_without_outcome"
@@ -2692,11 +3064,7 @@ export function createAutoContinueEngine(deps) {
2692
3064
  title: attentionTitle,
2693
3065
  summary: attentionSummary,
2694
3066
  urgency: "high",
2695
- options: [
2696
- "Retry this workstream slice",
2697
- "Pause autopilot and investigate",
2698
- "Skip this workstream for now",
2699
- ],
3067
+ options: defaultInterventionDecisionOptions(),
2700
3068
  blocking: true,
2701
3069
  decisionType: completionHadNoOutcome
2702
3070
  ? "autopilot_completed_without_outcome"
@@ -3704,16 +4072,27 @@ export function createAutoContinueEngine(deps) {
3704
4072
  const logsDir = join(getOrgxPluginConfigDir(), AUTO_CONTINUE_SLICE_LOG_DIRNAME);
3705
4073
  const logPath = join(logsDir, `${sliceRunId}.log`);
3706
4074
  const outputPath = join(logsDir, `${sliceRunId}.output.json`);
3707
- const configuredWorkerCwd = (process.env.ORGX_AUTOPILOT_CWD ?? "").trim();
4075
+ const workerEnvOverrides = run.workerEnvOverrides ?? defaultWorkerEnvOverrides;
4076
+ const configuredWorkerCwd = (workerEnvOverrides?.ORGX_AUTOPILOT_CWD ??
4077
+ process.env.ORGX_AUTOPILOT_CWD ??
4078
+ "").trim();
3708
4079
  let workerCwd = configuredWorkerCwd || resolveAutopilotDefaultCwd(__filename);
3709
4080
  // LaunchAgents sometimes start with cwd="/". Fall back to plugin root (or home if unresolved).
3710
4081
  if (!workerCwd || workerCwd === "/") {
3711
4082
  workerCwd = resolveAutopilotDefaultCwd(__filename);
3712
4083
  }
3713
4084
  const sliceAgent = resolveOrgxAgentForDomain(executionPolicy.domain);
3714
- const workerKind = (process.env.ORGX_AUTOPILOT_WORKER_KIND ?? "").trim().toLowerCase();
4085
+ const workerKind = (workerEnvOverrides?.ORGX_AUTOPILOT_WORKER_KIND ??
4086
+ process.env.ORGX_AUTOPILOT_WORKER_KIND ??
4087
+ "")
4088
+ .trim()
4089
+ .toLowerCase();
3715
4090
  const inferredExecutor = workerKind === "claude-code" || workerKind === "claude_code" ? "claude-code" : "codex";
3716
- const executorRaw = (process.env.ORGX_AUTOPILOT_EXECUTOR ?? "").trim().toLowerCase() || inferredExecutor;
4091
+ const executorRaw = (workerEnvOverrides?.ORGX_AUTOPILOT_EXECUTOR ??
4092
+ process.env.ORGX_AUTOPILOT_EXECUTOR ??
4093
+ "")
4094
+ .trim()
4095
+ .toLowerCase() || inferredExecutor;
3717
4096
  const executorSourceClient = executorRaw === "claude-code" || executorRaw === "claude_code" ? "claude-code" : "codex";
3718
4097
  let runtimeHookUrl = null;
3719
4098
  let runtimeHookToken = null;
@@ -3738,6 +4117,7 @@ export function createAutoContinueEngine(deps) {
3738
4117
  outputSchemaPath: schemaPath,
3739
4118
  resumeSessionId: resumedFromSessionId,
3740
4119
  env: {
4120
+ ...(workerEnvOverrides ?? {}),
3741
4121
  ORGX_SOURCE_CLIENT: executorSourceClient,
3742
4122
  ORGX_RUN_ID: sliceRunId,
3743
4123
  ORGX_CORRELATION_ID: sliceRunId,
@@ -3915,12 +4295,6 @@ export function createAutoContinueEngine(deps) {
3915
4295
  // Clear stale errors when a new slice dispatches successfully.
3916
4296
  run.lastError = null;
3917
4297
  run.updatedAt = now;
3918
- try {
3919
- await client.updateEntity("initiative", run.initiativeId, { status: "active" });
3920
- }
3921
- catch {
3922
- // best effort
3923
- }
3924
4298
  try {
3925
4299
  await updateInitiativeAutoContinueState({
3926
4300
  initiativeId: run.initiativeId,
@@ -4013,6 +4387,7 @@ export function createAutoContinueEngine(deps) {
4013
4387
  const sourceEvent = (input.event ?? "").trim() || null;
4014
4388
  const requestedByAgentId = (input.requestedByAgentId ?? "").trim() || null;
4015
4389
  const requestedByAgentName = (input.requestedByAgentName ?? "").trim() || null;
4390
+ const autoFixWorkerEnv = captureAutopilotWorkerEnv();
4016
4391
  const providedGraceMs = typeof input.graceMs === "number" && Number.isFinite(input.graceMs)
4017
4392
  ? Math.floor(input.graceMs)
4018
4393
  : null;
@@ -4188,6 +4563,7 @@ export function createAutoContinueEngine(deps) {
4188
4563
  null;
4189
4564
  const dispatchRun = await startAutoContinueRun({
4190
4565
  initiativeId,
4566
+ workspaceId: latestRun?.workspaceId ?? null,
4191
4567
  agentId: dispatchAgentId,
4192
4568
  agentName: dispatchAgentName,
4193
4569
  // Auto-fix retries should follow current defaults unless an operator explicitly
@@ -4199,6 +4575,7 @@ export function createAutoContinueEngine(deps) {
4199
4575
  parallelMode: latestRun?.parallelMode ?? "iwmt",
4200
4576
  stopAfterSlice: true,
4201
4577
  ignoreSpawnGuardRateLimit: latestRun?.ignoreSpawnGuardRateLimit ?? false,
4578
+ workerEnvOverrides: autoFixWorkerEnv,
4202
4579
  });
4203
4580
  await tickAutoContinueRun(dispatchRun);
4204
4581
  await emitActivitySafe({
@@ -4293,11 +4670,15 @@ export function createAutoContinueEngine(deps) {
4293
4670
  }
4294
4671
  async function startAutoContinueRun(input) {
4295
4672
  const now = new Date().toISOString();
4673
+ const nextWorkerEnvOverrides = input.workerEnvOverrides && typeof input.workerEnvOverrides === "object"
4674
+ ? { ...input.workerEnvOverrides }
4675
+ : { ...defaultWorkerEnvOverrides };
4296
4676
  const existing = autoContinueRuns.get(input.initiativeId) ?? null;
4297
4677
  const existingIsLive = existing?.status === RunStatus.RUNNING || existing?.status === RunStatus.STOPPING;
4298
4678
  const run = existing ??
4299
4679
  {
4300
4680
  initiativeId: input.initiativeId,
4681
+ workspaceId: null,
4301
4682
  agentId: input.agentId,
4302
4683
  agentName: input.agentName ?? null,
4303
4684
  includeVerification: false,
@@ -4325,8 +4706,14 @@ export function createAutoContinueEngine(deps) {
4325
4706
  activeTaskId: null,
4326
4707
  activeRunId: null,
4327
4708
  activeTaskTokenEstimate: null,
4709
+ workerEnvOverrides: null,
4710
+ lastInitiativeStatus: null,
4328
4711
  };
4329
4712
  ensureRunInternals(run);
4713
+ run.workspaceId =
4714
+ typeof input.workspaceId === "string" && input.workspaceId.trim().length > 0
4715
+ ? input.workspaceId.trim()
4716
+ : run.workspaceId;
4330
4717
  run.agentId = input.agentId;
4331
4718
  run.agentName =
4332
4719
  typeof input.agentName === "string" && input.agentName.trim().length > 0
@@ -4339,6 +4726,7 @@ export function createAutoContinueEngine(deps) {
4339
4726
  run.stopAfterSlice = Boolean(input.stopAfterSlice);
4340
4727
  run.ignoreSpawnGuardRateLimit = Boolean(input.ignoreSpawnGuardRateLimit);
4341
4728
  run.scope = input.scope ?? "task";
4729
+ run.workerEnvOverrides = nextWorkerEnvOverrides;
4342
4730
  const hasExplicitTokenBudgetInput = input.tokenBudget !== null &&
4343
4731
  input.tokenBudget !== undefined &&
4344
4732
  !(typeof input.tokenBudget === "string" && input.tokenBudget.trim().length === 0);
@@ -4375,11 +4763,6 @@ export function createAutoContinueEngine(deps) {
4375
4763
  }
4376
4764
  syncLegacyRunPointers(run);
4377
4765
  autoContinueRuns.set(input.initiativeId, run);
4378
- void client
4379
- .updateEntity("initiative", input.initiativeId, { status: "active" })
4380
- .catch(() => {
4381
- // best effort
4382
- });
4383
4766
  void updateInitiativeAutoContinueState({
4384
4767
  initiativeId: input.initiativeId,
4385
4768
  run,
@@ -4438,7 +4821,7 @@ export function createAutoContinueEngine(deps) {
4438
4821
  old_state: LaneState.IDLE,
4439
4822
  new_state: LaneState.RUNNING,
4440
4823
  reason: "started",
4441
- workspace_id: run.allowedWorkstreamIds?.[0] ?? null,
4824
+ workspace_id: run.workspaceId ?? null,
4442
4825
  },
4443
4826
  });
4444
4827
  }