oh-my-codex 0.16.0 → 0.16.1
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 +5 -5
- package/Cargo.toml +1 -1
- package/crates/omx-explore/src/main.rs +434 -28
- package/dist/agents/__tests__/native-config.test.js +50 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +3 -2
- package/dist/agents/native-config.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +118 -1
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.d.ts +2 -0
- package/dist/cli/__tests__/imagegen-continuation.test.d.ts.map +1 -0
- package/dist/cli/__tests__/imagegen-continuation.test.js +135 -0
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -0
- package/dist/cli/__tests__/index.test.js +182 -18
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +88 -2
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +62 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +45 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +465 -12
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +40 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +208 -8
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +11 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +124 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +37 -3
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +93 -4
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +1 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +42 -7
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +6 -3
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +5 -0
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +18 -1
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +4 -1
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/models.d.ts +6 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +37 -0
- package/dist/config/models.js.map +1 -1
- package/dist/exec/followup.d.ts +1 -0
- package/dist/exec/followup.d.ts.map +1 -1
- package/dist/exec/followup.js +9 -3
- package/dist/exec/followup.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +19 -0
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +19 -2
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +40 -0
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.js +28 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +32 -0
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/codebase-map.d.ts.map +1 -1
- package/dist/hooks/codebase-map.js +3 -2
- package/dist/hooks/codebase-map.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +6 -4
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/logging.d.ts.map +1 -1
- package/dist/hooks/extensibility/logging.js +3 -2
- package/dist/hooks/extensibility/logging.js.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.js +4 -3
- package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +22 -12
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +8 -7
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +1 -1
- package/dist/hud/__tests__/state.test.js +24 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/index.js +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +22 -8
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/imagegen/continuation.d.ts +44 -0
- package/dist/imagegen/continuation.d.ts.map +1 -0
- package/dist/imagegen/continuation.js +220 -0
- package/dist/imagegen/continuation.js.map +1 -0
- package/dist/mcp/__tests__/bootstrap.test.js +47 -2
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +49 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +2 -0
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +95 -15
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/lifecycle-telemetry.d.ts +16 -0
- package/dist/mcp/lifecycle-telemetry.d.ts.map +1 -0
- package/dist/mcp/lifecycle-telemetry.js +95 -0
- package/dist/mcp/lifecycle-telemetry.js.map +1 -0
- package/dist/pipeline/__tests__/stages.test.js +274 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/team-exec.d.ts +2 -0
- package/dist/pipeline/stages/team-exec.d.ts.map +1 -1
- package/dist/pipeline/stages/team-exec.js +51 -26
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/planning/__tests__/artifacts.test.js +138 -3
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.d.ts +2 -0
- package/dist/planning/__tests__/context-pack-status.test.d.ts.map +1 -0
- package/dist/planning/__tests__/context-pack-status.test.js +271 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -0
- package/dist/planning/artifacts.d.ts +12 -1
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +32 -9
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +42 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -0
- package/dist/planning/context-pack-status.js +479 -0
- package/dist/planning/context-pack-status.js.map +1 -0
- package/dist/runtime/__tests__/process-tree.test.d.ts +2 -0
- package/dist/runtime/__tests__/process-tree.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/process-tree.test.js +107 -0
- package/dist/runtime/__tests__/process-tree.test.js.map +1 -0
- package/dist/runtime/process-tree.d.ts +28 -0
- package/dist/runtime/process-tree.d.ts.map +1 -0
- package/dist/runtime/process-tree.js +230 -0
- package/dist/runtime/process-tree.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +205 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-state-io.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-state-io.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +40 -0
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +111 -7
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +6 -9
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
- package/dist/scripts/notify-hook/process-runner.js +4 -1
- package/dist/scripts/notify-hook/process-runner.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +4 -7
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook.js +25 -3
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/verify-native-agents.d.ts.map +1 -1
- package/dist/scripts/verify-native-agents.js +3 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/sidecar/__tests__/tmux.test.js +1 -1
- package/dist/sidecar/__tests__/tmux.test.js.map +1 -1
- package/dist/sidecar/tmux.js +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +45 -1
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +2 -2
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +2 -2
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +96 -0
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/followup-planner.test.js +16 -0
- package/dist/team/__tests__/followup-planner.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +16 -0
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.js +20 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +16 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +209 -11
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +110 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +9 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +6 -0
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts +13 -0
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +40 -22
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/followup-planner.d.ts +1 -0
- package/dist/team/followup-planner.d.ts.map +1 -1
- package/dist/team/followup-planner.js +9 -9
- package/dist/team/followup-planner.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/model-contract.js +4 -3
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +1 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
- package/dist/team/repo-aware-decomposition.js +5 -1
- package/dist/team/repo-aware-decomposition.js.map +1 -1
- package/dist/team/runtime-cli.d.ts +4 -0
- package/dist/team/runtime-cli.d.ts.map +1 -1
- package/dist/team/runtime-cli.js +14 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +46 -16
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +13 -6
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +7 -0
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +51 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.d.ts +2 -0
- package/dist/ultragoal/__tests__/docs-contract.test.d.ts.map +1 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js +23 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -0
- package/dist/ultragoal/artifacts.d.ts +2 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +37 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +44 -14
- package/dist/verification/__tests__/ci-rust-gates.test.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/ai-slop-cleaner/SKILL.md +9 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +25 -2
- package/plugins/oh-my-codex/skills/plan/SKILL.md +7 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +13 -3
- package/plugins/oh-my-codex/skills/team/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +8 -0
- package/prompts/planner.md +1 -1
- package/skills/ai-slop-cleaner/SKILL.md +9 -0
- package/skills/deep-interview/SKILL.md +25 -2
- package/skills/plan/SKILL.md +7 -4
- package/skills/ralplan/SKILL.md +13 -3
- package/skills/team/SKILL.md +2 -2
- package/skills/visual-ralph/SKILL.md +8 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +231 -1
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/codex-native-hook.ts +129 -14
- package/src/scripts/notify-hook/managed-tmux.ts +6 -7
- package/src/scripts/notify-hook/process-runner.ts +4 -1
- package/src/scripts/notify-hook/state-io.ts +5 -7
- package/src/scripts/notify-hook.ts +26 -3
- package/src/scripts/verify-native-agents.ts +3 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
|
|
3
|
-
import { mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
3
|
+
import { appendFile, mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
4
4
|
import { extname, join, relative, resolve } from "path";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
6
|
import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
7
|
import {
|
|
8
8
|
extractSessionIdFromInitializedStatePath,
|
|
9
|
+
getSkillActiveStatePaths,
|
|
9
10
|
listActiveSkills,
|
|
11
|
+
readSkillActiveState,
|
|
10
12
|
readVisibleSkillActiveState,
|
|
13
|
+
type SkillActiveStateLike,
|
|
11
14
|
} from "../state/skill-active.js";
|
|
12
15
|
import {
|
|
13
16
|
readSubagentSessionSummary,
|
|
@@ -652,6 +655,7 @@ function readParentPid(pid: number): number | null {
|
|
|
652
655
|
const raw = execFileSync("ps", ["-o", "ppid=", "-p", String(pid)], {
|
|
653
656
|
encoding: "utf-8",
|
|
654
657
|
stdio: ["ignore", "pipe", "ignore"],
|
|
658
|
+
windowsHide: true,
|
|
655
659
|
}).trim();
|
|
656
660
|
const ppid = Number.parseInt(raw, 10);
|
|
657
661
|
return Number.isFinite(ppid) && ppid > 0 ? ppid : null;
|
|
@@ -671,6 +675,7 @@ function readProcessCommand(pid: number): string {
|
|
|
671
675
|
return execFileSync("ps", ["-o", "command=", "-p", String(pid)], {
|
|
672
676
|
encoding: "utf-8",
|
|
673
677
|
stdio: ["ignore", "pipe", "ignore"],
|
|
678
|
+
windowsHide: true,
|
|
674
679
|
}).trim();
|
|
675
680
|
} catch {
|
|
676
681
|
return "";
|
|
@@ -1924,6 +1929,87 @@ async function readBlockingSkillForStop(
|
|
|
1924
1929
|
return null;
|
|
1925
1930
|
}
|
|
1926
1931
|
|
|
1932
|
+
function uniqueNonEmpty(values: Array<string | undefined>): string[] {
|
|
1933
|
+
return [...new Set(values.map((value) => safeString(value).trim()).filter(Boolean))];
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
function isTerminalOrInactiveModeState(state: Record<string, unknown> | null): boolean {
|
|
1937
|
+
if (!state) return true;
|
|
1938
|
+
if (state.active !== true) return true;
|
|
1939
|
+
if (getRunContinuationSnapshot(state)?.terminal === true) return true;
|
|
1940
|
+
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1941
|
+
return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
async function readSessionScopedModeStateForRootSkill(
|
|
1945
|
+
cwd: string,
|
|
1946
|
+
skill: string,
|
|
1947
|
+
sessionIds: string[],
|
|
1948
|
+
): Promise<Record<string, unknown> | null> {
|
|
1949
|
+
for (const sessionId of sessionIds) {
|
|
1950
|
+
const state = await readJsonIfExists(getStateFilePath(`${skill}-state.json`, cwd, sessionId));
|
|
1951
|
+
if (state) return state;
|
|
1952
|
+
}
|
|
1953
|
+
return null;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
async function reconcileStaleRootSkillActiveStateForStop(
|
|
1957
|
+
cwd: string,
|
|
1958
|
+
sessionId: string,
|
|
1959
|
+
): Promise<void> {
|
|
1960
|
+
const { rootPath } = getSkillActiveStatePaths(cwd);
|
|
1961
|
+
const rootState = await readSkillActiveState(rootPath);
|
|
1962
|
+
if (!rootState?.active) return;
|
|
1963
|
+
|
|
1964
|
+
const initializedSessionId = extractSessionIdFromInitializedStatePath(rootState.initialized_state_path);
|
|
1965
|
+
const rootSessionIds = uniqueNonEmpty([
|
|
1966
|
+
sessionId,
|
|
1967
|
+
safeString(rootState.session_id),
|
|
1968
|
+
initializedSessionId,
|
|
1969
|
+
...listActiveSkills(rootState).map((entry) => safeString(entry.session_id)),
|
|
1970
|
+
]);
|
|
1971
|
+
if (rootSessionIds.length === 0) return;
|
|
1972
|
+
|
|
1973
|
+
const activeEntries = listActiveSkills(rootState);
|
|
1974
|
+
let changed = false;
|
|
1975
|
+
const keptEntries = [];
|
|
1976
|
+
for (const entry of activeEntries) {
|
|
1977
|
+
const skill = safeString(entry.skill).trim();
|
|
1978
|
+
if (!skill) continue;
|
|
1979
|
+
const entrySessionId = safeString(entry.session_id).trim();
|
|
1980
|
+
const candidateSessionIds = uniqueNonEmpty([
|
|
1981
|
+
entrySessionId,
|
|
1982
|
+
sessionId,
|
|
1983
|
+
initializedSessionId,
|
|
1984
|
+
safeString(rootState.session_id),
|
|
1985
|
+
]);
|
|
1986
|
+
const modeState = await readSessionScopedModeStateForRootSkill(cwd, skill, candidateSessionIds);
|
|
1987
|
+
if (isTerminalOrInactiveModeState(modeState)) {
|
|
1988
|
+
changed = true;
|
|
1989
|
+
continue;
|
|
1990
|
+
}
|
|
1991
|
+
keptEntries.push(entry);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
if (!changed) return;
|
|
1995
|
+
|
|
1996
|
+
const nowIso = new Date().toISOString();
|
|
1997
|
+
const nextRoot: SkillActiveStateLike = {
|
|
1998
|
+
...rootState,
|
|
1999
|
+
active: keptEntries.length > 0,
|
|
2000
|
+
skill: keptEntries[0]?.skill ?? safeString(rootState.skill).trim(),
|
|
2001
|
+
phase: keptEntries[0]?.phase ?? safeString(rootState.phase).trim(),
|
|
2002
|
+
updated_at: nowIso,
|
|
2003
|
+
active_skills: keptEntries,
|
|
2004
|
+
reconciled_at: nowIso,
|
|
2005
|
+
reconciliation_reason: "stop_hook_session_state_terminal",
|
|
2006
|
+
};
|
|
2007
|
+
if (keptEntries.length === 0) {
|
|
2008
|
+
nextRoot.phase = "inactive";
|
|
2009
|
+
}
|
|
2010
|
+
await writeFile(rootPath, JSON.stringify(nextRoot, null, 2));
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1927
2013
|
function buildRalplanContinuationStatus(
|
|
1928
2014
|
blocker: { phase: string; latestPlanPath?: string; planningComplete?: boolean; runOutcome?: string },
|
|
1929
2015
|
activeSubagentCount: number,
|
|
@@ -2446,6 +2532,9 @@ async function buildStopHookOutput(
|
|
|
2446
2532
|
const sessionId = readPayloadSessionId(payload);
|
|
2447
2533
|
const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
2448
2534
|
const threadId = readPayloadThreadId(payload);
|
|
2535
|
+
if (canonicalSessionId) {
|
|
2536
|
+
await reconcileStaleRootSkillActiveStateForStop(cwd, canonicalSessionId);
|
|
2537
|
+
}
|
|
2449
2538
|
const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
|
|
2450
2539
|
if (execFollowupOutput) return execFollowupOutput;
|
|
2451
2540
|
const ralphState = options.skipRalphStopBlock === true
|
|
@@ -3002,12 +3091,40 @@ function writeNativeHookJsonStdout(output: Record<string, unknown>): void {
|
|
|
3002
3091
|
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
3003
3092
|
}
|
|
3004
3093
|
|
|
3094
|
+
async function logNativeHookCliError(
|
|
3095
|
+
cwd: string,
|
|
3096
|
+
type: string,
|
|
3097
|
+
error: unknown,
|
|
3098
|
+
payload: CodexHookPayload = {},
|
|
3099
|
+
): Promise<void> {
|
|
3100
|
+
const logsDir = join(cwd || process.cwd(), ".omx", "logs");
|
|
3101
|
+
await mkdir(logsDir, { recursive: true }).catch(() => {});
|
|
3102
|
+
const logPath = join(logsDir, `native-hook-${new Date().toISOString().split("T")[0]}.jsonl`);
|
|
3103
|
+
await appendFile(
|
|
3104
|
+
logPath,
|
|
3105
|
+
JSON.stringify({
|
|
3106
|
+
timestamp: new Date().toISOString(),
|
|
3107
|
+
type,
|
|
3108
|
+
hook_event_name: readHookEventName(payload) ?? "Unknown",
|
|
3109
|
+
session_id: readPayloadSessionId(payload) || undefined,
|
|
3110
|
+
thread_id: readPayloadThreadId(payload) || undefined,
|
|
3111
|
+
turn_id: readPayloadTurnId(payload) || undefined,
|
|
3112
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3113
|
+
}) + "\n",
|
|
3114
|
+
).catch(() => {});
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3005
3117
|
function isStopDispatchFailureTestTrigger(payload: CodexHookPayload): boolean {
|
|
3006
3118
|
return process.env.NODE_ENV === "test"
|
|
3007
3119
|
&& process.env.OMX_NATIVE_HOOK_TEST_THROW_STOP_DISPATCH === "1"
|
|
3008
3120
|
&& readHookEventName(payload) === "Stop";
|
|
3009
3121
|
}
|
|
3010
3122
|
|
|
3123
|
+
function isDispatchFailureTestTrigger(): boolean {
|
|
3124
|
+
return process.env.NODE_ENV === "test"
|
|
3125
|
+
&& process.env.OMX_NATIVE_HOOK_TEST_THROW_DISPATCH === "1";
|
|
3126
|
+
}
|
|
3127
|
+
|
|
3011
3128
|
function buildStopDispatchFailureOutput(error: unknown): Record<string, unknown> {
|
|
3012
3129
|
const detail = error instanceof Error ? error.message : String(error);
|
|
3013
3130
|
const reason =
|
|
@@ -3023,6 +3140,7 @@ function buildStopDispatchFailureOutput(error: unknown): Record<string, unknown>
|
|
|
3023
3140
|
export async function runCodexNativeHookCli(): Promise<void> {
|
|
3024
3141
|
const { payload, parseError } = await readStdinJson();
|
|
3025
3142
|
if (parseError) {
|
|
3143
|
+
await logNativeHookCliError(process.cwd(), "native_hook_stdin_parse_error", parseError);
|
|
3026
3144
|
writeNativeHookJsonStdout({
|
|
3027
3145
|
decision: "block",
|
|
3028
3146
|
reason: "OMX native hook received malformed JSON input. Preserve runtime state, inspect the emitting hook payload yourself, and retry with valid JSON.",
|
|
@@ -3039,6 +3157,9 @@ export async function runCodexNativeHookCli(): Promise<void> {
|
|
|
3039
3157
|
if (isStopDispatchFailureTestTrigger(payload)) {
|
|
3040
3158
|
throw new Error("test-induced Stop dispatch failure");
|
|
3041
3159
|
}
|
|
3160
|
+
if (isDispatchFailureTestTrigger()) {
|
|
3161
|
+
throw new Error("test-induced dispatch failure");
|
|
3162
|
+
}
|
|
3042
3163
|
|
|
3043
3164
|
const result = await dispatchCodexNativeHook(payload);
|
|
3044
3165
|
if (result.outputJson) {
|
|
@@ -3047,25 +3168,19 @@ export async function runCodexNativeHookCli(): Promise<void> {
|
|
|
3047
3168
|
writeNativeHookJsonStdout({});
|
|
3048
3169
|
}
|
|
3049
3170
|
} catch (error) {
|
|
3050
|
-
|
|
3051
|
-
|
|
3171
|
+
const cwd = safeString(payload.cwd).trim() || process.cwd();
|
|
3172
|
+
await logNativeHookCliError(cwd, "native_hook_dispatch_error", error, payload);
|
|
3173
|
+
if (readHookEventName(payload) === "Stop") {
|
|
3174
|
+
writeNativeHookJsonStdout(buildStopDispatchFailureOutput(error));
|
|
3175
|
+
} else {
|
|
3176
|
+
process.exitCode = 1;
|
|
3052
3177
|
}
|
|
3053
|
-
process.stderr.write(
|
|
3054
|
-
`[omx] codex-native Stop hook dispatch failed: ${
|
|
3055
|
-
error instanceof Error ? error.message : String(error)
|
|
3056
|
-
}\n`,
|
|
3057
|
-
);
|
|
3058
|
-
writeNativeHookJsonStdout(buildStopDispatchFailureOutput(error));
|
|
3059
3178
|
}
|
|
3060
3179
|
}
|
|
3061
3180
|
|
|
3062
3181
|
if (isCodexNativeHookMainModule(import.meta.url, process.argv[1])) {
|
|
3063
3182
|
runCodexNativeHookCli().catch((error) => {
|
|
3064
|
-
process.stderr.write(
|
|
3065
|
-
`[omx] codex-native-hook failed: ${
|
|
3066
|
-
error instanceof Error ? error.message : String(error)
|
|
3067
|
-
}\n`,
|
|
3068
|
-
);
|
|
3069
3183
|
process.exitCode = 1;
|
|
3184
|
+
void logNativeHookCliError(process.cwd(), "native_hook_fatal_error", error);
|
|
3070
3185
|
});
|
|
3071
3186
|
}
|
|
@@ -75,6 +75,7 @@ function readCurrentTmuxSessionName(): string {
|
|
|
75
75
|
encoding: 'utf-8',
|
|
76
76
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
77
77
|
timeout: 2000,
|
|
78
|
+
windowsHide: true,
|
|
78
79
|
}).trim();
|
|
79
80
|
} catch {
|
|
80
81
|
return '';
|
|
@@ -104,13 +105,10 @@ async function readTmuxPaneInstanceId(paneTarget: string): Promise<string> {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
function warnPaneInstanceFallback(paneTarget: string): void {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
} catch {
|
|
112
|
-
// warning is best effort only
|
|
113
|
-
}
|
|
108
|
+
// Notify hooks run inside Codex foreground hook surfaces. Keep this
|
|
109
|
+
// compatibility fallback silent; downstream tmux-hook events still record
|
|
110
|
+
// skipped/failed injection decisions in .omx/logs.
|
|
111
|
+
void paneTarget;
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
export async function resolveTmuxSessionForInstance(instanceId: string): Promise<string> {
|
|
@@ -146,6 +144,7 @@ function readParentPid(pid: number): number | null {
|
|
|
146
144
|
const raw = execFileSync('ps', ['-o', 'ppid=', '-p', String(pid)], {
|
|
147
145
|
encoding: 'utf-8',
|
|
148
146
|
timeout: 2000,
|
|
147
|
+
windowsHide: true,
|
|
149
148
|
}).trim();
|
|
150
149
|
const ppid = Number(raw);
|
|
151
150
|
return Number.isFinite(ppid) && ppid > 0 ? ppid : null;
|
|
@@ -10,7 +10,10 @@ export function runProcess(command: string, args: string[], timeoutMs = 3000): P
|
|
|
10
10
|
const relaxingTestTmuxTimeout = command === 'tmux' && process.env.OMX_TEST_RELAX_TMUX_TIMEOUT === '1';
|
|
11
11
|
const executable = usingTestTmux ? process.env.OMX_TEST_TMUX_BIN as string : command;
|
|
12
12
|
const effectiveTimeoutMs = usingTestTmux || relaxingTestTmuxTimeout ? Math.max(timeoutMs, 10_000) : timeoutMs;
|
|
13
|
-
const child = spawn(executable, args, {
|
|
13
|
+
const child = spawn(executable, args, {
|
|
14
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
15
|
+
windowsHide: true,
|
|
16
|
+
});
|
|
14
17
|
let stdout = '';
|
|
15
18
|
let stderr = '';
|
|
16
19
|
let finished = false;
|
|
@@ -52,18 +52,16 @@ export async function resolveScopedStateDir(
|
|
|
52
52
|
baseStateDir: string,
|
|
53
53
|
explicitSessionId?: string,
|
|
54
54
|
): Promise<string> {
|
|
55
|
+
const normalizedExplicit = safeString(explicitSessionId).trim();
|
|
56
|
+
if (SESSION_ID_PATTERN.test(normalizedExplicit)) {
|
|
57
|
+
return join(baseStateDir, 'sessions', normalizedExplicit);
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
const currentSessionId = await readCurrentSessionId(baseStateDir);
|
|
56
61
|
if (currentSessionId) {
|
|
57
62
|
return join(baseStateDir, 'sessions', currentSessionId);
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
const normalizedExplicit = safeString(explicitSessionId).trim();
|
|
61
|
-
if (SESSION_ID_PATTERN.test(normalizedExplicit)) {
|
|
62
|
-
const explicitDir = join(baseStateDir, 'sessions', normalizedExplicit);
|
|
63
|
-
if (existsSync(explicitDir)) {
|
|
64
|
-
return explicitDir;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
65
|
return baseStateDir;
|
|
68
66
|
}
|
|
69
67
|
|
|
@@ -771,8 +771,31 @@ async function main() {
|
|
|
771
771
|
}
|
|
772
772
|
}
|
|
773
773
|
|
|
774
|
+
async function logFatalNotifyHookError(err: unknown): Promise<void> {
|
|
775
|
+
let cwd = process.cwd();
|
|
776
|
+
try {
|
|
777
|
+
const rawPayload = process.argv[process.argv.length - 1];
|
|
778
|
+
if (rawPayload && !rawPayload.startsWith('-')) {
|
|
779
|
+
const payload = JSON.parse(rawPayload) as Record<string, unknown>;
|
|
780
|
+
cwd = safeString(payload.cwd || payload['cwd'] || cwd) || cwd;
|
|
781
|
+
}
|
|
782
|
+
} catch {
|
|
783
|
+
// Keep notification hook failures silent in Codex TUI surfaces.
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const logsDir = join(cwd, '.omx', 'logs');
|
|
787
|
+
await mkdir(logsDir, { recursive: true }).catch(() => {});
|
|
788
|
+
const logPath = join(logsDir, `notify-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
|
|
789
|
+
await appendFile(logPath, JSON.stringify({
|
|
790
|
+
timestamp: new Date().toISOString(),
|
|
791
|
+
type: 'notify_hook_fatal_error',
|
|
792
|
+
error: err instanceof Error ? err.message : String(err),
|
|
793
|
+
}) + '\n').catch(() => {});
|
|
794
|
+
}
|
|
795
|
+
|
|
774
796
|
main().catch((err) => {
|
|
775
|
-
|
|
776
|
-
//
|
|
777
|
-
|
|
797
|
+
// Notify hooks are auxiliary background work. Avoid printing stack traces into
|
|
798
|
+
// Codex TUI/PowerShell foreground panes; record diagnostics in .omx/logs.
|
|
799
|
+
process.exitCode = 0;
|
|
800
|
+
void logFatalNotifyHookError(err);
|
|
778
801
|
});
|
|
@@ -188,7 +188,9 @@ export async function verifyNativeAgents(
|
|
|
188
188
|
const promptContent = options.promptNames
|
|
189
189
|
? `${name} prompt fixture`
|
|
190
190
|
: await readFile(promptPath, "utf-8");
|
|
191
|
-
const toml = generateAgentToml(agent, promptContent
|
|
191
|
+
const toml = generateAgentToml(agent, promptContent, {
|
|
192
|
+
codexHomeOverride: join(root, ".omx", "verify-native-agents-codex-home"),
|
|
193
|
+
});
|
|
192
194
|
assertTomlStructure(name, agent, toml);
|
|
193
195
|
}
|
|
194
196
|
|