oh-my-codex 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +8 -1
- package/crates/omx-api/src/lib.rs +3 -3
- package/crates/omx-api/tests/cli.rs +4 -4
- package/crates/omx-explore/src/main.rs +4 -4
- package/crates/omx-sparkshell/src/codex_bridge.rs +2 -2
- package/dist/agents/__tests__/definitions.test.js +3 -3
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +71 -42
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +3 -3
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -2
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +7 -5
- package/dist/agents/native-config.js.map +1 -1
- package/dist/autopilot/__tests__/planner-routing.test.js +19 -12
- package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +151 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/planner-routing.d.ts.map +1 -1
- package/dist/autopilot/planner-routing.js +4 -2
- package/dist/autopilot/planner-routing.js.map +1 -1
- package/dist/autopilot/ralplan-gate.d.ts +1 -0
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +38 -2
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/autoresearch/runtime.d.ts +2 -0
- package/dist/autoresearch/runtime.d.ts.map +1 -1
- package/dist/autoresearch/runtime.js +8 -0
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/__tests__/lockfile.test.d.ts +2 -0
- package/dist/capabilities/__tests__/lockfile.test.d.ts.map +1 -0
- package/dist/capabilities/__tests__/lockfile.test.js +115 -0
- package/dist/capabilities/__tests__/lockfile.test.js.map +1 -0
- package/dist/capabilities/lockfile.d.ts +102 -0
- package/dist/capabilities/lockfile.d.ts.map +1 -0
- package/dist/capabilities/lockfile.js +334 -0
- package/dist/capabilities/lockfile.js.map +1 -0
- package/dist/cli/__tests__/agents.test.js +5 -5
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.d.ts +2 -0
- package/dist/cli/__tests__/capabilities.test.d.ts.map +1 -0
- package/dist/cli/__tests__/capabilities.test.js +135 -0
- package/dist/cli/__tests__/capabilities.test.js.map +1 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js +237 -6
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js +9 -9
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +1 -1
- package/dist/cli/__tests__/doctor-spark-routing.test.js +22 -6
- package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +53 -18
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/mission.test.d.ts +2 -0
- package/dist/cli/__tests__/mission.test.d.ts.map +1 -0
- package/dist/cli/__tests__/mission.test.js +239 -0
- package/dist/cli/__tests__/mission.test.js.map +1 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +3 -3
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +95 -6
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +67 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +46 -18
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +3 -3
- package/dist/cli/__tests__/setup-refresh.test.js +29 -7
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +1 -1
- package/dist/cli/__tests__/uninstall.test.js +4 -4
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/agents.js +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/capabilities.d.ts +3 -0
- package/dist/cli/capabilities.d.ts.map +1 -0
- package/dist/cli/capabilities.js +118 -0
- package/dist/cli/capabilities.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +9 -4
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +7 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +107 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mission.d.ts +36 -0
- package/dist/cli/mission.d.ts.map +1 -0
- package/dist/cli/mission.js +443 -0
- package/dist/cli/mission.js.map +1 -0
- package/dist/cli/plugin-marketplace.d.ts +1 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +31 -0
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +7 -4
- package/dist/cli/setup.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +23 -23
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +9 -9
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +51 -26
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +1 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/models.d.ts +16 -6
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +19 -8
- package/dist/config/models.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +12 -4
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +2 -2
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/tmux-hook-engine.test.js +2 -2
- package/dist/hud/__tests__/state.test.js +31 -6
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +7 -3
- package/dist/hud/state.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +108 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +26 -0
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +170 -0
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +32 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +4 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +6 -15
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/base.d.ts +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +27 -1
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts +2 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +1 -0
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.d.ts +5 -1
- package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
- package/dist/pipeline/stages/ultragoal.js +14 -4
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +193 -0
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +132 -0
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.js +24 -3
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +17 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +97 -1
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +762 -20
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +306 -22
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-catalog-docs.js +1 -0
- package/dist/scripts/generate-catalog-docs.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +737 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +59 -0
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +14 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +80 -17
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.js +3 -3
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.d.ts +8 -0
- package/dist/state/terminal-normalization.d.ts.map +1 -0
- package/dist/state/terminal-normalization.js +127 -0
- package/dist/state/terminal-normalization.js.map +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +3 -1
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/team/__tests__/delegation-policy.test.js +2 -2
- package/dist/team/__tests__/delegation-policy.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +25 -25
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +28 -28
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +7 -7
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js +5 -5
- package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +12 -12
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +57 -9
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +3 -3
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/model-contract.d.ts +1 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +11 -0
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +2 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +6 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +82 -5
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +5 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +111 -14
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/agents-model-table.test.js +7 -7
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/dist/utils/__tests__/worktree-tool-context.test.d.ts +2 -0
- package/dist/utils/__tests__/worktree-tool-context.test.d.ts.map +1 -0
- package/dist/utils/__tests__/worktree-tool-context.test.js +118 -0
- package/dist/utils/__tests__/worktree-tool-context.test.js.map +1 -0
- package/dist/utils/worktree-tool-context.d.ts +25 -0
- package/dist/utils/worktree-tool-context.d.ts.map +1 -0
- package/dist/utils/worktree-tool-context.js +116 -0
- package/dist/utils/worktree-tool-context.js.map +1 -0
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +96 -10
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +5 -5
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +2 -2
- package/prompts/prometheus-strict-metis.md +1 -1
- package/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/skills/code-review/SKILL.md +1 -1
- package/skills/ecomode/references/agent-tiers.md +1 -1
- package/skills/omx-setup/SKILL.md +5 -5
- package/skills/prometheus-strict/SKILL.md +3 -3
- package/skills/ralplan/SKILL.md +1 -1
- package/skills/team/SKILL.md +1 -1
- package/skills/ultrawork/references/agent-tiers.md +2 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +824 -7
- package/src/scripts/codex-native-hook.ts +347 -20
- package/src/scripts/generate-catalog-docs.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA+CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiCtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAyDlE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAmfD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAsxBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AA4tCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AA0uKD,wBAAsB,wCAAwC,CAC5D,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAqDzC;AA83CD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CA6VnC;AA6BD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AAyOD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyC3D"}
|
|
@@ -6,7 +6,7 @@ import { pathToFileURL } from "url";
|
|
|
6
6
|
import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
7
|
import { redactAuthSecrets } from "../auth/redact.js";
|
|
8
8
|
import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
9
|
-
import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
9
|
+
import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentSessionLedger, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
10
10
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
11
11
|
import { inferTerminalLifecycleOutcome } from "../runtime/run-outcome.js";
|
|
12
12
|
import { appendToLog, isSessionStale, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
@@ -31,7 +31,7 @@ import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWiki
|
|
|
31
31
|
import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
|
|
32
32
|
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
33
33
|
import { deriveAutopilotChildPhase, normalizeAutopilotPhase } from "../autopilot/fsm.js";
|
|
34
|
-
import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, actionKindForConductorArtifact, authorizeConductorAction, classifyConductorArtifactKind, } from "../leader/contract.js";
|
|
34
|
+
import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE, actionKindForConductorArtifact, authorizeConductorAction, buildUnsupportedNativeSubagentGuidance, classifyConductorArtifactKind, isUnsupportedNativeSubagentEvidence, resolveNativeSubagentSupportStatus, } from "../leader/contract.js";
|
|
35
35
|
import { readRunState } from "../runtime/run-state.js";
|
|
36
36
|
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
37
37
|
import { buildCodexGoalTerminalCleanupNotice, } from "../goal-workflows/codex-goal-snapshot.js";
|
|
@@ -1463,6 +1463,76 @@ async function ensureOmxLocalIgnoreEntry(cwd) {
|
|
|
1463
1463
|
await writeFile(excludePath, next);
|
|
1464
1464
|
return { changed: true, excludePath };
|
|
1465
1465
|
}
|
|
1466
|
+
function readSessionStartSource(payload) {
|
|
1467
|
+
return safeString(payload?.source ?? payload?.session_start_source ?? payload?.sessionStartSource).trim().toLowerCase();
|
|
1468
|
+
}
|
|
1469
|
+
function shouldBuildSubagentReopenContext(options) {
|
|
1470
|
+
if (options.hookEventName !== "SessionStart")
|
|
1471
|
+
return false;
|
|
1472
|
+
const source = readSessionStartSource(options.payload);
|
|
1473
|
+
return source === "startup" || source === "resume";
|
|
1474
|
+
}
|
|
1475
|
+
function formatSubagentLedgerMetadata(entry) {
|
|
1476
|
+
const metadata = [
|
|
1477
|
+
entry.role ? `role: ${entry.role}` : null,
|
|
1478
|
+
entry.laneId ? `lane: ${entry.laneId}` : null,
|
|
1479
|
+
entry.scope ? `scope: ${entry.scope}` : null,
|
|
1480
|
+
entry.status ? `status: ${entry.status}` : null,
|
|
1481
|
+
entry.lastHandoffSummary ? `handoff: ${entry.lastHandoffSummary.slice(0, 120)}` : null,
|
|
1482
|
+
entry.resumeFailureReason ? `last failure: ${entry.resumeFailureReason.slice(0, 120)}` : null,
|
|
1483
|
+
].filter((item) => Boolean(item));
|
|
1484
|
+
return metadata.length > 0 ? ` (${metadata.join("; ")})` : "";
|
|
1485
|
+
}
|
|
1486
|
+
async function buildPersistedSubagentReopenContext(cwd, sessionId, options) {
|
|
1487
|
+
if (!shouldBuildSubagentReopenContext(options))
|
|
1488
|
+
return null;
|
|
1489
|
+
const ledger = await readSubagentSessionLedger(cwd, sessionId).catch(() => null);
|
|
1490
|
+
if (!ledger || ledger.savedSubagents.length === 0)
|
|
1491
|
+
return null;
|
|
1492
|
+
const source = readSessionStartSource(options.payload);
|
|
1493
|
+
const reopenTargets = ledger.resumeTargets.filter((entry) => entry.status !== "unavailable");
|
|
1494
|
+
const unavailableTargets = ledger.unavailableSubagents;
|
|
1495
|
+
const failedTargets = ledger.savedSubagents.filter((entry) => entry.resumeFailedAt || entry.resumeFailureReason);
|
|
1496
|
+
const nowIso = new Date().toISOString();
|
|
1497
|
+
await Promise.all(reopenTargets.map((entry) => recordSubagentTurnForSession(cwd, {
|
|
1498
|
+
sessionId,
|
|
1499
|
+
threadId: entry.threadId,
|
|
1500
|
+
kind: "subagent",
|
|
1501
|
+
role: entry.role,
|
|
1502
|
+
laneId: entry.laneId,
|
|
1503
|
+
scope: entry.scope,
|
|
1504
|
+
agentNickname: entry.agentNickname,
|
|
1505
|
+
status: entry.status,
|
|
1506
|
+
resumeRequestedAt: nowIso,
|
|
1507
|
+
preserveCompletionEvidence: true,
|
|
1508
|
+
}).catch(() => null)));
|
|
1509
|
+
const lines = [
|
|
1510
|
+
"[Persisted subagent reopen]",
|
|
1511
|
+
`- SessionStart source: ${source}; saved subagent ids found: ${ledger.savedSubagents.length}.`,
|
|
1512
|
+
];
|
|
1513
|
+
if (reopenTargets.length > 0) {
|
|
1514
|
+
lines.push("- Reopen these persisted subagents by id before continuing work or spawning any same-role/same-lane replacement:");
|
|
1515
|
+
for (const entry of reopenTargets.slice(0, 12)) {
|
|
1516
|
+
lines.push(` - resume_agent(${JSON.stringify(entry.agentId)})${formatSubagentLedgerMetadata(entry)}`);
|
|
1517
|
+
}
|
|
1518
|
+
if (reopenTargets.length > 12) {
|
|
1519
|
+
lines.push(` - ... ${reopenTargets.length - 12} more saved subagent id(s) omitted from this compact SessionStart context; consult .omx/state/subagent-tracking.json before spawning replacements.`);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
else {
|
|
1523
|
+
lines.push("- No compatible saved subagent id is currently marked reopenable; do not spawn a replacement merely because reopen was unavailable.");
|
|
1524
|
+
}
|
|
1525
|
+
lines.push("- Silver rule: when follow-up work targets an existing role/lane, reuse the matching reopened id; avoid duplicate same-type subagent spawns.");
|
|
1526
|
+
lines.push("- If resume_agent fails, surface a clear warning with the id and reason, then continue in the root or another compatible existing lane; do not spawn a new agent solely because reopen failed.");
|
|
1527
|
+
const warningEntries = [...new Map([...unavailableTargets, ...failedTargets].map((entry) => [entry.agentId, entry])).values()];
|
|
1528
|
+
if (warningEntries.length > 0) {
|
|
1529
|
+
lines.push("- Reopen warnings:");
|
|
1530
|
+
for (const entry of warningEntries.slice(0, 8)) {
|
|
1531
|
+
lines.push(` - ${entry.agentId}${formatSubagentLedgerMetadata(entry)}`);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return lines.join("\n");
|
|
1535
|
+
}
|
|
1466
1536
|
async function buildSessionStartContext(cwd, sessionId, options = {}) {
|
|
1467
1537
|
const sections = [];
|
|
1468
1538
|
sections.push(buildExecutionEnvironmentSection(cwd, {
|
|
@@ -1560,6 +1630,13 @@ async function buildSessionStartContext(cwd, sessionId, options = {}) {
|
|
|
1560
1630
|
if (subagentSummary && subagentSummary.activeSubagentThreadIds.length > 0) {
|
|
1561
1631
|
sections.push(`[Subagents]\n- active subagent threads: ${subagentSummary.activeSubagentThreadIds.length}`);
|
|
1562
1632
|
}
|
|
1633
|
+
const persistedSubagentReopenContext = await buildPersistedSubagentReopenContext(cwd, sessionId, {
|
|
1634
|
+
hookEventName: options.hookEventName,
|
|
1635
|
+
payload: options.payload,
|
|
1636
|
+
});
|
|
1637
|
+
if (persistedSubagentReopenContext) {
|
|
1638
|
+
sections.push(persistedSubagentReopenContext);
|
|
1639
|
+
}
|
|
1563
1640
|
return sections.length > 0 ? sections.join("\n\n") : null;
|
|
1564
1641
|
}
|
|
1565
1642
|
function resolveExecutionEnvironment(cwd, options = {}) {
|
|
@@ -1722,6 +1799,17 @@ function buildAutopilotPromptActivationNote(skillState, options = {}) {
|
|
|
1722
1799
|
const teamHandoff = readTeamModeConfig(options.cwd).enabled
|
|
1723
1800
|
? " (+ $team if needed)"
|
|
1724
1801
|
: "";
|
|
1802
|
+
const stateDir = getBaseStateDir(options.cwd);
|
|
1803
|
+
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
1804
|
+
payload: options.payload,
|
|
1805
|
+
persistedSupportBlocker: readJsonSyncIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
1806
|
+
persistedCapacityBlocker: readJsonSyncIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
1807
|
+
cwd: options.cwd,
|
|
1808
|
+
sessionId: options.sessionId,
|
|
1809
|
+
});
|
|
1810
|
+
const conductorGuidance = nativeSubagentSupport.status === "unsupported"
|
|
1811
|
+
? buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)
|
|
1812
|
+
: `${LEADER_CONDUCTOR_BLOCK} ${LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE}`;
|
|
1725
1813
|
return [
|
|
1726
1814
|
`Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal${teamHandoff} -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).`,
|
|
1727
1815
|
"Start/resume at current_phase=deep-interview unless the task is clear and bounded; if deep-interview is intentionally skipped, persist and state an explicit deep_interview_gate.skip_reason before moving to ralplan.",
|
|
@@ -1733,8 +1821,7 @@ function buildAutopilotPromptActivationNote(skillState, options = {}) {
|
|
|
1733
1821
|
"The ralplan phase is not complete until Planner output has been reviewed sequentially by Architect and then Critic; do not hand off to Ultragoal or implementation until the ralplan state/artifact records both ralplan_architect_review and ralplan_critic_review with approval or an explicit blocker.",
|
|
1734
1822
|
"Do not silently fall back to ordinary $plan/ralplan-only handling; keep autopilot-state.json, skill-active-state.json, HUD/statusline, and Codex goal-mode handoff guidance visible while the workflow is active.",
|
|
1735
1823
|
"When Codex goal tools are available, call get_goal/create_goal only from the active thread handoff and treat the active goal as the completion contract until code-review and ultraqa are clean.",
|
|
1736
|
-
|
|
1737
|
-
LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE,
|
|
1824
|
+
conductorGuidance,
|
|
1738
1825
|
].filter(Boolean).join(" ");
|
|
1739
1826
|
}
|
|
1740
1827
|
function formatExecutionHandoffList(cwd) {
|
|
@@ -1761,7 +1848,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1761
1848
|
: null;
|
|
1762
1849
|
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1763
1850
|
const markedQuestionAnswer = /^\s*\[omx question answered\]/i.test(prompt);
|
|
1764
|
-
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd });
|
|
1851
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
1765
1852
|
return [
|
|
1766
1853
|
`OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
|
|
1767
1854
|
promptPriorityMessage,
|
|
@@ -1785,7 +1872,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1785
1872
|
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
1786
1873
|
: null;
|
|
1787
1874
|
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1788
|
-
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd });
|
|
1875
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
1789
1876
|
return [
|
|
1790
1877
|
`OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}"; workflow-like tokens inside the marked omx question answer are treated as answer text, not a new workflow activation.`,
|
|
1791
1878
|
promptPriorityMessage,
|
|
@@ -1818,7 +1905,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1818
1905
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1819
1906
|
? "Ultragoal protocol: use `omx ultragoal create-goals` / `complete-goals` / `checkpoint` for `.omx/ultragoal` artifacts, then use Codex goal model tools only from the active agent handoff (`get_goal`, `create_goal`, `update_goal`) and never overwrite a different active Codex goal. Ultragoal does not call `/goal clear`; for multiple sequential ultragoal runs in one Codex session/thread, manually clear the completed Codex goal in the UI before creating the next aggregate goal."
|
|
1820
1907
|
: null;
|
|
1821
|
-
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { cwd });
|
|
1908
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
|
|
1822
1909
|
const combinedTransitionMessage = (() => {
|
|
1823
1910
|
if (!skillState?.transition_message)
|
|
1824
1911
|
return null;
|
|
@@ -2574,6 +2661,17 @@ function readPayloadTurnId(payload) {
|
|
|
2574
2661
|
function nativeSubagentCapacityBlockerPath(stateDir) {
|
|
2575
2662
|
return join(stateDir, NATIVE_SUBAGENT_CAPACITY_BLOCKER_FILE);
|
|
2576
2663
|
}
|
|
2664
|
+
function nativeSubagentSupportBlockerPath(stateDir) {
|
|
2665
|
+
return join(stateDir, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE);
|
|
2666
|
+
}
|
|
2667
|
+
function readJsonSyncIfExists(path) {
|
|
2668
|
+
try {
|
|
2669
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
2670
|
+
}
|
|
2671
|
+
catch {
|
|
2672
|
+
return null;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2577
2675
|
function stringifyUnknown(value) {
|
|
2578
2676
|
if (typeof value === "string")
|
|
2579
2677
|
return value;
|
|
@@ -2602,6 +2700,44 @@ function isNativeSubagentCapacityFailure(payload) {
|
|
|
2602
2700
|
const toolName = safeString(payload.tool_name).trim();
|
|
2603
2701
|
return !toolName || /(?:spawn_agent|multi_agent|subagent|collab|agent)/i.test(toolName);
|
|
2604
2702
|
}
|
|
2703
|
+
function nativeSubagentFailureReason(payload) {
|
|
2704
|
+
const evidence = payloadEvidenceText(payload);
|
|
2705
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
2706
|
+
if (toolName && !/(?:spawn_agent|multi_agent|subagent|collab|agent)/i.test(toolName))
|
|
2707
|
+
return null;
|
|
2708
|
+
if (/\bagent thread limit reached\b/i.test(evidence))
|
|
2709
|
+
return null;
|
|
2710
|
+
if (/\bnative subagents? (?:unsupported|disabled|not enabled|unavailable|not found)\b/i.test(evidence))
|
|
2711
|
+
return "native_subagents_unsupported";
|
|
2712
|
+
if (/\bmulti_agent_v1\b/i.test(evidence) && /\b(?:unavailable|unknown tool|disabled|not enabled|not found|unsupported)\b/i.test(evidence))
|
|
2713
|
+
return "multi_agent_v1_unavailable";
|
|
2714
|
+
if (/\b(?:unknown tool|tool not found|not enabled|disabled|unavailable|unsupported)\b/i.test(evidence))
|
|
2715
|
+
return "multi_agent_v1_unavailable";
|
|
2716
|
+
return null;
|
|
2717
|
+
}
|
|
2718
|
+
function summarizeNativeSubagentSupportFailure(text) {
|
|
2719
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
2720
|
+
return (normalized || "native subagent support unavailable").slice(0, 500);
|
|
2721
|
+
}
|
|
2722
|
+
async function recordNativeSubagentSupportBlocker(cwd, stateDir, payload) {
|
|
2723
|
+
const reason = nativeSubagentFailureReason(payload);
|
|
2724
|
+
if (!reason)
|
|
2725
|
+
return;
|
|
2726
|
+
const nowIso = new Date().toISOString();
|
|
2727
|
+
await mkdir(stateDir, { recursive: true });
|
|
2728
|
+
await writeFile(nativeSubagentSupportBlockerPath(stateDir), JSON.stringify({
|
|
2729
|
+
schema_version: 1,
|
|
2730
|
+
status: "unsupported",
|
|
2731
|
+
reason,
|
|
2732
|
+
...(readPayloadSessionId(payload) ? { session_id: readPayloadSessionId(payload) } : {}),
|
|
2733
|
+
...(readPayloadThreadId(payload) ? { thread_id: readPayloadThreadId(payload) } : {}),
|
|
2734
|
+
...(readPayloadTurnId(payload) ? { turn_id: readPayloadTurnId(payload) } : {}),
|
|
2735
|
+
...(safeString(payload.tool_name).trim() ? { tool_name: safeString(payload.tool_name).trim() } : {}),
|
|
2736
|
+
evidence: summarizeNativeSubagentSupportFailure(payloadEvidenceText(payload)),
|
|
2737
|
+
observed_at: nowIso,
|
|
2738
|
+
cwd,
|
|
2739
|
+
}, null, 2));
|
|
2740
|
+
}
|
|
2605
2741
|
function summarizeCapacityFailure(text) {
|
|
2606
2742
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
2607
2743
|
if (!normalized)
|
|
@@ -2791,6 +2927,7 @@ const PROTECTED_PLANNING_STATE_FILE_NAMES = new Set([
|
|
|
2791
2927
|
"ralplan-state.json",
|
|
2792
2928
|
"skill-active-state.json",
|
|
2793
2929
|
]);
|
|
2930
|
+
const RUNTIME_SESSION_ID_SEGMENT_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
2794
2931
|
const PLANNING_MODE_IMPLEMENTATION_TOOL_NAMES = new Set([
|
|
2795
2932
|
"Write",
|
|
2796
2933
|
"Edit",
|
|
@@ -2821,6 +2958,15 @@ function isActiveDeepInterviewPhase(state) {
|
|
|
2821
2958
|
return false;
|
|
2822
2959
|
return true;
|
|
2823
2960
|
}
|
|
2961
|
+
function isInactiveCompletedDeepInterviewPhase(state) {
|
|
2962
|
+
if (!state || state.active !== false)
|
|
2963
|
+
return false;
|
|
2964
|
+
const mode = safeString(state.mode).trim();
|
|
2965
|
+
if (mode && mode !== "deep-interview")
|
|
2966
|
+
return false;
|
|
2967
|
+
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
2968
|
+
return phase === "complete" || phase === "completed";
|
|
2969
|
+
}
|
|
2824
2970
|
function isActiveRalplanPhase(state) {
|
|
2825
2971
|
if (!state || state.active !== true)
|
|
2826
2972
|
return false;
|
|
@@ -2866,6 +3012,33 @@ function isProtectedPlanningStatePath(relativePath) {
|
|
|
2866
3012
|
const fileName = relativePath.split("/").pop() ?? "";
|
|
2867
3013
|
return PROTECTED_PLANNING_STATE_FILE_NAMES.has(fileName);
|
|
2868
3014
|
}
|
|
3015
|
+
function isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath) {
|
|
3016
|
+
const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
|
|
3017
|
+
if (!trimmed || trimmed.includes("\0"))
|
|
3018
|
+
return false;
|
|
3019
|
+
let targetPath;
|
|
3020
|
+
let baseStateDir;
|
|
3021
|
+
try {
|
|
3022
|
+
targetPath = resolve(cwd, trimmed);
|
|
3023
|
+
baseStateDir = resolve(getBaseStateDir(cwd));
|
|
3024
|
+
}
|
|
3025
|
+
catch {
|
|
3026
|
+
return false;
|
|
3027
|
+
}
|
|
3028
|
+
const localStateDir = resolve(cwd, ".omx", "state");
|
|
3029
|
+
if (baseStateDir === localStateDir)
|
|
3030
|
+
return false;
|
|
3031
|
+
const relativeToBase = relative(baseStateDir, targetPath).replace(/\\/g, "/");
|
|
3032
|
+
if (!relativeToBase || relativeToBase.startsWith("..") || relativeToBase.startsWith("/"))
|
|
3033
|
+
return false;
|
|
3034
|
+
const segments = relativeToBase.split("/");
|
|
3035
|
+
if (segments.length !== 3 || segments[0] !== "sessions")
|
|
3036
|
+
return false;
|
|
3037
|
+
const sessionId = segments[1] ?? "";
|
|
3038
|
+
const fileName = segments[2] ?? "";
|
|
3039
|
+
return RUNTIME_SESSION_ID_SEGMENT_PATTERN.test(sessionId)
|
|
3040
|
+
&& PROTECTED_PLANNING_STATE_FILE_NAMES.has(fileName);
|
|
3041
|
+
}
|
|
2869
3042
|
function isPlanningTmpRelativePath(relativePath) {
|
|
2870
3043
|
return relativePath === ".omx/tmp" || relativePath.startsWith(".omx/tmp/");
|
|
2871
3044
|
}
|
|
@@ -2881,9 +3054,9 @@ function isAllowedPlanningTmpScratchPath(relativePath) {
|
|
|
2881
3054
|
function isAllowedPlanningArtifactPath(cwd, rawPath, allowedPrefixes) {
|
|
2882
3055
|
const relativePath = normalizePlanningArtifactRelativePath(cwd, rawPath);
|
|
2883
3056
|
if (!relativePath)
|
|
2884
|
-
return
|
|
3057
|
+
return isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath);
|
|
2885
3058
|
if (isProtectedPlanningStatePath(relativePath))
|
|
2886
|
-
return
|
|
3059
|
+
return isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath);
|
|
2887
3060
|
if (isPlanningTmpRelativePath(relativePath)) {
|
|
2888
3061
|
return allowedPrefixes.includes(".omx/tmp") && isAllowedPlanningTmpScratchPath(relativePath);
|
|
2889
3062
|
}
|
|
@@ -5262,6 +5435,56 @@ function isPackageManagerCommandWord(word) {
|
|
|
5262
5435
|
const base = shellWordBaseName(word);
|
|
5263
5436
|
return base === "npm" || base === "pnpm" || base === "yarn" || base === "npx" || base === "pnpx";
|
|
5264
5437
|
}
|
|
5438
|
+
function isStructuredUltragoalSteeringShellCommand(command) {
|
|
5439
|
+
const segments = splitShellCommandSegments(stripHeredocBodiesForCommandScan(command));
|
|
5440
|
+
let sawStructuredSteer = false;
|
|
5441
|
+
for (const segment of segments) {
|
|
5442
|
+
const words = tokenizeShellWords(segment);
|
|
5443
|
+
let commandStart = true;
|
|
5444
|
+
let inForHeader = false;
|
|
5445
|
+
for (let index = 0; index < words.length; index += 1) {
|
|
5446
|
+
const word = words[index] ?? "";
|
|
5447
|
+
if (!word)
|
|
5448
|
+
continue;
|
|
5449
|
+
if (isShellCommandSeparator(word)) {
|
|
5450
|
+
commandStart = true;
|
|
5451
|
+
continue;
|
|
5452
|
+
}
|
|
5453
|
+
if (inForHeader) {
|
|
5454
|
+
if (word === "do") {
|
|
5455
|
+
inForHeader = false;
|
|
5456
|
+
commandStart = true;
|
|
5457
|
+
}
|
|
5458
|
+
continue;
|
|
5459
|
+
}
|
|
5460
|
+
if (isShellGroupingSyntaxWord(word))
|
|
5461
|
+
continue;
|
|
5462
|
+
if (commandStart && isEnvironmentAssignmentWord(word))
|
|
5463
|
+
continue;
|
|
5464
|
+
if (commandStart && CONDUCTOR_BASH_COMPOUND_SYNTAX_WORDS.has(word)) {
|
|
5465
|
+
if (word === "for")
|
|
5466
|
+
inForHeader = true;
|
|
5467
|
+
continue;
|
|
5468
|
+
}
|
|
5469
|
+
if (commandStart && word.startsWith("-"))
|
|
5470
|
+
continue;
|
|
5471
|
+
if (!commandStart)
|
|
5472
|
+
continue;
|
|
5473
|
+
const commandName = commandNameFromShellWord(word);
|
|
5474
|
+
if (commandName === "read" || commandName === "true" || commandName === ":") {
|
|
5475
|
+
commandStart = false;
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
if (commandName === "omx" && words[index + 1] === "ultragoal" && words[index + 2] === "steer") {
|
|
5479
|
+
sawStructuredSteer = true;
|
|
5480
|
+
commandStart = false;
|
|
5481
|
+
continue;
|
|
5482
|
+
}
|
|
5483
|
+
return false;
|
|
5484
|
+
}
|
|
5485
|
+
}
|
|
5486
|
+
return sawStructuredSteer;
|
|
5487
|
+
}
|
|
5265
5488
|
function hasDynamicNestedShellExecution(command) {
|
|
5266
5489
|
const commands = splitShellCommandSegments(stripHeredocBodiesForCommandScan(command));
|
|
5267
5490
|
for (const segment of commands) {
|
|
@@ -5289,13 +5512,13 @@ function hasDynamicNestedShellExecution(command) {
|
|
|
5289
5512
|
return true;
|
|
5290
5513
|
if (commandStringIndex !== null) {
|
|
5291
5514
|
const nestedCommand = words[commandStringIndex] ?? "";
|
|
5292
|
-
if (isDynamicNestedCommandString(nestedCommand))
|
|
5515
|
+
if (isDynamicNestedCommandString(nestedCommand) && !isStructuredUltragoalSteeringShellCommand(nestedCommand))
|
|
5293
5516
|
return true;
|
|
5294
5517
|
}
|
|
5295
5518
|
}
|
|
5296
5519
|
if (word === "eval") {
|
|
5297
5520
|
const nestedCommand = words.slice(index + 1).join(" ");
|
|
5298
|
-
if (isDynamicNestedCommandString(nestedCommand))
|
|
5521
|
+
if (isDynamicNestedCommandString(nestedCommand) && !isStructuredUltragoalSteeringShellCommand(nestedCommand))
|
|
5299
5522
|
return true;
|
|
5300
5523
|
}
|
|
5301
5524
|
}
|
|
@@ -6030,6 +6253,8 @@ async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionI
|
|
|
6030
6253
|
if (hasActiveDeepInterviewSkill)
|
|
6031
6254
|
return modeState;
|
|
6032
6255
|
}
|
|
6256
|
+
if (isInactiveCompletedDeepInterviewPhase(modeState))
|
|
6257
|
+
return null;
|
|
6033
6258
|
const autopilotState = sessionId
|
|
6034
6259
|
? await readStopSessionPinnedState("autopilot-state.json", cwd, sessionId, stateDir)
|
|
6035
6260
|
: await readJsonIfExists(join(stateDir, "autopilot-state.json"));
|
|
@@ -6174,7 +6399,7 @@ function buildDeepInterviewBashBlockedDetail(cwd, command) {
|
|
|
6174
6399
|
}
|
|
6175
6400
|
async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
|
|
6176
6401
|
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
|
|
6177
|
-
if (await
|
|
6402
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
6178
6403
|
return null;
|
|
6179
6404
|
const threadId = readPayloadThreadId(payload);
|
|
6180
6405
|
const activeState = await readActiveRalplanStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
@@ -6233,7 +6458,7 @@ async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, reso
|
|
|
6233
6458
|
}
|
|
6234
6459
|
async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
|
|
6235
6460
|
const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
|
|
6236
|
-
if (await
|
|
6461
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
6237
6462
|
return null;
|
|
6238
6463
|
const threadId = readPayloadThreadId(payload);
|
|
6239
6464
|
const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
@@ -6351,9 +6576,18 @@ async function buildPlanningRootPointerConflictPreToolUseOutput(payload, cwd, st
|
|
|
6351
6576
|
}
|
|
6352
6577
|
return blocked ? buildRalplanRootPointerConflictBlock(ralplanState) : null;
|
|
6353
6578
|
}
|
|
6354
|
-
async function
|
|
6579
|
+
async function hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId) {
|
|
6355
6580
|
if (hasTeamWorkerEnvironment())
|
|
6356
6581
|
return true;
|
|
6582
|
+
if (!isTypedAgentRolePayload(payload))
|
|
6583
|
+
return false;
|
|
6584
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
6585
|
+
const session = trackingState?.sessions?.[sessionId];
|
|
6586
|
+
if (!session)
|
|
6587
|
+
return false;
|
|
6588
|
+
const payloadThreadId = readPayloadThreadId(payload);
|
|
6589
|
+
if (payloadThreadId && isTrustedSubagentThread(session, payloadThreadId))
|
|
6590
|
+
return true;
|
|
6357
6591
|
const source = safeObject(payload.source);
|
|
6358
6592
|
const subagent = safeObject(source.subagent);
|
|
6359
6593
|
const threadSpawn = safeObject(subagent.thread_spawn);
|
|
@@ -6363,13 +6597,10 @@ async function hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload
|
|
|
6363
6597
|
?? threadSpawn.leaderThreadId).trim();
|
|
6364
6598
|
if (!parentThreadId)
|
|
6365
6599
|
return false;
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
6369
|
-
const session = trackingState?.sessions?.[sessionId];
|
|
6370
|
-
if (!session)
|
|
6600
|
+
const leaderThreadId = safeString(session.leader_thread_id).trim();
|
|
6601
|
+
if (payloadThreadId && leaderThreadId && payloadThreadId === leaderThreadId)
|
|
6371
6602
|
return false;
|
|
6372
|
-
return
|
|
6603
|
+
return leaderThreadId === parentThreadId || parentThreadId in session.threads;
|
|
6373
6604
|
}
|
|
6374
6605
|
function isActiveConductorModeState(state, mode, sessionId) {
|
|
6375
6606
|
if (!state || state.active !== true)
|
|
@@ -6396,7 +6627,7 @@ async function readActiveMainRootConductorStateForPreToolUse(payload, cwd, state
|
|
|
6396
6627
|
const threadId = readPayloadThreadId(payload);
|
|
6397
6628
|
if (!sessionId)
|
|
6398
6629
|
return null;
|
|
6399
|
-
if (await
|
|
6630
|
+
if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
|
|
6400
6631
|
return null;
|
|
6401
6632
|
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
6402
6633
|
if (!canonicalState)
|
|
@@ -7211,6 +7442,13 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7211
7442
|
const activeState = await readActiveMainRootConductorStateForPreToolUse(payload, cwd, stateDir, resolvedSessionId);
|
|
7212
7443
|
if (!activeState)
|
|
7213
7444
|
return null;
|
|
7445
|
+
const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
|
|
7446
|
+
payload,
|
|
7447
|
+
persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
|
|
7448
|
+
persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
|
|
7449
|
+
cwd,
|
|
7450
|
+
sessionId: resolvedSessionId || readPayloadSessionId(payload),
|
|
7451
|
+
});
|
|
7214
7452
|
const toolName = safeString(payload.tool_name).trim();
|
|
7215
7453
|
const command = readPreToolUseCommand(payload);
|
|
7216
7454
|
const pathCandidates = readPreToolUsePathCandidates(payload);
|
|
@@ -7237,6 +7475,9 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7237
7475
|
}
|
|
7238
7476
|
if (!blocked)
|
|
7239
7477
|
return null;
|
|
7478
|
+
const unsupportedNativeGuidance = isUnsupportedNativeSubagentEvidence(nativeSubagentSupport)
|
|
7479
|
+
? ` ${buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)} Treat the active conductor workflow as blocked/cancelled for native delegation recovery; do not call multi_agent_v1.close_agent.`
|
|
7480
|
+
: "";
|
|
7240
7481
|
return {
|
|
7241
7482
|
decision: "block",
|
|
7242
7483
|
reason: `Main-root Conductor mode is active (${activeState.mode} phase: ${formatPhase(activeState.phase, "active")}); direct plan/code writes are blocked and must be delegated; ${blockedDetail}.`,
|
|
@@ -7245,7 +7486,8 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
|
|
|
7245
7486
|
additionalContext: `${LEADER_CONDUCTOR_GOLDEN_RULE} `
|
|
7246
7487
|
+ "Use specialized agents for source edits and plan/spec authorship. "
|
|
7247
7488
|
+ `Main-root Conductor may write only orchestration metadata/transport/ledger artifacts under ${CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES.join(", ")}; path location alone is not authorization for substantive deliverables. `
|
|
7248
|
-
+
|
|
7489
|
+
+ unsupportedNativeGuidance
|
|
7490
|
+
+ " Autopilot rework and typed subagent/worker lanes are exempt from this guard.",
|
|
7249
7491
|
},
|
|
7250
7492
|
};
|
|
7251
7493
|
}
|
|
@@ -7380,6 +7622,44 @@ function modeStateHasExplicitMatchingCwd(state, cwd) {
|
|
|
7380
7622
|
return false;
|
|
7381
7623
|
}
|
|
7382
7624
|
}
|
|
7625
|
+
async function clearNativeStopSessionEntries(stateDir, payload, canonicalSessionId) {
|
|
7626
|
+
const statePath = join(stateDir, NATIVE_STOP_STATE_FILE);
|
|
7627
|
+
const state = await readJsonIfExists(statePath);
|
|
7628
|
+
if (!state)
|
|
7629
|
+
return;
|
|
7630
|
+
const sessions = safeObject(state.sessions);
|
|
7631
|
+
const keys = new Set(uniqueNonEmpty([
|
|
7632
|
+
readNativeStopSessionKey(payload, canonicalSessionId),
|
|
7633
|
+
canonicalSessionId,
|
|
7634
|
+
readPayloadSessionId(payload),
|
|
7635
|
+
readPayloadThreadId(payload),
|
|
7636
|
+
]));
|
|
7637
|
+
let changed = false;
|
|
7638
|
+
for (const key of keys) {
|
|
7639
|
+
if (Object.prototype.hasOwnProperty.call(sessions, key)) {
|
|
7640
|
+
delete sessions[key];
|
|
7641
|
+
changed = true;
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7644
|
+
if (!changed)
|
|
7645
|
+
return;
|
|
7646
|
+
await writeFile(statePath, JSON.stringify({ ...state, sessions }, null, 2));
|
|
7647
|
+
}
|
|
7648
|
+
async function hasAuthoritativeInactiveSkillStopState(cwd, stateDir, skill, sessionId, threadId) {
|
|
7649
|
+
const sessionModeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
7650
|
+
if (!sessionModeState || !isTerminalOrInactiveModeState(sessionModeState))
|
|
7651
|
+
return false;
|
|
7652
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
7653
|
+
if (canonicalState && !rootSkillStateHasNoActiveSkillForStopContext(canonicalState, skill, sessionId, threadId)) {
|
|
7654
|
+
return false;
|
|
7655
|
+
}
|
|
7656
|
+
const rootModeState = await readJsonIfExists(join(stateDir, `${skill}-state.json`));
|
|
7657
|
+
if (!rootModeState)
|
|
7658
|
+
return true;
|
|
7659
|
+
if (!modeStateMatchesSkillStopContext(rootModeState, cwd, sessionId))
|
|
7660
|
+
return true;
|
|
7661
|
+
return isTerminalOrInactiveModeState(rootModeState);
|
|
7662
|
+
}
|
|
7383
7663
|
async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requiredSkill) {
|
|
7384
7664
|
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
7385
7665
|
const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
|
|
@@ -8029,6 +8309,9 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
8029
8309
|
const suppressParentWorkflowStop = shouldSuppressParentWorkflowStopForSideConversation(payload);
|
|
8030
8310
|
if (canonicalSessionId) {
|
|
8031
8311
|
await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
|
|
8312
|
+
if (await hasAuthoritativeInactiveSkillStopState(cwd, stateDir, "ralplan", canonicalSessionId, threadId)) {
|
|
8313
|
+
await clearNativeStopSessionEntries(stateDir, payload, canonicalSessionId);
|
|
8314
|
+
}
|
|
8032
8315
|
}
|
|
8033
8316
|
if (suppressParentWorkflowStop) {
|
|
8034
8317
|
return null;
|
|
@@ -8454,6 +8737,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
8454
8737
|
}
|
|
8455
8738
|
else if (hookEventName === "PostToolUse") {
|
|
8456
8739
|
await recordNativeSubagentCapacityBlocker(cwd, stateDir, payload).catch(() => { });
|
|
8740
|
+
await recordNativeSubagentSupportBlocker(cwd, stateDir, payload).catch(() => { });
|
|
8457
8741
|
if (detectMcpTransportFailure(payload)) {
|
|
8458
8742
|
await markTeamTransportFailure(cwd, payload);
|
|
8459
8743
|
}
|