oh-my-codex 0.18.1 → 0.18.3
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 +4 -2
- package/dist/agents/__tests__/definitions.test.js +23 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +20 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +40 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +4 -0
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/config-sessions.test.d.ts +2 -0
- package/dist/auth/__tests__/config-sessions.test.d.ts.map +1 -0
- package/dist/auth/__tests__/config-sessions.test.js +48 -0
- package/dist/auth/__tests__/config-sessions.test.js.map +1 -0
- package/dist/auth/__tests__/quota-rotation.test.d.ts +2 -0
- package/dist/auth/__tests__/quota-rotation.test.d.ts.map +1 -0
- package/dist/auth/__tests__/quota-rotation.test.js +33 -0
- package/dist/auth/__tests__/quota-rotation.test.js.map +1 -0
- package/dist/auth/__tests__/redact.test.d.ts +2 -0
- package/dist/auth/__tests__/redact.test.d.ts.map +1 -0
- package/dist/auth/__tests__/redact.test.js +20 -0
- package/dist/auth/__tests__/redact.test.js.map +1 -0
- package/dist/auth/__tests__/storage.test.d.ts +2 -0
- package/dist/auth/__tests__/storage.test.d.ts.map +1 -0
- package/dist/auth/__tests__/storage.test.js +108 -0
- package/dist/auth/__tests__/storage.test.js.map +1 -0
- package/dist/auth/config.d.ts +9 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +77 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/hotswap.d.ts +36 -0
- package/dist/auth/hotswap.d.ts.map +1 -0
- package/dist/auth/hotswap.js +159 -0
- package/dist/auth/hotswap.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/paths.d.ts +12 -0
- package/dist/auth/paths.d.ts.map +1 -0
- package/dist/auth/paths.js +78 -0
- package/dist/auth/paths.js.map +1 -0
- package/dist/auth/quota-detector.d.ts +10 -0
- package/dist/auth/quota-detector.d.ts.map +1 -0
- package/dist/auth/quota-detector.js +40 -0
- package/dist/auth/quota-detector.js.map +1 -0
- package/dist/auth/redact.d.ts +2 -0
- package/dist/auth/redact.d.ts.map +1 -0
- package/dist/auth/redact.js +26 -0
- package/dist/auth/redact.js.map +1 -0
- package/dist/auth/rotation.d.ts +9 -0
- package/dist/auth/rotation.d.ts.map +1 -0
- package/dist/auth/rotation.js +26 -0
- package/dist/auth/rotation.js.map +1 -0
- package/dist/auth/sessions.d.ts +15 -0
- package/dist/auth/sessions.d.ts.map +1 -0
- package/dist/auth/sessions.js +62 -0
- package/dist/auth/sessions.js.map +1 -0
- package/dist/auth/storage.d.ts +27 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +111 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/catalog/__tests__/generator.test.js +4 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.d.ts +2 -0
- package/dist/cli/__tests__/auth.test.d.ts.map +1 -0
- package/dist/cli/__tests__/auth.test.js +168 -0
- package/dist/cli/__tests__/auth.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +112 -5
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +20 -0
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +171 -21
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +51 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +2 -2
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +30 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +47 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/auth.d.ts +4 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +89 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +190 -7
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +12 -0
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +27 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +245 -47
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +11 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +3 -3
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/deep-interview.test.d.ts +2 -0
- package/dist/config/__tests__/deep-interview.test.d.ts.map +1 -0
- package/dist/config/__tests__/deep-interview.test.js +239 -0
- package/dist/config/__tests__/deep-interview.test.js.map +1 -0
- package/dist/config/__tests__/generator-idempotent.test.js +123 -0
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +1 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2 -4
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/deep-interview.d.ts +22 -0
- package/dist/config/deep-interview.d.ts.map +1 -0
- package/dist/config/deep-interview.js +151 -0
- package/dist/config/deep-interview.js.map +1 -0
- package/dist/config/generator.d.ts +19 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +198 -29
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +3 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +45 -2
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +2 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +17 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-routing.test.js +1 -0
- package/dist/hooks/__tests__/explore-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +471 -15
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
- package/dist/hooks/deep-interview-config-instruction.d.ts +3 -0
- package/dist/hooks/deep-interview-config-instruction.d.ts.map +1 -0
- package/dist/hooks/deep-interview-config-instruction.js +47 -0
- package/dist/hooks/deep-interview-config-instruction.js.map +1 -0
- package/dist/hooks/explore-routing.d.ts.map +1 -1
- package/dist/hooks/explore-routing.js +1 -0
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +6 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +80 -14
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +1 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +11 -0
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +22 -0
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +213 -17
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +84 -0
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +51 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +171 -23
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/index.d.ts +1 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +8 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +14 -3
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +26 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +2 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +62 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +17 -3
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +96 -10
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +22 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +63 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +410 -4
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +29 -2
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +41 -6
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +43 -10
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/deep-interview.d.ts +2 -0
- package/dist/question/deep-interview.d.ts.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/ui.d.ts +12 -0
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +83 -46
- package/dist/question/ui.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +200 -10
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -0
- package/dist/ralplan/consensus-gate.js +212 -0
- package/dist/ralplan/consensus-gate.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +25 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +144 -8
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +1034 -28
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +57 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +2 -2
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +238 -36
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +188 -4
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/run-test-files.js +13 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/state/__tests__/planning-gate.test.d.ts +2 -0
- package/dist/state/__tests__/planning-gate.test.d.ts.map +1 -0
- package/dist/state/__tests__/planning-gate.test.js +219 -0
- package/dist/state/__tests__/planning-gate.test.js.map +1 -0
- package/dist/state/__tests__/workflow-transition.test.js +6 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +24 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +70 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +4 -3
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +36 -44
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +144 -18
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +10 -20
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +22 -6
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +50 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +28 -2
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +16 -4
- package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +10 -0
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/plan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +24 -5
- package/prompts/prometheus-strict-metis.md +274 -0
- package/prompts/prometheus-strict-momus.md +82 -0
- package/prompts/prometheus-strict-oracle.md +107 -0
- package/prompts/researcher.md +22 -3
- package/prompts/scholastic.md +11 -0
- package/skills/autopilot/SKILL.md +16 -4
- package/skills/autoresearch/SKILL.md +4 -0
- package/skills/autoresearch-goal/SKILL.md +1 -1
- package/skills/best-practice-research/SKILL.md +1 -1
- package/skills/deep-interview/SKILL.md +10 -0
- package/skills/pipeline/SKILL.md +1 -1
- package/skills/plan/SKILL.md +1 -1
- package/skills/prometheus-strict/README.md +35 -0
- package/skills/prometheus-strict/SKILL.md +219 -0
- package/skills/ralplan/SKILL.md +24 -5
- package/src/scripts/__tests__/codex-native-hook.test.ts +1307 -61
- package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
- package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
- package/src/scripts/__tests__/run-test-files.test.ts +67 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +2 -2
- package/src/scripts/codex-native-hook.ts +260 -31
- package/src/scripts/notify-dispatcher.ts +202 -4
- package/src/scripts/run-test-files.ts +13 -0
- package/templates/catalog-manifest.json +27 -0
|
@@ -3,9 +3,9 @@ import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
|
|
|
3
3
|
import { appendFile, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
|
|
4
4
|
import { extname, join, relative, resolve } from "path";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
|
-
import {
|
|
7
|
-
import { extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
8
|
-
import { readSubagentSessionSummary, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
6
|
+
import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
|
+
import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
8
|
+
import { readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
9
9
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
10
10
|
import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
11
11
|
import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
|
|
@@ -13,6 +13,7 @@ import { omxNotepadPath, resolveProjectMemoryPath } from "../utils/paths.js";
|
|
|
13
13
|
import { findGitLayout } from "../utils/git-layout.js";
|
|
14
14
|
import { getBaseStateDir, getStateFilePath, getStatePath } from "../mcp/state-paths.js";
|
|
15
15
|
import { detectKeywords, detectPrimaryKeyword, recordSkillActivation, } from "../hooks/keyword-detector.js";
|
|
16
|
+
import { buildDeepInterviewConfigInstruction } from "../hooks/deep-interview-config-instruction.js";
|
|
16
17
|
import { detectNativeStopStallPattern, loadAutoNudgeConfig, normalizeAutoNudgeSignatureText, resolveEffectiveAutoNudgeResponse, } from "./notify-hook/auto-nudge.js";
|
|
17
18
|
import { SLOPPY_FALLBACK_GROUNDING_PATTERNS, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS, SLOPPY_FALLBACK_PHRASE_PATTERNS, buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTransportFailure, hasAnyPattern, } from "./codex-native-pre-post.js";
|
|
18
19
|
import { handleTeamWorkerPostToolUseSuccess } from "./notify-hook/team-worker-posttooluse.js";
|
|
@@ -175,18 +176,29 @@ async function nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonica
|
|
|
175
176
|
return summary.allThreadIds.includes(parentThreadId);
|
|
176
177
|
}
|
|
177
178
|
async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId) {
|
|
178
|
-
const sessionId = canonicalSessionId.trim();
|
|
179
|
-
if (!sessionId)
|
|
180
|
-
return false;
|
|
181
|
-
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
182
|
-
if (!summary)
|
|
183
|
-
return false;
|
|
184
179
|
const candidateIds = [nativeSessionId, threadId]
|
|
185
180
|
.map((value) => value.trim())
|
|
186
181
|
.filter(Boolean);
|
|
187
182
|
if (candidateIds.length === 0)
|
|
188
183
|
return false;
|
|
189
|
-
|
|
184
|
+
const sessionId = canonicalSessionId.trim();
|
|
185
|
+
if (sessionId) {
|
|
186
|
+
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
187
|
+
if (summary && candidateIds.some((id) => summary.allSubagentThreadIds.includes(id))) {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Native Codex resume can report the child native session as the canonical
|
|
192
|
+
// session id before OMX reconciles it back to the owning session. In that
|
|
193
|
+
// window the per-session summary lookup above misses the child and a
|
|
194
|
+
// subagent UserPromptSubmit can accidentally activate workflow keywords from
|
|
195
|
+
// quoted review context. Fall back to the global tracking index so any known
|
|
196
|
+
// subagent thread is treated as subagent-scoped, regardless of the current
|
|
197
|
+
// hook payload's session-id mapping.
|
|
198
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
199
|
+
if (!trackingState)
|
|
200
|
+
return false;
|
|
201
|
+
return Object.values(trackingState.sessions).some((session) => (candidateIds.some((id) => session.threads[id]?.kind === "subagent")));
|
|
190
202
|
}
|
|
191
203
|
function shouldSuppressSubagentLifecycleHookDispatch() {
|
|
192
204
|
const config = getNotificationConfig();
|
|
@@ -1361,14 +1373,42 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
|
|
|
1361
1373
|
function buildSkillStateCliInstruction(mode, statePath) {
|
|
1362
1374
|
return `skill: ${mode} activated and initial state initialized at ${statePath}; use CLI-first state updates via \`omx state write/read/clear --input '<json>' --json\`; use omx_state MCP only when explicit MCP compatibility is enabled.`;
|
|
1363
1375
|
}
|
|
1376
|
+
function buildAutopilotPromptActivationNote(skillState) {
|
|
1377
|
+
if (skillState?.initialized_mode !== "autopilot")
|
|
1378
|
+
return null;
|
|
1379
|
+
return [
|
|
1380
|
+
"Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal (+ $team if needed) -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).",
|
|
1381
|
+
"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.",
|
|
1382
|
+
"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.",
|
|
1383
|
+
"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.",
|
|
1384
|
+
"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.",
|
|
1385
|
+
].join(" ");
|
|
1386
|
+
}
|
|
1364
1387
|
function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
|
|
1365
1388
|
if (!prompt)
|
|
1366
1389
|
return null;
|
|
1367
1390
|
const promptPriorityMessage = buildPromptPriorityMessage(prompt);
|
|
1368
1391
|
const matches = detectKeywords(prompt);
|
|
1369
1392
|
const match = detectPrimaryKeyword(prompt);
|
|
1370
|
-
if (!match)
|
|
1371
|
-
|
|
1393
|
+
if (!match) {
|
|
1394
|
+
const continuedSkill = safeString(skillState?.skill).trim();
|
|
1395
|
+
if (!continuedSkill)
|
|
1396
|
+
return promptPriorityMessage;
|
|
1397
|
+
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
1398
|
+
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
1399
|
+
: null;
|
|
1400
|
+
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1401
|
+
return [
|
|
1402
|
+
`OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
|
|
1403
|
+
promptPriorityMessage,
|
|
1404
|
+
skillState?.initialized_mode && skillState.initialized_state_path
|
|
1405
|
+
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1406
|
+
: null,
|
|
1407
|
+
deepInterviewPromptActivationNote,
|
|
1408
|
+
deepInterviewConfigPromptActivationNote,
|
|
1409
|
+
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
1410
|
+
].filter(Boolean).join(" ");
|
|
1411
|
+
}
|
|
1372
1412
|
const detectedKeywordMessage = matches.length > 1
|
|
1373
1413
|
? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
|
|
1374
1414
|
: `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
|
|
@@ -1385,12 +1425,14 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1385
1425
|
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
1386
1426
|
? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
|
|
1387
1427
|
: null;
|
|
1428
|
+
const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
|
|
1388
1429
|
const ultraworkPromptActivationNote = skillState?.initialized_mode === "ultrawork"
|
|
1389
1430
|
? "Ultrawork protocol: ground the task before editing, define pass/fail acceptance criteria, keep shared-file work local, and use direct-tool plus background evidence lanes only for truly independent work. Direct ultrawork provides lightweight verification only; Ralph owns persistence and the full verified-completion promise."
|
|
1390
1431
|
: null;
|
|
1391
1432
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1392
1433
|
? "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."
|
|
1393
1434
|
: null;
|
|
1435
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState);
|
|
1394
1436
|
const combinedTransitionMessage = (() => {
|
|
1395
1437
|
if (!skillState?.transition_message)
|
|
1396
1438
|
return null;
|
|
@@ -1419,6 +1461,8 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1419
1461
|
: null,
|
|
1420
1462
|
promptPriorityMessage,
|
|
1421
1463
|
ultragoalPromptActivationNote,
|
|
1464
|
+
autopilotPromptActivationNote,
|
|
1465
|
+
deepInterviewConfigPromptActivationNote,
|
|
1422
1466
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
1423
1467
|
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1424
1468
|
: null,
|
|
@@ -1442,8 +1486,10 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1442
1486
|
promptPriorityMessage,
|
|
1443
1487
|
initializedStateMessage,
|
|
1444
1488
|
deepInterviewPromptActivationNote,
|
|
1489
|
+
deepInterviewConfigPromptActivationNote,
|
|
1445
1490
|
ultraworkPromptActivationNote,
|
|
1446
1491
|
ultragoalPromptActivationNote,
|
|
1492
|
+
autopilotPromptActivationNote,
|
|
1447
1493
|
buildTeamRuntimeInstruction(cwd, payload),
|
|
1448
1494
|
buildTeamHelpInstruction(cwd, payload),
|
|
1449
1495
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
@@ -1459,13 +1505,15 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1459
1505
|
promptPriorityMessage,
|
|
1460
1506
|
buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path),
|
|
1461
1507
|
deepInterviewPromptActivationNote,
|
|
1508
|
+
deepInterviewConfigPromptActivationNote,
|
|
1462
1509
|
ultraworkPromptActivationNote,
|
|
1463
1510
|
ultragoalPromptActivationNote,
|
|
1511
|
+
autopilotPromptActivationNote,
|
|
1464
1512
|
ralphPromptActivationNote,
|
|
1465
1513
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
1466
1514
|
].join(" ");
|
|
1467
1515
|
}
|
|
1468
|
-
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1516
|
+
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, autopilotPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1469
1517
|
}
|
|
1470
1518
|
function parseTeamWorkerEnv(rawValue) {
|
|
1471
1519
|
const match = /^([a-z0-9][a-z0-9-]{0,29})\/(worker-\d+)$/.exec(rawValue.trim());
|
|
@@ -1664,6 +1712,7 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1664
1712
|
`If get_goal returns a completed task-scoped objective for the same aggregate ultragoal plan, checkpoint ${goalId} with evidence naming ${goalId} plus .omx/ultragoal/goals.json or ledger.jsonl and pass final quality-gate JSON; OMX will reconcile the completed planned scope without mutating Codex goal state.`,
|
|
1665
1713
|
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1666
1714
|
`Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>'.`,
|
|
1715
|
+
`If get_goal itself is unavailable with a Codex DB/schema/context error such as "no such table: thread_goals", record an auditable safe-recovery blocker instead: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<unavailable get_goal error JSON or path>' --evidence '<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>'.`,
|
|
1667
1716
|
"Then continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the intended goal there.",
|
|
1668
1717
|
].join(" "),
|
|
1669
1718
|
};
|
|
@@ -1744,30 +1793,46 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1744
1793
|
systemMessage,
|
|
1745
1794
|
};
|
|
1746
1795
|
}
|
|
1747
|
-
|
|
1796
|
+
function teamStateMatchesThreadForStop(state, threadId, options = {}) {
|
|
1797
|
+
const normalizedThreadId = safeString(threadId).trim();
|
|
1798
|
+
if (!normalizedThreadId)
|
|
1799
|
+
return true;
|
|
1800
|
+
const ownerThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
1801
|
+
if (!ownerThreadId)
|
|
1802
|
+
return options.requireOwnerThread !== true;
|
|
1803
|
+
return ownerThreadId === normalizedThreadId;
|
|
1804
|
+
}
|
|
1805
|
+
async function readTeamModeStateForStop(cwd, stateDir, sessionId, threadId) {
|
|
1748
1806
|
const normalizedSessionId = safeString(sessionId).trim();
|
|
1749
|
-
if (!normalizedSessionId)
|
|
1750
|
-
return
|
|
1751
|
-
}
|
|
1807
|
+
if (!normalizedSessionId)
|
|
1808
|
+
return null;
|
|
1752
1809
|
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
|
|
1753
|
-
if (scopedState)
|
|
1754
|
-
return scopedState
|
|
1810
|
+
if (scopedState) {
|
|
1811
|
+
return teamStateMatchesThreadForStop(scopedState, threadId)
|
|
1812
|
+
? { state: scopedState, scope: "session" }
|
|
1813
|
+
: null;
|
|
1814
|
+
}
|
|
1755
1815
|
const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
|
|
1756
1816
|
if (rootState?.active !== true)
|
|
1757
1817
|
return null;
|
|
1818
|
+
const teamName = safeString(rootState.team_name).trim();
|
|
1819
|
+
if (!teamName)
|
|
1820
|
+
return null;
|
|
1758
1821
|
const ownerSessionId = safeString(rootState.session_id).trim();
|
|
1759
|
-
if (ownerSessionId
|
|
1822
|
+
if (!ownerSessionId || ownerSessionId !== normalizedSessionId)
|
|
1760
1823
|
return null;
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1824
|
+
if (!teamStateMatchesThreadForStop(rootState, threadId, { requireOwnerThread: true }))
|
|
1825
|
+
return null;
|
|
1826
|
+
return { state: rootState, scope: "root" };
|
|
1763
1827
|
}
|
|
1764
|
-
async function buildTeamStopOutput(cwd, sessionId) {
|
|
1828
|
+
async function buildTeamStopOutput(cwd, sessionId, threadId) {
|
|
1765
1829
|
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
|
|
1766
1830
|
return null;
|
|
1767
1831
|
}
|
|
1768
|
-
const
|
|
1769
|
-
if (
|
|
1832
|
+
const teamStateForStop = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId, threadId);
|
|
1833
|
+
if (!teamStateForStop || teamStateForStop.state.active !== true)
|
|
1770
1834
|
return null;
|
|
1835
|
+
const teamState = teamStateForStop.state;
|
|
1771
1836
|
const teamName = safeString(teamState.team_name).trim();
|
|
1772
1837
|
if (teamName) {
|
|
1773
1838
|
const canonicalTeamDir = join(resolveCanonicalTeamStateRoot(cwd), "team", teamName);
|
|
@@ -1776,7 +1841,10 @@ async function buildTeamStopOutput(cwd, sessionId) {
|
|
|
1776
1841
|
}
|
|
1777
1842
|
}
|
|
1778
1843
|
const coarsePhase = teamState.current_phase;
|
|
1779
|
-
const
|
|
1844
|
+
const canonicalPhaseState = teamName ? await readTeamPhase(teamName, cwd) : null;
|
|
1845
|
+
if (teamStateForStop.scope === "root" && !canonicalPhaseState)
|
|
1846
|
+
return null;
|
|
1847
|
+
const canonicalPhase = canonicalPhaseState?.current_phase ?? coarsePhase;
|
|
1780
1848
|
if (!isNonTerminalPhase(canonicalPhase))
|
|
1781
1849
|
return null;
|
|
1782
1850
|
return buildTeamStopOutputForPhase(teamName, formatPhase(canonicalPhase));
|
|
@@ -1859,6 +1927,137 @@ async function readStopSessionPinnedState(fileName, cwd, sessionId, stateDir) {
|
|
|
1859
1927
|
: getStateFilePath(fileName, cwd, sessionId || undefined);
|
|
1860
1928
|
return readJsonIfExists(statePath);
|
|
1861
1929
|
}
|
|
1930
|
+
const DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES = [
|
|
1931
|
+
".omx/context",
|
|
1932
|
+
".omx/interviews",
|
|
1933
|
+
".omx/specs",
|
|
1934
|
+
".omx/state",
|
|
1935
|
+
];
|
|
1936
|
+
const DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES = new Set([
|
|
1937
|
+
"Write",
|
|
1938
|
+
"Edit",
|
|
1939
|
+
"MultiEdit",
|
|
1940
|
+
"apply_patch",
|
|
1941
|
+
"ApplyPatch",
|
|
1942
|
+
]);
|
|
1943
|
+
function isActiveDeepInterviewPhase(state) {
|
|
1944
|
+
if (!state || state.active !== true)
|
|
1945
|
+
return false;
|
|
1946
|
+
const mode = safeString(state.mode).trim();
|
|
1947
|
+
if (mode && mode !== "deep-interview")
|
|
1948
|
+
return false;
|
|
1949
|
+
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1950
|
+
if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing"))
|
|
1951
|
+
return false;
|
|
1952
|
+
return true;
|
|
1953
|
+
}
|
|
1954
|
+
function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
|
|
1955
|
+
const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
|
|
1956
|
+
if (!trimmed || trimmed.includes("\0"))
|
|
1957
|
+
return false;
|
|
1958
|
+
let relativePath;
|
|
1959
|
+
try {
|
|
1960
|
+
const absolute = resolve(cwd, trimmed);
|
|
1961
|
+
relativePath = relative(cwd, absolute).replace(/\\/g, "/");
|
|
1962
|
+
}
|
|
1963
|
+
catch {
|
|
1964
|
+
return false;
|
|
1965
|
+
}
|
|
1966
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath.startsWith("/"))
|
|
1967
|
+
return false;
|
|
1968
|
+
return DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES.some((prefix) => (relativePath === prefix || relativePath.startsWith(`${prefix}/`)));
|
|
1969
|
+
}
|
|
1970
|
+
function readPreToolUseCommand(payload) {
|
|
1971
|
+
const toolInput = safeObject(payload.tool_input);
|
|
1972
|
+
return safeString(toolInput.command).trim();
|
|
1973
|
+
}
|
|
1974
|
+
function readPreToolUsePathCandidates(payload) {
|
|
1975
|
+
const input = safeObject(payload.tool_input);
|
|
1976
|
+
const candidates = [
|
|
1977
|
+
input.file_path,
|
|
1978
|
+
input.filePath,
|
|
1979
|
+
input.path,
|
|
1980
|
+
input.target_path,
|
|
1981
|
+
input.targetPath,
|
|
1982
|
+
];
|
|
1983
|
+
return candidates.map((candidate) => safeString(candidate).trim()).filter(Boolean);
|
|
1984
|
+
}
|
|
1985
|
+
function commandHasDeepInterviewWriteIntent(command) {
|
|
1986
|
+
return /\bapply_patch\b/.test(command)
|
|
1987
|
+
|| /(?:^|[;&|]\s*)(?:cat|printf|echo)\b[\s\S]{0,240}>\s*[^\s&|;]+/.test(command)
|
|
1988
|
+
|| /\btee\s+(?:-a\s+)?[^\s&|;]+/.test(command)
|
|
1989
|
+
|| /\bsed\s+(?:[^\n;&|]*\s)?-i(?:\b|['"])/.test(command)
|
|
1990
|
+
|| /\b(?:python3?|node|perl|ruby)\b[\s\S]{0,260}\b(?:writeFileSync|writeFile|write_text|open\([^)]*["']w|File\.write|Path\()/.test(command)
|
|
1991
|
+
|| /\b(?:git\s+(?:checkout|switch|restore|reset|apply|am|merge|rebase)|npm\s+(?:install|i|ci)|pnpm\s+(?:install|i)|yarn\s+(?:install|add))\b/.test(command);
|
|
1992
|
+
}
|
|
1993
|
+
function extractDeepInterviewCommandWriteTargets(command) {
|
|
1994
|
+
const targets = [];
|
|
1995
|
+
for (const match of command.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
1996
|
+
const candidate = safeString(match[2]).trim();
|
|
1997
|
+
if (candidate)
|
|
1998
|
+
targets.push(candidate);
|
|
1999
|
+
}
|
|
2000
|
+
for (const match of command.matchAll(/\btee\s+(?:-a\s+)?(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2001
|
+
const candidate = safeString(match[2]).trim();
|
|
2002
|
+
if (candidate)
|
|
2003
|
+
targets.push(candidate);
|
|
2004
|
+
}
|
|
2005
|
+
return targets;
|
|
2006
|
+
}
|
|
2007
|
+
function isAllowedDeepInterviewBashWrite(cwd, command) {
|
|
2008
|
+
if (!commandHasDeepInterviewWriteIntent(command))
|
|
2009
|
+
return true;
|
|
2010
|
+
if (/\bomx\s+(?:state\s+(?:write|read|clear)|question)\b/.test(command))
|
|
2011
|
+
return true;
|
|
2012
|
+
const targets = extractDeepInterviewCommandWriteTargets(command);
|
|
2013
|
+
return targets.length > 0 && targets.every((target) => isAllowedDeepInterviewArtifactPath(cwd, target));
|
|
2014
|
+
}
|
|
2015
|
+
async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId) {
|
|
2016
|
+
const modeState = sessionId
|
|
2017
|
+
? await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir)
|
|
2018
|
+
: await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
2019
|
+
if (!isActiveDeepInterviewPhase(modeState) || !modeState)
|
|
2020
|
+
return null;
|
|
2021
|
+
if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
|
|
2022
|
+
return null;
|
|
2023
|
+
const canonicalState = sessionId
|
|
2024
|
+
? await readVisibleSkillActiveStateForStateDir(stateDir, sessionId)
|
|
2025
|
+
: await readSkillActiveState(join(stateDir, SKILL_ACTIVE_STATE_FILE));
|
|
2026
|
+
if (!canonicalState)
|
|
2027
|
+
return modeState;
|
|
2028
|
+
const hasActiveDeepInterviewSkill = listActiveSkills(canonicalState).some((entry) => (entry.skill === "deep-interview"
|
|
2029
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
2030
|
+
return hasActiveDeepInterviewSkill ? modeState : null;
|
|
2031
|
+
}
|
|
2032
|
+
async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir) {
|
|
2033
|
+
const sessionId = readPayloadSessionId(payload);
|
|
2034
|
+
const threadId = readPayloadThreadId(payload);
|
|
2035
|
+
const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
2036
|
+
if (!activeState)
|
|
2037
|
+
return null;
|
|
2038
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
2039
|
+
const command = readPreToolUseCommand(payload);
|
|
2040
|
+
const pathCandidates = readPreToolUsePathCandidates(payload);
|
|
2041
|
+
let blocked = false;
|
|
2042
|
+
if (toolName === "Bash") {
|
|
2043
|
+
blocked = !isAllowedDeepInterviewBashWrite(cwd, command);
|
|
2044
|
+
}
|
|
2045
|
+
else if (DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES.has(toolName)) {
|
|
2046
|
+
blocked = pathCandidates.length === 0
|
|
2047
|
+
|| !pathCandidates.every((candidate) => isAllowedDeepInterviewArtifactPath(cwd, candidate));
|
|
2048
|
+
}
|
|
2049
|
+
if (!blocked)
|
|
2050
|
+
return null;
|
|
2051
|
+
const phase = formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning");
|
|
2052
|
+
return {
|
|
2053
|
+
decision: "block",
|
|
2054
|
+
reason: `Deep-interview is active (phase: ${phase}); implementation/write tools are blocked until an explicit handoff workflow is activated.`,
|
|
2055
|
+
hookSpecificOutput: {
|
|
2056
|
+
hookEventName: "PreToolUse",
|
|
2057
|
+
additionalContext: "Deep-interview is requirements/spec mode. Treat detailed user answers as interview/spec material, not implicit implementation authorization. You may write only deep-interview artifacts under `.omx/context/`, `.omx/interviews/`, `.omx/specs/`, or required `.omx/state/` files. To implement, first ask for or process an explicit transition such as `$ralplan`, `$autopilot`, `$ralph`, `$team`, or `$ultragoal`.",
|
|
2058
|
+
},
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
1862
2061
|
function matchesSkillStopContext(entry, state, sessionId, threadId) {
|
|
1863
2062
|
const entrySessionId = safeString(entry.session_id ?? state.session_id).trim();
|
|
1864
2063
|
const entryThreadId = safeString(entry.thread_id ?? state.thread_id).trim();
|
|
@@ -2310,7 +2509,7 @@ async function maybeReturnRepeatableStopOutput(payload, stateDir, signature, out
|
|
|
2310
2509
|
async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId, options = { allowRepeatDuringStopHook: true }) {
|
|
2311
2510
|
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId, options);
|
|
2312
2511
|
}
|
|
2313
|
-
async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
2512
|
+
async function findCanonicalActiveTeamForSession(cwd, sessionId, threadId) {
|
|
2314
2513
|
if (!sessionId.trim())
|
|
2315
2514
|
return null;
|
|
2316
2515
|
const teamsRoot = join(resolveCanonicalTeamStateRoot(cwd), "team");
|
|
@@ -2332,6 +2531,8 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
2332
2531
|
const ownerSessionId = (manifest.leader?.session_id ?? "").trim();
|
|
2333
2532
|
if (ownerSessionId && ownerSessionId !== sessionId.trim())
|
|
2334
2533
|
continue;
|
|
2534
|
+
if (!teamStateMatchesThreadForStop(manifest.leader, threadId))
|
|
2535
|
+
continue;
|
|
2335
2536
|
if (!isNonTerminalPhase(phaseState.current_phase))
|
|
2336
2537
|
continue;
|
|
2337
2538
|
return {
|
|
@@ -2341,18 +2542,18 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
2341
2542
|
}
|
|
2342
2543
|
return null;
|
|
2343
2544
|
}
|
|
2344
|
-
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId) {
|
|
2345
|
-
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
|
|
2346
|
-
const directTeamName = safeString(directState?.team_name).trim();
|
|
2347
|
-
if (directState?.active === true && directTeamName)
|
|
2545
|
+
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId, threadId) {
|
|
2546
|
+
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId, threadId);
|
|
2547
|
+
const directTeamName = safeString(directState?.state.team_name).trim();
|
|
2548
|
+
if (directState?.state.active === true && directTeamName)
|
|
2348
2549
|
return directTeamName;
|
|
2349
|
-
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId);
|
|
2550
|
+
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId, threadId);
|
|
2350
2551
|
return canonicalTeam?.teamName ?? "";
|
|
2351
2552
|
}
|
|
2352
2553
|
async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, sessionId) {
|
|
2353
2554
|
if (!sessionId)
|
|
2354
2555
|
return { matched: false, output: null };
|
|
2355
|
-
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
|
|
2556
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId, readPayloadThreadId(payload));
|
|
2356
2557
|
if (!teamName)
|
|
2357
2558
|
return { matched: false, output: null };
|
|
2358
2559
|
const explicitReleaseReadinessContext = hasReleaseReadinessMode(payload)
|
|
@@ -2569,7 +2770,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2569
2770
|
const releaseReadinessFinalizeResult = await maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, canonicalSessionId);
|
|
2570
2771
|
if (releaseReadinessFinalizeResult.matched)
|
|
2571
2772
|
return releaseReadinessFinalizeResult.output;
|
|
2572
|
-
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId);
|
|
2773
|
+
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId, threadId);
|
|
2573
2774
|
if (teamOutput) {
|
|
2574
2775
|
return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
|
|
2575
2776
|
}
|
|
@@ -2580,7 +2781,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2580
2781
|
}
|
|
2581
2782
|
const canonicalTeam = await readCanonicalTerminalRunStateForStop(cwd, canonicalSessionId, "team")
|
|
2582
2783
|
? null
|
|
2583
|
-
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
|
|
2784
|
+
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId, threadId);
|
|
2584
2785
|
if (canonicalTeam) {
|
|
2585
2786
|
const canonicalTeamOutput = buildTeamStopOutputForPhase(canonicalTeam.teamName, canonicalTeam.phase);
|
|
2586
2787
|
const repeatedCanonicalTeamOutput = await returnPersistentStopBlock(payload, stateDir, "team-stop", `${canonicalTeam.teamName}|${canonicalTeam.phase}`, canonicalTeamOutput, canonicalSessionId);
|
|
@@ -2857,7 +3058,8 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2857
3058
|
}
|
|
2858
3059
|
}
|
|
2859
3060
|
else if (hookEventName === "PreToolUse") {
|
|
2860
|
-
outputJson =
|
|
3061
|
+
outputJson = await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir)
|
|
3062
|
+
?? buildNativePreToolUseOutput(payload);
|
|
2861
3063
|
}
|
|
2862
3064
|
else if (hookEventName === "PostToolUse") {
|
|
2863
3065
|
if (detectMcpTransportFailure(payload)) {
|