oh-my-codex 0.18.13 → 0.18.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +41 -18
- package/dist/agents/__tests__/native-config.test.js +62 -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 +15 -2
- package/dist/agents/native-config.js.map +1 -1
- package/dist/autopilot/__tests__/fsm.test.js +7 -0
- package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
- package/dist/autopilot/__tests__/planner-routing.test.d.ts +2 -0
- package/dist/autopilot/__tests__/planner-routing.test.d.ts.map +1 -0
- package/dist/autopilot/__tests__/planner-routing.test.js +74 -0
- package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js +315 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +2 -2
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autopilot/fsm.js +3 -0
- package/dist/autopilot/fsm.js.map +1 -1
- package/dist/autopilot/planner-routing.d.ts +21 -0
- package/dist/autopilot/planner-routing.d.ts.map +1 -0
- package/dist/autopilot/planner-routing.js +59 -0
- package/dist/autopilot/planner-routing.js.map +1 -0
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +30 -0
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/autoresearch/goal.d.ts.map +1 -1
- package/dist/autoresearch/goal.js +10 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js +33 -0
- package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +3 -0
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js +158 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.js +33 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js +13 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +132 -2
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +5 -0
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +40 -0
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +4 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +7 -1
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/performance-goal.test.js +22 -0
- package/dist/cli/__tests__/performance-goal.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts +2 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts.map +1 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +64 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +96 -0
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +162 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js +36 -0
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +70 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +33 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +17 -3
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +37 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +81 -2
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.d.ts +2 -0
- package/dist/cli/__tests__/url.test.d.ts.map +1 -0
- package/dist/cli/__tests__/url.test.js +82 -0
- package/dist/cli/__tests__/url.test.js.map +1 -0
- package/dist/cli/autoresearch-goal.d.ts.map +1 -1
- package/dist/cli/autoresearch-goal.js +2 -1
- package/dist/cli/autoresearch-goal.js.map +1 -1
- package/dist/cli/autoresearch-intake.d.ts.map +1 -1
- package/dist/cli/autoresearch-intake.js +2 -0
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/doctor.d.ts +39 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +460 -40
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +71 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/performance-goal.d.ts.map +1 -1
- package/dist/cli/performance-goal.js +4 -2
- package/dist/cli/performance-goal.js.map +1 -1
- 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 +88 -67
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.d.ts +2 -0
- package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js +112 -5
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +15 -6
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +5 -1
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +23 -4
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.d.ts +8 -0
- package/dist/cli/url.d.ts.map +1 -0
- package/dist/cli/url.js +69 -0
- package/dist/cli/url.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +20 -4
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +21 -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 +1 -4
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/models.d.ts +5 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +23 -0
- package/dist/config/models.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +2 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +10 -0
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +7 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +46 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +100 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +75 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +225 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +75 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +563 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +187 -12
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +225 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +75 -0
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +4 -0
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +137 -2
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +107 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +17 -0
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +21 -7
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +9 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +43 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +6 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +24 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +53 -0
- package/dist/mcp/__tests__/state-paths.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 +32 -6
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +11 -5
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-autopilot-gates.test.js +48 -0
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +1 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/http-client.test.js +9 -0
- package/dist/notifications/__tests__/http-client.test.js.map +1 -1
- package/dist/notifications/http-client.js +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/performance-goal/artifacts.d.ts.map +1 -1
- package/dist/performance-goal/artifacts.js +10 -1
- package/dist/performance-goal/artifacts.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +112 -0
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +133 -21
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +1251 -13
- 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 +601 -24
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +1 -0
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +279 -86
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +87 -8
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/run-compiled-ci.d.ts +2 -0
- package/dist/scripts/run-compiled-ci.d.ts.map +1 -0
- package/dist/scripts/run-compiled-ci.js +77 -0
- package/dist/scripts/run-compiled-ci.js.map +1 -0
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +1 -0
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/session-history/search.d.ts.map +1 -1
- package/dist/session-history/search.js +24 -9
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/args.test.d.ts +2 -0
- package/dist/sidecar/__tests__/args.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/args.test.js +18 -0
- package/dist/sidecar/__tests__/args.test.js.map +1 -0
- package/dist/sidecar/index.d.ts.map +1 -1
- package/dist/sidecar/index.js +12 -4
- package/dist/sidecar/index.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +107 -3
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +57 -2
- package/dist/state/operations.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +22 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +57 -1
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +1468 -110
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +63 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +24 -1
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +512 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +42 -9
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/model-contract.d.ts +16 -0
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +41 -1
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +116 -30
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +9 -1
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/types.d.ts +2 -0
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state.d.ts +3 -0
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +20 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +38 -3
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +275 -36
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +26 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +388 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +3 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +23 -0
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +275 -12
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/__tests__/url-reader.test.d.ts +2 -0
- package/dist/url-reader/__tests__/url-reader.test.d.ts.map +1 -0
- package/dist/url-reader/__tests__/url-reader.test.js +433 -0
- package/dist/url-reader/__tests__/url-reader.test.js.map +1 -0
- package/dist/url-reader/index.d.ts +4 -0
- package/dist/url-reader/index.d.ts.map +1 -0
- package/dist/url-reader/index.js +522 -0
- package/dist/url-reader/index.js.map +1 -0
- package/dist/url-reader/types.d.ts +41 -0
- package/dist/url-reader/types.d.ts.map +1 -0
- package/dist/url-reader/types.js +2 -0
- package/dist/url-reader/types.js.map +1 -0
- package/dist/utils/__tests__/agents-md.test.js +39 -1
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/__tests__/agents-model-table.test.js +28 -0
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts +4 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +28 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/utils/agents-model-table.d.ts +7 -3
- package/dist/utils/agents-model-table.d.ts.map +1 -1
- package/dist/utils/agents-model-table.js +16 -8
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/platform-command.d.ts +7 -1
- package/dist/utils/platform-command.d.ts.map +1 -1
- package/dist/utils/platform-command.js +12 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +4 -0
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/vscode/__tests__/index.test.d.ts +2 -0
- package/dist/vscode/__tests__/index.test.d.ts.map +1 -0
- package/dist/vscode/__tests__/index.test.js +236 -0
- package/dist/vscode/__tests__/index.test.js.map +1 -0
- package/dist/vscode/index.d.ts +76 -0
- package/dist/vscode/index.d.ts.map +1 -0
- package/dist/vscode/index.js +196 -0
- package/dist/vscode/index.js.map +1 -0
- package/package.json +3 -3
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +59 -8
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +9 -5
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +22 -4
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +61 -0
- package/skills/autopilot/SKILL.md +9 -5
- package/skills/autoresearch-goal/SKILL.md +3 -0
- package/skills/ecomode/SKILL.md +1 -1
- package/skills/ecomode/references/agent-tiers.md +61 -0
- package/skills/performance-goal/SKILL.md +3 -0
- package/skills/ralplan/SKILL.md +1 -1
- package/skills/ultragoal/SKILL.md +22 -4
- package/skills/ultrawork/SKILL.md +2 -2
- package/skills/ultrawork/references/agent-tiers.md +61 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +1560 -181
- package/src/scripts/codex-native-hook.ts +663 -24
- package/src/scripts/notify-hook/team-leader-nudge.ts +298 -91
- package/src/scripts/notify-hook/team-tmux-guard.ts +92 -8
- package/src/scripts/notify-hook/tmux-injection.ts +1 -1
- package/src/scripts/run-compiled-ci.ts +85 -0
- package/src/scripts/sync-plugin-mirror.ts +1 -0
- package/templates/AGENTS.md +6 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { appendFile, mkdir, open, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
|
-
import { formatCodexGoalReconciliation, parseCodexGoalSnapshot, reconcileCodexGoalSnapshot, } from '../goal-workflows/codex-goal-snapshot.js';
|
|
4
|
+
import { formatCodexGoalReconciliation, buildCompletedCodexGoalRemediation, parseCodexGoalSnapshot, reconcileCodexGoalSnapshot, } from '../goal-workflows/codex-goal-snapshot.js';
|
|
5
5
|
export const ULTRAGOAL_DIR = '.omx/ultragoal';
|
|
6
6
|
export const ULTRAGOAL_BRIEF = 'brief.md';
|
|
7
7
|
export const ULTRAGOAL_GOALS = 'goals.json';
|
|
@@ -207,6 +207,22 @@ async function snapshotObjectiveMapsToUltragoalPlan(cwd, snapshotObjective) {
|
|
|
207
207
|
return false;
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
+
function unresolvedReviewBlockedGoals(plan) {
|
|
211
|
+
return plan.goals.filter((candidate) => candidate.status === 'review_blocked' && !isReviewBlockedResolved(candidate, plan));
|
|
212
|
+
}
|
|
213
|
+
function isDesignatedReviewBlockerResolver(goal, parent) {
|
|
214
|
+
return parent?.status === 'review_blocked'
|
|
215
|
+
&& goal.resolvesReviewBlockedGoalId === parent.id
|
|
216
|
+
&& parent.reviewBlockerResolution?.resolverGoalId === goal.id;
|
|
217
|
+
}
|
|
218
|
+
function canUseCleanFinalResolverPathForReviewBlockedParent(plan, goal, finalRunCheckpoint, allowActiveFinalCodexGoal) {
|
|
219
|
+
const unresolvedReviewBlocked = unresolvedReviewBlockedGoals(plan);
|
|
220
|
+
if (unresolvedReviewBlocked.length !== 1)
|
|
221
|
+
return false;
|
|
222
|
+
return finalRunCheckpoint
|
|
223
|
+
&& !allowActiveFinalCodexGoal
|
|
224
|
+
&& isDesignatedReviewBlockerResolver(goal, unresolvedReviewBlocked[0]);
|
|
225
|
+
}
|
|
210
226
|
async function canReconcileCompletedTaskScopedAggregateSnapshot(cwd, plan, goal, snapshotObjective, evidence) {
|
|
211
227
|
if (codexGoalMode(plan) !== 'aggregate')
|
|
212
228
|
return false;
|
|
@@ -295,16 +311,29 @@ function isSupersededResolved(goal, plan) {
|
|
|
295
311
|
return replacement !== undefined && isResolvedStatus(replacement.status);
|
|
296
312
|
});
|
|
297
313
|
}
|
|
314
|
+
function isReviewBlockedResolved(goal, plan) {
|
|
315
|
+
if (goal.status !== 'review_blocked')
|
|
316
|
+
return false;
|
|
317
|
+
const resolverId = goal.reviewBlockerResolution?.resolverGoalId;
|
|
318
|
+
if (!resolverId || goal.reviewBlockerResolution?.status !== 'complete')
|
|
319
|
+
return false;
|
|
320
|
+
const resolver = plan.goals.find((candidate) => candidate.id === resolverId);
|
|
321
|
+
return resolver?.status === 'complete';
|
|
322
|
+
}
|
|
298
323
|
function isCompletionBlocking(goal, plan) {
|
|
299
324
|
if (goal.steeringStatus === 'superseded')
|
|
300
325
|
return !isSupersededResolved(goal, plan);
|
|
301
326
|
if (goal.steeringStatus === 'blocked')
|
|
302
327
|
return true;
|
|
328
|
+
if (goal.status === 'review_blocked')
|
|
329
|
+
return !isReviewBlockedResolved(goal, plan);
|
|
303
330
|
return !isResolvedStatus(goal.status);
|
|
304
331
|
}
|
|
305
332
|
function isCompletionBlockingForFinalCandidate(candidate, finalCandidate, plan) {
|
|
306
333
|
if (candidate.id === finalCandidate.id)
|
|
307
334
|
return false;
|
|
335
|
+
if (candidate.status === 'review_blocked' && candidate.reviewBlockerResolution?.resolverGoalId === finalCandidate.id)
|
|
336
|
+
return false;
|
|
308
337
|
if (candidate.steeringStatus === 'superseded') {
|
|
309
338
|
const replacements = candidate.supersededBy ?? [];
|
|
310
339
|
if (replacements.length === 0)
|
|
@@ -488,13 +517,15 @@ export async function createUltragoalPlan(cwd, options) {
|
|
|
488
517
|
});
|
|
489
518
|
}
|
|
490
519
|
export function summarizeUltragoalPlan(plan) {
|
|
520
|
+
const activeReviewBlocked = plan.goals.filter((goal) => goal.status === 'review_blocked' && !isReviewBlockedResolved(goal, plan)).length;
|
|
491
521
|
return {
|
|
492
522
|
total: plan.goals.length,
|
|
493
523
|
pending: plan.goals.filter((goal) => goal.status === 'pending').length,
|
|
494
524
|
inProgress: plan.goals.filter((goal) => goal.status === 'in_progress').length,
|
|
495
525
|
complete: plan.goals.filter((goal) => goal.status === 'complete').length,
|
|
496
526
|
failed: plan.goals.filter((goal) => goal.status === 'failed').length,
|
|
497
|
-
reviewBlocked:
|
|
527
|
+
reviewBlocked: activeReviewBlocked,
|
|
528
|
+
historicalReviewBlocked: plan.goals.filter((goal) => goal.status === 'review_blocked').length - activeReviewBlocked,
|
|
498
529
|
needsUserDecision: plan.goals.filter((goal) => goal.status === 'needs_user_decision').length,
|
|
499
530
|
superseded: plan.goals.filter((goal) => goal.steeringStatus === 'superseded').length,
|
|
500
531
|
steeringBlocked: plan.goals.filter((goal) => goal.steeringStatus === 'blocked').length,
|
|
@@ -548,6 +579,7 @@ function appendGoalToPlan(plan, options, nowOverride) {
|
|
|
548
579
|
createdAt: now,
|
|
549
580
|
updatedAt: now,
|
|
550
581
|
evidence: options.evidence,
|
|
582
|
+
resolvesReviewBlockedGoalId: options.resolvesReviewBlockedGoalId,
|
|
551
583
|
};
|
|
552
584
|
plan.goals.push(goal);
|
|
553
585
|
plan.updatedAt = now;
|
|
@@ -909,9 +941,160 @@ export async function steerUltragoal(cwd, proposal, options = {}) {
|
|
|
909
941
|
return { plan, accepted: invariant.accepted, audit, rejectedReasons: invariant.rejectedReasons, deduped: false };
|
|
910
942
|
});
|
|
911
943
|
}
|
|
912
|
-
function
|
|
944
|
+
function normalizeInvariantText(value) {
|
|
945
|
+
return value.replace(/[`*_~]/g, '').replace(/\s+/g, ' ').trim().toLowerCase();
|
|
946
|
+
}
|
|
947
|
+
function requiredInvariantSourceKey(invariant) {
|
|
948
|
+
return `${normalizeInvariantText(invariant.invariant)}\u0000${invariant.sourceArtifact}`;
|
|
949
|
+
}
|
|
950
|
+
function uniqueRequiredArchitectureInvariants(invariants) {
|
|
951
|
+
const seen = new Set();
|
|
952
|
+
const unique = [];
|
|
953
|
+
for (const invariant of invariants) {
|
|
954
|
+
const key = requiredInvariantSourceKey(invariant);
|
|
955
|
+
if (seen.has(key))
|
|
956
|
+
continue;
|
|
957
|
+
seen.add(key);
|
|
958
|
+
unique.push(invariant);
|
|
959
|
+
}
|
|
960
|
+
return unique;
|
|
961
|
+
}
|
|
962
|
+
function architectureInvariantSectionSlug(label) {
|
|
963
|
+
return label
|
|
964
|
+
.replace(/[`*_~]/g, '')
|
|
965
|
+
.toLowerCase()
|
|
966
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
967
|
+
.replace(/^-|-$/g, '') || 'architecture-invariants';
|
|
968
|
+
}
|
|
969
|
+
function normalizeSourceArtifact(value) {
|
|
970
|
+
return value.trim().split('#', 1)[0]?.replace(/\\/g, '/') ?? '';
|
|
971
|
+
}
|
|
972
|
+
function sourceReferencesArtifact(source, artifact) {
|
|
973
|
+
return normalizeSourceArtifact(source) === normalizeSourceArtifact(artifact);
|
|
974
|
+
}
|
|
975
|
+
function sourceReferencesAnyArtifact(source, artifacts) {
|
|
976
|
+
return artifacts.some((artifact) => sourceReferencesArtifact(source, artifact));
|
|
977
|
+
}
|
|
978
|
+
function invariantFromInlineDeclaration(line) {
|
|
979
|
+
const trimmed = cleanLine(line).replace(/^['"]|['"]$/g, '').trim();
|
|
980
|
+
const match = /\b(?:(?:non-negotiable|required)\s+)?(?:architecture|architectural|domain)\s+(?:invariants?|constraints?|non-negotiables?)\s*:\s*(.+)$/i.exec(trimmed)
|
|
981
|
+
?? /\bnon-negotiables?\s+(?:architecture|architectural|domain)\s+(?:invariants?|constraints?)\s*:\s*(.+)$/i.exec(trimmed);
|
|
982
|
+
const invariant = match?.[1]?.trim().replace(/[.;]\s*$/, '').trim();
|
|
983
|
+
return invariant || undefined;
|
|
984
|
+
}
|
|
985
|
+
function extractArchitectureInvariantsFromArtifact(text, sourceArtifact, sourcePrefix) {
|
|
986
|
+
const lines = text.split(/\r?\n/);
|
|
987
|
+
const invariants = [];
|
|
988
|
+
let inInvariantSection = false;
|
|
989
|
+
let sectionSlug = 'architecture-invariants';
|
|
990
|
+
for (const line of lines) {
|
|
991
|
+
const heading = line.match(/^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
992
|
+
if (heading) {
|
|
993
|
+
const label = heading[1] ?? '';
|
|
994
|
+
const normalizedLabel = label.toLowerCase();
|
|
995
|
+
inInvariantSection = /\b(?:architecture|architectural|domain|non-negotiable)\b/.test(normalizedLabel) && /\binvariants?\b|\bconstraints?\b|\bnon-negotiables?\b/.test(normalizedLabel);
|
|
996
|
+
if (inInvariantSection)
|
|
997
|
+
sectionSlug = architectureInvariantSectionSlug(label);
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
const inline = invariantFromInlineDeclaration(line);
|
|
1001
|
+
if (inline) {
|
|
1002
|
+
invariants.push({ invariant: inline, sourceArtifact, source: `${sourceArtifact}#${sourcePrefix ?? 'inline-architecture-invariant'}` });
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (!inInvariantSection)
|
|
1006
|
+
continue;
|
|
1007
|
+
const item = cleanLine(line);
|
|
1008
|
+
if (!item || item === line.trim())
|
|
1009
|
+
continue;
|
|
1010
|
+
invariants.push({ invariant: item, sourceArtifact, source: `${sourceArtifact}#${sourcePrefix ? `${sourcePrefix}-${sectionSlug}` : sectionSlug}` });
|
|
1011
|
+
}
|
|
1012
|
+
return uniqueRequiredArchitectureInvariants(invariants.map((item) => ({ ...item, invariant: item.invariant.trim() })).filter((item) => item.invariant));
|
|
1013
|
+
}
|
|
1014
|
+
function extractArchitectureInvariantsFromBrief(brief) {
|
|
1015
|
+
return extractArchitectureInvariantsFromArtifact(brief, `${ULTRAGOAL_DIR}/${ULTRAGOAL_BRIEF}`);
|
|
1016
|
+
}
|
|
1017
|
+
function extractArchitectureInvariantsFromAcceptedSteering(entries) {
|
|
1018
|
+
const invariants = [];
|
|
1019
|
+
for (const [index, entry] of entries.entries()) {
|
|
1020
|
+
if (entry.event !== 'steering_accepted' || !entry.steering?.invariant.accepted)
|
|
1021
|
+
continue;
|
|
1022
|
+
const sourcePrefix = `steering-${index + 1}`;
|
|
1023
|
+
const steering = entry.steering;
|
|
1024
|
+
const texts = [
|
|
1025
|
+
entry.evidence,
|
|
1026
|
+
entry.message,
|
|
1027
|
+
steering.evidence,
|
|
1028
|
+
steering.rationale,
|
|
1029
|
+
steering.directiveText,
|
|
1030
|
+
].filter((value) => typeof value === 'string' && value.trim().length > 0);
|
|
1031
|
+
for (const text of texts) {
|
|
1032
|
+
invariants.push(...extractArchitectureInvariantsFromArtifact(text, `${ULTRAGOAL_DIR}/${ULTRAGOAL_LEDGER}`, sourcePrefix));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return uniqueRequiredArchitectureInvariants(invariants);
|
|
1036
|
+
}
|
|
1037
|
+
async function collectRequiredArchitectureInvariants(cwd) {
|
|
1038
|
+
const briefInvariants = extractArchitectureInvariantsFromBrief(await readFile(ultragoalBriefPath(cwd), 'utf-8'));
|
|
1039
|
+
const steeringInvariants = extractArchitectureInvariantsFromAcceptedSteering(await readSteeringLedgerEntries(cwd));
|
|
1040
|
+
return uniqueRequiredArchitectureInvariants([...briefInvariants, ...steeringInvariants]);
|
|
1041
|
+
}
|
|
1042
|
+
function validateArchitectureInvariantGate(gate, requiredInvariants) {
|
|
1043
|
+
const invariantGate = gate.architectureInvariantGate;
|
|
1044
|
+
if (!invariantGate || typeof invariantGate !== 'object') {
|
|
1045
|
+
throw new UltragoalError('Final quality gate is missing architectureInvariantGate evidence; include derived architecture/domain invariants, source artifacts, implementation/test/review evidence, or record final blockers for unproved invariants.');
|
|
1046
|
+
}
|
|
1047
|
+
if (invariantGate.status !== 'passed') {
|
|
1048
|
+
throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.status="passed"; record blocker-resolution work for unproved invariants.');
|
|
1049
|
+
}
|
|
1050
|
+
if (!Array.isArray(invariantGate.sourceArtifacts)) {
|
|
1051
|
+
throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.sourceArtifacts.');
|
|
1052
|
+
}
|
|
1053
|
+
const sourceArtifacts = invariantGate.sourceArtifacts.map((source) => assertNonEmpty(source, 'architectureInvariantGate.sourceArtifacts[]'));
|
|
1054
|
+
for (const required of requiredInvariants) {
|
|
1055
|
+
if (!sourceArtifacts.some((source) => sourceReferencesArtifact(source, required.sourceArtifact))) {
|
|
1056
|
+
throw new UltragoalError(`Final architecture-invariant gate sourceArtifacts must include required invariant source artifact: ${required.sourceArtifact}`);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
assertNonEmpty(invariantGate.evidence, 'architectureInvariantGate.evidence');
|
|
1060
|
+
if (!Array.isArray(invariantGate.invariants)) {
|
|
1061
|
+
throw new UltragoalError('Final architecture-invariant gate requires architectureInvariantGate.invariants.');
|
|
1062
|
+
}
|
|
1063
|
+
const provided = new Map();
|
|
1064
|
+
for (const invariant of invariantGate.invariants) {
|
|
1065
|
+
if (!invariant || typeof invariant !== 'object')
|
|
1066
|
+
throw new UltragoalError('Final architecture-invariant gate invariants must be objects.');
|
|
1067
|
+
const record = invariant;
|
|
1068
|
+
const text = assertNonEmpty(record.invariant, 'architectureInvariantGate.invariants[].invariant');
|
|
1069
|
+
const source = assertNonEmpty(record.source, 'architectureInvariantGate.invariants[].source');
|
|
1070
|
+
if (!sourceReferencesAnyArtifact(source, sourceArtifacts)) {
|
|
1071
|
+
throw new UltragoalError(`Final architecture invariant "${text}" source must reference one of architectureInvariantGate.sourceArtifacts; decorative provenance labels are not sufficient.`);
|
|
1072
|
+
}
|
|
1073
|
+
if (record.status !== 'proved')
|
|
1074
|
+
throw new UltragoalError(`Final architecture invariant "${text}" is not proved; record blocker-resolution work before final completion.`);
|
|
1075
|
+
if (record.blockers !== undefined)
|
|
1076
|
+
throw new UltragoalError(`Final architecture invariant "${text}" has blockers; record blocker-resolution work before final completion.`);
|
|
1077
|
+
assertNonEmpty(record.implementationEvidence, 'architectureInvariantGate.invariants[].implementationEvidence');
|
|
1078
|
+
assertNonEmpty(record.testEvidence, 'architectureInvariantGate.invariants[].testEvidence');
|
|
1079
|
+
assertNonEmpty(record.reviewEvidence, 'architectureInvariantGate.invariants[].reviewEvidence');
|
|
1080
|
+
const key = normalizeInvariantText(text);
|
|
1081
|
+
const records = provided.get(key) ?? [];
|
|
1082
|
+
records.push(record);
|
|
1083
|
+
provided.set(key, records);
|
|
1084
|
+
}
|
|
1085
|
+
for (const required of requiredInvariants) {
|
|
1086
|
+
const matches = provided.get(normalizeInvariantText(required.invariant)) ?? [];
|
|
1087
|
+
if (matches.length === 0) {
|
|
1088
|
+
throw new UltragoalError(`Final architecture-invariant gate is missing proof for required invariant from ${required.sourceArtifact}: ${required.invariant}`);
|
|
1089
|
+
}
|
|
1090
|
+
if (!matches.some((record) => sourceReferencesArtifact(record.source, required.sourceArtifact))) {
|
|
1091
|
+
throw new UltragoalError(`Final architecture-invariant gate proof for required invariant must reference ${required.sourceArtifact}: ${required.invariant}`);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function validateQualityGate(value, requiredInvariants = []) {
|
|
913
1096
|
if (!value || typeof value !== 'object') {
|
|
914
|
-
throw new UltragoalError('Final ultragoal completion requires --quality-gate-json with ai-slop-cleaner, verification,
|
|
1097
|
+
throw new UltragoalError('Final ultragoal completion requires --quality-gate-json with ai-slop-cleaner, verification, code-review, and architecture-invariant evidence.');
|
|
915
1098
|
}
|
|
916
1099
|
const gate = value;
|
|
917
1100
|
const cleaner = gate.aiSlopCleaner;
|
|
@@ -960,6 +1143,7 @@ function validateQualityGate(value) {
|
|
|
960
1143
|
throw new UltragoalError('Final code-review must use an independent architect subagent; self-review or default/authoring-lane review cannot approve the ultragoal gate.');
|
|
961
1144
|
}
|
|
962
1145
|
assertNonEmpty(architect.evidence, 'codeReview.independentReview.architect.evidence');
|
|
1146
|
+
validateArchitectureInvariantGate(gate, requiredInvariants);
|
|
963
1147
|
return gate;
|
|
964
1148
|
}
|
|
965
1149
|
export async function startNextUltragoal(cwd, options = {}) {
|
|
@@ -1059,6 +1243,7 @@ export async function checkpointUltragoal(cwd, options) {
|
|
|
1059
1243
|
return plan;
|
|
1060
1244
|
}
|
|
1061
1245
|
let aggregateCompletion;
|
|
1246
|
+
let normalFinalAggregateCompletion;
|
|
1062
1247
|
if (options.status === 'complete') {
|
|
1063
1248
|
const expectedObjective = expectedCodexObjective(plan, goal);
|
|
1064
1249
|
const aggregateMode = codexGoalMode(plan) === 'aggregate';
|
|
@@ -1080,12 +1265,19 @@ export async function checkpointUltragoal(cwd, options) {
|
|
|
1080
1265
|
&& normalizeObjective(snapshot.objective ?? '') !== normalizeObjective(expectedObjective)
|
|
1081
1266
|
&& await canReconcileCompletedTaskScopedAggregateSnapshot(cwd, plan, goal, snapshot.objective ?? '', options.evidence);
|
|
1082
1267
|
if (completedTaskScopedAggregateSnapshot) {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1268
|
+
if (unresolvedReviewBlockedGoals(plan).length > 0) {
|
|
1269
|
+
if (!canUseCleanFinalResolverPathForReviewBlockedParent(plan, goal, finalRunCheckpoint, options.allowActiveFinalCodexGoal)) {
|
|
1270
|
+
throw new UltragoalError('Completed task-scoped aggregate reconciliation is not allowed while unresolved review_blocked parent goals exist; only the parent\'s designated resolver may continue through the clean final quality gate path.');
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
else {
|
|
1274
|
+
aggregateCompletion = {
|
|
1275
|
+
status: 'complete',
|
|
1276
|
+
completedAt: now,
|
|
1277
|
+
evidence: assertNonEmpty(options.evidence, '--evidence'),
|
|
1278
|
+
codexGoal: options.codexGoal,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1089
1281
|
}
|
|
1090
1282
|
else {
|
|
1091
1283
|
const taskScopedRequirement = aggregateMode && snapshot?.status === 'complete' && Boolean(snapshot.objective)
|
|
@@ -1102,11 +1294,25 @@ export async function checkpointUltragoal(cwd, options) {
|
|
|
1102
1294
|
throw new UltragoalError(`${formatCodexGoalReconciliation(reconciliation)}${taskScopedRequirement}${remediation}`);
|
|
1103
1295
|
}
|
|
1104
1296
|
}
|
|
1297
|
+
const designatedReviewBlockerResolver = goal.resolvesReviewBlockedGoalId
|
|
1298
|
+
? isDesignatedReviewBlockerResolver(goal, plan.goals.find((candidate) => candidate.id === goal.resolvesReviewBlockedGoalId))
|
|
1299
|
+
: false;
|
|
1300
|
+
if (aggregateMode && finalRunCheckpoint && !options.allowActiveFinalCodexGoal && designatedReviewBlockerResolver) {
|
|
1301
|
+
normalFinalAggregateCompletion = {
|
|
1302
|
+
status: 'complete',
|
|
1303
|
+
completedAt: now,
|
|
1304
|
+
evidence: assertNonEmpty(options.evidence, '--evidence'),
|
|
1305
|
+
codexGoal: options.codexGoal,
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1105
1308
|
if (finalRunCheckpoint && !options.allowActiveFinalCodexGoal)
|
|
1106
1309
|
goal.evidence = options.evidence;
|
|
1107
1310
|
}
|
|
1311
|
+
const requiredArchitectureInvariants = options.status === 'complete' && (aggregateCompletion !== undefined || (isFinalRunCompletionCandidate(plan, goal) && !options.allowActiveFinalCodexGoal))
|
|
1312
|
+
? await collectRequiredArchitectureInvariants(cwd)
|
|
1313
|
+
: [];
|
|
1108
1314
|
const qualityGate = options.status === 'complete' && (aggregateCompletion !== undefined || (isFinalRunCompletionCandidate(plan, goal) && !options.allowActiveFinalCodexGoal))
|
|
1109
|
-
? validateQualityGate(options.qualityGate)
|
|
1315
|
+
? validateQualityGate(options.qualityGate, requiredArchitectureInvariants)
|
|
1110
1316
|
: undefined;
|
|
1111
1317
|
if (aggregateCompletion) {
|
|
1112
1318
|
plan.aggregateCompletion = aggregateCompletion;
|
|
@@ -1134,6 +1340,23 @@ export async function checkpointUltragoal(cwd, options) {
|
|
|
1134
1340
|
goal.failureReason = undefined;
|
|
1135
1341
|
goal.failedAt = undefined;
|
|
1136
1342
|
clearGoalBlockerFields(goal);
|
|
1343
|
+
if (normalFinalAggregateCompletion)
|
|
1344
|
+
plan.aggregateCompletion = normalFinalAggregateCompletion;
|
|
1345
|
+
const resolvedParent = goal.resolvesReviewBlockedGoalId
|
|
1346
|
+
? plan.goals.find((candidate) => candidate.id === goal.resolvesReviewBlockedGoalId)
|
|
1347
|
+
: undefined;
|
|
1348
|
+
if (resolvedParent?.status === 'review_blocked' && resolvedParent.reviewBlockerResolution?.resolverGoalId === goal.id && qualityGate) {
|
|
1349
|
+
resolvedParent.status = 'complete';
|
|
1350
|
+
resolvedParent.completedAt = now;
|
|
1351
|
+
resolvedParent.updatedAt = now;
|
|
1352
|
+
resolvedParent.reviewBlockerResolution = {
|
|
1353
|
+
resolverGoalId: goal.id,
|
|
1354
|
+
status: 'complete',
|
|
1355
|
+
resolvedAt: now,
|
|
1356
|
+
evidence: options.evidence,
|
|
1357
|
+
};
|
|
1358
|
+
clearGoalBlockerFields(resolvedParent);
|
|
1359
|
+
}
|
|
1137
1360
|
if (plan.activeGoalId === goal.id)
|
|
1138
1361
|
delete plan.activeGoalId;
|
|
1139
1362
|
}
|
|
@@ -1173,6 +1396,33 @@ export async function checkpointUltragoal(cwd, options) {
|
|
|
1173
1396
|
? `Blocked on repeated external authorization. Required decision: ${goal.requiredExternalDecision}.`
|
|
1174
1397
|
: undefined,
|
|
1175
1398
|
});
|
|
1399
|
+
if (options.status === 'complete' && goal.resolvesReviewBlockedGoalId) {
|
|
1400
|
+
const resolvedParent = plan.goals.find((candidate) => candidate.id === goal.resolvesReviewBlockedGoalId);
|
|
1401
|
+
if (resolvedParent?.reviewBlockerResolution?.status === 'complete' && resolvedParent.reviewBlockerResolution.resolverGoalId === goal.id) {
|
|
1402
|
+
await appendLedger(cwd, {
|
|
1403
|
+
ts: now,
|
|
1404
|
+
event: 'goal_completed',
|
|
1405
|
+
goalId: resolvedParent.id,
|
|
1406
|
+
status: resolvedParent.status,
|
|
1407
|
+
evidence: options.evidence,
|
|
1408
|
+
codexGoal: options.codexGoal,
|
|
1409
|
+
qualityGate,
|
|
1410
|
+
message: `Review-blocked final story resolved by ${goal.id}; original failed review remains in prior final_review_failed/goal_review_blocked ledger entries.`,
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (normalFinalAggregateCompletion) {
|
|
1415
|
+
await appendLedger(cwd, {
|
|
1416
|
+
ts: now,
|
|
1417
|
+
event: 'aggregate_completed',
|
|
1418
|
+
goalId: goal.id,
|
|
1419
|
+
status: goal.status,
|
|
1420
|
+
evidence: options.evidence,
|
|
1421
|
+
codexGoal: options.codexGoal,
|
|
1422
|
+
qualityGate,
|
|
1423
|
+
message: 'Aggregate ultragoal plan completed with a clean final quality gate.',
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1176
1426
|
return plan;
|
|
1177
1427
|
});
|
|
1178
1428
|
}
|
|
@@ -1202,7 +1452,7 @@ export async function recordFinalReviewBlockers(cwd, options) {
|
|
|
1202
1452
|
if (!reconciliation.ok) {
|
|
1203
1453
|
throw new UltragoalError(formatCodexGoalReconciliation(reconciliation));
|
|
1204
1454
|
}
|
|
1205
|
-
const addedGoal = appendGoalToPlan(plan, { ...options, now: options.now });
|
|
1455
|
+
const addedGoal = appendGoalToPlan(plan, { ...options, now: options.now, resolvesReviewBlockedGoalId: goal.id });
|
|
1206
1456
|
goal.status = 'review_blocked';
|
|
1207
1457
|
goal.reviewBlockedAt = now;
|
|
1208
1458
|
goal.updatedAt = now;
|
|
@@ -1210,6 +1460,11 @@ export async function recordFinalReviewBlockers(cwd, options) {
|
|
|
1210
1460
|
goal.failedAt = undefined;
|
|
1211
1461
|
goal.failureReason = undefined;
|
|
1212
1462
|
goal.evidence = options.evidence;
|
|
1463
|
+
goal.reviewBlockerResolution = {
|
|
1464
|
+
resolverGoalId: addedGoal.id,
|
|
1465
|
+
status: 'pending',
|
|
1466
|
+
evidence: options.evidence,
|
|
1467
|
+
};
|
|
1213
1468
|
if (plan.activeGoalId === goal.id)
|
|
1214
1469
|
delete plan.activeGoalId;
|
|
1215
1470
|
plan.updatedAt = now;
|
|
@@ -1263,6 +1518,7 @@ function buildPerStoryCodexGoalInstruction(goal, plan) {
|
|
|
1263
1518
|
'',
|
|
1264
1519
|
'Codex goal integration constraints:',
|
|
1265
1520
|
'- First call get_goal. If no active goal exists, call create_goal with the payload below.',
|
|
1521
|
+
`- If get_goal reports status complete before create_goal, do not call create_goal over it. ${buildCompletedCodexGoalRemediation('Ultragoal preflight')}`,
|
|
1266
1522
|
'- If a different active Codex goal exists, finish/checkpoint that goal before starting this ultragoal.',
|
|
1267
1523
|
'- Ultragoal cannot call /goal clear from the model/shell tool surface. For another per-story goal in the same session/thread after a completed Codex goal, manually run /goal clear in the Codex UI before creating the next goal.',
|
|
1268
1524
|
'- If get_goal returns a different completed legacy/thread goal and create_goal rejects because this thread already has a completed goal, continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the payload there.',
|
|
@@ -1289,6 +1545,9 @@ function buildPerStoryCodexGoalInstruction(goal, plan) {
|
|
|
1289
1545
|
finalStory
|
|
1290
1546
|
? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
|
|
1291
1547
|
: null,
|
|
1548
|
+
finalStory
|
|
1549
|
+
? '- After the final checkpoint command succeeds, treat `/goal clear` as the explicit terminal cleanup step before another same-thread goal.'
|
|
1550
|
+
: null,
|
|
1292
1551
|
'- If blocked or failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.',
|
|
1293
1552
|
'',
|
|
1294
1553
|
'create_goal payload:',
|
|
@@ -1313,6 +1572,7 @@ function buildAggregateCodexGoalInstruction(goal, plan) {
|
|
|
1313
1572
|
'- Codex goal = the whole ultragoal run; OMX G001/G002/etc. = ledger stories.',
|
|
1314
1573
|
'- First call get_goal. If no active goal exists, call create_goal with the aggregate payload below.',
|
|
1315
1574
|
'- If get_goal reports the same aggregate objective as active, continue this OMX story without creating a new Codex goal.',
|
|
1575
|
+
`- If get_goal reports status complete before create_goal, do not call create_goal over it. ${buildCompletedCodexGoalRemediation('Ultragoal preflight')}`,
|
|
1316
1576
|
'- If a different active or incomplete Codex goal exists, finish/checkpoint that goal before starting this ultragoal; do not replace hidden Codex state from the shell.',
|
|
1317
1577
|
'- Ultragoal does not call /goal clear. After a completed aggregate run, manually run /goal clear in the Codex UI before starting another ultragoal run in the same session/thread.',
|
|
1318
1578
|
finalStory
|
|
@@ -1330,6 +1590,9 @@ function buildAggregateCodexGoalInstruction(goal, plan) {
|
|
|
1330
1590
|
finalStory
|
|
1331
1591
|
? '- If final $code-review is clean (APPROVE + CLEAR + independent code-reviewer and architect subagent evidence), call update_goal({status: "complete"}), call get_goal again for a fresh complete snapshot, then checkpoint with --quality-gate-json.'
|
|
1332
1592
|
: null,
|
|
1593
|
+
finalStory
|
|
1594
|
+
? '- After the final checkpoint command succeeds, treat `/goal clear` as the explicit terminal cleanup step before another same-thread goal.'
|
|
1595
|
+
: null,
|
|
1333
1596
|
`- Checkpoint this OMX story with a fresh get_goal snapshot whose objective matches the aggregate payload and whose status is ${checkpointStatus}:`,
|
|
1334
1597
|
finalStory
|
|
1335
1598
|
? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
|