oh-my-opencode 4.18.1 → 4.19.0
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/scripts/lsp-e2e.sh +39 -16
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +4 -4
- package/README.ru.md +2 -2
- package/README.zh-cn.md +2 -2
- package/bin/AGENTS.md +33 -0
- package/dist/agents/atlas/agent.d.ts +6 -5
- package/dist/agents/sisyphus/index.d.ts +5 -0
- package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
- package/dist/agents/sisyphus-junior/index.d.ts +2 -0
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +690 -139
- package/dist/cli-node/index.js +690 -139
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/browser-automation.d.ts +1 -0
- package/dist/config/schema/commands.d.ts +1 -3
- package/dist/config/schema/default-mode.d.ts +1 -1
- package/dist/config/schema/goal.d.ts +7 -0
- package/dist/config/schema/hooks.d.ts +1 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
- package/dist/config/schema/ralph-loop.d.ts +1 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/create-hooks.d.ts +1 -1
- package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
- package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
- package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
- package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
- package/dist/hooks/comment-checker/hook.d.ts +8 -1
- package/dist/hooks/goal/command-arguments.d.ts +13 -0
- package/dist/hooks/goal/controller.d.ts +26 -0
- package/dist/hooks/goal/index.d.ts +23 -0
- package/dist/hooks/goal/prompt.d.ts +3 -0
- package/dist/hooks/goal/store.d.ts +8 -0
- package/dist/hooks/goal/tools.d.ts +10 -0
- package/dist/hooks/goal/types.d.ts +93 -0
- package/dist/hooks/goal/validation.d.ts +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/keyword-detector/hook.d.ts +1 -2
- package/dist/hooks/ralph-loop/types.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
- package/dist/index.js +3706 -4329
- package/dist/oh-my-opencode.schema.json +23 -19
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
- package/dist/plugin/chat-message/types.d.ts +23 -10
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
- package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin/stop-continuation.d.ts +2 -2
- package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
- package/dist/shared/system-directive.d.ts +0 -1
- package/dist/skills/ulw-plan/SKILL.md +11 -7
- package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/dist/skills/ulw-research/SKILL.md +3 -3
- package/dist/tools/delegate-task/types.d.ts +0 -1
- package/dist/tui.js +115 -28
- package/package.json +14 -14
- package/packages/git-bash-mcp/dist/cli.js +81 -19
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
- package/packages/lsp-daemon/dist/cli.js +262 -63
- package/packages/lsp-daemon/dist/client.js +194 -50
- package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
- package/packages/lsp-daemon/dist/daemon-client.js +26 -2
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
- package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
- package/packages/lsp-daemon/dist/index.js +262 -63
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +79 -23
- package/packages/lsp-tools-mcp/dist/cli.js +82 -20
- package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
- package/packages/lsp-tools-mcp/dist/tools.js +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
- 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 +7 -6
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -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/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
- 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/lsp/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
- 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/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
- 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/src/boulder-reader.ts +4 -72
- package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
- package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -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/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 +10 -10
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
- 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 +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -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-guarding-ulw-loop-spawns.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/stop-checking-ulw-loop-resume.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/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
- package/dist/skills/ultraresearch/SKILL.md +0 -10
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
|
@@ -44,6 +44,7 @@ describe("plugin package metadata", () => {
|
|
|
44
44
|
expect(postCompactCommand).toBe(`node "${pluginRoot}/dist/cli.js" hook post-compact`);
|
|
45
45
|
expect(lspServer?.command).toBe("node");
|
|
46
46
|
expect(lspServer?.args).toEqual(["../../../../lsp-daemon/dist/cli.js", "mcp"]);
|
|
47
|
+
expect(lspServer?.startup_timeout_sec).toBe(10);
|
|
47
48
|
expect(cliSource).not.toContain("./lazy-lsp-mcp.js");
|
|
48
49
|
expect(cliSource).toContain("resolveLspDaemonCliPath");
|
|
49
50
|
expect(daemonCliPathSource).toContain("@code-yeongyu/lsp-daemon/cli");
|
|
@@ -74,7 +74,7 @@ Diagnostics catch type errors, not logic bugs; tests cover only what their autho
|
|
|
74
74
|
|
|
75
75
|
# Global Review and Debugging Gate
|
|
76
76
|
|
|
77
|
-
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills.
|
|
77
|
+
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. Each passing review lane and debugging audit binds to the exact full commit SHA it reviewed. Immediately append a durable task-evidence/ledger record with its name, full SHA, verdict, and report artifact/source. Before reuse after continuation or compaction, re-read the record and require the exact lane/SHA pair; memory or an unstamped report is not coverage. Every missing pair at the current SHA still runs, and new commits require fresh applicable coverage. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
78
78
|
|
|
79
79
|
# Failure Recovery
|
|
80
80
|
|
|
@@ -19,13 +19,15 @@ Status requests are not stop signals: give the update, keep working. Honor every
|
|
|
19
19
|
|
|
20
20
|
# Discovery
|
|
21
21
|
|
|
22
|
-
Never speculate about code you have not read: verify with tools and re-read on every hand-off.
|
|
22
|
+
Never speculate about code you have not read: verify with tools and re-read on every hand-off. **USE CODE MODE AGGRESSIVELY FOR BOUNDED DISCOVERY.** When multiple independent tool calls produce results that can be materially filtered, joined, deduplicated, or reduced, make ONE `exec` / eval JavaScript program that calls eligible tools concurrently with `Promise.all` and returns only decision-relevant evidence. For shell-native repo work without programmatic tool access, use ONE Python script with `concurrent.futures`, `subprocess`, and utility functions to batch commands and reduce output. **USE LSP FOR SYMBOLS** - definitions, references, rename impact, workspace symbols, and diagnostics - instead of reconstructing semantics with text search. Use direct calls when one result chooses the next action, outputs are already small, semantic judgment is required between calls, approval or side effects are involved, or native artifacts must be preserved. Retrieve again only for a missing required fact or a second-order question that changes the design. Stop when you can act; prefer the root fix over the symptom.
|
|
23
23
|
|
|
24
24
|
# Operating Loop
|
|
25
25
|
|
|
26
26
|
Explore -> Plan (`update_plan`, per Task Tracking) -> Implement -> Verify -> Manually QA.
|
|
27
27
|
|
|
28
|
-
Implement surgically, matching codebase style (naming, indentation, imports, error handling) even when you would write it differently. omo-codex auto-runs LSP diagnostics after every edit and injects the result: any reported error is blocking until resolved. Verify with targeted tests and builds for changed behavior; if validation cannot run, say why and name the next best check.
|
|
28
|
+
Implement surgically, matching codebase style (naming, indentation, imports, error handling) even when you would write it differently. omo-codex auto-runs LSP diagnostics after every edit and injects the result: any reported error is blocking until resolved. Verify with targeted tests and builds for changed behavior; if validation cannot run, say why and name the next best check. Re-run a validation command only when its inputs changed since its last green run; one full pass right before the final message replaces repeated identical reruns.
|
|
29
|
+
|
|
30
|
+
Waiting is not free: a status poll replays the whole accumulated context through the model. Run a long command (install, build, suite, container, CI watch) to completion in ONE `exec` call with a timeout sized to the expected wait - or send output to a log file read once on a completion signal - never re-poll the same surface with empty reads or sub-minute waits. If two consecutive checks show no state change, double the wait or switch to a completion signal.
|
|
29
31
|
|
|
30
32
|
# Subagents
|
|
31
33
|
|
|
@@ -52,7 +54,7 @@ Diagnostics catch type errors, not logic bugs; tests cover only what their autho
|
|
|
52
54
|
|
|
53
55
|
"This should work" from reading source does not pass. A defect found in usage is yours to fix this turn.
|
|
54
56
|
|
|
55
|
-
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills.
|
|
57
|
+
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. Each passing review lane and debugging audit binds to the exact full commit SHA it reviewed. Immediately append a durable task-evidence/ledger record with its name, full SHA, verdict, and report artifact/source. Before reuse after continuation or compaction, re-read the record and require the exact lane/SHA pair; memory or an unstamped report is not coverage. Every missing pair at the current SHA still runs, and new commits require fresh applicable coverage. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
56
58
|
|
|
57
59
|
# Failure Recovery
|
|
58
60
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 4.
|
|
10
|
+
"statusMessage": "(OmO 4.19.0) Loading Project Rules"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
|
|
21
21
|
"timeout": 10,
|
|
22
|
-
"statusMessage": "(OmO 4.
|
|
22
|
+
"statusMessage": "(OmO 4.19.0) Loading Project Rules"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"type": "command",
|
|
33
33
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
|
|
34
34
|
"timeout": 10,
|
|
35
|
-
"statusMessage": "(OmO 4.
|
|
35
|
+
"statusMessage": "(OmO 4.19.0) Matching Project Rules"
|
|
36
36
|
}
|
|
37
37
|
]
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"type": "command",
|
|
46
46
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
|
|
47
47
|
"timeout": 10,
|
|
48
|
-
"statusMessage": "(OmO 4.
|
|
48
|
+
"statusMessage": "(OmO 4.19.0) Resetting Project Rule Cache"
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
}
|
|
@@ -29,6 +29,13 @@ Conventions for human contributors and AI agents working on this repository.
|
|
|
29
29
|
- Never use Arrange-Act-Assert comments.
|
|
30
30
|
- Keep fixtures in `test/fixtures/`.
|
|
31
31
|
|
|
32
|
+
## Layout
|
|
33
|
+
|
|
34
|
+
- `src/boulder-reader.ts`: reads `.omo/boulder.json`, resolves the active work for the session, re-exports `getPlanChecklist`/`PlanChecklist` from `plan-checklist.ts`. `readContinuationState` returns null only when the plan has no readable top-level checklist (`total === 0`).
|
|
35
|
+
- `src/plan-checklist.ts`: `PlanChecklist` (`completed`/`remaining`/`total`/`nextTaskLabel`) and `getPlanChecklist`/`parsePlanChecklist`. Counts structured `## TODOs` rows (`N. <title>`) and `## Final Verification Wave` rows (`F<number>. <title>`); falls back to simple top-level `- [ ]`/`- [x]` checkboxes. Skips fenced blocks and respects `#`/`##` section boundaries.
|
|
36
|
+
- `src/codex-hook.ts`: Stop/SubagentStop hook; fills `REMAINING_COUNT`/`TOTAL_COUNT`/`NEXT_TASK_LABEL` from the checklist into `directive.md`.
|
|
37
|
+
- `directive.md`: directive template with placeholders, applied per invocation.
|
|
38
|
+
|
|
32
39
|
## Build and Hooks
|
|
33
40
|
|
|
34
41
|
- Build output goes to `dist/`.
|
|
@@ -41,3 +48,4 @@ Conventions for human contributors and AI agents working on this repository.
|
|
|
41
48
|
- Never make a network call from the hook.
|
|
42
49
|
- Keep the directive in `directive.md`. Do not inline it into TypeScript files.
|
|
43
50
|
- The hook only continues sessions listed in `.omo/boulder.json` as `codex:<session_id>`.
|
|
51
|
+
- The hook continues while the plan has a readable top-level checklist (`total > 0`). A fully-checked plan still blocks Stop until the final gate runs and the Boulder work is marked completed; an unreadable or empty checklist yields no output.
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Codex Stop-hook continuation injector for the omo-codex `start-work` skill.
|
|
4
4
|
|
|
5
|
-
It reads `.omo/boulder.json` in the hook payload `cwd`, resolves the active work, inspects the active plan
|
|
5
|
+
It reads `.omo/boulder.json` in the hook payload `cwd`, resolves the active work, inspects the active plan's top-level checklist, and emits Codex Stop-hook JSON while the plan still has unchecked tasks or its final review/debugging gate remains pending:
|
|
6
6
|
|
|
7
7
|
```json
|
|
8
8
|
{"decision":"block","reason":"<directive>"}
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The `reason` is loaded from `directive.md` on every invocation and filled with current plan state. The hook returns no output when `stop_hook_active` is `true`, when no active Boulder work exists, when the work is completed, when the active work is not tied to `codex:<session_id>`, or when
|
|
11
|
+
The `reason` is loaded from `directive.md` on every invocation and filled with current plan state. The hook returns no output when `stop_hook_active` is `true`, when no active Boulder work exists, when the work is completed, when the active work is not tied to `codex:<session_id>`, or when the plan has no readable top-level checklist. An active plan whose checklist is fully checked still blocks Stop until the final gate runs and Boulder is marked completed.
|
|
12
12
|
|
|
13
13
|
This pairs with the `start-work` skill at `plugin/skills/start-work/SKILL.md`. That skill writes `.omo/boulder.json` with Codex session ids prefixed as `codex:` so the hook can continue only its own active Codex session.
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ You are mid-flight on a Prometheus work plan; this turn is an automatic continua
|
|
|
16
16
|
# What to do this turn
|
|
17
17
|
|
|
18
18
|
1. Read `{{PLAN_PATH}}` AND `{{LEDGER_PATH}}` first — they are the only sources of truth for what remains and what evidence exists; do not trust your memory of prior turns.
|
|
19
|
-
2.
|
|
19
|
+
2. When the remaining count is `0`, skip checkbox execution and perform the Final gate now. Otherwise, pick the FIRST unchecked top-level checkbox in `## TODOs` or `## Final Verification Wave`. Ignore nested checkboxes under Acceptance Criteria / Evidence / Definition of Done.
|
|
20
20
|
3. Follow the `start-work` skill in full. The skill is already loaded from your earlier turn — re-read its file at `packages/omo-codex/plugin/skills/start-work/SKILL.md` if you have lost context.
|
|
21
21
|
4. Apply the checkbox's tier from its ledger entry, or classify it now per the start-work skill: LIGHT (default — a narrow change inside existing layers) needs one real-surface proof of the deliverable, with auxiliary surfaces first-class for CLI- or data-shaped work, and only trigger-mapped adversarial classes; HEAVY (new module/abstraction, auth/security, external integration, schema/migration, concurrency, cross-domain refactor, care signals) takes the full per-criterion regime. When unsure, take HEAVY; never downgrade.
|
|
22
22
|
5. Decompose the checkbox into atomic sub-tasks. Dispatch them in PARALLEL via `multi_agent_v1.spawn_agent` calls in this same response unless a sub-task has a NAMED blocking dependency (input from another sub-task or shared file). Use `fork_context: false` unless full history is truly required. Put role and specialty instructions inside `message`. Flat `spawn_agent` requiring `task_name` instead (`multi_agent_v2`)? Add `"task_name"`, use `fork_turns: "none"`, `wait_agent` takes only `timeout_ms`, finished agents end on their own.
|
|
@@ -40,7 +40,7 @@ You are mid-flight on a Prometheus work plan; this turn is an automatic continua
|
|
|
40
40
|
|
|
41
41
|
# Final gate
|
|
42
42
|
|
|
43
|
-
Before completion,
|
|
43
|
+
Before completion, satisfy all five `review-work` lanes and a `debugging` runtime audit; inconclusive lanes or an inconclusive audit fail. Each pass binds to the exact full commit SHA it reviewed. Immediately append a durable task-evidence record to `{{LEDGER_PATH}}` for every passing lane and the debugging audit with its name, full SHA, verdict, and report artifact/source. Before same-SHA reuse after any continuation or compaction, re-read the ledger record and verify the exact lane/SHA pair; memory, chat history, or an unstamped report is not coverage. New commits require fresh applicable coverage. Do not create a PR, PR handoff, branch handoff, merge, or final completion answer until this gate passes. For PR/branch work, stay in the task-owned worktree: create/update the PR, wait for CI/review/Cubic gates, merge by default unless explicitly opted out, then clean up. After the gate and lifecycle pass, mark the Boulder work completed before the final answer. Redact secrets, tokens, credentials, auth headers, cookies, env dumps, logs, and PII.
|
|
44
44
|
|
|
45
45
|
# Stop conditions for THIS turn
|
|
46
46
|
|
|
@@ -54,6 +54,6 @@ Before completion, run `review-work` and a `debugging` runtime audit; inconclusi
|
|
|
54
54
|
- Surface only state changes: sub-agent dispatched, scenario PASS/FAIL with artifact path, checkbox marked, evidence appended.
|
|
55
55
|
- Do NOT print "Should I continue?", restate the plan, or recap prior turns — the Stop hook continues you; the ledger and plan are the durable record.
|
|
56
56
|
|
|
57
|
-
Begin now.
|
|
57
|
+
Begin now. If no checkbox remains, run the Final gate; otherwise pick the next checkbox, dispatch the parallel sub-agents, verify, mark, continue.
|
|
58
58
|
|
|
59
59
|
</start-work-continuation>
|
|
@@ -1,37 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// components/start-work-continuation/src/cli.ts
|
|
4
|
-
import { readFileSync as
|
|
4
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
5
5
|
import { stdin as processStdin, stdout as processStdout } from "node:process";
|
|
6
6
|
|
|
7
7
|
// components/start-work-continuation/src/boulder-reader.ts
|
|
8
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
9
9
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (work === null || !isContinuableStatus(work.status))
|
|
21
|
-
return null;
|
|
22
|
-
const planPath = resolveBoulderPlanPathForWork(cwd, work);
|
|
23
|
-
const checklist = getPlanChecklist(planPath);
|
|
24
|
-
if (checklist.remaining === 0)
|
|
25
|
-
return null;
|
|
26
|
-
return {
|
|
27
|
-
planName: work.planName,
|
|
28
|
-
planPath,
|
|
29
|
-
boulderPath,
|
|
30
|
-
ledgerPath: join(cwd, ".omo", "start-work", "ledger.jsonl"),
|
|
31
|
-
worktreePath: work.worktreePath ?? null,
|
|
32
|
-
checklist
|
|
33
|
-
};
|
|
34
|
-
}
|
|
10
|
+
|
|
11
|
+
// components/start-work-continuation/src/plan-checklist.ts
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
var TODO_HEADING_PATTERN = /^##[ \t]+TODOs(?:[ \t]+#+)?[ \t]*$/i;
|
|
14
|
+
var FINAL_VERIFICATION_HEADING_PATTERN = /^##[ \t]+Final Verification Wave(?:[ \t]+#+)?[ \t]*$/i;
|
|
15
|
+
var SECTION_BOUNDARY_HEADING_PATTERN = /^#{1,2}(?:[ \t]+|$)/;
|
|
16
|
+
var FENCE_PATTERN = /^[ \t]{0,3}(`{3,}|~{3,})(.*)$/;
|
|
17
|
+
var SIMPLE_CHECKBOX_PATTERN = /^[-*][ \t]*\[[ \t]*([xX]?)[ \t]*\][ \t]+(.+)$/;
|
|
18
|
+
var TODO_CHECKBOX_PATTERN = /^- \[([ xX])\] ([1-9]\d*\. .+)$/;
|
|
19
|
+
var FINAL_WAVE_CHECKBOX_PATTERN = /^- \[([ xX])\] (F[1-9]\d*\. .+)$/i;
|
|
35
20
|
function getPlanChecklist(planPath) {
|
|
36
21
|
if (!existsSync(planPath))
|
|
37
22
|
return emptyChecklist();
|
|
@@ -45,34 +30,155 @@ function getPlanChecklist(planPath) {
|
|
|
45
30
|
}
|
|
46
31
|
function parsePlanChecklist(markdown) {
|
|
47
32
|
const lines = markdown.split(/\r?\n/);
|
|
48
|
-
|
|
33
|
+
if (!hasStructuredSection(lines))
|
|
34
|
+
return parseSimpleChecklist(lines);
|
|
49
35
|
let completed = 0;
|
|
50
36
|
let remaining = 0;
|
|
51
37
|
let nextTaskLabel = null;
|
|
52
|
-
let
|
|
38
|
+
let section = "other";
|
|
39
|
+
let fence = null;
|
|
53
40
|
for (const line of lines) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
41
|
+
if (fence !== null) {
|
|
42
|
+
if (isClosingFence(line, fence))
|
|
43
|
+
fence = null;
|
|
57
44
|
continue;
|
|
58
45
|
}
|
|
59
|
-
|
|
46
|
+
const openingFence = parseOpeningFence(line);
|
|
47
|
+
if (openingFence !== null) {
|
|
48
|
+
fence = openingFence;
|
|
60
49
|
continue;
|
|
61
|
-
|
|
50
|
+
}
|
|
51
|
+
if (SECTION_BOUNDARY_HEADING_PATTERN.test(line)) {
|
|
52
|
+
section = parseStructuredSectionHeading(line);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (section === "other")
|
|
56
|
+
continue;
|
|
57
|
+
const checkbox = parseStructuredCheckbox(line, section);
|
|
62
58
|
if (checkbox === null)
|
|
63
59
|
continue;
|
|
64
|
-
if (checkbox.checked)
|
|
60
|
+
if (checkbox.checked)
|
|
65
61
|
completed += 1;
|
|
66
|
-
|
|
62
|
+
else {
|
|
67
63
|
remaining += 1;
|
|
68
64
|
nextTaskLabel = nextTaskLabel ?? checkbox.label;
|
|
69
65
|
}
|
|
70
66
|
}
|
|
71
67
|
return { completed, remaining, total: completed + remaining, nextTaskLabel };
|
|
72
68
|
}
|
|
69
|
+
function hasStructuredSection(lines) {
|
|
70
|
+
let fence = null;
|
|
71
|
+
for (const line of lines) {
|
|
72
|
+
if (fence !== null) {
|
|
73
|
+
if (isClosingFence(line, fence))
|
|
74
|
+
fence = null;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const openingFence = parseOpeningFence(line);
|
|
78
|
+
if (openingFence !== null) {
|
|
79
|
+
fence = openingFence;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (parseStructuredSectionHeading(line) !== "other")
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function parseSimpleChecklist(lines) {
|
|
88
|
+
let completed = 0;
|
|
89
|
+
let remaining = 0;
|
|
90
|
+
let nextTaskLabel = null;
|
|
91
|
+
let fence = null;
|
|
92
|
+
for (const line of lines) {
|
|
93
|
+
if (fence !== null) {
|
|
94
|
+
if (isClosingFence(line, fence))
|
|
95
|
+
fence = null;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const openingFence = parseOpeningFence(line);
|
|
99
|
+
if (openingFence !== null) {
|
|
100
|
+
fence = openingFence;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const checkbox = parseSimpleTopLevelCheckbox(line);
|
|
104
|
+
if (checkbox === null)
|
|
105
|
+
continue;
|
|
106
|
+
if (checkbox.checked)
|
|
107
|
+
completed += 1;
|
|
108
|
+
else {
|
|
109
|
+
remaining += 1;
|
|
110
|
+
nextTaskLabel = nextTaskLabel ?? checkbox.label;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { completed, remaining, total: completed + remaining, nextTaskLabel };
|
|
114
|
+
}
|
|
115
|
+
function parseStructuredSectionHeading(line) {
|
|
116
|
+
if (TODO_HEADING_PATTERN.test(line))
|
|
117
|
+
return "todo";
|
|
118
|
+
if (FINAL_VERIFICATION_HEADING_PATTERN.test(line))
|
|
119
|
+
return "final-wave";
|
|
120
|
+
return "other";
|
|
121
|
+
}
|
|
122
|
+
function parseStructuredCheckbox(line, section) {
|
|
123
|
+
const pattern = section === "todo" ? TODO_CHECKBOX_PATTERN : FINAL_WAVE_CHECKBOX_PATTERN;
|
|
124
|
+
const match = line.match(pattern);
|
|
125
|
+
const marker = match?.[1];
|
|
126
|
+
const label = match?.[2];
|
|
127
|
+
if (marker === undefined || label === undefined)
|
|
128
|
+
return null;
|
|
129
|
+
return { checked: marker.toLowerCase() === "x", label };
|
|
130
|
+
}
|
|
131
|
+
function parseSimpleTopLevelCheckbox(line) {
|
|
132
|
+
const match = line.match(SIMPLE_CHECKBOX_PATTERN);
|
|
133
|
+
const marker = match?.[1];
|
|
134
|
+
const label = match?.[2];
|
|
135
|
+
if (marker === undefined || label === undefined)
|
|
136
|
+
return null;
|
|
137
|
+
return { checked: marker.toLowerCase() === "x", label };
|
|
138
|
+
}
|
|
139
|
+
function parseOpeningFence(line) {
|
|
140
|
+
const match = line.match(FENCE_PATTERN);
|
|
141
|
+
const run = match?.[1];
|
|
142
|
+
const info = match?.[2];
|
|
143
|
+
const marker = run?.charAt(0);
|
|
144
|
+
if (run === undefined || info === undefined || marker !== "`" && marker !== "~" || marker === "`" && info.includes("`"))
|
|
145
|
+
return null;
|
|
146
|
+
return { marker, length: run.length };
|
|
147
|
+
}
|
|
148
|
+
function isClosingFence(line, fence) {
|
|
149
|
+
const run = line.match(/^[ \t]{0,3}(`{3,}|~{3,})[ \t]*$/)?.[1];
|
|
150
|
+
return run?.charAt(0) === fence.marker && run.length >= fence.length;
|
|
151
|
+
}
|
|
152
|
+
function emptyChecklist() {
|
|
153
|
+
return { completed: 0, remaining: 0, total: 0, nextTaskLabel: null };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// components/start-work-continuation/src/boulder-reader.ts
|
|
157
|
+
var SESSION_ID_PREFIX_PATTERN = /^(codex|opencode):/;
|
|
158
|
+
function readContinuationState(cwd, sessionId) {
|
|
159
|
+
const boulderPath = getBoulderFilePath(cwd);
|
|
160
|
+
const boulderState = readBoulderState(boulderPath);
|
|
161
|
+
if (boulderState === null)
|
|
162
|
+
return null;
|
|
163
|
+
const work = getWorkForSession(boulderState, normalizeSessionId(sessionId, "codex"));
|
|
164
|
+
if (work === null || !isContinuableStatus(work.status))
|
|
165
|
+
return null;
|
|
166
|
+
const planPath = resolveBoulderPlanPathForWork(cwd, work);
|
|
167
|
+
const checklist = getPlanChecklist(planPath);
|
|
168
|
+
if (checklist.total === 0)
|
|
169
|
+
return null;
|
|
170
|
+
return {
|
|
171
|
+
planName: work.planName,
|
|
172
|
+
planPath,
|
|
173
|
+
boulderPath,
|
|
174
|
+
ledgerPath: join(cwd, ".omo", "start-work", "ledger.jsonl"),
|
|
175
|
+
worktreePath: work.worktreePath ?? null,
|
|
176
|
+
checklist
|
|
177
|
+
};
|
|
178
|
+
}
|
|
73
179
|
function readBoulderState(path) {
|
|
74
180
|
try {
|
|
75
|
-
const parsed = JSON.parse(
|
|
181
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
76
182
|
return parseBoulderState(parsed);
|
|
77
183
|
} catch (error) {
|
|
78
184
|
if (error instanceof Error)
|
|
@@ -150,27 +256,11 @@ function resolveBoulderPlanPathForWork(cwd, work) {
|
|
|
150
256
|
return absolutePlanPath;
|
|
151
257
|
}
|
|
152
258
|
const worktreePlanPath = resolve(resolveTrackedPath(cwd, worktreePath), relativePlanPath);
|
|
153
|
-
return
|
|
259
|
+
return existsSync2(worktreePlanPath) ? worktreePlanPath : absolutePlanPath;
|
|
154
260
|
}
|
|
155
261
|
function resolveTrackedPath(baseDirectory, trackedPath) {
|
|
156
262
|
return isAbsolute(trackedPath) ? resolve(trackedPath) : resolve(baseDirectory, trackedPath);
|
|
157
263
|
}
|
|
158
|
-
function parseTopLevelCheckbox(line) {
|
|
159
|
-
if (line.startsWith("- [ ] "))
|
|
160
|
-
return { checked: false, label: line.slice(CHECKBOX_PREFIX_LENGTH) };
|
|
161
|
-
if (line.startsWith("- [x] ") || line.startsWith("- [X] ")) {
|
|
162
|
-
return { checked: true, label: line.slice(CHECKBOX_PREFIX_LENGTH) };
|
|
163
|
-
}
|
|
164
|
-
return null;
|
|
165
|
-
}
|
|
166
|
-
function parseLevelTwoHeading(line) {
|
|
167
|
-
if (!line.startsWith("## "))
|
|
168
|
-
return null;
|
|
169
|
-
return line.slice("## ".length).trim();
|
|
170
|
-
}
|
|
171
|
-
function isCountedHeading(heading) {
|
|
172
|
-
return heading === TODO_HEADING || heading === FINAL_VERIFICATION_HEADING;
|
|
173
|
-
}
|
|
174
264
|
function parseBoulderWorkStatus(value) {
|
|
175
265
|
if (value === "active" || value === "paused" || value === "completed" || value === "abandoned")
|
|
176
266
|
return value;
|
|
@@ -203,16 +293,13 @@ function isContinuableStatus(status) {
|
|
|
203
293
|
function getBoulderFilePath(cwd) {
|
|
204
294
|
return join(cwd, ".omo", "boulder.json");
|
|
205
295
|
}
|
|
206
|
-
function emptyChecklist() {
|
|
207
|
-
return { completed: 0, remaining: 0, total: 0, nextTaskLabel: null };
|
|
208
|
-
}
|
|
209
296
|
function isRecord(value) {
|
|
210
297
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
211
298
|
}
|
|
212
299
|
|
|
213
300
|
// components/start-work-continuation/src/directive.ts
|
|
214
|
-
import { readFileSync as
|
|
215
|
-
var START_WORK_CONTINUATION_DIRECTIVE =
|
|
301
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
302
|
+
var START_WORK_CONTINUATION_DIRECTIVE = readFileSync3(new URL("../directive.md", import.meta.url), "utf8");
|
|
216
303
|
|
|
217
304
|
// components/start-work-continuation/src/codex-hook.ts
|
|
218
305
|
function runStopHook(input, fs) {
|
|
@@ -239,7 +326,7 @@ function renderDirective(state, sessionId) {
|
|
|
239
326
|
BOULDER_PATH: state.boulderPath,
|
|
240
327
|
REMAINING_COUNT: String(state.checklist.remaining),
|
|
241
328
|
TOTAL_COUNT: String(state.checklist.total),
|
|
242
|
-
NEXT_TASK_LABEL: state.checklist.nextTaskLabel ?? "",
|
|
329
|
+
NEXT_TASK_LABEL: state.checklist.nextTaskLabel ?? "none (final gate pending)",
|
|
243
330
|
WORKTREE_BLOCK: worktreeBlock,
|
|
244
331
|
LEDGER_PATH: state.ledgerPath,
|
|
245
332
|
SESSION_ID: sessionId
|
|
@@ -285,7 +372,7 @@ function isRecord2(value) {
|
|
|
285
372
|
// components/start-work-continuation/src/cli.ts
|
|
286
373
|
var nodeFileSystem = {
|
|
287
374
|
readFileSync(path, encoding) {
|
|
288
|
-
return
|
|
375
|
+
return readFileSync4(path, encoding);
|
|
289
376
|
}
|
|
290
377
|
};
|
|
291
378
|
var command = process.argv[2];
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 4.
|
|
10
|
+
"statusMessage": "(OmO 4.19.0) Checking Start-Work Continuation"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook subagent-stop",
|
|
21
21
|
"timeout": 10,
|
|
22
|
-
"statusMessage": "(OmO 4.
|
|
22
|
+
"statusMessage": "(OmO 4.19.0) Checking Start-Work Continuation"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { getPlanChecklist, type PlanChecklist } from "./plan-checklist.js";
|
|
3
4
|
|
|
4
|
-
export type PlanChecklist
|
|
5
|
-
|
|
6
|
-
readonly remaining: number;
|
|
7
|
-
readonly total: number;
|
|
8
|
-
readonly nextTaskLabel: string | null;
|
|
9
|
-
};
|
|
5
|
+
export type { PlanChecklist } from "./plan-checklist.js";
|
|
6
|
+
export { getPlanChecklist } from "./plan-checklist.js";
|
|
10
7
|
|
|
11
8
|
type BoulderWorkStatus = "active" | "paused" | "completed" | "abandoned";
|
|
12
9
|
|
|
@@ -35,9 +32,6 @@ export type ContinuationState = {
|
|
|
35
32
|
readonly checklist: PlanChecklist;
|
|
36
33
|
};
|
|
37
34
|
|
|
38
|
-
const TODO_HEADING = "TODOs";
|
|
39
|
-
const FINAL_VERIFICATION_HEADING = "Final Verification Wave";
|
|
40
|
-
const CHECKBOX_PREFIX_LENGTH = "- [ ] ".length;
|
|
41
35
|
const SESSION_ID_PREFIX_PATTERN = /^(codex|opencode):/;
|
|
42
36
|
|
|
43
37
|
export function readContinuationState(cwd: string, sessionId: string): ContinuationState | null {
|
|
@@ -50,7 +44,7 @@ export function readContinuationState(cwd: string, sessionId: string): Continuat
|
|
|
50
44
|
|
|
51
45
|
const planPath = resolveBoulderPlanPathForWork(cwd, work);
|
|
52
46
|
const checklist = getPlanChecklist(planPath);
|
|
53
|
-
if (checklist.
|
|
47
|
+
if (checklist.total === 0) return null;
|
|
54
48
|
|
|
55
49
|
return {
|
|
56
50
|
planName: work.planName,
|
|
@@ -62,47 +56,6 @@ export function readContinuationState(cwd: string, sessionId: string): Continuat
|
|
|
62
56
|
};
|
|
63
57
|
}
|
|
64
58
|
|
|
65
|
-
export function getPlanChecklist(planPath: string): PlanChecklist {
|
|
66
|
-
if (!existsSync(planPath)) return emptyChecklist();
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
return parsePlanChecklist(readFileSync(planPath, "utf8"));
|
|
70
|
-
} catch (error) {
|
|
71
|
-
if (error instanceof Error) return emptyChecklist();
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function parsePlanChecklist(markdown: string): PlanChecklist {
|
|
77
|
-
const lines = markdown.split(/\r?\n/);
|
|
78
|
-
const hasCountedSections = lines.some((line) => isCountedHeading(parseLevelTwoHeading(line)));
|
|
79
|
-
let completed = 0;
|
|
80
|
-
let remaining = 0;
|
|
81
|
-
let nextTaskLabel: string | null = null;
|
|
82
|
-
let isCountedSection = !hasCountedSections;
|
|
83
|
-
|
|
84
|
-
for (const line of lines) {
|
|
85
|
-
const heading = parseLevelTwoHeading(line);
|
|
86
|
-
if (heading !== null) {
|
|
87
|
-
isCountedSection = isCountedHeading(heading);
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (!isCountedSection) continue;
|
|
91
|
-
|
|
92
|
-
const checkbox = parseTopLevelCheckbox(line);
|
|
93
|
-
if (checkbox === null) continue;
|
|
94
|
-
|
|
95
|
-
if (checkbox.checked) {
|
|
96
|
-
completed += 1;
|
|
97
|
-
} else {
|
|
98
|
-
remaining += 1;
|
|
99
|
-
nextTaskLabel = nextTaskLabel ?? checkbox.label;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return { completed, remaining, total: completed + remaining, nextTaskLabel };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
59
|
function readBoulderState(path: string): BoulderState | null {
|
|
107
60
|
try {
|
|
108
61
|
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -193,23 +146,6 @@ function resolveTrackedPath(baseDirectory: string, trackedPath: string): string
|
|
|
193
146
|
return isAbsolute(trackedPath) ? resolve(trackedPath) : resolve(baseDirectory, trackedPath);
|
|
194
147
|
}
|
|
195
148
|
|
|
196
|
-
function parseTopLevelCheckbox(line: string): { readonly checked: boolean; readonly label: string } | null {
|
|
197
|
-
if (line.startsWith("- [ ] ")) return { checked: false, label: line.slice(CHECKBOX_PREFIX_LENGTH) };
|
|
198
|
-
if (line.startsWith("- [x] ") || line.startsWith("- [X] ")) {
|
|
199
|
-
return { checked: true, label: line.slice(CHECKBOX_PREFIX_LENGTH) };
|
|
200
|
-
}
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function parseLevelTwoHeading(line: string): string | null {
|
|
205
|
-
if (!line.startsWith("## ")) return null;
|
|
206
|
-
return line.slice("## ".length).trim();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function isCountedHeading(heading: string | null): boolean {
|
|
210
|
-
return heading === TODO_HEADING || heading === FINAL_VERIFICATION_HEADING;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
149
|
function parseBoulderWorkStatus(value: unknown): BoulderWorkStatus | undefined {
|
|
214
150
|
if (value === "active" || value === "paused" || value === "completed" || value === "abandoned") return value;
|
|
215
151
|
return undefined;
|
|
@@ -243,10 +179,6 @@ function getBoulderFilePath(cwd: string): string {
|
|
|
243
179
|
return join(cwd, ".omo", "boulder.json");
|
|
244
180
|
}
|
|
245
181
|
|
|
246
|
-
function emptyChecklist(): PlanChecklist {
|
|
247
|
-
return { completed: 0, remaining: 0, total: 0, nextTaskLabel: null };
|
|
248
|
-
}
|
|
249
|
-
|
|
250
182
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
251
183
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
252
184
|
}
|
|
@@ -27,7 +27,7 @@ function renderDirective(state: ContinuationState, sessionId: string): string {
|
|
|
27
27
|
BOULDER_PATH: state.boulderPath,
|
|
28
28
|
REMAINING_COUNT: String(state.checklist.remaining),
|
|
29
29
|
TOTAL_COUNT: String(state.checklist.total),
|
|
30
|
-
NEXT_TASK_LABEL: state.checklist.nextTaskLabel ?? "",
|
|
30
|
+
NEXT_TASK_LABEL: state.checklist.nextTaskLabel ?? "none (final gate pending)",
|
|
31
31
|
WORKTREE_BLOCK: worktreeBlock,
|
|
32
32
|
LEDGER_PATH: state.ledgerPath,
|
|
33
33
|
SESSION_ID: sessionId,
|