oh-my-opencode 4.18.2 → 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/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/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 +648 -136
- package/dist/cli-node/index.js +648 -136
- 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/auto-slash-command/executor.d.ts +1 -0
- 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/index.js +3515 -4365
- 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/stop-continuation.d.ts +2 -2
- 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 +73 -25
- package/package.json +14 -14
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -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 +97 -30
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- 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/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/dist/cli.js +147 -60
- 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 +3 -71
- 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 +198 -23
- 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 +6 -5
- 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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- 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/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- 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 +3 -18
- 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/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-test-support.mjs +3 -18
- 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
package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
5
5
|
import { getPlanChecklist, readContinuationState } from "../src/boulder-reader.js";
|
|
6
6
|
|
|
7
7
|
const cleanupRoots: string[] = [];
|
|
8
|
+
const SCAFFOLD_PLAN_MARKDOWN = readFileSync(new URL("./fixtures/plan-scaffold.md", import.meta.url), "utf8");
|
|
8
9
|
|
|
9
10
|
afterEach(() => {
|
|
10
11
|
for (const root of cleanupRoots.splice(0)) rmSync(root, { recursive: true, force: true });
|
|
11
12
|
});
|
|
12
13
|
|
|
13
14
|
describe("start-work plan checklist consumption", () => {
|
|
14
|
-
it("#given
|
|
15
|
+
it("#given scaffold headings and canonical numbered rows #when parsed #then structured totals and next label match", () => {
|
|
15
16
|
// given
|
|
16
|
-
const planPath = createPlan(
|
|
17
|
-
["# Plan", "", "## TODOs", "- [ ] First", "- [x] Done", "- [X] Also done", "- [ ] Second"].join("\n"),
|
|
18
|
-
);
|
|
17
|
+
const planPath = createPlan(SCAFFOLD_PLAN_MARKDOWN);
|
|
19
18
|
|
|
20
19
|
// when
|
|
21
20
|
const checklist = getPlanChecklist(planPath);
|
|
22
21
|
|
|
23
22
|
// then
|
|
24
|
-
expect(checklist).toEqual({
|
|
23
|
+
expect(checklist).toEqual({
|
|
24
|
+
completed: 2,
|
|
25
|
+
remaining: 2,
|
|
26
|
+
total: 4,
|
|
27
|
+
nextTaskLabel: "1. Implement checklist parser parity",
|
|
28
|
+
});
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
it("#given nested checkboxes #when parsed #then ignores non-column-zero items", () => {
|
|
28
32
|
// given
|
|
29
33
|
const planPath = createPlan(
|
|
30
|
-
["## TODOs", "- [ ] Top-level", " - [ ] Nested", "\t- [ ] Tab nested", "- [x] Complete"].join("\n"),
|
|
34
|
+
["## TODOs", "- [ ] 1. Top-level", " - [ ] Nested", "\t- [ ] Tab nested", "- [x] 2. Complete"].join("\n"),
|
|
31
35
|
);
|
|
32
36
|
|
|
33
37
|
// when
|
|
34
38
|
const checklist = getPlanChecklist(planPath);
|
|
35
39
|
|
|
36
40
|
// then
|
|
37
|
-
expect(checklist).toEqual({ completed: 1, remaining: 1, total: 2, nextTaskLabel: "Top-level" });
|
|
41
|
+
expect(checklist).toEqual({ completed: 1, remaining: 1, total: 2, nextTaskLabel: "1. Top-level" });
|
|
38
42
|
});
|
|
39
43
|
|
|
40
44
|
it("#given checkboxes outside counted sections #when parsed #then ignores unrelated top-level tasks", () => {
|
|
@@ -44,12 +48,12 @@ describe("start-work plan checklist consumption", () => {
|
|
|
44
48
|
"# Plan",
|
|
45
49
|
"- [ ] Preamble task",
|
|
46
50
|
"## TODOs",
|
|
47
|
-
"- [ ] Build hook",
|
|
51
|
+
"- [ ] 1. Build hook",
|
|
48
52
|
"## Acceptance Criteria",
|
|
49
53
|
"- [ ] Acceptance item",
|
|
50
54
|
"## Final Verification Wave",
|
|
51
|
-
"- [x] Run tests",
|
|
52
|
-
"- [ ] Run smoke",
|
|
55
|
+
"- [x] F1. Run tests",
|
|
56
|
+
"- [ ] F2. Run smoke",
|
|
53
57
|
].join("\n"),
|
|
54
58
|
);
|
|
55
59
|
|
|
@@ -57,18 +61,184 @@ describe("start-work plan checklist consumption", () => {
|
|
|
57
61
|
const checklist = getPlanChecklist(planPath);
|
|
58
62
|
|
|
59
63
|
// then
|
|
60
|
-
expect(checklist).toEqual({ completed: 1, remaining: 2, total: 3, nextTaskLabel: "Build hook" });
|
|
64
|
+
expect(checklist).toEqual({ completed: 1, remaining: 2, total: 3, nextTaskLabel: "1. Build hook" });
|
|
61
65
|
});
|
|
62
66
|
|
|
63
67
|
it("#given all top-level tasks complete #when parsed #then next task is null", () => {
|
|
64
68
|
// given
|
|
65
|
-
const planPath = createPlan(
|
|
69
|
+
const planPath = createPlan(
|
|
70
|
+
["## Todos", "- [x] 1. First", "- [X] 2. Second", "## Final verification wave", "- [x] F1. Final"].join("\n"),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// when
|
|
74
|
+
const checklist = getPlanChecklist(planPath);
|
|
75
|
+
|
|
76
|
+
// then
|
|
77
|
+
expect(checklist).toEqual({ completed: 3, remaining: 0, total: 3, nextTaskLabel: null });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("#given no structured headings #when parsed #then legacy top-level checkbox fallback remains", () => {
|
|
81
|
+
// given
|
|
82
|
+
const planPath = createPlan(["# Plan", "- [ ] First", "- [x] Done", " - [ ] Nested"].join("\n"));
|
|
83
|
+
|
|
84
|
+
// when
|
|
85
|
+
const checklist = getPlanChecklist(planPath);
|
|
86
|
+
|
|
87
|
+
// then
|
|
88
|
+
expect(checklist).toEqual({ completed: 1, remaining: 1, total: 2, nextTaskLabel: "First" });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("#given a heading-free legacy star checklist #when parsed #then fallback behavior is preserved", () => {
|
|
92
|
+
// given
|
|
93
|
+
const planPath = createPlan(["# Plan", "* [ ] First", "* [x] Done", " * [ ] Nested"].join("\n"));
|
|
94
|
+
|
|
95
|
+
// when
|
|
96
|
+
const checklist = getPlanChecklist(planPath);
|
|
97
|
+
|
|
98
|
+
// then
|
|
99
|
+
expect(checklist).toEqual({ completed: 1, remaining: 1, total: 2, nextTaskLabel: "First" });
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("#given noncanonical structured rows #when parsed #then only exact positive-number grammar is counted", () => {
|
|
103
|
+
// given
|
|
104
|
+
const planPath = createPlan(
|
|
105
|
+
[
|
|
106
|
+
"## Todos",
|
|
107
|
+
"- [ ] 0. Zero is invalid",
|
|
108
|
+
"- [ ] 01. Leading zero is invalid",
|
|
109
|
+
"* [ ] 2. Star marker is invalid",
|
|
110
|
+
"-[ ] 3. Missing spaces are invalid",
|
|
111
|
+
"- [ ] 4. Canonical implementation",
|
|
112
|
+
"## Final verification wave",
|
|
113
|
+
"- [ ] F0. Zero final verifier is invalid",
|
|
114
|
+
"- [ ] F01. Leading zero final verifier is invalid",
|
|
115
|
+
"- [x] F2. Canonical final verifier",
|
|
116
|
+
].join("\n"),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// when
|
|
120
|
+
const checklist = getPlanChecklist(planPath);
|
|
121
|
+
|
|
122
|
+
// then
|
|
123
|
+
expect(checklist).toEqual({
|
|
124
|
+
completed: 1,
|
|
125
|
+
remaining: 1,
|
|
126
|
+
total: 2,
|
|
127
|
+
nextTaskLabel: "4. Canonical implementation",
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("#given fenced examples and a higher-level heading #when parsed #then section scope excludes them", () => {
|
|
132
|
+
// given
|
|
133
|
+
const planPath = createPlan(
|
|
134
|
+
[
|
|
135
|
+
"## Todos",
|
|
136
|
+
"- [ ] 1. Counted implementation",
|
|
137
|
+
"```md",
|
|
138
|
+
"- [ ] 2. Fenced example",
|
|
139
|
+
"```",
|
|
140
|
+
"# Appendix",
|
|
141
|
+
"- [ ] 3. Appendix checkbox",
|
|
142
|
+
"## Final verification wave",
|
|
143
|
+
"- [x] F1. Counted verifier",
|
|
144
|
+
].join("\n"),
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
// when
|
|
148
|
+
const checklist = getPlanChecklist(planPath);
|
|
149
|
+
|
|
150
|
+
// then
|
|
151
|
+
expect(checklist).toEqual({
|
|
152
|
+
completed: 1,
|
|
153
|
+
remaining: 1,
|
|
154
|
+
total: 2,
|
|
155
|
+
nextTaskLabel: "1. Counted implementation",
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("#given a child heading inside TODOs #when parsed #then canonical rows remain in the parent section", () => {
|
|
160
|
+
// given
|
|
161
|
+
const planPath = createPlan(["## TODOs", "- [x] 1. First task", "### Notes", "- [ ] 2. Second task"].join("\n"));
|
|
162
|
+
|
|
163
|
+
// when
|
|
164
|
+
const checklist = getPlanChecklist(planPath);
|
|
165
|
+
|
|
166
|
+
// then
|
|
167
|
+
expect(checklist).toEqual({ completed: 1, remaining: 1, total: 2, nextTaskLabel: "2. Second task" });
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("#given a four-backtick fence containing triple-backtick examples #when parsed #then shorter fences do not close it", () => {
|
|
171
|
+
// given
|
|
172
|
+
const planPath = createPlan(
|
|
173
|
+
[
|
|
174
|
+
"## Todos",
|
|
175
|
+
"- [x] 1. Counted implementation",
|
|
176
|
+
"````md",
|
|
177
|
+
"```ts",
|
|
178
|
+
"- [ ] 2. Fenced example",
|
|
179
|
+
"```",
|
|
180
|
+
"````",
|
|
181
|
+
"## Final verification wave",
|
|
182
|
+
"- [ ] F1. Counted verifier",
|
|
183
|
+
].join("\n"),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// when
|
|
187
|
+
const checklist = getPlanChecklist(planPath);
|
|
188
|
+
|
|
189
|
+
// then
|
|
190
|
+
expect(checklist).toEqual({
|
|
191
|
+
completed: 1,
|
|
192
|
+
remaining: 1,
|
|
193
|
+
total: 2,
|
|
194
|
+
nextTaskLabel: "F1. Counted verifier",
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("#given structured headings with ATX closing markers #when parsed #then canonical tasks remain structured", () => {
|
|
199
|
+
// given
|
|
200
|
+
const planPath = createPlan(
|
|
201
|
+
["## TODOs ##", "- [ ] 1. Implement", "## Final Verification Wave ###", "- [ ] F1. Verify"].join("\n"),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// when
|
|
205
|
+
const checklist = getPlanChecklist(planPath);
|
|
206
|
+
|
|
207
|
+
// then
|
|
208
|
+
expect(checklist).toEqual({
|
|
209
|
+
completed: 0,
|
|
210
|
+
remaining: 2,
|
|
211
|
+
total: 2,
|
|
212
|
+
nextTaskLabel: "1. Implement",
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("#given inline backtick code before a canonical task #when parsed #then it does not open a fence", () => {
|
|
217
|
+
// given
|
|
218
|
+
const planPath = createPlan(["## TODOs", "```example```", "- [ ] 1. Implement"].join("\n"));
|
|
219
|
+
|
|
220
|
+
// when
|
|
221
|
+
const checklist = getPlanChecklist(planPath);
|
|
222
|
+
|
|
223
|
+
// then
|
|
224
|
+
expect(checklist.total).toBe(1);
|
|
225
|
+
expect(checklist.nextTaskLabel).toBe("1. Implement");
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("#given a heading-free fenced checkbox example #when parsed #then legacy fallback ignores it", () => {
|
|
229
|
+
// given
|
|
230
|
+
const planPath = createPlan(["````md", "- [ ] 1. Example only", "````"].join("\n"));
|
|
66
231
|
|
|
67
232
|
// when
|
|
68
233
|
const checklist = getPlanChecklist(planPath);
|
|
69
234
|
|
|
70
235
|
// then
|
|
71
|
-
expect(checklist).toEqual({
|
|
236
|
+
expect(checklist).toEqual({
|
|
237
|
+
completed: 0,
|
|
238
|
+
remaining: 0,
|
|
239
|
+
total: 0,
|
|
240
|
+
nextTaskLabel: null,
|
|
241
|
+
});
|
|
72
242
|
});
|
|
73
243
|
});
|
|
74
244
|
|
|
@@ -77,7 +247,7 @@ describe("start-work boulder state reader", () => {
|
|
|
77
247
|
// given
|
|
78
248
|
const workspace = createWorkspace({
|
|
79
249
|
boulderJson: createBoulderJson({ status: "active", sessionIds: ["codex:sess_abc"] }),
|
|
80
|
-
planMarkdown:
|
|
250
|
+
planMarkdown: SCAFFOLD_PLAN_MARKDOWN,
|
|
81
251
|
});
|
|
82
252
|
|
|
83
253
|
// when
|
|
@@ -90,7 +260,12 @@ describe("start-work boulder state reader", () => {
|
|
|
90
260
|
boulderPath: join(workspace, ".omo", "boulder.json"),
|
|
91
261
|
ledgerPath: join(workspace, ".omo", "start-work", "ledger.jsonl"),
|
|
92
262
|
worktreePath: null,
|
|
93
|
-
checklist: {
|
|
263
|
+
checklist: {
|
|
264
|
+
completed: 2,
|
|
265
|
+
remaining: 2,
|
|
266
|
+
total: 4,
|
|
267
|
+
nextTaskLabel: "1. Implement checklist parser parity",
|
|
268
|
+
},
|
|
94
269
|
});
|
|
95
270
|
});
|
|
96
271
|
|
|
@@ -98,7 +273,7 @@ describe("start-work boulder state reader", () => {
|
|
|
98
273
|
// given
|
|
99
274
|
const workspace = createWorkspace({
|
|
100
275
|
boulderJson: createBoulderJson({ status: "completed", sessionIds: ["codex:sess_abc"] }),
|
|
101
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [ ] First\n",
|
|
276
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [ ] 1. First\n",
|
|
102
277
|
});
|
|
103
278
|
|
|
104
279
|
// when
|
|
@@ -112,7 +287,7 @@ describe("start-work boulder state reader", () => {
|
|
|
112
287
|
// given
|
|
113
288
|
const workspace = createWorkspace({
|
|
114
289
|
boulderJson: createBoulderJson({ status: "paused", sessionIds: ["codex:sess_abc"] }),
|
|
115
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [ ] First\n",
|
|
290
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [ ] 1. First\n",
|
|
116
291
|
});
|
|
117
292
|
|
|
118
293
|
// when
|
|
@@ -120,14 +295,14 @@ describe("start-work boulder state reader", () => {
|
|
|
120
295
|
|
|
121
296
|
// then
|
|
122
297
|
expect(state?.planName).toBe("launch-plan");
|
|
123
|
-
expect(state?.checklist).toEqual({ completed: 0, remaining: 1, total: 1, nextTaskLabel: "First" });
|
|
298
|
+
expect(state?.checklist).toEqual({ completed: 0, remaining: 1, total: 1, nextTaskLabel: "1. First" });
|
|
124
299
|
});
|
|
125
300
|
|
|
126
301
|
it("#given active codex work with no remaining checklist items #when state is read #then final gate continuation remains present", () => {
|
|
127
302
|
// given
|
|
128
303
|
const workspace = createWorkspace({
|
|
129
304
|
boulderJson: createBoulderJson({ status: "active", sessionIds: ["codex:sess_abc"] }),
|
|
130
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [x] First\n",
|
|
305
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [x] 1. First\n",
|
|
131
306
|
});
|
|
132
307
|
|
|
133
308
|
// when
|
|
@@ -155,7 +330,7 @@ describe("start-work boulder state reader", () => {
|
|
|
155
330
|
// given
|
|
156
331
|
const workspace = createWorkspace({
|
|
157
332
|
boulderJson: "{",
|
|
158
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [ ] First\n",
|
|
333
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [ ] 1. First\n",
|
|
159
334
|
});
|
|
160
335
|
|
|
161
336
|
// when
|
|
@@ -169,7 +344,7 @@ describe("start-work boulder state reader", () => {
|
|
|
169
344
|
// given
|
|
170
345
|
const workspace = createWorkspace({
|
|
171
346
|
boulderJson: createBoulderJson({ status: "active", sessionIds: ["sess_abc"] }),
|
|
172
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [ ] First\n",
|
|
347
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [ ] 1. First\n",
|
|
173
348
|
});
|
|
174
349
|
|
|
175
350
|
// when
|
|
@@ -201,7 +376,7 @@ describe("start-work boulder state reader", () => {
|
|
|
201
376
|
started_at: "2026-06-12T00:00:00.000Z",
|
|
202
377
|
session_ids: ["codex:sess_abc"],
|
|
203
378
|
}),
|
|
204
|
-
planMarkdown: "# Plan\n\n## TODOs\n- [ ] First\n",
|
|
379
|
+
planMarkdown: "# Plan\n\n## TODOs\n- [ ] 1. First\n",
|
|
205
380
|
});
|
|
206
381
|
|
|
207
382
|
// when
|
|
@@ -6,6 +6,7 @@ import { execPath } from "node:process";
|
|
|
6
6
|
import { afterEach, describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
8
|
const cleanupRoots: string[] = [];
|
|
9
|
+
const SCAFFOLD_PLAN_MARKDOWN = readFileSync(new URL("./fixtures/plan-scaffold.md", import.meta.url), "utf8");
|
|
9
10
|
|
|
10
11
|
afterEach(() => {
|
|
11
12
|
for (const root of cleanupRoots.splice(0)) rmSync(root, { recursive: true, force: true });
|
|
@@ -25,8 +26,8 @@ describe("start-work continuation CLI", () => {
|
|
|
25
26
|
expect(result.status).toBe(0);
|
|
26
27
|
const output = parseStopHookOutput(result.stdout);
|
|
27
28
|
expect(output.decision).toBe("block");
|
|
28
|
-
expect(output.reason).toContain("Remaining top-level checkboxes: `2` of `
|
|
29
|
-
expect(output.reason).toContain("Next incomplete task: `
|
|
29
|
+
expect(output.reason).toContain("Remaining top-level checkboxes: `2` of `4`");
|
|
30
|
+
expect(output.reason).toContain("Next incomplete task: `1. Implement checklist parser parity`");
|
|
30
31
|
expect(output.reason).toContain("Your session id in boulder.json: `codex:s1`");
|
|
31
32
|
});
|
|
32
33
|
|
|
@@ -106,7 +107,7 @@ function createWorkspace(sessionIds: readonly string[]): string {
|
|
|
106
107
|
const root = mkdtempSync(join(tmpdir(), "codex-continuation-cli-"));
|
|
107
108
|
cleanupRoots.push(root);
|
|
108
109
|
mkdirSync(join(root, ".omo", "plans"), { recursive: true });
|
|
109
|
-
writeFileSync(join(root, ".omo", "plans", "plan.md"),
|
|
110
|
+
writeFileSync(join(root, ".omo", "plans", "plan.md"), SCAFFOLD_PLAN_MARKDOWN);
|
|
110
111
|
const work = {
|
|
111
112
|
work_id: "w1",
|
|
112
113
|
active_plan: ".omo/plans/plan.md",
|
package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
@@ -8,6 +8,7 @@ import type { ReadonlyFileSystem, StopInput } from "../src/types.js";
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_WORKSPACE = "/repo";
|
|
10
10
|
const cleanupRoots: string[] = [];
|
|
11
|
+
const SCAFFOLD_PLAN_MARKDOWN = readFileSync(new URL("./fixtures/plan-scaffold.md", import.meta.url), "utf8");
|
|
11
12
|
|
|
12
13
|
afterEach(() => {
|
|
13
14
|
for (const root of cleanupRoots.splice(0)) rmSync(root, { recursive: true, force: true });
|
|
@@ -49,7 +50,7 @@ describe("start-work Stop hook", () => {
|
|
|
49
50
|
status: "active",
|
|
50
51
|
worktreePath: "/tmp/worktree",
|
|
51
52
|
}),
|
|
52
|
-
planMarkdown:
|
|
53
|
+
planMarkdown: SCAFFOLD_PLAN_MARKDOWN,
|
|
53
54
|
});
|
|
54
55
|
const fs = createMemoryFs();
|
|
55
56
|
|
|
@@ -62,8 +63,8 @@ describe("start-work Stop hook", () => {
|
|
|
62
63
|
expect(parsed.reason).toContain("- Plan: `launch-plan`");
|
|
63
64
|
expect(parsed.reason).toContain(`- Plan file: \`${join(workspace, ".omo", "plans", "plan.md")}\``);
|
|
64
65
|
expect(parsed.reason).toContain(`- Boulder state: \`${join(workspace, ".omo", "boulder.json")}\``);
|
|
65
|
-
expect(parsed.reason).toContain("- Remaining top-level checkboxes: `2` of `
|
|
66
|
-
expect(parsed.reason).toContain("- Next incomplete task: `
|
|
66
|
+
expect(parsed.reason).toContain("- Remaining top-level checkboxes: `2` of `4`");
|
|
67
|
+
expect(parsed.reason).toContain("- Next incomplete task: `1. Implement checklist parser parity`");
|
|
67
68
|
expect(parsed.reason).toContain("- Worktree: `/tmp/worktree`");
|
|
68
69
|
expect(parsed.reason).toContain(`- Ledger: \`${join(workspace, ".omo", "start-work", "ledger.jsonl")}\``);
|
|
69
70
|
expect(parsed.reason).toContain("- Your session id in boulder.json: `codex:sess_abc`");
|
|
@@ -73,7 +74,7 @@ describe("start-work Stop hook", () => {
|
|
|
73
74
|
// given
|
|
74
75
|
const workspace = createWorkspace({
|
|
75
76
|
boulderJson: createBoulderJson({ sessionIds: ["codex:sess_abc"], status: "active" }),
|
|
76
|
-
planMarkdown: ["# Plan", "", "## TODOs", "- [x] Done"].join("\n"),
|
|
77
|
+
planMarkdown: ["# Plan", "", "## TODOs", "- [x] 1. Done"].join("\n"),
|
|
77
78
|
});
|
|
78
79
|
const fs = createMemoryFs();
|
|
79
80
|
|
package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Scaffold Parser Parity
|
|
2
|
+
|
|
3
|
+
## Todos
|
|
4
|
+
- [ ] 1. Implement checklist parser parity
|
|
5
|
+
- [ ] Nested acceptance detail
|
|
6
|
+
- [x] 2. Preserve completed implementation rows
|
|
7
|
+
- [ ] Missing numeric prefix must be ignored
|
|
8
|
+
|
|
9
|
+
## Acceptance Criteria
|
|
10
|
+
- [ ] Outside tracked sections must be ignored
|
|
11
|
+
|
|
12
|
+
## Final verification wave
|
|
13
|
+
- [ ] F1. Exercise the Codex Stop surface
|
|
14
|
+
- [X] F2. Preserve completed final verification rows
|
|
15
|
+
- [ ] 3. Wrong final-wave label must be ignored
|
|
@@ -13,19 +13,19 @@ Conventions for human contributors and AI agents working on this repository.
|
|
|
13
13
|
|
|
14
14
|
## Layout
|
|
15
15
|
|
|
16
|
-
- `src/cli.ts
|
|
17
|
-
- `src/codex-hook.ts
|
|
18
|
-
- `src/skill-pointer.ts
|
|
19
|
-
- `directive.md
|
|
20
|
-
- `skills/ultrawork/SKILL.md
|
|
21
|
-
- `skills/ulw-plan
|
|
22
|
-
- `agents/*.toml
|
|
23
|
-
- `hooks/hooks.json
|
|
24
|
-
- `.codex-plugin/plugin.json
|
|
16
|
+
- `src/cli.ts`: `UserPromptSubmit` hook CLI. Reads JSON on stdin, writes a compact `<ultrawork-mode>` skill pointer to stdout when the keyword matches (full directive as fallback), exits 0 otherwise.
|
|
17
|
+
- `src/codex-hook.ts`: pure detector/hook behavior; skips on context-pressure/recovery transcripts and when the directive is already in the transcript.
|
|
18
|
+
- `src/skill-pointer.ts`: `buildUltraworkAdditionalContext()`: emits the <4096-byte pointer (Codex App truncates large hook output) directing the model to `create_goal` then read the bundled `ultrawork` skill; falls back to the full `ULTRAWORK_DIRECTIVE` when the plugin skills tree is absent. Pointer size + `ulw-loop` mirror byte-identity pinned by `plugin/test/ultrawork-skill-pointer.test.mjs`.
|
|
19
|
+
- `directive.md`: bundled ultrawork directive text.
|
|
20
|
+
- `skills/ultrawork/SKILL.md`: full directive as a skill, generated by `scripts/sync-directive.mjs`; pinned byte-for-byte to `directive.md` by `test/directive-source.test.ts`. `plugin/scripts/sync-skills.mjs` materializes it into the aggregate `plugin/skills/` tree the pointer path targets.
|
|
21
|
+
- `skills/ulw-plan/`: dual-maintained copy of the ulw-plan skill (component copy wins over `packages/shared-skills/skills/ulw-plan/` in sync-skills; keep both in step by hand).
|
|
22
|
+
- `agents/*.toml`: bundled Codex agent role files. Installed as regular files into `CODEX_HOME/agents/` by `src/cli/install-codex/link-cached-plugin-agents.ts` at install time. Public `sisyphuslabs` installs source them from Codex's installed-marketplace snapshot, not the versioned plugin cache, so they survive Codex auto-update cache pruning and temporary snapshot cleanup. No runtime `SessionStart` hook is involved.
|
|
23
|
+
- `hooks/hooks.json`: registers the prompt-detector hook only.
|
|
24
|
+
- `.codex-plugin/plugin.json`: Codex plugin manifest. Marketplace metadata lives here, not in `package.json`.
|
|
25
25
|
|
|
26
26
|
## Constraints
|
|
27
27
|
|
|
28
|
-
- Never let the hook block a turn
|
|
28
|
+
- Never let the hook block a turn. Exit code is always 0.
|
|
29
29
|
- Never make a network call from the hook.
|
|
30
30
|
- Keep the directive in `directive.md`. Do not inline it into TypeScript files.
|
|
31
31
|
- Keep bundled agent role prompts concise and model-specific; measure prompt length when changing them.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
name = "momus"
|
|
2
|
-
description = "Deep plan reviewer. Verifies a work plan is executable: references exist, tasks are startable, QA scenarios are concrete. Runs at
|
|
2
|
+
description = "Deep plan reviewer. Verifies a work plan is executable: references exist, tasks are startable, QA scenarios are concrete. Runs at High and may take a long time; callers must wait for its terminal result instead of cancelling or duplicating it. Issues OKAY, ITERATE, or REJECT. Read-only."
|
|
3
3
|
nickname_candidates = ["Reviewer"]
|
|
4
|
-
model = "gpt-5.6-
|
|
5
|
-
model_reasoning_effort = "
|
|
4
|
+
model = "gpt-5.6-terra"
|
|
5
|
+
model_reasoning_effort = "high"
|
|
6
6
|
|
|
7
7
|
developer_instructions = """
|
|
8
8
|
Role: plan reviewer. You verify a work plan is executable and its references are valid. You are a blocker-finder, not a perfectionist: your job is to UNBLOCK work. Read-only - you never write plans or code.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-ultrawork",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"description": "Codex plugin that injects the ultrawork orchestration directive and ships LazyCodex planning, review, QA, and gate agent roles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -24,24 +24,28 @@ After grounding, make ONE judgment, record `intent: clear|unclear` plus `review_
|
|
|
24
24
|
|
|
25
25
|
- **OVERRIDE - explicit ask wins:** if the user explicitly asks to be questioned or interviewed ("ask me", "interview me", "why aren't you asking me" - in any language), route **CLEAR**, run the interview, and turn the adopt-default filter OFF: the user has claimed the forks, so every surviving one is ASKED, not defaulted. This beats the OUTCOME test below, even on a fuzzy brief.
|
|
26
26
|
- **CLEAR** - the user knows the outcome; the only open items are preferences/tradeoffs the repo cannot answer (genuine owner-decisions). Read **`references/intent-clear.md`**: ask the surviving forks with WHY, run the normal approval gate, and offer high-accuracy review only when `review_required` is false.
|
|
27
|
-
- **UNCLEAR** - the outcome itself is fuzzy (a vague brief, a bootstrap, `$start-work` with no selectable plan, a goal the user cannot yet articulate). Asking would offload your own job onto the user. Read **`references/intent-unclear.md`**: research maximally, adopt and ANNOUNCE best-practice defaults, do NOT ask the user extra questions, and
|
|
27
|
+
- **UNCLEAR** - the outcome itself is fuzzy (a vague brief, a bootstrap, `$start-work` with no selectable plan, a goal the user cannot yet articulate). Asking would offload your own job onto the user. Read **`references/intent-unclear.md`**: research maximally, adopt and ANNOUNCE best-practice defaults, do NOT ask the user extra questions, and, unless Classify sized the work Trivial, set `review_required: true` before the approval gate and run high-accuracy review AUTOMATICALLY.
|
|
28
28
|
- **ON THE FENCE** - when CLEAR vs UNCLEAR is genuinely ambiguous, treat it as CLEAR and ask exactly ONE question. A user wrongly silenced is worse than one extra question. The dominant failure to guard against is mis-routing a CLEAR request to UNCLEAR, which silently applies defaults and overrides forks the user wanted to own.
|
|
29
29
|
|
|
30
30
|
WORKED: "add a 5/min-per-IP rate-limit to `/login`" = CLEAR. "make auth better" = UNCLEAR.
|
|
31
31
|
|
|
32
32
|
Both intent paths ALSO read **`references/full-workflow.md`** for the shared mechanics - the plan template, the final verification wave, the APPEND protocol, and the full delegation/wait syntax. Read the phase you are in.
|
|
33
33
|
|
|
34
|
-
## RUN THE SCRIPT - do not hand-build
|
|
34
|
+
## RUN THE SCRIPT - do not hand-build artifacts
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
As soon as `<slug>` and intent are known, before recording draft state, RUN:
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
node "<skill-root>/scripts/scaffold-plan.mjs" <slug> [--clear|--unclear]
|
|
39
|
+
node "<skill-root>/scripts/scaffold-plan.mjs" <slug> [--clear|--unclear] --draft-only [--review-required]
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
(Replace `<skill-root>` with this skill's own directory; `bun` is
|
|
42
|
+
(Replace `<skill-root>` with this skill's own directory; `bun` is accepted.) This creates only `.omo/drafts/<slug>.md`, the compaction-safe resume point; it does not create a plan before approval. Include `--review-required` when an explicit modifier requires review or the classified route is non-Trivial UNCLEAR, so the first durable write contains the complete pending review request. After approval, rerun without `--draft-only` to create `.omo/plans/<slug>.md`, then **APPEND** task batches into `## Todos` - never rewrite script-emitted headers.
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Both invocations are resume-safe no-ops for artifacts already present. Do NOT hand-build them; use `--reset` only for a structural reset (`--reset --force` discards edits). If a same-named non-artifact file exists, choose another slug.
|
|
45
|
+
|
|
46
|
+
## Plan artifact producer contract
|
|
47
|
+
|
|
48
|
+
When producing the plan, encode every executable item as a column-zero Markdown task row: implementation rows MUST match `- [ ] N. <title>` (where `N` is a positive decimal integer), and final-verifier rows MUST match `- [ ] F<number>. <title>`. Prose headings, numbered paragraphs, and ordinary bullets are not task substitutes and MUST NOT be counted as implementation or final-verifier tasks. Before handoff, run a structural self-check over the plan: verify that every implementation row and final-verifier row is column-zero, matches its required grammar, and appears in the intended `## Todos` or `## Final verification wave` section; verify that no prose heading or bullet is being used as a task; and repair the plan before handoff if any check fails.
|
|
45
49
|
|
|
46
50
|
## Universal invariants (hold on every path)
|
|
47
51
|
|
|
@@ -58,7 +62,7 @@ Run it ONCE at plan generation. A plain re-run on an existing plan is a safe no-
|
|
|
58
62
|
|
|
59
63
|
## Approval gate
|
|
60
64
|
|
|
61
|
-
When exploration is exhausted and the unknowns are answered, record the gate in the draft (`status: awaiting-approval`,
|
|
65
|
+
When exploration is exhausted and the unknowns are answered, record the gate in the draft (`status: awaiting-approval`, approach, and the next workflow action), present a short brief once, then **wait for the user's explicit okay**. Approval authorizes plan creation only; any already-required review runs afterward under its existing authorization. Full mechanics: `references/full-workflow.md`.
|
|
62
66
|
|
|
63
67
|
## Delegation (Codex-native)
|
|
64
68
|
|