oh-my-codex 0.16.0 → 0.16.2
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/README.md +2 -2
- 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__/doctor-warning-copy.test.js +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +120 -3
- 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 +48 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +12 -0
- package/dist/cli/__tests__/setup-scope.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 +50 -5
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +6 -2
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +211 -12
- 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 +100 -9
- 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 +29 -8
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +2 -1
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +97 -2
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +22 -0
- package/dist/config/__tests__/generator-notify.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/__tests__/wiki-config-contract.test.js +2 -1
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +17 -3
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +102 -2
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +4 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +69 -12
- package/dist/config/generator.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__/keyword-detector.test.js +37 -25
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -4
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +32 -0
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/wiki-docs-contract.test.js +6 -4
- package/dist/hooks/__tests__/wiki-docs-contract.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/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2 -4
- package/dist/hooks/keyword-detector.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/__tests__/state-server.test.js +145 -6
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.js +97 -1
- package/dist/mcp/__tests__/wiki-server.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/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +11 -2
- package/dist/mcp/wiki-server.js.map +1 -1
- 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 +267 -2
- 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-execution-surface.d.ts +1 -1
- package/dist/scripts/codex-execution-surface.d.ts.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +141 -9
- 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__/operations.test.js +79 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +10 -18
- package/dist/state/__tests__/skill-active.test.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/operations.d.ts.map +1 -1
- package/dist/state/operations.js +1 -20
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +1 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +28 -18
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +3 -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 +129 -4
- 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 +31 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -0
- package/dist/ultragoal/artifacts.d.ts +6 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +108 -4
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/paths.d.ts +3 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +6 -2
- package/dist/utils/paths.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/dist/wiki/__tests__/ingest.test.js +35 -1
- package/dist/wiki/__tests__/ingest.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js +14 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js +28 -3
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/session-hooks.test.js +30 -2
- package/dist/wiki/__tests__/session-hooks.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js +62 -22
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/index.d.ts +2 -2
- package/dist/wiki/index.d.ts.map +1 -1
- package/dist/wiki/index.js +2 -2
- package/dist/wiki/index.js.map +1 -1
- package/dist/wiki/ingest.js +2 -2
- package/dist/wiki/ingest.js.map +1 -1
- package/dist/wiki/lifecycle.d.ts +5 -0
- package/dist/wiki/lifecycle.d.ts.map +1 -1
- package/dist/wiki/lifecycle.js +31 -4
- package/dist/wiki/lifecycle.js.map +1 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +12 -8
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.d.ts.map +1 -1
- package/dist/wiki/query.js +3 -2
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.d.ts +4 -0
- package/dist/wiki/storage.d.ts.map +1 -1
- package/dist/wiki/storage.js +54 -18
- package/dist/wiki/storage.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/omx-setup/SKILL.md +1 -1
- 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/ultragoal/SKILL.md +11 -7
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +8 -0
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +5 -5
- 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/omx-setup/SKILL.md +1 -1
- package/skills/plan/SKILL.md +7 -4
- package/skills/ralplan/SKILL.md +13 -3
- package/skills/team/SKILL.md +2 -2
- package/skills/ultragoal/SKILL.md +11 -7
- package/skills/visual-ralph/SKILL.md +8 -0
- package/skills/wiki/SKILL.md +5 -5
- package/src/scripts/__tests__/codex-native-hook.test.ts +302 -2
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/codex-execution-surface.ts +2 -0
- package/src/scripts/codex-native-hook.ts +163 -16
- 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,16 +1,19 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
import { afterEach, beforeEach, describe, it } from 'node:test';
|
|
3
4
|
import assert from 'node:assert/strict';
|
|
4
5
|
import { existsSync } from 'node:fs';
|
|
5
6
|
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
6
7
|
import { spawn } from 'node:child_process';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
+
import { join, relative } from 'node:path';
|
|
8
9
|
import { tmpdir } from 'node:os';
|
|
9
10
|
import { fileURLToPath } from 'node:url';
|
|
10
11
|
import { buildLeaderMonitoringHints, parseTeamStartArgs, teamCommand } from '../team.js';
|
|
11
12
|
import { readModeState } from '../../modes/base.js';
|
|
12
13
|
import { readApprovedExecutionLaunchHint } from '../../planning/artifacts.js';
|
|
14
|
+
import { buildRepoAwareTeamExecutionPlan } from '../../team/repo-aware-decomposition.js';
|
|
13
15
|
import { DEFAULT_MAX_WORKERS } from '../../team/state.js';
|
|
16
|
+
import { shutdownTeam } from '../../team/runtime.js';
|
|
14
17
|
import { sameFilePath } from '../../utils/paths.js';
|
|
15
18
|
import { appendTeamEvent, createTask, initTeamState, readTeamConfig, saveTeamConfig, updateWorkerHeartbeat, writeMonitorSnapshot, writeTaskApproval, writeWorkerStatus, } from '../../team/state.js';
|
|
16
19
|
import { buildApprovedTeamExecutionBinding, writePersistedApprovedTeamExecutionBinding, } from '../../team/approved-execution.js';
|
|
@@ -23,6 +26,48 @@ function encodeApprovedExecutionTask(task, quote) {
|
|
|
23
26
|
? `'${task.replace(/'/g, "\\'")}'`
|
|
24
27
|
: `"${task.replace(/"/g, '\\"')}"`;
|
|
25
28
|
}
|
|
29
|
+
function computeGitBlobSha1(content) {
|
|
30
|
+
const buffer = Buffer.from(content, 'utf-8');
|
|
31
|
+
const header = Buffer.from(`blob ${buffer.length}\0`, 'utf-8');
|
|
32
|
+
return createHash('sha1').update(header).update(buffer).digest('hex');
|
|
33
|
+
}
|
|
34
|
+
function canonicalContextPackRelativePath(slug) {
|
|
35
|
+
return `.omx/context/context-20260507T120000Z-${slug}.json`;
|
|
36
|
+
}
|
|
37
|
+
function buildContextPackOutcome(relativePackPath) {
|
|
38
|
+
return [
|
|
39
|
+
'## Context Pack Outcome',
|
|
40
|
+
'',
|
|
41
|
+
`- pack: created \`${relativePackPath}\``,
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
async function writeContextPack(cwd, slug, prdPath, testSpecPath, roles) {
|
|
45
|
+
const contextDir = join(cwd, '.omx', 'context');
|
|
46
|
+
const packPath = join(cwd, canonicalContextPackRelativePath(slug));
|
|
47
|
+
const prdContent = await readFile(prdPath, 'utf-8');
|
|
48
|
+
const testSpecContent = await readFile(testSpecPath, 'utf-8');
|
|
49
|
+
await mkdir(contextDir, { recursive: true });
|
|
50
|
+
await writeFile(packPath, JSON.stringify({
|
|
51
|
+
slug,
|
|
52
|
+
basis: {
|
|
53
|
+
prd: {
|
|
54
|
+
path: relative(cwd, prdPath).replaceAll('\\', '/'),
|
|
55
|
+
sha1: computeGitBlobSha1(prdContent),
|
|
56
|
+
},
|
|
57
|
+
testSpecs: [{
|
|
58
|
+
path: relative(cwd, testSpecPath).replaceAll('\\', '/'),
|
|
59
|
+
sha1: computeGitBlobSha1(testSpecContent),
|
|
60
|
+
}],
|
|
61
|
+
},
|
|
62
|
+
entries: roles.map((role, index) => ({
|
|
63
|
+
path: `src/${role}-${index}.ts`,
|
|
64
|
+
roles: [role],
|
|
65
|
+
})),
|
|
66
|
+
}, null, 2));
|
|
67
|
+
}
|
|
68
|
+
async function writeReadyContextPack(cwd, slug, prdPath, testSpecPath) {
|
|
69
|
+
await writeContextPack(cwd, slug, prdPath, testSpecPath, ['scope', 'build', 'verify']);
|
|
70
|
+
}
|
|
26
71
|
beforeEach(() => {
|
|
27
72
|
delete process.env.OMX_TEAM_WORKER;
|
|
28
73
|
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
@@ -226,8 +271,16 @@ describe('parseTeamStartArgs', () => {
|
|
|
226
271
|
const plansDir = join(wd, '.omx', 'plans');
|
|
227
272
|
await mkdir(plansDir, { recursive: true });
|
|
228
273
|
const boundPrdPath = join(plansDir, 'prd-20260501T010203Z-issue-831.md');
|
|
229
|
-
|
|
230
|
-
await writeFile(
|
|
274
|
+
const boundTestSpecPath = join(plansDir, 'test-spec-20260501T010203Z-issue-831.md');
|
|
275
|
+
await writeFile(boundPrdPath, [
|
|
276
|
+
'# Approved plan',
|
|
277
|
+
'',
|
|
278
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-831')),
|
|
279
|
+
'',
|
|
280
|
+
'Launch via omx team 2:executor "Execute approved issue 831 plan"',
|
|
281
|
+
].join('\n'));
|
|
282
|
+
await writeFile(boundTestSpecPath, '# Test spec\n');
|
|
283
|
+
await writeReadyContextPack(wd, 'issue-831', boundPrdPath, boundTestSpecPath);
|
|
231
284
|
await writeFile(join(plansDir, 'prd-20260502T010203Z-issue-999.md'), '# Approved plan\n\nLaunch via omx team 5:debugger "Execute newer approved issue 999 plan"\n');
|
|
232
285
|
await writeFile(join(plansDir, 'test-spec-20260502T010203Z-issue-999.md'), '# Test spec\n');
|
|
233
286
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
@@ -260,8 +313,16 @@ describe('parseTeamStartArgs', () => {
|
|
|
260
313
|
const boundTask = "Fix Bob's regression in C:\\\\tmp";
|
|
261
314
|
const boundCommand = `omx team 2:executor ${encodeApprovedExecutionTask(boundTask, 'single')}`;
|
|
262
315
|
const boundPrdPath = join(plansDir, 'prd-issue-831-quoted.md');
|
|
263
|
-
|
|
264
|
-
await writeFile(
|
|
316
|
+
const boundTestSpecPath = join(plansDir, 'test-spec-issue-831-quoted.md');
|
|
317
|
+
await writeFile(boundPrdPath, [
|
|
318
|
+
'# Approved plan',
|
|
319
|
+
'',
|
|
320
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-831-quoted')),
|
|
321
|
+
'',
|
|
322
|
+
`Launch via ${boundCommand}`,
|
|
323
|
+
].join('\n'));
|
|
324
|
+
await writeFile(boundTestSpecPath, '# Test spec\n');
|
|
325
|
+
await writeReadyContextPack(wd, 'issue-831-quoted', boundPrdPath, boundTestSpecPath);
|
|
265
326
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
266
327
|
await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-team-quoted' }, null, 2));
|
|
267
328
|
const approvedHint = readApprovedExecutionLaunchHint(wd, 'team');
|
|
@@ -291,8 +352,16 @@ describe('parseTeamStartArgs', () => {
|
|
|
291
352
|
const boundTask = String.raw `Use C:\tmp and keep \n literal plus "quotes"`;
|
|
292
353
|
const boundCommand = `omx team 2:executor ${encodeApprovedExecutionTask(boundTask, 'double')}`;
|
|
293
354
|
const boundPrdPath = join(plansDir, 'prd-issue-831-double-quoted.md');
|
|
294
|
-
|
|
295
|
-
await writeFile(
|
|
355
|
+
const boundTestSpecPath = join(plansDir, 'test-spec-issue-831-double-quoted.md');
|
|
356
|
+
await writeFile(boundPrdPath, [
|
|
357
|
+
'# Approved plan',
|
|
358
|
+
'',
|
|
359
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-831-double-quoted')),
|
|
360
|
+
'',
|
|
361
|
+
`Launch via ${boundCommand}`,
|
|
362
|
+
].join('\n'));
|
|
363
|
+
await writeFile(boundTestSpecPath, '# Test spec\n');
|
|
364
|
+
await writeReadyContextPack(wd, 'issue-831-double-quoted', boundPrdPath, boundTestSpecPath);
|
|
296
365
|
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
297
366
|
await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-team-double-quoted' }, null, 2));
|
|
298
367
|
const approvedHint = readApprovedExecutionLaunchHint(wd, 'team');
|
|
@@ -346,6 +415,99 @@ describe('parseTeamStartArgs', () => {
|
|
|
346
415
|
await rm(wd, { recursive: true, force: true });
|
|
347
416
|
}
|
|
348
417
|
});
|
|
418
|
+
it('keeps plan-only short follow-ups on the generic path even when a persisted approved binding exists', async () => {
|
|
419
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-plan-only-'));
|
|
420
|
+
const previousCwd = process.cwd();
|
|
421
|
+
try {
|
|
422
|
+
process.chdir(wd);
|
|
423
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
424
|
+
await mkdir(plansDir, { recursive: true });
|
|
425
|
+
const prdPath = join(plansDir, 'prd-issue-2085.md');
|
|
426
|
+
const command = 'omx team 3:executor "Execute approved issue 2085 plan"';
|
|
427
|
+
await writeFile(prdPath, `# Approved plan\n\nLaunch via ${command}\n`);
|
|
428
|
+
await writeFile(join(plansDir, 'test-spec-issue-2085.md'), '# Test spec\n');
|
|
429
|
+
await mkdir(join(wd, '.omx', 'state'), { recursive: true });
|
|
430
|
+
await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-plan-only-team' }, null, 2));
|
|
431
|
+
await writePersistedApprovedTeamExecutionBinding('bound-plan-only-team', wd, {
|
|
432
|
+
prd_path: prdPath,
|
|
433
|
+
task: 'Execute approved issue 2085 plan',
|
|
434
|
+
command,
|
|
435
|
+
});
|
|
436
|
+
const result = parseTeamStartArgs(['team']);
|
|
437
|
+
assert.equal(result.parsed.task, 'Execute approved issue 2085 plan');
|
|
438
|
+
assert.equal(result.parsed.workerCount, 3);
|
|
439
|
+
assert.equal(result.parsed.agentType, 'executor');
|
|
440
|
+
assert.equal(result.parsed.approvedExecution, undefined);
|
|
441
|
+
}
|
|
442
|
+
finally {
|
|
443
|
+
process.chdir(previousCwd);
|
|
444
|
+
await rm(wd, { recursive: true, force: true });
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
it('fails short follow-up reuse when the latest approved handoff is nonready', async () => {
|
|
448
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-nonready-'));
|
|
449
|
+
const previousCwd = process.cwd();
|
|
450
|
+
try {
|
|
451
|
+
process.chdir(wd);
|
|
452
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
453
|
+
await mkdir(plansDir, { recursive: true });
|
|
454
|
+
await writeFile(join(plansDir, 'prd-issue-2086.md'), [
|
|
455
|
+
'# Approved plan',
|
|
456
|
+
'',
|
|
457
|
+
'## Context Pack Outcome',
|
|
458
|
+
'',
|
|
459
|
+
'- pack: created `.omx/context/context-20260507T120000Z-other.json`',
|
|
460
|
+
'',
|
|
461
|
+
'Launch via omx team 3:executor "Execute approved issue 2086 plan"',
|
|
462
|
+
].join('\n'));
|
|
463
|
+
await writeFile(join(plansDir, 'test-spec-issue-2086.md'), '# Test spec\n');
|
|
464
|
+
assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:invalid/);
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
process.chdir(previousCwd);
|
|
468
|
+
await rm(wd, { recursive: true, force: true });
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
it('fails short follow-up reuse when the latest approved handoff is missing its baseline', async () => {
|
|
472
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-missing-baseline-'));
|
|
473
|
+
const previousCwd = process.cwd();
|
|
474
|
+
try {
|
|
475
|
+
process.chdir(wd);
|
|
476
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
477
|
+
await mkdir(plansDir, { recursive: true });
|
|
478
|
+
await writeFile(join(plansDir, 'prd-issue-2086-missing-baseline.md'), '# Approved plan\n\nLaunch via omx team 3:executor "Execute approved issue 2086 missing-baseline plan"\n');
|
|
479
|
+
assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:missing-baseline/);
|
|
480
|
+
}
|
|
481
|
+
finally {
|
|
482
|
+
process.chdir(previousCwd);
|
|
483
|
+
await rm(wd, { recursive: true, force: true });
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
it('fails short follow-up reuse when the latest approved handoff is incomplete', async () => {
|
|
487
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-incomplete-'));
|
|
488
|
+
const previousCwd = process.cwd();
|
|
489
|
+
try {
|
|
490
|
+
process.chdir(wd);
|
|
491
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
492
|
+
await mkdir(plansDir, { recursive: true });
|
|
493
|
+
const prdPath = join(plansDir, 'prd-issue-2086-incomplete.md');
|
|
494
|
+
const testSpecPath = join(plansDir, 'test-spec-issue-2086-incomplete.md');
|
|
495
|
+
await writeFile(prdPath, [
|
|
496
|
+
'# Approved plan',
|
|
497
|
+
'',
|
|
498
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-2086-incomplete')),
|
|
499
|
+
'',
|
|
500
|
+
'Launch via omx team 3:executor "Execute approved issue 2086 incomplete plan"',
|
|
501
|
+
].join('\n'));
|
|
502
|
+
await writeFile(testSpecPath, '# Test spec\n');
|
|
503
|
+
await writeContextPack(wd, 'issue-2086-incomplete', prdPath, testSpecPath, ['scope']);
|
|
504
|
+
assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:incomplete/);
|
|
505
|
+
}
|
|
506
|
+
finally {
|
|
507
|
+
process.chdir(previousCwd);
|
|
508
|
+
await rm(wd, { recursive: true, force: true });
|
|
509
|
+
}
|
|
510
|
+
});
|
|
349
511
|
it('fails closed for a short follow-up when the persisted approved binding is malformed', async () => {
|
|
350
512
|
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-malformed-binding-'));
|
|
351
513
|
const previousCwd = process.cwd();
|
|
@@ -397,6 +559,40 @@ describe('parseTeamStartArgs', () => {
|
|
|
397
559
|
await rm(wd, { recursive: true, force: true });
|
|
398
560
|
}
|
|
399
561
|
});
|
|
562
|
+
it('fails closed for a short follow-up when the persisted approved binding is ambiguous', async () => {
|
|
563
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-bound-ambiguous-'));
|
|
564
|
+
const previousCwd = process.cwd();
|
|
565
|
+
const approvedTask = 'Execute approved issue 956 plan';
|
|
566
|
+
try {
|
|
567
|
+
process.chdir(wd);
|
|
568
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
569
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
570
|
+
await mkdir(plansDir, { recursive: true });
|
|
571
|
+
await writeFile(join(plansDir, 'prd-issue-956.md'), [
|
|
572
|
+
'# Approved plan',
|
|
573
|
+
'',
|
|
574
|
+
`Launch via omx team 4:executor "${approvedTask}"`,
|
|
575
|
+
`Launch via omx team 6:debugger "${approvedTask}"`,
|
|
576
|
+
].join('\n'));
|
|
577
|
+
await writeFile(join(plansDir, 'test-spec-issue-956.md'), '# Test spec\n');
|
|
578
|
+
await mkdir(stateDir, { recursive: true });
|
|
579
|
+
await writeFile(join(stateDir, 'team-state.json'), JSON.stringify({
|
|
580
|
+
active: true,
|
|
581
|
+
team_name: 'bound-team-ambiguous',
|
|
582
|
+
task_description: approvedTask,
|
|
583
|
+
agent_count: 4,
|
|
584
|
+
}, null, 2));
|
|
585
|
+
await writePersistedApprovedTeamExecutionBinding('bound-team-ambiguous', wd, {
|
|
586
|
+
prd_path: join(plansDir, 'prd-issue-956.md'),
|
|
587
|
+
task: approvedTask,
|
|
588
|
+
});
|
|
589
|
+
assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_binding_ambiguous:.*Execute approved issue 956 plan/);
|
|
590
|
+
}
|
|
591
|
+
finally {
|
|
592
|
+
process.chdir(previousCwd);
|
|
593
|
+
await rm(wd, { recursive: true, force: true });
|
|
594
|
+
}
|
|
595
|
+
});
|
|
400
596
|
it('fails closed for a short team follow-up when the selected PRD lists multiple team launch hints', async () => {
|
|
401
597
|
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-ambiguous-'));
|
|
402
598
|
const previousCwd = process.cwd();
|
|
@@ -451,15 +647,25 @@ describe('parseTeamStartArgs', () => {
|
|
|
451
647
|
await rm(wd, { recursive: true, force: true });
|
|
452
648
|
}
|
|
453
649
|
});
|
|
454
|
-
it('attaches approved repository context summary only for matching team launches', async () => {
|
|
650
|
+
it('attaches approved repository context summary only for matching ready team launches', async () => {
|
|
455
651
|
const wd = await mkdtemp(join(tmpdir(), 'omx-team-context-approved-'));
|
|
456
652
|
const previousCwd = process.cwd();
|
|
457
653
|
try {
|
|
458
654
|
process.chdir(wd);
|
|
459
|
-
|
|
460
|
-
await
|
|
461
|
-
|
|
462
|
-
|
|
655
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
656
|
+
await mkdir(plansDir, { recursive: true });
|
|
657
|
+
const prdPath = join(plansDir, 'prd-issue-2039.md');
|
|
658
|
+
const testSpecPath = join(plansDir, 'test-spec-issue-2039.md');
|
|
659
|
+
await writeFile(prdPath, [
|
|
660
|
+
'# Approved plan',
|
|
661
|
+
'',
|
|
662
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-2039')),
|
|
663
|
+
'',
|
|
664
|
+
'Launch via omx team 3:executor "Execute approved issue 2039 plan"',
|
|
665
|
+
].join('\n'));
|
|
666
|
+
await writeFile(testSpecPath, '# Test spec\n');
|
|
667
|
+
await writeReadyContextPack(wd, 'issue-2039', prdPath, testSpecPath);
|
|
668
|
+
await writeFile(join(plansDir, 'repo-context-issue-2039.md'), 'Key boundary: latest approved handoff only.\n');
|
|
463
669
|
const approved = parseTeamStartArgs(['3:executor', 'Execute', 'approved', 'issue', '2039', 'plan']);
|
|
464
670
|
assert.equal(approved.parsed.approvedRepositoryContextSummary?.content, 'Key boundary: latest approved handoff only.');
|
|
465
671
|
const unrelated = parseTeamStartArgs(['3:executor', 'fix', 'unrelated', 'bug']);
|
|
@@ -470,6 +676,139 @@ describe('parseTeamStartArgs', () => {
|
|
|
470
676
|
await rm(wd, { recursive: true, force: true });
|
|
471
677
|
}
|
|
472
678
|
});
|
|
679
|
+
it('keeps ready approved execution generic when staffing no longer matches the approved launch hint', async () => {
|
|
680
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-context-ready-mismatch-'));
|
|
681
|
+
const previousCwd = process.cwd();
|
|
682
|
+
try {
|
|
683
|
+
process.chdir(wd);
|
|
684
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
685
|
+
await mkdir(plansDir, { recursive: true });
|
|
686
|
+
const prdPath = join(plansDir, 'prd-issue-2040.md');
|
|
687
|
+
const testSpecPath = join(plansDir, 'test-spec-issue-2040.md');
|
|
688
|
+
await writeFile(prdPath, [
|
|
689
|
+
'# Approved plan',
|
|
690
|
+
'',
|
|
691
|
+
buildContextPackOutcome(canonicalContextPackRelativePath('issue-2040')),
|
|
692
|
+
'',
|
|
693
|
+
'Launch via omx team 3:executor "Execute approved issue 2040 plan"',
|
|
694
|
+
].join('\n'));
|
|
695
|
+
await writeFile(testSpecPath, '# Test spec\n');
|
|
696
|
+
await writeReadyContextPack(wd, 'issue-2040', prdPath, testSpecPath);
|
|
697
|
+
await writeFile(join(plansDir, 'repo-context-issue-2040.md'), 'Keep approved context off generic mismatches.\n');
|
|
698
|
+
const result = parseTeamStartArgs(['2:debugger', 'Execute', 'approved', 'issue', '2040', 'plan']);
|
|
699
|
+
assert.equal(result.parsed.allowRepoAwareDagHandoff, false);
|
|
700
|
+
assert.equal(result.parsed.approvedExecution, undefined);
|
|
701
|
+
assert.equal(result.parsed.approvedRepositoryContextSummary, undefined);
|
|
702
|
+
}
|
|
703
|
+
finally {
|
|
704
|
+
process.chdir(previousCwd);
|
|
705
|
+
await rm(wd, { recursive: true, force: true });
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
it('does not carry approved execution for explicit plan-only team launches', async () => {
|
|
709
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-explicit-plan-only-'));
|
|
710
|
+
const previousCwd = process.cwd();
|
|
711
|
+
try {
|
|
712
|
+
process.chdir(wd);
|
|
713
|
+
await mkdir(join(wd, '.omx', 'plans'), { recursive: true });
|
|
714
|
+
await writeFile(join(wd, '.omx', 'plans', 'prd-issue-2087.md'), '# Approved plan\n\nLaunch via omx team 3:executor "Execute approved issue 2087 plan"\n');
|
|
715
|
+
await writeFile(join(wd, '.omx', 'plans', 'test-spec-issue-2087.md'), '# Test spec\n');
|
|
716
|
+
await writeFile(join(wd, '.omx', 'plans', 'repo-context-issue-2087.md'), 'Do not widen plan-only context.\n');
|
|
717
|
+
const result = parseTeamStartArgs(['3:executor', 'Execute', 'approved', 'issue', '2087', 'plan']);
|
|
718
|
+
assert.equal(result.parsed.allowRepoAwareDagHandoff, true);
|
|
719
|
+
assert.equal(result.parsed.approvedExecution, undefined);
|
|
720
|
+
assert.equal(result.parsed.approvedRepositoryContextSummary, undefined);
|
|
721
|
+
}
|
|
722
|
+
finally {
|
|
723
|
+
process.chdir(previousCwd);
|
|
724
|
+
await rm(wd, { recursive: true, force: true });
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
it('preserves lifecycle-specific DAG fallback reasons for explicit nonready approved launches', async () => {
|
|
728
|
+
const previousCwd = process.cwd();
|
|
729
|
+
const cases = [
|
|
730
|
+
{
|
|
731
|
+
name: 'missing-baseline',
|
|
732
|
+
slug: 'issue-2090-missing-baseline',
|
|
733
|
+
includeOutcome: false,
|
|
734
|
+
writeTestSpec: false,
|
|
735
|
+
packSetup: async (_wd, _prdPath, _testSpecPath) => { },
|
|
736
|
+
expected: 'context_pack_not_followup_ready:missing-baseline',
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
name: 'incomplete',
|
|
740
|
+
slug: 'issue-2090-incomplete',
|
|
741
|
+
includeOutcome: true,
|
|
742
|
+
writeTestSpec: true,
|
|
743
|
+
packSetup: async (wd, prdPath, testSpecPath) => {
|
|
744
|
+
await writeContextPack(wd, 'issue-2090-incomplete', prdPath, testSpecPath, ['scope']);
|
|
745
|
+
},
|
|
746
|
+
expected: 'context_pack_not_followup_ready:incomplete',
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
name: 'invalid',
|
|
750
|
+
slug: 'issue-2090-invalid',
|
|
751
|
+
includeOutcome: true,
|
|
752
|
+
writeTestSpec: true,
|
|
753
|
+
packSetup: async (_wd, _prdPath, _testSpecPath) => { },
|
|
754
|
+
expected: 'context_pack_not_followup_ready:invalid',
|
|
755
|
+
},
|
|
756
|
+
];
|
|
757
|
+
try {
|
|
758
|
+
for (const scenario of cases) {
|
|
759
|
+
const wd = await mkdtemp(join(tmpdir(), `omx-team-dag-fallback-${scenario.name}-`));
|
|
760
|
+
try {
|
|
761
|
+
process.chdir(wd);
|
|
762
|
+
const plansDir = join(wd, '.omx', 'plans');
|
|
763
|
+
await mkdir(plansDir, { recursive: true });
|
|
764
|
+
const prdPath = join(plansDir, `prd-${scenario.slug}.md`);
|
|
765
|
+
const testSpecPath = join(plansDir, `test-spec-${scenario.slug}.md`);
|
|
766
|
+
const outcomePath = scenario.name === 'invalid'
|
|
767
|
+
? canonicalContextPackRelativePath('other')
|
|
768
|
+
: canonicalContextPackRelativePath(scenario.slug);
|
|
769
|
+
const prdSections = ['# Approved plan', ''];
|
|
770
|
+
if (scenario.includeOutcome) {
|
|
771
|
+
prdSections.push(buildContextPackOutcome(outcomePath), '');
|
|
772
|
+
}
|
|
773
|
+
prdSections.push(`Launch via omx team 3:executor "Execute approved ${scenario.name} DAG plan"`);
|
|
774
|
+
await writeFile(prdPath, prdSections.join('\n'));
|
|
775
|
+
if (scenario.writeTestSpec) {
|
|
776
|
+
await writeFile(testSpecPath, '# Test spec\n');
|
|
777
|
+
}
|
|
778
|
+
await writeFile(join(plansDir, `team-dag-${scenario.slug}.json`), '{"schema_version":1,"nodes":[{"id":"impl","subject":"Impl","description":"Impl"}]}\n');
|
|
779
|
+
await scenario.packSetup(wd, prdPath, testSpecPath);
|
|
780
|
+
const parsed = parseTeamStartArgs(['3:executor', 'Execute', 'approved', scenario.name, 'DAG', 'plan']);
|
|
781
|
+
const executionPlan = buildRepoAwareTeamExecutionPlan({
|
|
782
|
+
task: parsed.parsed.task,
|
|
783
|
+
workerCount: parsed.parsed.workerCount,
|
|
784
|
+
agentType: parsed.parsed.agentType,
|
|
785
|
+
explicitAgentType: parsed.parsed.explicitAgentType,
|
|
786
|
+
explicitWorkerCount: parsed.parsed.explicitWorkerCount,
|
|
787
|
+
cwd: wd,
|
|
788
|
+
buildLegacyPlan: (task, workerCount, agentType) => ({
|
|
789
|
+
workerCount,
|
|
790
|
+
tasks: [{ subject: task, description: task, owner: 'worker-1', role: agentType }],
|
|
791
|
+
}),
|
|
792
|
+
allowDagHandoff: parsed.parsed.allowRepoAwareDagHandoff,
|
|
793
|
+
dagFallbackReason: parsed.parsed.dagFallbackReason,
|
|
794
|
+
approvedRepositoryContextSummary: parsed.parsed.approvedRepositoryContextSummary,
|
|
795
|
+
});
|
|
796
|
+
assert.equal(parsed.parsed.allowRepoAwareDagHandoff, false);
|
|
797
|
+
assert.equal(parsed.parsed.dagFallbackReason, scenario.expected);
|
|
798
|
+
assert.equal(parsed.parsed.approvedExecution, undefined);
|
|
799
|
+
assert.equal(executionPlan.metadata?.decomposition_source, 'legacy_text');
|
|
800
|
+
assert.equal(executionPlan.metadata?.fallback_reason, scenario.expected);
|
|
801
|
+
}
|
|
802
|
+
finally {
|
|
803
|
+
process.chdir(previousCwd);
|
|
804
|
+
await rm(wd, { recursive: true, force: true });
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
finally {
|
|
809
|
+
process.chdir(previousCwd);
|
|
810
|
+
}
|
|
811
|
+
});
|
|
473
812
|
it('preserves explicit team staffing overrides while reusing the approved plan task', async () => {
|
|
474
813
|
const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-override-'));
|
|
475
814
|
const previousCwd = process.cwd();
|
|
@@ -1764,6 +2103,120 @@ describe('teamCommand status', () => {
|
|
|
1764
2103
|
});
|
|
1765
2104
|
});
|
|
1766
2105
|
describe('teamCommand await', () => {
|
|
2106
|
+
it('applies project-scope agentReasoning overrides when CODEX_HOME is unset', async () => {
|
|
2107
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-team-project-reasoning-'));
|
|
2108
|
+
const binDir = join(wd, 'bin');
|
|
2109
|
+
const fakeCodexPath = join(binDir, 'codex');
|
|
2110
|
+
const captureDir = join(wd, 'captures');
|
|
2111
|
+
const previousCwd = process.cwd();
|
|
2112
|
+
const previousPath = process.env.PATH;
|
|
2113
|
+
const previousCodexHome = process.env.CODEX_HOME;
|
|
2114
|
+
const previousTmux = process.env.TMUX;
|
|
2115
|
+
const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
2116
|
+
const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
2117
|
+
const previousCaptureDir = process.env.OMX_ARGV_CAPTURE_DIR;
|
|
2118
|
+
const previousLaunchArgs = process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2119
|
+
const previousSkipReadyWait = process.env.OMX_TEAM_SKIP_READY_WAIT;
|
|
2120
|
+
const logs = [];
|
|
2121
|
+
const originalLog = console.log;
|
|
2122
|
+
const teamTask = 'project scoped architect reasoning override';
|
|
2123
|
+
let displayTeamName = '';
|
|
2124
|
+
await mkdir(binDir, { recursive: true });
|
|
2125
|
+
await mkdir(captureDir, { recursive: true });
|
|
2126
|
+
await mkdir(join(wd, '.omx'), { recursive: true });
|
|
2127
|
+
await mkdir(join(wd, '.codex', 'prompts'), { recursive: true });
|
|
2128
|
+
await writeFile(join(wd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'project' }, null, 2));
|
|
2129
|
+
await writeFile(join(wd, '.codex', '.omx-config.json'), JSON.stringify({
|
|
2130
|
+
agentReasoning: {
|
|
2131
|
+
architect: 'xhigh',
|
|
2132
|
+
},
|
|
2133
|
+
}, null, 2));
|
|
2134
|
+
await writeFile(join(wd, '.codex', 'prompts', 'architect.md'), '<identity>You are Architect.</identity>');
|
|
2135
|
+
await writeFile(fakeCodexPath, `#!/usr/bin/env node
|
|
2136
|
+
const fs = require('fs');
|
|
2137
|
+
const path = require('path');
|
|
2138
|
+
const worker = String(process.env.OMX_TEAM_WORKER || 'unknown').replace(/[^a-zA-Z0-9_-]+/g, '__');
|
|
2139
|
+
const out = path.join(process.env.OMX_ARGV_CAPTURE_DIR, worker + '.json');
|
|
2140
|
+
fs.writeFileSync(out, JSON.stringify({
|
|
2141
|
+
argv: process.argv.slice(2),
|
|
2142
|
+
codexHome: process.env.CODEX_HOME || null,
|
|
2143
|
+
worker,
|
|
2144
|
+
}, null, 2));
|
|
2145
|
+
process.stdin.resume();
|
|
2146
|
+
setTimeout(() => process.exit(0), 5000);
|
|
2147
|
+
process.on('SIGTERM', () => process.exit(0));
|
|
2148
|
+
`, { mode: 0o755 });
|
|
2149
|
+
let runtimeTeamName = null;
|
|
2150
|
+
try {
|
|
2151
|
+
process.chdir(wd);
|
|
2152
|
+
process.env.PATH = `${binDir}:${previousPath ?? ''}`;
|
|
2153
|
+
delete process.env.CODEX_HOME;
|
|
2154
|
+
delete process.env.TMUX;
|
|
2155
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2156
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'prompt';
|
|
2157
|
+
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
2158
|
+
process.env.OMX_ARGV_CAPTURE_DIR = captureDir;
|
|
2159
|
+
process.env.OMX_TEAM_SKIP_READY_WAIT = '1';
|
|
2160
|
+
console.log = (...args) => logs.push(args.map(String).join(' '));
|
|
2161
|
+
displayTeamName = parseTeamStartArgs(['1:architect', teamTask]).parsed.teamName;
|
|
2162
|
+
await withMockPromptModeCodexAllowed(() => withoutTeamTestWorkerEnv(() => teamCommand(['1:architect', teamTask])));
|
|
2163
|
+
const startedState = await readModeState('team', wd);
|
|
2164
|
+
runtimeTeamName = String(startedState?.team_name ?? parseTeamStartArgs(['1:architect', teamTask]).parsed.teamName);
|
|
2165
|
+
let captured = null;
|
|
2166
|
+
for (let attempt = 0; attempt < 50; attempt += 1) {
|
|
2167
|
+
const capturePath = join(captureDir, `${displayTeamName}__worker-1.json`);
|
|
2168
|
+
if (existsSync(capturePath)) {
|
|
2169
|
+
captured = JSON.parse(await readFile(capturePath, 'utf-8'));
|
|
2170
|
+
break;
|
|
2171
|
+
}
|
|
2172
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2173
|
+
}
|
|
2174
|
+
assert.ok(captured, 'worker argv capture file should be written');
|
|
2175
|
+
assert.equal(captured.codexHome, join(process.cwd(), '.codex'));
|
|
2176
|
+
assert.match(captured.argv.join(' '), /model_reasoning_effort="xhigh"/);
|
|
2177
|
+
assert.match(logs.join('\n'), /architect x1 .*xhigh reasoning/);
|
|
2178
|
+
}
|
|
2179
|
+
finally {
|
|
2180
|
+
console.log = originalLog;
|
|
2181
|
+
if (runtimeTeamName) {
|
|
2182
|
+
await shutdownTeam(runtimeTeamName, wd, { force: true }).catch(() => { });
|
|
2183
|
+
}
|
|
2184
|
+
process.chdir(previousCwd);
|
|
2185
|
+
if (typeof previousPath === 'string')
|
|
2186
|
+
process.env.PATH = previousPath;
|
|
2187
|
+
else
|
|
2188
|
+
delete process.env.PATH;
|
|
2189
|
+
if (typeof previousCodexHome === 'string')
|
|
2190
|
+
process.env.CODEX_HOME = previousCodexHome;
|
|
2191
|
+
else
|
|
2192
|
+
delete process.env.CODEX_HOME;
|
|
2193
|
+
if (typeof previousTmux === 'string')
|
|
2194
|
+
process.env.TMUX = previousTmux;
|
|
2195
|
+
else
|
|
2196
|
+
delete process.env.TMUX;
|
|
2197
|
+
if (typeof previousLaunchMode === 'string')
|
|
2198
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
|
|
2199
|
+
else
|
|
2200
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
2201
|
+
if (typeof previousWorkerCli === 'string')
|
|
2202
|
+
process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
|
|
2203
|
+
else
|
|
2204
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
2205
|
+
if (typeof previousCaptureDir === 'string')
|
|
2206
|
+
process.env.OMX_ARGV_CAPTURE_DIR = previousCaptureDir;
|
|
2207
|
+
else
|
|
2208
|
+
delete process.env.OMX_ARGV_CAPTURE_DIR;
|
|
2209
|
+
if (typeof previousLaunchArgs === 'string')
|
|
2210
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = previousLaunchArgs;
|
|
2211
|
+
else
|
|
2212
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2213
|
+
if (typeof previousSkipReadyWait === 'string')
|
|
2214
|
+
process.env.OMX_TEAM_SKIP_READY_WAIT = previousSkipReadyWait;
|
|
2215
|
+
else
|
|
2216
|
+
delete process.env.OMX_TEAM_SKIP_READY_WAIT;
|
|
2217
|
+
await rm(wd, { recursive: true, force: true });
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
1767
2220
|
it('returns next canonical event for a team in JSON mode', async () => {
|
|
1768
2221
|
const wd = await mkdtemp(join(tmpdir(), 'omx-team-await-'));
|
|
1769
2222
|
const previousCwd = process.cwd();
|