oh-my-opencode 4.15.1 → 4.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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/doctor/checks/tui-plugin-config.d.ts +4 -4
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +792 -744
- package/dist/cli/install-senpi/index.d.ts +1 -0
- package/dist/cli/run/poll-for-completion.d.ts +4 -0
- package/dist/cli/run/session-resolver.d.ts +1 -0
- package/dist/cli/senpi-platform-flag.d.ts +4 -0
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli-node/index.js +792 -744
- package/dist/features/background-agent/manager.d.ts +16 -0
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/monitor/process.d.ts +17 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/aggressive-truncation-strategy.d.ts +1 -0
- package/dist/index.js +2206 -1971
- package/dist/skills/debugging/references/methodology/06-fix.md +6 -0
- package/dist/skills/frontend/ATTRIBUTION.md +10 -1
- package/dist/skills/frontend/SKILL.md +12 -7
- package/dist/skills/frontend/references/design/README.md +8 -4
- package/dist/skills/frontend/references/design/_INDEX.md +2 -2
- package/dist/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/dist/skills/frontend/references/design/lazyweb.md +77 -0
- package/dist/skills/frontend/references/design/stitch-design-example.md +121 -0
- 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/programming/SKILL.md +10 -1
- package/dist/skills/programming/references/logging.md +91 -0
- package/dist/skills/start-work/SKILL.md +2 -2
- package/dist/skills/ulw-plan/SKILL.md +5 -5
- package/dist/skills/ulw-plan/references/full-workflow.md +7 -7
- package/dist/skills/ulw-plan/references/intent-unclear.md +3 -3
- package/dist/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/dist/skills/ulw-research/SKILL.md +28 -7
- package/dist/skills/visual-qa/SKILL.md +13 -17
- package/dist/tools/skill/description-formatter.d.ts +1 -0
- package/dist/tools/skill/description-formatter.test-support.d.ts +9 -0
- package/dist/tools/skill/zauc-mocks-skill-tools/test-support.d.ts +25 -0
- package/dist/tui.js +121 -419
- package/docs/reference/web-terminal-visual-qa.md +39 -45
- package/package.json +48 -25
- package/packages/git-bash-mcp/dist/cli.js +2 -2
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/AGENTS.md +55 -0
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +19 -16
- 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/AGENTS.md +51 -0
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +936 -248
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +233 -135
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +29 -0
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +13 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +25 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +30 -1
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +16 -2
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +80 -0
- package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +107 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +26 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +29 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +8 -21
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +108 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +76 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +17 -111
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +45 -67
- package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +56 -0
- 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/AGENTS.md +31 -0
- 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/AGENTS.md +45 -0
- 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 +37 -102
- 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 +2 -2
- 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/teammode/AGENTS.md +46 -0
- 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/telemetry/dist/cli.js +6 -0
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +6 -0
- 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/AGENTS.md +5 -2
- package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +18 -10
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +51 -2
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +14 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +388 -0
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +16 -2
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +5 -3
- package/packages/omo-codex/plugin/components/ultrawork/src/skill-pointer.ts +56 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +26 -5
- package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +12 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +82 -0
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +18 -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 +145 -32
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +5 -1
- 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/dist/ultrawork-directive.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.js +5 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.d.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.js +46 -0
- 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 +1 -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/codex-hook.ts +5 -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/src/ultrawork-directive.ts +9 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-skill-pointer.ts +55 -0
- 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/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/components/ulw-loop/test/ultrawork-directive.test.ts +49 -0
- 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/build-components.mjs +63 -17
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +10 -6
- package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +10 -3
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -0
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +18 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +6 -0
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +10 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +12 -7
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +8 -4
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/lazyweb.md +77 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stitch-design-example.md +121 -0
- 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/programming/SKILL.md +10 -1
- package/packages/omo-codex/plugin/skills/programming/references/logging.md +91 -0
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +388 -0
- package/packages/omo-codex/plugin/skills/ultrawork/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -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 +16 -2
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +28 -7
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +13 -17
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -4
- 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/install-time-build-runtime.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
- package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +56 -0
- package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +52 -0
- package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +98 -0
- package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +6 -6
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +310 -3979
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +6 -0
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +10 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +12 -7
- package/packages/shared-skills/skills/frontend/references/design/README.md +8 -4
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +24 -2
- package/packages/shared-skills/skills/frontend/references/design/lazyweb.md +77 -0
- package/packages/shared-skills/skills/frontend/references/design/stitch-design-example.md +121 -0
- 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/programming/SKILL.md +10 -1
- package/packages/shared-skills/skills/programming/references/logging.md +91 -0
- package/packages/shared-skills/skills/start-work/SKILL.md +2 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +5 -5
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +7 -7
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +3 -3
- package/packages/shared-skills/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/packages/shared-skills/skills/ulw-research/SKILL.md +28 -7
- 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
|
@@ -36,7 +36,7 @@ Make ONE judgment and follow ONE reference. Review modifiers are not routing sig
|
|
|
36
36
|
- CLEAR -> `intent-clear.md`: run the **two filters** on every candidate question; ask only surviving forks (owner-decisions), with WHY.
|
|
37
37
|
- UNCLEAR -> `intent-unclear.md`: research maximally, adopt announced best-practice defaults, do not ask the user extra questions.
|
|
38
38
|
|
|
39
|
-
If a draft/plan already exists and the user
|
|
39
|
+
If a draft/plan already exists and the user says a review modifier - even appended to an otherwise unrelated follow-up question - or asks to make the plan more accurate, do not reroute from scratch unless the scope changed. Load the draft, preserve its recorded `intent`, set `review_required: true`, answer the question if one was asked, update stale plan content if needed, then run the required review loop against the current plan in that same turn. A more rigorous answer is not a substitute for the review.
|
|
40
40
|
|
|
41
41
|
Both paths record `intent`, `review_required`, and decisions to `.omo/drafts/<slug>.md` as they go - long sessions outlive your context, and plan generation reads the draft, not your memory.
|
|
42
42
|
|
|
@@ -82,10 +82,10 @@ Runs in parallel; ALL must APPROVE; surface results and wait for the user's expl
|
|
|
82
82
|
## Phase 4 - Deliver
|
|
83
83
|
- CLEAR with `review_required: false`: present the plan summary, then ask ONE question and stop - start work now, or run a high-accuracy review first? Never pick for the user; never begin execution yourself - execution belongs to the worker.
|
|
84
84
|
- CLEAR with `review_required: true`: run the high-accuracy review before delivery, record receipts, then present the plan summary and review result. Do not ask whether to run the review; the user already asked.
|
|
85
|
-
- UNCLEAR: run
|
|
85
|
+
- UNCLEAR: run the high-accuracy review AUTOMATICALLY before presenting (unless Classify=Trivial), then present a brief that LEADS with the derived approach and the adopted defaults; still wait for the user's explicit okay.
|
|
86
86
|
|
|
87
87
|
### High-accuracy review (dual review)
|
|
88
|
-
The high-accuracy review is DUAL and both passes must return OKAY before handoff: (1) the native `momus` reviewer subagent, and (2) an independent Codex CLI review on gpt-5.5 at xhigh reasoning, run in a disposable isolated workspace and `CODEX_HOME` with the harness's normal approval and sandbox policy. Do not add flags that disable approvals or sandboxing.
|
|
88
|
+
The high-accuracy review is DUAL and both passes must return OKAY before handoff: (1) the native `momus` reviewer subagent, and (2) an independent Codex CLI review on gpt-5.5 at xhigh reasoning, run in a disposable isolated workspace and `CODEX_HOME` with the harness's normal approval and sandbox policy. Do not add flags that disable approvals or sandboxing. One round = exactly ONE `momus` + ONE independent review, dispatched together against the COMPLETE plan file (todos + TL;DR filled) - never a second `momus` while a round is in flight. After both verdicts return, fix every cited issue and resubmit both fresh until each approves. CLEAR: runs when the user opts in or `review_required: true`. UNCLEAR: runs automatically unless Classify=Trivial.
|
|
89
89
|
|
|
90
90
|
The draft must record the native Momus session/result, the independent Codex CLI review command/result, and the fix/retry summary. Do not say "high-accuracy review completed" unless both receipts exist and both final verdicts are unconditional approval.
|
|
91
91
|
|
|
@@ -99,6 +99,6 @@ multi_agent_v1.spawn_agent({"message":"TASK: act as an explorer. DELIVERABLE: ..
|
|
|
99
99
|
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
100
|
|
|
101
101
|
## Stop rules
|
|
102
|
-
- Plan file exists, template filled, every todo has references + acceptance + QA + commit, dependency matrix consistent: present the summary, ask the start-or-high-accuracy question (CLEAR
|
|
102
|
+
- Plan file exists, template filled, every todo has references + acceptance + QA + commit, dependency matrix consistent, and any required high-accuracy receipts recorded: present the summary, then (CLEAR without `review_required`) ask the start-or-high-accuracy question, or (CLEAR with `review_required` / UNCLEAR) report the review result - and stop. Execution belongs to the worker, never to you.
|
|
103
103
|
- Brief presented and `status: awaiting-approval` recorded: wait. Do not re-explore unless the user changes scope.
|
|
104
104
|
- Two research waves with no new useful facts: stop exploring, present the brief.
|
|
@@ -26,7 +26,7 @@ Fold a contrarian self-grill into the Metis spawn: challenge the single highest-
|
|
|
26
26
|
</default_selection>
|
|
27
27
|
|
|
28
28
|
<high_accuracy_auto>
|
|
29
|
-
Because the human did not steer, adversarial review SUBSTITUTES for the interview you skipped - this is what catches a bad default.
|
|
29
|
+
Because the human did not steer, adversarial review SUBSTITUTES for the interview you skipped - this is what catches a bad default. Metis runs during plan generation as always; after Metis findings are folded and the plan file is complete, run the dual high-accuracy review defined in `full-workflow.md` AUTOMATICALLY - no "do you want a review?" question - and resubmit fresh until BOTH passes APPROVE, fixing every cited issue.
|
|
30
30
|
|
|
31
31
|
TRIVIAL-TIER GUARD: if Classify sized the work Trivial, the auto-Momus loop is SUPPRESSED (Metis still runs once) - a vague-but-tiny request ("clean this up") must not trigger the full adversarial loop. UNCLEAR raises the research-plus-default posture; it does not override the Trivial cost guard for Momus.
|
|
32
32
|
</high_accuracy_auto>
|
|
@@ -40,5 +40,5 @@ Request: "make auth better".
|
|
|
40
40
|
1. Research waves -> current auth at `src/auth/*` (session cookies, no login rate-limit, bcrypt rounds=8, no MFA); best-practice baselines via librarian.
|
|
41
41
|
2. Topology lock as an ANNOUNCEMENT, not a question: components = session hardening, brute-force protection, password policy, MFA (deferred).
|
|
42
42
|
3. Adopted-defaults table (assumption | default | rationale | reversible?): bcrypt rounds 8 -> 12 (reversible), add 5/min-per-IP login limit (reversible), rotate session id on privilege change (reversible).
|
|
43
|
-
4.
|
|
43
|
+
4. Metis folded -> auto dual review (fix cited gaps until both approve) -> brief LEADING with the approach and the defaults, surfaced in the human TL;DR for veto.
|
|
44
44
|
</worked_example>
|
|
@@ -7,9 +7,9 @@ is adapted into this skill's prompt contract.
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## 1. insane-research (fivetaku) — inspiration for the claim-
|
|
10
|
+
## 1. insane-research (fivetaku) — inspiration for the claim-graph verification gate
|
|
11
11
|
|
|
12
|
-
The non-code claim-
|
|
12
|
+
The non-code claim-graph verification gate (Phase 3b: a data-flow-lock where the
|
|
13
13
|
synthesis may assert a high-risk non-code claim only after it clears `>= 2 independent
|
|
14
14
|
source domains + 1 counter-search + a primary source`, otherwise it is abstained to an
|
|
15
15
|
unresolved/refuted annex) is inspired by the data-flow-lock verification design in
|
|
@@ -51,9 +51,22 @@ The research is done when all of these hold:
|
|
|
51
51
|
- Every EXPAND lead was investigated or explicitly closed as a duplicate or dead end, and convergence was reached under the Phase 2 rules.
|
|
52
52
|
- Claims that were contested, undocumented, or performance-shaped were proven or refuted by executed code.
|
|
53
53
|
- Every claim in the deliverable cites a source or a verification artifact.
|
|
54
|
+
- Every asserted claim is represented in the claim graph, tied to an intent-vs-reality diff when an expected truth exists, and backed by observation manifest entries from independent observation groups or a documented single-source exception; convergence or exception status is explicit.
|
|
54
55
|
- Final materials follow the Phase 5 format default or the user's explicit format.
|
|
55
56
|
- The session journal reconstructs what was searched, found, and expanded, wave by wave.
|
|
56
57
|
|
|
58
|
+
## Epistemic instrumentation
|
|
59
|
+
|
|
60
|
+
Saturation is not just more searching; it is a knowledge-production protocol. The session journal must make the path from observation to claim to verdict auditable. The orchestrator owns these artifacts:
|
|
61
|
+
|
|
62
|
+
- `intent-diff.md` — one row per expected truth derived from the user intent, design/spec text, branch history, or authoritative docs. Required fields: `intent_id`, expected truth, observed reality, diff, violated invariant, intent source, supporting observations, status (`true`, `violated`, or `unknown`), and linked claim ids.
|
|
63
|
+
- `claim-graph.md` — the single claim store; one node per claim. Required fields: `claim_id`, statement, claim type, risk tier, scope, intent ids, supporting observations, contradicting observations, independent observation groups, convergence status, counter-search result, primary source backing, dependencies, status (`supported`, `partial`, `refuted`, or `unresolved`), and final synthesis location. High-risk non-code nodes that clear the Phase 3b gate are mirrored into a `verified-claims` digest section at the top of the file — the sole allowlist the synthesis draws non-code claims from.
|
|
64
|
+
- `observation-manifest.md` — one row per observation. Required fields: `observation_id`, source path or URL, evidence layer, observer group, independence basis, observer, `observed_at`, `valid_at` or `claim_valid_at`, artifact path, quote or line anchor, and contamination notes.
|
|
65
|
+
- `verification-economics.md` — one row per proof decision. Required fields: claim, risk, error cost, verification cost/time, chosen verification path, defer/verify decision, outcome, and residual risk.
|
|
66
|
+
- `cause-disappearance.md` — one row per causal finding. Required fields: cause id, expected truth, previous observation, `last_seen`, disconfirming observation, replacement cause if any, current status, and whether the violation is no longer observed.
|
|
67
|
+
|
|
68
|
+
Observation candidates and claim candidates travel back from workers as message text. The orchestrator writes the instrumentation artifacts, links candidates into the intent diff and claim graph, and records where each observation entered the synthesis. A conclusion is not ready for final materials until its expected truth/reality diff is closed or marked unknown, its claim node exists, and its independent-observation convergence status is supported or explicitly excepted.
|
|
69
|
+
|
|
57
70
|
## Run the swarm as a cooperating team
|
|
58
71
|
|
|
59
72
|
Saturation research defaults to teammode, not isolated fire-and-forget workers: a lead one worker surfaces almost always reshapes what another should search next. When your harness gives you real cooperating members — Codex: the `teammode` skill (`codex_app` threads); OpenCode: `team_mode` — run this swarm as a team. Fall back to the background-worker swarm below only when team mode is unavailable, or the axes are genuinely independent with no cross-pollination expected.
|
|
@@ -80,7 +93,7 @@ Every research spawn message contains, in order:
|
|
|
80
93
|
2. The budget lift: "This is an explicit exhaustive-research assignment. Your default retrieval budget and stop-when-answered rules do not apply — run the full protocol below and report every lead."
|
|
81
94
|
3. Scope — the axis, the sources to hit, and what a complete answer contains.
|
|
82
95
|
4. The role protocol (Phase 1).
|
|
83
|
-
5. The reply tail. EXPAND markers travel back as message text, never as files. Every worker ends the reply with:
|
|
96
|
+
5. The reply tail. EXPAND markers, observation candidates, and claim candidates travel back as message text, never as files. Every worker ends the reply with:
|
|
84
97
|
|
|
85
98
|
```
|
|
86
99
|
## EXPAND
|
|
@@ -92,7 +105,7 @@ A worker with nothing to expand writes `## EXPAND` followed by `none — <one-li
|
|
|
92
105
|
|
|
93
106
|
## Phase 0 — Decompose and open the journal
|
|
94
107
|
|
|
95
|
-
Before spawning anything, decompose the query:
|
|
108
|
+
Before spawning anything, decompose the query. Start from "what must be true if the user's intent/spec is true?", not "what looks broken?" Seed `intent-diff.md` with those expected truths before treating code, current docs, or web results as the source of truth:
|
|
96
109
|
|
|
97
110
|
```
|
|
98
111
|
<analysis>
|
|
@@ -112,6 +125,11 @@ This is `$SESSION_DIR`. The orchestrator owns the journal: you write every file
|
|
|
112
125
|
|
|
113
126
|
- `wave-<N>-<kind>-<axis>.md` — your digest of each worker return: key findings, sources with URLs, and the worker's EXPAND markers verbatim.
|
|
114
127
|
- `expansion-log.md` — per wave: workers spawned, markers gained, leads opened and closed.
|
|
128
|
+
- `intent-diff.md` — orchestrator-owned expected-truth ledger comparing intent/spec/history to observed reality.
|
|
129
|
+
- `claim-graph.md` — orchestrator-owned claim graph linking every final assertion to observations, counterevidence, dependencies, and verdict.
|
|
130
|
+
- `observation-manifest.md` — orchestrator-owned observation manifest with `observed_at`, temporal validity, artifact paths, and contamination notes.
|
|
131
|
+
- `verification-economics.md` — proof-cost ledger mapping claim risk to verification path, deferral decisions, and residual risk.
|
|
132
|
+
- `cause-disappearance.md` — cause ledger tracking expected truth, previous observation, `last_seen`, disconfirming observation, and whether the violation is no longer observed.
|
|
115
133
|
- `verify-<slug>.md`, `SYNTHESIS.md`, `REPORT.*` from later phases.
|
|
116
134
|
|
|
117
135
|
Append each digest the moment its worker returns, not in a batch at the end — the journal is your recovery point after context loss and the user's audit trail.
|
|
@@ -183,19 +201,21 @@ Reply with: the exact code, the full output, environment (OS, runtime, dependenc
|
|
|
183
201
|
|
|
184
202
|
Journal each verdict to `verify-<slug>.md`.
|
|
185
203
|
|
|
186
|
-
## Phase 3b — Lock non-code claims through
|
|
204
|
+
## Phase 3b — Lock non-code claims through the claim graph
|
|
187
205
|
|
|
188
206
|
Code settles code-shaped claims (Phase 3). Numeric, market-share, legal, dated, causal, and financial claims cannot be run — so they pass through a data-flow-lock instead (the verification idea adapted from fivetaku/insane-research): the synthesis may assert a high-risk non-code claim **only** if it cleared this gate, and the gate's output is the sole allowlist the synthesis draws from. Skip the gate and there is nothing to synthesize — the lock is self-enforcing.
|
|
189
207
|
|
|
190
|
-
The claim
|
|
208
|
+
The claim graph is orchestrator-owned. Workers only return verified-claim markers, observation candidates, and claim candidates as message text, the same channel as EXPAND markers — never a file. As leads resolve, you record one node per asserted claim in `claim-graph.md` and compute its status; workers report claim candidates in their replies, and you decide. The graph is the single claim store: final synthesis may not draw from free-form claims that skipped it.
|
|
191
209
|
|
|
192
210
|
A high-risk claim clears the gate to `verified-claims` only when all hold:
|
|
193
211
|
|
|
194
212
|
- **>= 2 independent source domains** corroborate it (two pages on the same domain count once).
|
|
213
|
+
- **>= 2 independent observation groups** converge on it, unless the graph records why a primary-only source is the correct single-source exception.
|
|
195
214
|
- **One counter-search** actively looked for a refutation and did not find a stronger one.
|
|
196
215
|
- **A primary source** (the standard, filing, dataset, or first-party doc) backs it, not only secondary commentary.
|
|
216
|
+
- **Temporal evidence is explicit**: each supporting observation records `observed_at` and either `valid_at` or `claim_valid_at`, so branch-only, historical, release, and current-runtime claims cannot be conflated.
|
|
197
217
|
|
|
198
|
-
Anything that fails goes to an `Unresolved` (insufficient evidence) or `Refuted` (counter-search won) annex — abstention is a correct outcome, not a gap to paper over.
|
|
218
|
+
Anything that fails goes to an `Unresolved` (insufficient evidence) or `Refuted` (counter-search won) annex — abstention is a correct outcome, not a gap to paper over. Record each gate outcome on the claim node itself — risk tier, independent source domains, counter-search result, primary source backing, and status — and mirror the cleared nodes into the `verified-claims` digest section at the top of `claim-graph.md`. Worker reply marker (message text, same channel as EXPAND):
|
|
199
219
|
|
|
200
220
|
```
|
|
201
221
|
## CLAIMS
|
|
@@ -204,7 +224,7 @@ Anything that fails goes to an `Unresolved` (insufficient evidence) or `Refuted`
|
|
|
204
224
|
|
|
205
225
|
## Phase 4 — Synthesize
|
|
206
226
|
|
|
207
|
-
After convergence and all verifications, re-read the whole journal and write `SYNTHESIS.md`:
|
|
227
|
+
After convergence and all verifications, re-read the whole journal, start from `intent-diff.md`, `claim-graph.md`, and `observation-manifest.md`, then write `SYNTHESIS.md`:
|
|
208
228
|
|
|
209
229
|
```
|
|
210
230
|
# ULW-Research Synthesis: <query>
|
|
@@ -215,8 +235,9 @@ Workers: <total> · Waves: <count> · Sources: <count> · Verifications: <count>
|
|
|
215
235
|
## Codebase findings — absolute paths with line references
|
|
216
236
|
## Sources (ranked) — URL, what it contains, reliability, access date
|
|
217
237
|
## Verified claims — code: claim | verdict | verify-<slug>.md · non-code: only rows cleared into verified-claims
|
|
238
|
+
## Epistemic instrumentation — intent-vs-reality diff closure, claim graph coverage, observation manifest coverage, independent-observation convergence, verification economics summary, cause-disappearance records
|
|
218
239
|
## Contradictions — source A vs source B, resolution with evidence
|
|
219
|
-
## Gaps — what saturation could not answer · unresolved/refuted claim-
|
|
240
|
+
## Gaps — what saturation could not answer · unresolved/refuted claim-graph nodes
|
|
220
241
|
## Expansion trace — per wave: workers → markers; convergence reason
|
|
221
242
|
```
|
|
222
243
|
|
|
@@ -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 () => {
|
|
@@ -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
|
});
|
|
@@ -14,7 +14,7 @@ test("#given aggregate build scripts #when inspected #then component CLIs are bu
|
|
|
14
14
|
const componentBuildScript = buildComponentsScript;
|
|
15
15
|
|
|
16
16
|
// then
|
|
17
|
-
assert.match(componentBuildScript, /
|
|
17
|
+
assert.match(componentBuildScript, /"bun", \["build", entry, "--target", "node", "--format", "esm", "--outfile", output\]/);
|
|
18
18
|
assert.doesNotMatch(componentBuildScript, /\bbun\s+run\b/);
|
|
19
19
|
});
|
|
20
20
|
|
|
@@ -88,10 +88,10 @@ test("#given source package versions and component without hooks #when hook stat
|
|
|
88
88
|
const aggregateHooks = await readJson(join(root, "hooks", "hooks.json"));
|
|
89
89
|
const componentHooks = await readJson(join(root, "components", "comment-checker", "hooks", "hooks.json"));
|
|
90
90
|
const lspHooks = await readJson(join(root, "components", "lsp", "hooks", "hooks.json"));
|
|
91
|
-
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking Comments");
|
|
92
|
-
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[1].statusMessage, "(OmO) Checking LSP Diagnostics");
|
|
93
|
-
assert.equal(componentHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking Comments");
|
|
94
|
-
assert.equal(lspHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking LSP Diagnostics");
|
|
91
|
+
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 0.1.0) Checking Comments");
|
|
92
|
+
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[1].statusMessage, "(OmO 0.1.0) Checking LSP Diagnostics");
|
|
93
|
+
assert.equal(componentHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 0.1.1) Checking Comments");
|
|
94
|
+
assert.equal(lspHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 0.2.0) Checking LSP Diagnostics");
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
test("#given release version override #when hook status messages sync #then aggregate hooks use release version", async () => {
|
|
@@ -139,6 +139,6 @@ test("#given release version override #when hook status messages sync #then aggr
|
|
|
139
139
|
// then
|
|
140
140
|
const aggregateHooks = await readJson(join(root, "hooks", "hooks.json"));
|
|
141
141
|
const componentHooks = await readJson(join(root, "components", "comment-checker", "hooks", "hooks.json"));
|
|
142
|
-
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking Comments");
|
|
143
|
-
assert.equal(componentHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO) Checking Comments");
|
|
142
|
+
assert.equal(aggregateHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 4.8.0) Checking Comments");
|
|
143
|
+
assert.equal(componentHooks.hooks.PostToolUse[0].hooks[0].statusMessage, "(OmO 4.8.0) Checking Comments");
|
|
144
144
|
});
|
|
@@ -25,6 +25,7 @@ export const expectedSkills = [
|
|
|
25
25
|
"start-work",
|
|
26
26
|
"teammode",
|
|
27
27
|
"ultimate-browsing",
|
|
28
|
+
"ultrawork",
|
|
28
29
|
"ulw-loop",
|
|
29
30
|
"ulw-plan",
|
|
30
31
|
"ulw-research",
|
|
@@ -40,6 +41,7 @@ export const componentSkillSources = [
|
|
|
40
41
|
["teammode", "components/teammode/skills/teammode"],
|
|
41
42
|
["ulw-loop", "components/ulw-loop/skills/ulw-loop"],
|
|
42
43
|
["ulw-plan", "components/ultrawork/skills/ulw-plan"],
|
|
44
|
+
["ultrawork", "components/ultrawork/skills/ultrawork"],
|
|
43
45
|
];
|
|
44
46
|
|
|
45
47
|
const codexCompatibilityEndMarkers = [
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import { root } from "./aggregate-plugin-fixture.mjs";
|
|
8
|
+
|
|
9
|
+
const POINTER_MAX_BYTES = 4096;
|
|
10
|
+
const skillPath = join(root, "skills", "ultrawork", "SKILL.md");
|
|
11
|
+
|
|
12
|
+
function runUserPromptSubmitCli(component, extraArgs = []) {
|
|
13
|
+
const payload = {
|
|
14
|
+
hook_event_name: "UserPromptSubmit",
|
|
15
|
+
session_id: "s-ultrawork-pointer",
|
|
16
|
+
turn_id: "t-ultrawork-pointer",
|
|
17
|
+
transcript_path: null,
|
|
18
|
+
cwd: root,
|
|
19
|
+
model: "gpt-5.5",
|
|
20
|
+
permission_mode: "default",
|
|
21
|
+
prompt: "ulw this change",
|
|
22
|
+
};
|
|
23
|
+
return spawnSync(
|
|
24
|
+
process.execPath,
|
|
25
|
+
[join(root, "components", component, "dist", "cli.js"), "hook", "user-prompt-submit", ...extraArgs],
|
|
26
|
+
{ cwd: root, encoding: "utf8", input: `${JSON.stringify(payload)}\n` },
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
test("#given synced skills #when the ultrawork skill is inspected #then it carries the full directive body", () => {
|
|
31
|
+
assert.equal(existsSync(skillPath), true);
|
|
32
|
+
const skill = readFileSync(skillPath, "utf8");
|
|
33
|
+
const directive = readFileSync(join(root, "components", "ultrawork", "directive.md"), "utf8");
|
|
34
|
+
assert.match(skill, /^---\nname: ultrawork\n/);
|
|
35
|
+
assert.equal(skill.endsWith(directive), true);
|
|
36
|
+
assert.match(skill, /## 1\. Create the goal with binding success criteria/);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("#given the built ultrawork CLI #when a ulw prompt is submitted #then a compact skill pointer is emitted", () => {
|
|
40
|
+
const result = runUserPromptSubmitCli("ultrawork");
|
|
41
|
+
assert.equal(result.status, 0);
|
|
42
|
+
const output = JSON.parse(result.stdout);
|
|
43
|
+
const context = output.hookSpecificOutput.additionalContext;
|
|
44
|
+
assert.match(context, /^<ultrawork-mode>/);
|
|
45
|
+
assert.match(context, /First user-visible line this turn MUST be exactly:/);
|
|
46
|
+
assert.match(context, /create_goal/);
|
|
47
|
+
assert.equal(context.includes(skillPath), true);
|
|
48
|
+
assert.equal(context.includes("Tier triage"), false);
|
|
49
|
+
assert.equal(Buffer.byteLength(context, "utf8") < POINTER_MAX_BYTES, true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("#given the built ultrawork and ulw-loop CLIs #when both emit the pointer #then the payloads match byte for byte", () => {
|
|
53
|
+
const ultrawork = JSON.parse(runUserPromptSubmitCli("ultrawork").stdout);
|
|
54
|
+
const ulwLoop = JSON.parse(runUserPromptSubmitCli("ulw-loop", ["--with-ultrawork"]).stdout);
|
|
55
|
+
assert.equal(ulwLoop.hookSpecificOutput.additionalContext, ultrawork.hookSpecificOutput.additionalContext);
|
|
56
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
|
|
9
|
+
async function readUlwPlanCopies() {
|
|
10
|
+
const componentPath = join(root, "components", "ultrawork", "skills", "ulw-plan", "SKILL.md");
|
|
11
|
+
const packagedPath = join(root, "skills", "ulw-plan", "SKILL.md");
|
|
12
|
+
return [
|
|
13
|
+
{ label: "component", path: componentPath, content: await readFile(componentPath, "utf8") },
|
|
14
|
+
{ label: "packaged", path: packagedPath, content: await readFile(packagedPath, "utf8") },
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
test("#given ulw-plan skill #when Codex delegation is inspected #then spawned planners block dependent work", async () => {
|
|
19
|
+
for (const copy of await readUlwPlanCopies()) {
|
|
20
|
+
assert.match(copy.content, /multi_agent_v1\.spawn_agent/, `${copy.label}: must document Codex spawning`);
|
|
21
|
+
assert.match(copy.content, /multi_agent_v1\.wait_agent/, `${copy.label}: must document Codex waiting`);
|
|
22
|
+
assert.match(
|
|
23
|
+
copy.content,
|
|
24
|
+
/Spawn every independent child for the current wave first/i,
|
|
25
|
+
`${copy.label}: must preserve independent spawn waves`,
|
|
26
|
+
);
|
|
27
|
+
assert.match(
|
|
28
|
+
copy.content,
|
|
29
|
+
/After the wave\s+is launched[\s\S]{0,240}multi_agent_v1\.wait_agent[\s\S]{0,240}terminal status/i,
|
|
30
|
+
`${copy.label}: must wait after the wave is launched`,
|
|
31
|
+
);
|
|
32
|
+
assert.doesNotMatch(
|
|
33
|
+
copy.content,
|
|
34
|
+
/Immediately after any `multi_agent_v1\.spawn_agent`/i,
|
|
35
|
+
`${copy.label}: must not serialize independent spawns`,
|
|
36
|
+
);
|
|
37
|
+
assert.match(copy.content, /terminal status/i, `${copy.label}: must wait until terminal status`);
|
|
38
|
+
assert.match(copy.content, /WORKING:/, `${copy.label}: must keep progress liveness guidance`);
|
|
39
|
+
assert.match(copy.content, /BLOCKED:/, `${copy.label}: must keep blocked liveness guidance`);
|
|
40
|
+
assert.match(
|
|
41
|
+
copy.content,
|
|
42
|
+
/timeout only means no new mailbox update arrived/i,
|
|
43
|
+
`${copy.label}: must frame wait timeouts as mailbox silence`,
|
|
44
|
+
);
|
|
45
|
+
assert.match(copy.content, /Fallback only when/, `${copy.label}: must keep explicit fallback conditions`);
|
|
46
|
+
assert.match(
|
|
47
|
+
copy.content,
|
|
48
|
+
/do not start dependent planning, drafting, approval-gate work, or final handoff/i,
|
|
49
|
+
`${copy.label}: must block dependent planning work before child results are integrated`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { sharedSkillsRootPath } from "@oh-my-opencode/shared-skills";
|
|
7
|
+
|
|
8
|
+
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
|
|
10
|
+
async function readUlwResearchCopies() {
|
|
11
|
+
const sharedPath = join(sharedSkillsRootPath(), "ulw-research", "SKILL.md");
|
|
12
|
+
const packagedPath = join(root, "skills", "ulw-research", "SKILL.md");
|
|
13
|
+
return [
|
|
14
|
+
{ label: "shared", path: sharedPath, content: await readFile(sharedPath, "utf8") },
|
|
15
|
+
{ label: "packaged", path: packagedPath, content: await readFile(packagedPath, "utf8") },
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function escapeRegExp(value) {
|
|
20
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function markdownSection(content, heading, nextHeading) {
|
|
24
|
+
const headingPattern = new RegExp(`^${escapeRegExp(heading)}\\r?$`, "m");
|
|
25
|
+
const headingMatch = content.match(headingPattern);
|
|
26
|
+
assert.notEqual(headingMatch, null, `SKILL.md section not found: ${heading}`);
|
|
27
|
+
assert.notEqual(headingMatch.index, undefined, `SKILL.md section index not found: ${heading}`);
|
|
28
|
+
const bodyStart = headingMatch.index + headingMatch[0].length;
|
|
29
|
+
if (nextHeading === undefined) return content.slice(bodyStart);
|
|
30
|
+
const nextHeadingIndex = content.indexOf(`\n${nextHeading}`, bodyStart);
|
|
31
|
+
assert.notEqual(nextHeadingIndex, -1, `SKILL.md next section not found: ${nextHeading}`);
|
|
32
|
+
return content.slice(bodyStart, nextHeadingIndex);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test("#given ulw-research epistemic instrumentation #when the research contract is inspected #then the meta-layer artifacts and fields are required", async () => {
|
|
36
|
+
for (const copy of await readUlwResearchCopies()) {
|
|
37
|
+
const section = markdownSection(copy.content, "## Epistemic instrumentation", "## Run the swarm as a cooperating team");
|
|
38
|
+
assert.match(section, /intent-diff\.md/i, `${copy.label}: body must require an intent-vs-reality diff artifact`);
|
|
39
|
+
assert.match(section, /expected truth/i, `${copy.label}: intent diff must record expected truth`);
|
|
40
|
+
assert.match(section, /observed reality/i, `${copy.label}: intent diff must record observed reality`);
|
|
41
|
+
assert.match(section, /diff, violated invariant/i, `${copy.label}: intent diff must record the diff gap field and violated invariant`);
|
|
42
|
+
assert.match(section, /claim-graph\.md/i, `${copy.label}: body must require a claim graph`);
|
|
43
|
+
assert.match(section, /independent observation groups/i, `${copy.label}: claim graph must track independent observation groups`);
|
|
44
|
+
assert.match(section, /convergence status/i, `${copy.label}: claim graph must track convergence status`);
|
|
45
|
+
const claimGraphBullet = section.split("\n").find((line) => line.includes("`claim-graph.md`"));
|
|
46
|
+
assert.notEqual(claimGraphBullet, undefined, `${copy.label}: claim graph bullet must exist`);
|
|
47
|
+
assert.match(claimGraphBullet, /single claim store/i, `${copy.label}: claim graph must be the single claim store`);
|
|
48
|
+
assert.match(claimGraphBullet, /risk tier/i, `${copy.label}: claim graph nodes must carry a risk tier`);
|
|
49
|
+
assert.match(claimGraphBullet, /counter-search/i, `${copy.label}: claim graph nodes must carry the counter-search result`);
|
|
50
|
+
assert.match(claimGraphBullet, /primary source/i, `${copy.label}: claim graph nodes must carry primary source backing`);
|
|
51
|
+
assert.match(claimGraphBullet, /verified-claims/i, `${copy.label}: cleared nodes must feed the verified-claims digest`);
|
|
52
|
+
assert.match(section, /observation-manifest\.md/i, `${copy.label}: body must require an observation manifest`);
|
|
53
|
+
assert.match(section, /observer group/i, `${copy.label}: observation manifest must record observer groups`);
|
|
54
|
+
assert.match(section, /independence basis/i, `${copy.label}: observation manifest must record independence basis`);
|
|
55
|
+
assert.match(section, /observed_at/i, `${copy.label}: temporal evidence must include observed_at`);
|
|
56
|
+
assert.match(section, /valid_at|claim_valid_at/i, `${copy.label}: temporal evidence must include a validity field`);
|
|
57
|
+
assert.match(section, /verification-economics\.md/i, `${copy.label}: body must require verification economics`);
|
|
58
|
+
assert.match(section, /cause-disappearance\.md/i, `${copy.label}: body must require cause-disappearance records`);
|
|
59
|
+
assert.match(section, /last_seen/i, `${copy.label}: cause-disappearance records must track last_seen`);
|
|
60
|
+
assert.match(section, /disconfirming observation/i, `${copy.label}: cause-disappearance records must track disconfirming observations`);
|
|
61
|
+
assert.match(section, /no longer observed/i, `${copy.label}: cause-disappearance records must support no-longer-observed verdicts`);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("#given ulw-research readiness gates #when synthesis rules are inspected #then diff closure and independent convergence are required", async () => {
|
|
66
|
+
for (const copy of await readUlwResearchCopies()) {
|
|
67
|
+
const success = markdownSection(copy.content, "## Success criteria", "## Epistemic instrumentation");
|
|
68
|
+
const phase4 = markdownSection(copy.content, "## Phase 4 — Synthesize", "## Phase 5 — Final materials");
|
|
69
|
+
assert.match(success, /intent-vs-reality diff/i, `${copy.label}: success criteria must require intent diff closure`);
|
|
70
|
+
assert.match(success, /independent observation groups/i, `${copy.label}: success criteria must require independent observations`);
|
|
71
|
+
assert.match(success, /convergence/i, `${copy.label}: success criteria must require convergence`);
|
|
72
|
+
assert.match(phase4, /intent-diff\.md/i, `${copy.label}: synthesis must start from the intent diff`);
|
|
73
|
+
assert.match(phase4, /independent-observation convergence/i, `${copy.label}: synthesis must summarize independent convergence`);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("#given ulw-research observation instrumentation #when worker ownership is inspected #then workers return candidates as message text and the orchestrator writes manifests", async () => {
|
|
78
|
+
for (const copy of await readUlwResearchCopies()) {
|
|
79
|
+
assert.match(copy.content, /observation candidates?|claim candidates?/i, `${copy.label}: workers must return claim and observation candidates`);
|
|
80
|
+
assert.match(copy.content, /message text/i, `${copy.label}: claim and observation candidates must travel as message text`);
|
|
81
|
+
assert.match(copy.content, /orchestrator-owned|orchestrator owns/i, `${copy.label}: instrumentation artifacts must be orchestrator-owned`);
|
|
82
|
+
assert.doesNotMatch(
|
|
83
|
+
copy.content,
|
|
84
|
+
/worker[^.]*\b(?:write|append|create)s?\b[^.]*(?:intent-diff|observation-manifest|claim-graph|verification-economics|cause-disappearance)/i,
|
|
85
|
+
`${copy.label}: workers must not write instrumentation artifacts directly`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("#given the claim graph as the single claim store #when the retired ledger is scanned #then claim-ledger is gone and the gate lives on graph nodes", async () => {
|
|
91
|
+
for (const copy of await readUlwResearchCopies()) {
|
|
92
|
+
assert.doesNotMatch(copy.content, /claim[- ]ledger/i, `${copy.label}: the retired claim-ledger artifact must not appear`);
|
|
93
|
+
const phase3b = markdownSection(copy.content, "## Phase 3b — Lock non-code claims through the claim graph", "## Phase 4 — Synthesize");
|
|
94
|
+
assert.match(phase3b, /claim-graph\.md/i, `${copy.label}: the gate must record outcomes on claim-graph nodes`);
|
|
95
|
+
assert.match(phase3b, /verified-claims/i, `${copy.label}: the verified-claims allowlist digest must survive the merge`);
|
|
96
|
+
assert.match(phase3b, /sole allowlist/i, `${copy.label}: the data-flow-lock must stay self-enforcing`);
|
|
97
|
+
}
|
|
98
|
+
});
|