oh-my-opencode 4.16.0 → 4.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/.agents/skills/codex-qa/SKILL.md +9 -7
- package/.agents/skills/codex-qa/references/logging-debug.md +6 -4
- package/.agents/skills/opencode-qa/SKILL.md +9 -9
- package/.agents/skills/opencode-qa/references/tui-tmux.md +10 -8
- package/dist/cli/codex-ulw-loop.d.ts +8 -0
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +260 -207
- package/dist/cli-node/index.js +260 -207
- package/dist/features/background-agent/parent-wake-dedupe.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-flush-runner.d.ts +2 -0
- package/dist/features/background-agent/parent-wake-prompt-dispatch.d.ts +1 -0
- package/dist/features/builtin-commands/templates/refactor-sections/intro-and-analysis.d.ts +1 -1
- package/dist/features/builtin-commands/templates/remove-ai-slops.d.ts +1 -1
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/monitor/process.d.ts +17 -1
- package/dist/index.js +1098 -1020
- package/dist/skills/frontend/SKILL.md +9 -9
- package/dist/skills/frontend/references/design/README.md +7 -3
- package/dist/skills/frontend/references/design/_INDEX.md +1 -1
- package/dist/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/dist/skills/frontend/references/designpowers/README.md +2 -2
- package/dist/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/dist/skills/review-work/SKILL.md +3 -1
- package/dist/skills/start-work/SKILL.md +4 -2
- package/dist/skills/ulw-research/SKILL.md +3 -1
- package/dist/skills/visual-qa/SKILL.md +13 -17
- package/docs/reference/web-terminal-visual-qa.md +39 -45
- package/package.json +31 -25
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -1
- package/packages/omo-codex/plugin/components/teammode/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +3 -3
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +19 -10
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +19 -10
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +13 -0
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -1
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +19 -10
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +15 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +89 -27
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +55 -9
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-snapshot.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-snapshot.js +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.d.ts +10 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +15 -11
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +7 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +17 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +59 -11
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-snapshot.ts +38 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-types.ts +11 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +15 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +16 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +260 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-snapshot.test.ts +124 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +101 -2
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +64 -17
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +10 -6
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +186 -20
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +51 -3
- package/packages/omo-codex/plugin/scripts/migrate-codex-config.mjs +33 -5
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +9 -9
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +7 -3
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -3
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +3 -3
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +19 -10
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +7 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +13 -0
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +2 -0
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +14 -18
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +1 -1
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +35 -1
- package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +22 -9
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +275 -19
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +33 -0
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +4 -2
- package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +52 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +65 -39
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/shared-skills/skills/frontend/SKILL.md +9 -9
- package/packages/shared-skills/skills/frontend/references/design/README.md +7 -3
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +1 -1
- package/packages/shared-skills/skills/review-work/SKILL.md +3 -1
- package/packages/shared-skills/skills/start-work/SKILL.md +4 -2
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -1
- package/packages/shared-skills/skills/visual-qa/SKILL.md +13 -17
- package/script/qa/strip-ansi.mjs +10 -0
- package/script/qa/web-terminal-visual-qa.mjs +112 -195
- package/script/qa/xterm-live-terminal.mjs +180 -0
- package/script/qa/web-terminal-renderer.mjs +0 -218
|
@@ -19,7 +19,7 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
|
|
|
19
19
|
|
|
20
20
|
Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. `agent_type` works the same on both surfaces. If a code block below conflicts with this section, this section wins.
|
|
23
23
|
|
|
24
24
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
25
25
|
|
|
@@ -18,7 +18,7 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
|
|
|
18
18
|
|
|
19
19
|
Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. `agent_type` works the same on both surfaces. If a code block below conflicts with this section, this section wins.
|
|
22
22
|
|
|
23
23
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
24
24
|
|
|
@@ -19,7 +19,7 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
|
|
|
19
19
|
|
|
20
20
|
Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. `agent_type` works the same on both surfaces. If a code block below conflicts with this section, this section wins.
|
|
23
23
|
|
|
24
24
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
25
25
|
|
|
@@ -108,10 +108,10 @@ Each sub-task message must include:
|
|
|
108
108
|
4. Automated verification commands to run.
|
|
109
109
|
5. One Manual-QA channel, named with the exact tool and exact invocation (the literal `curl`, `send-keys`, `browser:control-in-app-browser` action, `page.click`, payload, selectors, and the binary observable that decides PASS/FAIL), not "verify it works". A LIGHT checkbox needs one real-surface proof of its deliverable, and auxiliary surfaces (CLI stdout, DB state diff, parsed config dump) are first-class when the surface is CLI- or data-shaped:
|
|
110
110
|
- HTTP call: `curl -i` against the live endpoint.
|
|
111
|
-
-
|
|
111
|
+
- Terminal / TUI: drive a real pty; `tmux send-keys` is fine for a boot/behavior smoke, but color/layout/CJK evidence goes through the xterm.js web terminal below, NEVER `tmux capture-pane`.
|
|
112
112
|
- Browser use: in Codex, use `browser:control-in-app-browser` first when available and the scenario does not need an authenticated or persistent user browser profile; otherwise drive the real page with Chrome, or agent-browser (https://github.com/vercel-labs/agent-browser) when Chrome is unavailable.
|
|
113
113
|
- Computer use: OS-level GUI automation against the running desktop app when the surface is not a page.
|
|
114
|
-
- TUI visual evidence: when a
|
|
114
|
+
- TUI visual evidence: when a TUI claim needs visual QA or PR proof, run `node script/qa/web-terminal-visual-qa.mjs --command "<cmd>" --input "{Enter}" --evidence-dir <dir>` (real pty rendered through xterm.js in Chrome) and attach `terminal.png` plus `metadata.json`.
|
|
115
115
|
6. The adversarial classes that apply to this sub-task (from the 9 ultraqa classes) and how each is probed.
|
|
116
116
|
7. Required artifact path and cleanup receipt.
|
|
117
117
|
|
|
@@ -19,7 +19,7 @@ Use a TEAM when EITHER holds:
|
|
|
19
19
|
- one task still needs exploration, yet its GOAL is already clear - parallel investigation under
|
|
20
20
|
a fixed objective.
|
|
21
21
|
|
|
22
|
-
Use plain subagents (`$ulw` / `multi_agent_v1.spawn_agent`) - NOT a team - when EITHER holds:
|
|
22
|
+
Use plain subagents (`$ulw` / `multi_agent_v1.spawn_agent` / flat `spawn_agent` on `multi_agent_v2`) - NOT a team - when EITHER holds:
|
|
23
23
|
- the work IS perfectly isolated, so there is no coordination cost worth paying; or
|
|
24
24
|
- the GOAL is still ambiguous, where one mind should resolve direction before any fan-out.
|
|
25
25
|
|
|
@@ -39,7 +39,7 @@ merge), not the keystrokes.
|
|
|
39
39
|
## Compose by part, ownership, or perspective - not by job title
|
|
40
40
|
|
|
41
41
|
A team is ALWAYS two or more members - never a single-member team. One worker on an isolated
|
|
42
|
-
job is a subagent
|
|
42
|
+
job is a spawned subagent, not a team; if you end up with a single member,
|
|
43
43
|
either split off a second distinct slice or drop the team and use a subagent.
|
|
44
44
|
|
|
45
45
|
Compose the team from what you actually KNOW about the work. Ground the split in real knowledge
|
|
@@ -110,7 +110,7 @@ do not treat the intended mutation as complete; retry after the named command fi
|
|
|
110
110
|
lose in the sidebar without this link.
|
|
111
111
|
|
|
112
112
|
Every team member is a real Codex thread created with `codex_app.create_thread` - this is strict,
|
|
113
|
-
not a preference. NEVER substitute `multi_agent_v1.spawn_agent
|
|
113
|
+
not a preference. NEVER substitute a spawned in-process subagent (`multi_agent_v1.spawn_agent` or flat `spawn_agent`)
|
|
114
114
|
for a team member: a spawned agent is an ephemeral helper that does not show up as a team thread,
|
|
115
115
|
cannot carry the `[team name] <member name>` title, and cannot be inspected, titled, archived, or
|
|
116
116
|
re-opened with the `codex_app.*` thread tools - which defeats the entire point of a durable team.
|
|
@@ -56,9 +56,10 @@ exercises the surface; capture the artifact.
|
|
|
56
56
|
1. HTTP call — hit the live endpoint with `curl -i` (or a
|
|
57
57
|
Playwright APIRequestContext); capture status line + headers +
|
|
58
58
|
body.
|
|
59
|
-
2.
|
|
60
|
-
|
|
61
|
-
is
|
|
59
|
+
2. Terminal / TUI - drive a real pty and prove it through the
|
|
60
|
+
xterm.js web terminal (see the TUI visual QA note below). tmux
|
|
61
|
+
`send-keys` is fine for a boot smoke; NEVER `tmux capture-pane`
|
|
62
|
+
for color / layout / CJK evidence, which degrades truecolor.
|
|
62
63
|
3. Browser use — in Codex, use `browser:control-in-app-browser`
|
|
63
64
|
first when available and no authenticated/persistent user browser
|
|
64
65
|
profile is required. Otherwise use Chrome to drive the REAL page;
|
|
@@ -86,13 +87,13 @@ channel scenario when the behavior is user-facing. `--dry-run`,
|
|
|
86
87
|
printing the command, "should respond", and "looks correct" never
|
|
87
88
|
count.
|
|
88
89
|
|
|
89
|
-
For TUI visual QA,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
For TUI visual QA, render the terminal through the real xterm.js web
|
|
91
|
+
terminal and screenshot it - never a `tmux capture-pane` dump, which
|
|
92
|
+
degrades color and wide-glyph width. In this repo:
|
|
93
|
+
`node script/qa/web-terminal-visual-qa.mjs --title "<surface>" --command "<cmd>" --input "{Enter}" --evidence-dir <dir>`
|
|
94
|
+
(live pty + xterm.js in Chrome; `--from-file <capture>` replays a raw
|
|
95
|
+
stream). Outside this repo, capture equivalent browser-rendered terminal
|
|
96
|
+
evidence: screenshot + plain transcript + cleanup receipt.
|
|
96
97
|
|
|
97
98
|
# Bootstrap (DO ALL FOUR BEFORE ANY OTHER WORK — NO SKIPPING)
|
|
98
99
|
|
|
@@ -265,6 +266,7 @@ Every `multi_agent_v1.spawn_agent` message is self-contained and starts with
|
|
|
265
266
|
handoff. Use `fork_context: false` unless full history is truly
|
|
266
267
|
required; paste only the context the child needs. Full-history forks can
|
|
267
268
|
make the child continue old parent context instead of the delegated task.
|
|
269
|
+
If your tool list has a flat `spawn_agent` with a required `task_name` instead of `multi_agent_v1.*` (`multi_agent_v2`), rewrite: `fork_context: false` becomes `fork_turns: "none"`, `send_input` becomes `send_message`, finished agents end on their own (no `close_agent`; `followup_task` re-tasks, `interrupt_agent` stops), and `wait_agent` takes only `timeout_ms`, returning on any child mailbox activity.
|
|
268
270
|
|
|
269
271
|
# TOML-backed subagent routing compatibility
|
|
270
272
|
Treat TOML-backed role routing as **routing-unverified**. The
|
|
@@ -294,6 +296,13 @@ evidence for that step. Do not start dependent implementation until the
|
|
|
294
296
|
audit, research, or review result is integrated or explicitly recorded
|
|
295
297
|
as inconclusive. Do not generate a plan before spawned research lanes
|
|
296
298
|
that feed the plan have returned or been closed as inconclusive.
|
|
299
|
+
Spawn every independent child for the current wave first. After the wave
|
|
300
|
+
is launched, run `multi_agent_v1.wait_agent` for each spawned child until
|
|
301
|
+
each reaches terminal status (`completed`, `failed`, `blocked`, or
|
|
302
|
+
explicitly recorded inconclusive) before any dependent `update_plan`
|
|
303
|
+
transition, `create_goal` continuation, implementation tool call, plan
|
|
304
|
+
drafting, approval-gate work, PR handoff, or final response. A timeout is
|
|
305
|
+
not terminal status.
|
|
297
306
|
Do not write the final answer, PR handoff, or completion summary while
|
|
298
307
|
active child agents remain open. Use short `multi_agent_v1.wait_agent` cycles.
|
|
299
308
|
After two silent waits send `TASK STILL ACTIVE: return <deliverable> or
|
|
@@ -22,7 +22,7 @@ This skill is intentionally compact. The full workflow lives in `references/full
|
|
|
22
22
|
- Use the ulw-loop CLI state under `.omo/ulw-loop`; do not hand-edit goal state.
|
|
23
23
|
- After any compaction or context loss, re-read brief + goals + ledger FIRST plus `omo ulw-loop status --json`, then resume; never re-plan from scratch.
|
|
24
24
|
- If `omo ulw-loop create-goals` says the existing aggregate is already complete, start unrelated new work with a fresh `--session-id <new-id>` instead of steering or forcing the completed default state. Use `--force` only to intentionally overwrite completed evidence.
|
|
25
|
-
- Every success criterion needs observable evidence from a real surface: a channel (
|
|
25
|
+
- Every success criterion needs observable evidence from a real surface: a channel (terminal/TUI via the xterm.js web terminal, HTTP, browser, computer-use) or, for CLI- or data-shaped criteria, an auxiliary surface (CLI stdout, DB diff, parsed config dump).
|
|
26
26
|
- Record evidence through the CLI only after cleanup receipts are available.
|
|
27
27
|
- Delegate code edits, test writes, fixes, and QA execution to right-sized Codex subagents when the workflow requires it.
|
|
28
28
|
- Every `multi_agent_v1.spawn_agent` message starts with `TASK:`, then names `DELIVERABLE`, `SCOPE`, and `VERIFY`; put role and specialty instructions inside `message`; use `fork_context: false` unless full history is truly required.
|
|
@@ -46,4 +46,6 @@ The full workflow may mention OpenCode-style orchestration examples. In Codex, t
|
|
|
46
46
|
| Wait for background result | `multi_agent_v1.wait_agent(...)` |
|
|
47
47
|
| Clean up finished worker | `multi_agent_v1.close_agent(...)` |
|
|
48
48
|
|
|
49
|
+
Flat `spawn_agent` requiring `task_name` instead (`multi_agent_v2`)? Rewrite rows: add `"task_name"`, `"fork_context":false` → `"fork_turns":"none"`, `wait_agent` takes only `timeout_ms`, no `close_agent` — finished agents end on their own.
|
|
50
|
+
|
|
49
51
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`.
|
|
@@ -19,16 +19,16 @@ Audit each pass, fail, block, steering change, and checkpoint in `.omo/ulw-loop/
|
|
|
19
19
|
Run each criterion's real-surface proof yourself through the channel that faithfully exercises it; capture the artifact before recording PASS.
|
|
20
20
|
|
|
21
21
|
1. **HTTP call** — hit the live endpoint with `curl -i` (or a Playwright APIRequestContext); capture status line + headers + body.
|
|
22
|
-
2. **
|
|
22
|
+
2. **Terminal / TUI** - prove it through the xterm.js web terminal; tmux `send-keys` is fine for a boot smoke, but NEVER `tmux capture-pane` for color/layout/CJK evidence (it degrades truecolor).
|
|
23
23
|
3. **Browser use** — in Codex, use `browser:control-in-app-browser` first when available and the scenario does not need an authenticated or persistent user browser profile. Otherwise use Chrome to drive the REAL page; if unavailable, use agent-browser. Capture action log + screenshot path. Never downgrade a browser-facing criterion.
|
|
24
24
|
4. **Computer use** — for desktop/GUI apps, drive the running app via OS automation (computer-use, AppleScript, xdotool, etc.); capture action log + screenshot.
|
|
25
25
|
|
|
26
|
-
For TUI visual QA,
|
|
27
|
-
screenshot
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
For TUI visual QA, render the terminal through the real xterm.js web terminal and
|
|
27
|
+
screenshot it - NEVER a `tmux capture-pane` dump (it degrades color and wide-glyph
|
|
28
|
+
width). In this repo run `node script/qa/web-terminal-visual-qa.mjs --command
|
|
29
|
+
"<cmd>" --input "{Enter}" --evidence-dir <dir>` (live pty + xterm.js in Chrome;
|
|
30
|
+
`--from-file` replays a raw stream) and record `terminal.png`, `terminal.txt`, and
|
|
31
|
+
`metadata.json`. Mandatory when a PR or review must inspect the terminal screen.
|
|
32
32
|
|
|
33
33
|
Auxiliary surfaces (CLI stdout / DB state diff / parsed config dump) are first-class evidence for CLI- or data-shaped criteria; use a channel scenario when the behavior is user-facing. `--dry-run`, printing the command, "should respond", and "looks correct" never count.
|
|
34
34
|
|
|
@@ -67,6 +67,19 @@ Fan out read-only research before deciding. Every spawn names DELIVERABLE / SCOP
|
|
|
67
67
|
multi_agent_v1.spawn_agent({"message":"TASK: act as an explorer. DELIVERABLE: ... SCOPE: ... VERIFY: ...","agent_type":"explorer","fork_context":false})
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
If your tool list has a flat `spawn_agent` with a required `task_name` instead of `multi_agent_v1.*` (`multi_agent_v2`), rewrite: add `"task_name":"<lowercase_digits_underscores>"`, replace `"fork_context":false` with `"fork_turns":"none"`, and `wait_agent` takes only `timeout_ms`, returning on any child mailbox activity (finished agents end on their own).
|
|
71
|
+
|
|
72
|
+
Spawn every independent child for the current wave first. After the wave
|
|
73
|
+
is launched, use `multi_agent_v1.wait_agent` for each child until each
|
|
74
|
+
reaches terminal status. A timeout is not terminal status. Do not start dependent planning, drafting, approval-gate work, or final handoff until each child result is integrated or recorded as inconclusive.
|
|
75
|
+
|
|
76
|
+
For work likely to exceed one wait cycle, require the child to send
|
|
77
|
+
`WORKING: <task> - <current phase>` before long passes and
|
|
78
|
+
`BLOCKED: <reason>` only when progress stops. A `multi_agent_v1.wait_agent`
|
|
79
|
+
timeout only means no new mailbox update arrived. Treat a running child as
|
|
80
|
+
alive. Fallback only when the child is completed without the deliverable,
|
|
81
|
+
ack-only after followup, explicitly `BLOCKED:`, or no longer running.
|
|
82
|
+
|
|
70
83
|
Roles: `explorer` (internal patterns/conventions/tests), `librarian` (external docs/contracts), `metis` (gap analysis), `momus` (high-accuracy plan review). Full spawn/wait/fallback discipline is in `references/full-workflow.md`.
|
|
71
84
|
|
|
72
85
|
## Stop rules
|
|
@@ -96,6 +96,8 @@ Every spawn starts with `TASK:`, then DELIVERABLE / SCOPE / VERIFY inside `messa
|
|
|
96
96
|
multi_agent_v1.spawn_agent({"message":"TASK: act as an explorer. DELIVERABLE: ... SCOPE: ... VERIFY: ...","agent_type":"explorer","fork_context":false})
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
If your tool list has a flat `spawn_agent` with a required `task_name` instead of `multi_agent_v1.*` (`multi_agent_v2`), rewrite: add `"task_name":"<lowercase_digits_underscores>"`, replace `"fork_context":false` with `"fork_turns":"none"`, and `wait_agent` takes only `timeout_ms`, returning on any child mailbox activity (finished agents end on their own — skip the close step).
|
|
100
|
+
|
|
99
101
|
Roles: `explorer`, `librarian`, `metis`, `momus`. Spawn long plan/reviewer agents in the background and poll with short waits; require the child to send `WORKING: <task> - <phase>` before long passes and `BLOCKED: <reason>` only when progress stops. A wait timeout only means no new mailbox update arrived; treat a running child as alive. Fall back only when the child completed without the deliverable, is ack-only after followup, explicitly `BLOCKED:`, or no longer running; then respawn a smaller `fork_context: false` job. Close each agent after integrating its result.
|
|
100
102
|
|
|
101
103
|
## Stop rules
|
|
@@ -19,7 +19,7 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
|
|
|
19
19
|
|
|
20
20
|
Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. `agent_type` works the same on both surfaces. If a code block below conflicts with this section, this section wins.
|
|
23
23
|
|
|
24
24
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
25
25
|
|
|
@@ -19,7 +19,7 @@ This skill may include examples copied from the OpenCode harness. In Codex, do n
|
|
|
19
19
|
|
|
20
20
|
Role-specific behavior must be described in a self-contained `message`. Use `fork_context: false` to start the child with only the initial prompt (no parent history); use `fork_context: true` only when full parent history is truly required. Include any required conversation context, files, diffs, constraints, and requested skill names directly in the spawned agent's `message`. OMO installs these selectable agent roles into `~/.codex/agents/`: `explorer`, `librarian`, `plan`, `momus`, `metis`, `lazycodex-code-reviewer`, `lazycodex-qa-executor`, and `lazycodex-gate-reviewer` - pass the matching name as `agent_type` so the child gets that role's model and instructions. If the spawn tool exposes no `agent_type` parameter, omit it and describe the role inside `message`. If a code block below conflicts with this section, this section wins.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Codex exposes ONE of two subagent tool surfaces per session; check your own tool list and route accordingly. If `multi_agent_v1.*` tools exist, use the table above as written. If instead a flat `spawn_agent` with a required `task_name` exists (`multi_agent_v2`), rewrite every `multi_agent_v1.*` example: `multi_agent_v1.spawn_agent({...,"fork_context":false})` becomes `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":...,"agent_type":...,"fork_turns":"none"})` (`"all"` only when full parent history is truly required); `send_input` becomes `send_message`; do not call `close_agent`/`resume_agent` (finished agents end on their own; `followup_task` re-tasks one, `interrupt_agent` stops one); `wait_agent` takes only `timeout_ms` and returns on any child mailbox activity. `agent_type` works the same on both surfaces. If a code block below conflicts with this section, this section wins.
|
|
23
23
|
|
|
24
24
|
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
|
|
25
25
|
|
|
@@ -79,32 +79,28 @@ For reference-fidelity work, repeat the capture and diff for every referenced vi
|
|
|
79
79
|
|
|
80
80
|
### TUI
|
|
81
81
|
|
|
82
|
-
1.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
tmux capture-pane -e -p > capture-ansi.txt
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
2. When the TUI evidence will be attached to a PR or reviewed visually, render
|
|
90
|
-
the capture through the browser helper from the repository root:
|
|
82
|
+
1. Render the TUI through the REAL xterm.js web terminal and screenshot it -
|
|
83
|
+
NEVER `tmux capture-pane`, which degrades truecolor and misaligns wide (CJK)
|
|
84
|
+
glyphs. Run the command in a real pty and capture the browser render from the
|
|
85
|
+
repository root:
|
|
91
86
|
|
|
92
87
|
```
|
|
93
88
|
node script/qa/web-terminal-visual-qa.mjs --title "TUI Visual QA" \
|
|
94
|
-
--
|
|
89
|
+
--command "<tui-command>" \
|
|
90
|
+
--input "{ArrowDown}" --input "{Enter}" \
|
|
95
91
|
--evidence-dir .omo/evidence/<slug>/tui-web-terminal
|
|
96
92
|
```
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
`terminal
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
metadata with cleanup receipt.
|
|
94
|
+
Replay a saved raw stream with `--from-file <capture.ansi>` instead of
|
|
95
|
+
`--command`. This produces `terminal.png` (the true-color artifact),
|
|
96
|
+
`terminal.txt`, `terminal-ansi.txt`, and `metadata.json`. Treat this as the
|
|
97
|
+
standard TUI visual artifact pattern. Outside this repo, copy the pattern:
|
|
98
|
+
real pty -> xterm.js in a browser -> PNG + metadata with cleanup receipt.
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
2. Run the width check on the produced text and keep the JSON:
|
|
105
101
|
|
|
106
102
|
```
|
|
107
|
-
node "$SKILL_DIR/scripts/visual-qa.mjs" tui-check
|
|
103
|
+
node "$SKILL_DIR/scripts/visual-qa.mjs" tui-check .omo/evidence/<slug>/tui-web-terminal/terminal.txt --cols <N>
|
|
108
104
|
```
|
|
109
105
|
|
|
110
106
|
Key fields: `maxWidth`, `overflowLines[]`, `borderMisaligned`, `wideCharColumns[]`, `hasAnsi`.
|
|
@@ -68,7 +68,7 @@ test("#given aggregate SubagentStop hooks #when inspected #then start-work and L
|
|
|
68
68
|
assert.equal(verifierGroups.length, 1);
|
|
69
69
|
assert.equal(verifierGroups[0]?.groupIndex, 0);
|
|
70
70
|
assert.equal(verifierGroups[0]?.handler.timeout, 10);
|
|
71
|
-
assert.
|
|
71
|
+
assert.match(verifierGroups[0]?.handler.statusMessage ?? "", /^\(OmO [^)]+\) Verifying LazyCodex Executor Evidence$/);
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
test("#given aggregate PostCompact hooks #when hooks are inspected #then LSP diagnostics cache reset is registered", async () => {
|
|
@@ -84,7 +84,7 @@ test("#given aggregate PostCompact hooks #when hooks are inspected #then LSP dia
|
|
|
84
84
|
|
|
85
85
|
// then
|
|
86
86
|
assert.equal(lspPostCompactHooks.length, 1);
|
|
87
|
-
assert.
|
|
87
|
+
assert.match(lspPostCompactHooks[0]?.handler.statusMessage ?? "", /^\(OmO [^)]+\) Resetting LSP Diagnostics Cache$/);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
test("#given aggregate hook commands #when inspected #then every command exposes a Codex status message", async () => {
|
|
@@ -218,7 +218,7 @@ test("#given aggregate PostToolUse hooks #when inspected #then CodeGraph init gu
|
|
|
218
218
|
// then
|
|
219
219
|
assert.equal(codegraphPostToolUseHooks.length, 1);
|
|
220
220
|
assert.equal(codegraphPostToolUseHooks[0]?.matcher, "^(codegraph[._].*|mcp__codegraph__.*)$");
|
|
221
|
-
assert.
|
|
221
|
+
assert.match(codegraphPostToolUseHooks[0]?.handler.statusMessage ?? "", /^\(OmO [^)]+\) Checking CodeGraph Init Guidance$/);
|
|
222
222
|
});
|
|
223
223
|
|
|
224
224
|
test("#given aggregate PostToolUse hooks #when inspected #then thread title hygiene is registered for created Codex threads", async () => {
|
|
@@ -235,7 +235,7 @@ test("#given aggregate PostToolUse hooks #when inspected #then thread title hygi
|
|
|
235
235
|
// then
|
|
236
236
|
assert.equal(threadTitleHooks.length, 1);
|
|
237
237
|
assert.equal(threadTitleHooks[0]?.matcher, "^(create_thread|codex_app\\.create_thread)$");
|
|
238
|
-
assert.
|
|
238
|
+
assert.match(threadTitleHooks[0]?.handler.statusMessage ?? "", /^\(OmO [^)]+\) Checking Thread Title Hygiene$/);
|
|
239
239
|
});
|
|
240
240
|
|
|
241
241
|
test("#given aggregate plugin packaging #when inspected #then hooks and compatibility sentinels stay Python-free", async () => {
|
|
@@ -88,7 +88,7 @@ export function findSpawnAgentCallsWithoutForkContextFalse(content) {
|
|
|
88
88
|
const regex = /spawn_agent\(([^)]*)\)/g;
|
|
89
89
|
for (const match of content.matchAll(regex)) {
|
|
90
90
|
const call = match[0];
|
|
91
|
-
if (!/"fork_context"\s*:\s*false|fork_context:\s*false|fork_context=false/.test(call)) {
|
|
91
|
+
if (!/"fork_context"\s*:\s*false|fork_context:\s*false|fork_context=false|"fork_turns"\s*:\s*"none"|fork_turns:\s*"none"|fork_turns="none"/.test(call)) {
|
|
92
92
|
missingForkContext.push(call);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -2,9 +2,10 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { mkdir, mkdtemp, readFile, symlink, utimes, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { PassThrough } from "node:stream";
|
|
5
6
|
import test from "node:test";
|
|
6
7
|
|
|
7
|
-
import { resolveAutoUpdatePlan, resolveLazyCodexUpdatePlan, runAutoUpdateCheck } from "../scripts/auto-update.mjs";
|
|
8
|
+
import { readSessionModelFromStdin, resolveAutoUpdatePlan, resolveLazyCodexUpdatePlan, runAutoUpdateCheck } from "../scripts/auto-update.mjs";
|
|
8
9
|
import { detectInstallFlow } from "../scripts/install-flow.mjs";
|
|
9
10
|
import { resolveSpawnInvocation } from "../scripts/spawn-command.mjs";
|
|
10
11
|
|
|
@@ -20,6 +21,12 @@ function autoUpdateEnv(root, extra = {}) {
|
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
function stdinFrom(payload) {
|
|
25
|
+
const stream = new PassThrough();
|
|
26
|
+
stream.end(payload);
|
|
27
|
+
return stream;
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
test("#given auto update is disabled #when resolving plan #then no command is scheduled", () => {
|
|
24
31
|
const plan = resolveAutoUpdatePlan({
|
|
25
32
|
env: { LAZYCODEX_AUTO_UPDATE_DISABLED: "1" },
|
|
@@ -31,6 +38,33 @@ test("#given auto update is disabled #when resolving plan #then no command is sc
|
|
|
31
38
|
assert.equal(plan.reason, "disabled");
|
|
32
39
|
});
|
|
33
40
|
|
|
41
|
+
test("#given SessionStart payload with model #when reading stdin #then returns the model", async () => {
|
|
42
|
+
const payload = JSON.stringify({
|
|
43
|
+
hook_event_name: "SessionStart",
|
|
44
|
+
session_id: "s-1",
|
|
45
|
+
cwd: "/tmp",
|
|
46
|
+
model: "gpt-5.6-terra",
|
|
47
|
+
permission_mode: "default",
|
|
48
|
+
source: "startup",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
assert.equal(await readSessionModelFromStdin(stdinFrom(payload)), "gpt-5.6-terra");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("#given empty or malformed stdin #when reading session model #then returns null", async () => {
|
|
55
|
+
assert.equal(await readSessionModelFromStdin(stdinFrom("")), null);
|
|
56
|
+
assert.equal(await readSessionModelFromStdin(stdinFrom("not json")), null);
|
|
57
|
+
assert.equal(await readSessionModelFromStdin(stdinFrom(JSON.stringify({ model: " " }))), null);
|
|
58
|
+
assert.equal(await readSessionModelFromStdin(stdinFrom(JSON.stringify({ session_id: "s-1" }))), null);
|
|
59
|
+
assert.equal(await readSessionModelFromStdin(null), null);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("#given a TTY stdin #when reading session model #then returns null without waiting", async () => {
|
|
63
|
+
const stream = stdinFrom("{}");
|
|
64
|
+
stream.isTTY = true;
|
|
65
|
+
assert.equal(await readSessionModelFromStdin(stream), null);
|
|
66
|
+
});
|
|
67
|
+
|
|
34
68
|
test("#given stale state #when resolving plan #then installer update command is scheduled", () => {
|
|
35
69
|
const plan = resolveAutoUpdatePlan({
|
|
36
70
|
env: { LAZYCODEX_CURRENT_VERSION: "1.0.0", LAZYCODEX_LATEST_VERSION: "1.0.1" },
|
|
@@ -171,7 +171,7 @@ test("#given the bootstrap component #when its SessionStart registration is insp
|
|
|
171
171
|
assert.equal(typeof handler.timeout, "number");
|
|
172
172
|
assert(handler.timeout <= 60, `${label} bootstrap timeout must stay <= 60 seconds`);
|
|
173
173
|
assert.equal(typeof handler.statusMessage, "string");
|
|
174
|
-
assert.match(handler.statusMessage, /^\(OmO
|
|
174
|
+
assert.match(handler.statusMessage, /^\(OmO [^)]+\) .+$/);
|
|
175
175
|
}
|
|
176
176
|
});
|
|
177
177
|
|
|
@@ -128,7 +128,7 @@ function collectCommandHooks(hooks, source, version) {
|
|
|
128
128
|
return commandHooks;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
test("#given hook status label #when formatting #then prefixes OmO display namespace", async () => {
|
|
131
|
+
test("#given hook status label #when formatting #then prefixes OmO display namespace and version", async () => {
|
|
132
132
|
// given
|
|
133
133
|
const version = (await readRepoJson("package.json")).version;
|
|
134
134
|
const label = "Checking Comments";
|
|
@@ -137,10 +137,10 @@ test("#given hook status label #when formatting #then prefixes OmO display names
|
|
|
137
137
|
const message = formatLazyCodexHookStatusMessage(version, label);
|
|
138
138
|
|
|
139
139
|
// then
|
|
140
|
-
assert.equal(message,
|
|
140
|
+
assert.equal(message, `(OmO ${version}) Checking Comments`);
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
-
test("#given hook status label with blank version #when formatting #then
|
|
143
|
+
test("#given hook status label with blank version #when formatting #then uses local OmO display version", () => {
|
|
144
144
|
// given
|
|
145
145
|
const version = " ";
|
|
146
146
|
const label = "Checking Comments";
|
|
@@ -149,7 +149,7 @@ test("#given hook status label with blank version #when formatting #then still p
|
|
|
149
149
|
const message = formatLazyCodexHookStatusMessage(version, label);
|
|
150
150
|
|
|
151
151
|
// then
|
|
152
|
-
assert.equal(message, "(OmO) Checking Comments");
|
|
152
|
+
assert.equal(message, "(OmO local) Checking Comments");
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
test("#given loose legacy status label #when normalizing #then removes OMO wording and title-cases label", async () => {
|
|
@@ -163,7 +163,7 @@ test("#given loose legacy status label #when normalizing #then removes OMO wordi
|
|
|
163
163
|
|
|
164
164
|
// then
|
|
165
165
|
assert.equal(normalized, "Checking Comments");
|
|
166
|
-
assert.equal(message,
|
|
166
|
+
assert.equal(message, `(OmO ${version}) Checking Comments`);
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
test("#given LazyCodex appears inside hook label #when normalizing #then product casing is preserved", async () => {
|
|
@@ -177,7 +177,7 @@ test("#given LazyCodex appears inside hook label #when normalizing #then product
|
|
|
177
177
|
|
|
178
178
|
// then
|
|
179
179
|
assert.equal(normalized, "Verifying LazyCodex Executor Evidence");
|
|
180
|
-
assert.equal(message,
|
|
180
|
+
assert.equal(message, `(OmO ${version}) Verifying LazyCodex Executor Evidence`);
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
test("#given MCP appears inside hook label #when normalizing #then protocol casing is preserved", () => {
|
|
@@ -190,7 +190,20 @@ test("#given MCP appears inside hook label #when normalizing #then protocol casi
|
|
|
190
190
|
|
|
191
191
|
// then
|
|
192
192
|
assert.equal(normalized, "Recommending Git Bash MCP");
|
|
193
|
-
assert.equal(message, "(OmO) Recommending Git Bash MCP");
|
|
193
|
+
assert.equal(message, "(OmO 4.10.0) Recommending Git Bash MCP");
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("#given versioned OmO status label #when normalizing #then it does not duplicate display prefix", () => {
|
|
197
|
+
// given
|
|
198
|
+
const label = "(OmO 4.16.0) checking comments";
|
|
199
|
+
|
|
200
|
+
// when
|
|
201
|
+
const parsed = parseLazyCodexHookStatusMessage(label);
|
|
202
|
+
const message = formatLazyCodexHookStatusMessage("4.16.1", label);
|
|
203
|
+
|
|
204
|
+
// then
|
|
205
|
+
assert.deepEqual(parsed, { version: "4.16.0", label: "checking comments" });
|
|
206
|
+
assert.equal(message, "(OmO 4.16.1) Checking Comments");
|
|
194
207
|
});
|
|
195
208
|
test("#given aggregate comment-checker hook #when status is inspected #then it uses OmO comments label", async () => {
|
|
196
209
|
// given
|
|
@@ -201,7 +214,7 @@ test("#given aggregate comment-checker hook #when status is inspected #then it u
|
|
|
201
214
|
const commentCheckerHook = hooks.find((hook) => hook.command.includes("components/comment-checker/dist/cli.js"));
|
|
202
215
|
|
|
203
216
|
// then
|
|
204
|
-
assert.equal(commentCheckerHook?.statusMessage, formatLazyCodexHookStatusMessage("", "Checking Comments"));
|
|
217
|
+
assert.equal(commentCheckerHook?.statusMessage, formatLazyCodexHookStatusMessage(commentCheckerHook?.version ?? "", "Checking Comments"));
|
|
205
218
|
assert.doesNotMatch(JSON.stringify(aggregateManifests), /checking\s+OMO\s+comments/i);
|
|
206
219
|
});
|
|
207
220
|
|
|
@@ -231,6 +244,6 @@ test("#given aggregate and component hooks #when status messages are inspected #
|
|
|
231
244
|
const actualLabels = new Set(commandHooks.map((hook) => parseLazyCodexHookStatusMessage(hook.statusMessage)?.label));
|
|
232
245
|
assert.deepEqual([...expectedLabels.values()].filter((label) => !actualLabels.has(label)), []);
|
|
233
246
|
for (const hook of commandHooks) {
|
|
234
|
-
assert.match(hook.statusMessage, /^\(OmO
|
|
247
|
+
assert.match(hook.statusMessage, /^\(OmO [^)]+\) /);
|
|
235
248
|
}
|
|
236
249
|
});
|