lazycodex-ai 5.0.0-beta.8 → 5.0.0-beta.9
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/dist/cli/index.js +34 -31
- package/dist/cli/run/on-complete-hook.d.ts +2 -0
- package/dist/cli-node/index.js +34 -31
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +2 -2
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +2 -2
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +3 -17
- 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/rules/test/bundled-rules-priority.test.ts +11 -16
- package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +16 -23
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
- package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
- package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
- package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +37 -69
- package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
- package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +1 -15
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +0 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +2 -16
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +3 -9
- 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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
- package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
- 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/test/checkpoint-continuation.test.ts +0 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +2 -35
- package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +4 -5
- 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 +20 -20
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +35 -8
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -24
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
- package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
- package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
- package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
- package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +1 -119
- package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
- package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
- package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
- package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
- package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
- package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +0 -3
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +35 -8
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
- package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
- package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
|
@@ -8,13 +8,18 @@ const FORMAT_OPTIONS = {
|
|
|
8
8
|
maxResultChars: 10_000,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// Runtime sentinel: the rules hook emits and re-greps this marker when
|
|
12
|
+
// deduplicating injected rules against the transcript (transcript-rule-filter.ts).
|
|
13
|
+
const INSTRUCTIONS_FROM = "Instructions from: ";
|
|
14
|
+
|
|
11
15
|
describe("rules formatter hook context", () => {
|
|
12
16
|
it("#given multiline dynamic rules #when formatting PostToolUse context #then labels and bodies render on separate lines", () => {
|
|
13
17
|
// given
|
|
18
|
+
const body = "DYN_BODY_SENTINEL_LINE_1\n\nDYN_BODY_SENTINEL_LINE_2";
|
|
14
19
|
const rule = loadedRule({
|
|
15
20
|
path: "/repo/packages/CONTEXT.md",
|
|
16
21
|
relativePath: "packages/CONTEXT.md",
|
|
17
|
-
body
|
|
22
|
+
body,
|
|
18
23
|
});
|
|
19
24
|
|
|
20
25
|
// when
|
|
@@ -25,124 +30,86 @@ describe("rules formatter hook context", () => {
|
|
|
25
30
|
);
|
|
26
31
|
|
|
27
32
|
// then
|
|
28
|
-
expect(block).
|
|
29
|
-
|
|
30
|
-
"Additional project instructions matched for packages/omo-codex/plugin/components/ulw-loop/src/paths.ts:",
|
|
31
|
-
"",
|
|
32
|
-
"Instructions from: /repo/packages/CONTEXT.md",
|
|
33
|
-
"",
|
|
34
|
-
"# packages",
|
|
35
|
-
"",
|
|
36
|
-
"## OVERVIEW",
|
|
37
|
-
"23 sibling packages.",
|
|
38
|
-
"",
|
|
39
|
-
"## CONVENTIONS",
|
|
40
|
-
"Use npm.",
|
|
41
|
-
].join("\n"),
|
|
42
|
-
);
|
|
33
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/packages/CONTEXT.md\n\n${body}`);
|
|
34
|
+
expect(occurrenceCount(block, INSTRUCTIONS_FROM)).toBe(1);
|
|
43
35
|
});
|
|
44
36
|
|
|
45
37
|
it("#given static rules #when formatting SessionStart context #then it injects rule bodies inline", () => {
|
|
46
38
|
// given
|
|
39
|
+
const body = "STATIC_BODY_SENTINEL";
|
|
47
40
|
const rule = loadedRule({
|
|
48
41
|
path: "/repo/CONTEXT.md",
|
|
49
42
|
relativePath: "CONTEXT.md",
|
|
50
|
-
body
|
|
43
|
+
body,
|
|
51
44
|
});
|
|
52
45
|
|
|
53
46
|
// when
|
|
54
47
|
const block = formatStaticBlock([rule], FORMAT_OPTIONS);
|
|
55
48
|
|
|
56
49
|
// then
|
|
57
|
-
expect(block).
|
|
58
|
-
[
|
|
59
|
-
"## Project Instructions",
|
|
60
|
-
"",
|
|
61
|
-
"Instructions from: /repo/CONTEXT.md",
|
|
62
|
-
"",
|
|
63
|
-
"Keep generated hook context readable.",
|
|
64
|
-
].join("\n"),
|
|
65
|
-
);
|
|
50
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/CONTEXT.md\n\n${body}`);
|
|
66
51
|
});
|
|
67
52
|
|
|
68
53
|
it("#given CRLF and bare CR rule bodies #when formatting context #then it normalizes line endings", () => {
|
|
69
54
|
// given
|
|
70
55
|
const rule = loadedRule({
|
|
71
|
-
body: "
|
|
56
|
+
body: "A1\r\n B2\rC3",
|
|
72
57
|
});
|
|
73
58
|
|
|
74
59
|
// when
|
|
75
60
|
const block = formatDynamicBlock([rule], "src/app.ts", FORMAT_OPTIONS);
|
|
76
61
|
|
|
77
62
|
// then
|
|
78
|
-
expect(block).toContain("
|
|
63
|
+
expect(block).toContain("A1\n B2\nC3");
|
|
79
64
|
expect(block).not.toContain("\r");
|
|
80
65
|
});
|
|
81
66
|
|
|
82
67
|
it("#given duplicate static rules with different line endings #when formatting context #then it injects one copy", () => {
|
|
83
68
|
// given
|
|
69
|
+
const sharedBody = "SHARED_L1\r\nSHARED_L2";
|
|
70
|
+
const normalizedSharedBody = "SHARED_L1\nSHARED_L2";
|
|
84
71
|
const lfRule = loadedRule({
|
|
85
72
|
path: "/repo/CONTEXT.md",
|
|
86
73
|
relativePath: "CONTEXT.md",
|
|
87
|
-
body:
|
|
74
|
+
body: normalizedSharedBody,
|
|
88
75
|
});
|
|
89
76
|
const crlfRule = loadedRule({
|
|
90
77
|
path: "/repo/packages/CONTEXT.md",
|
|
91
78
|
relativePath: "packages/CONTEXT.md",
|
|
92
|
-
body:
|
|
79
|
+
body: sharedBody,
|
|
93
80
|
});
|
|
94
81
|
|
|
95
82
|
// when
|
|
96
83
|
const block = formatStaticBlock([lfRule, crlfRule], FORMAT_OPTIONS);
|
|
97
84
|
|
|
98
85
|
// then
|
|
99
|
-
expect(occurrenceCount(block,
|
|
100
|
-
expect(occurrenceCount(block,
|
|
86
|
+
expect(occurrenceCount(block, `${INSTRUCTIONS_FROM}/repo/CONTEXT.md`)).toBe(1);
|
|
87
|
+
expect(occurrenceCount(block, normalizedSharedBody)).toBe(1);
|
|
101
88
|
expect(block).not.toContain("/repo/packages/CONTEXT.md");
|
|
102
89
|
});
|
|
103
90
|
|
|
104
91
|
it("#given a Hephaestus static rule #when formatting SessionStart context #then it injects its body before other rule bodies", () => {
|
|
105
92
|
// given
|
|
106
93
|
const rules = [
|
|
107
|
-
loadedRule({ path: "/repo/alpha.md", relativePath: "alpha.md", body: "
|
|
94
|
+
loadedRule({ path: "/repo/alpha.md", relativePath: "alpha.md", body: "ALPHA_BODY_SENTINEL" }),
|
|
108
95
|
loadedRule({
|
|
109
96
|
path: "/repo/bundled-rules/hephaestus.md",
|
|
110
97
|
relativePath: "bundled-rules/hephaestus.md",
|
|
111
|
-
body: "
|
|
98
|
+
body: "HEPHAESTUS_BODY_SENTINEL",
|
|
112
99
|
}),
|
|
113
|
-
loadedRule({ path: "/repo/beta.md", relativePath: "beta.md", body: "
|
|
100
|
+
loadedRule({ path: "/repo/beta.md", relativePath: "beta.md", body: "BETA_BODY_SENTINEL" }),
|
|
114
101
|
];
|
|
115
102
|
|
|
116
103
|
// when
|
|
117
104
|
const block = formatStaticBlock(rules, FORMAT_OPTIONS);
|
|
118
105
|
|
|
119
106
|
// then
|
|
120
|
-
expect(block).toContain(
|
|
121
|
-
expect(block).toContain("
|
|
122
|
-
expect(block).toContain("
|
|
123
|
-
expect(block).toContain("
|
|
124
|
-
expect(block.indexOf("
|
|
125
|
-
expect(block.indexOf("
|
|
126
|
-
expect(block).not.toContain("must read project rules:");
|
|
127
|
-
expect(block).not.toContain("- [hephaestus.md]");
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("#given only a Hephaestus static rule #when formatting SessionStart context #then it emits no project rule link section", () => {
|
|
131
|
-
// given
|
|
132
|
-
const rule = loadedRule({
|
|
133
|
-
path: "/repo/bundled-rules/hephaestus.md",
|
|
134
|
-
relativePath: "bundled-rules/hephaestus.md",
|
|
135
|
-
body: "Hephaestus guidance.",
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// when
|
|
139
|
-
const block = formatStaticBlock([rule], FORMAT_OPTIONS);
|
|
140
|
-
|
|
141
|
-
// then
|
|
142
|
-
expect(block).toContain("Instructions from: /repo/bundled-rules/hephaestus.md");
|
|
143
|
-
expect(block).toContain("Hephaestus guidance.");
|
|
144
|
-
expect(block).not.toContain("- [hephaestus.md]");
|
|
145
|
-
expect(block).not.toContain("must read project rules:");
|
|
107
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/bundled-rules/hephaestus.md`);
|
|
108
|
+
expect(block).toContain("HEPHAESTUS_BODY_SENTINEL");
|
|
109
|
+
expect(block).toContain("ALPHA_BODY_SENTINEL");
|
|
110
|
+
expect(block).toContain("BETA_BODY_SENTINEL");
|
|
111
|
+
expect(block.indexOf("HEPHAESTUS_BODY_SENTINEL")).toBeLessThan(block.indexOf("ALPHA_BODY_SENTINEL"));
|
|
112
|
+
expect(block.indexOf("ALPHA_BODY_SENTINEL")).toBeLessThan(block.indexOf("BETA_BODY_SENTINEL"));
|
|
146
113
|
});
|
|
147
114
|
|
|
148
115
|
it("#given an oversized Hephaestus static rule #when formatting under a tight result budget #then its body is never truncated", () => {
|
|
@@ -162,7 +129,6 @@ describe("rules formatter hook context", () => {
|
|
|
162
129
|
|
|
163
130
|
// then
|
|
164
131
|
expect(block).toContain(tailMarker);
|
|
165
|
-
expect(block).not.toContain("[Truncated. Full:");
|
|
166
132
|
});
|
|
167
133
|
|
|
168
134
|
it("#given multiple oversized rules #when formatting under a tight result budget #then every rule receives a fair truncated share with a read-full guide", () => {
|
|
@@ -180,13 +146,15 @@ describe("rules formatter hook context", () => {
|
|
|
180
146
|
});
|
|
181
147
|
|
|
182
148
|
// then
|
|
183
|
-
expect(block).toContain(
|
|
184
|
-
expect(block).toContain(
|
|
185
|
-
expect(block).toContain(
|
|
186
|
-
expect(block).toContain("
|
|
187
|
-
expect(block).toContain("
|
|
188
|
-
expect(block).toContain("
|
|
189
|
-
expect(
|
|
149
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/alpha.md`);
|
|
150
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/beta.md`);
|
|
151
|
+
expect(block).toContain(`${INSTRUCTIONS_FROM}/repo/gamma.md`);
|
|
152
|
+
expect(block).toContain("alpha-");
|
|
153
|
+
expect(block).toContain("beta-");
|
|
154
|
+
expect(block).toContain("gamma-");
|
|
155
|
+
expect(block).not.toContain("A".repeat(400));
|
|
156
|
+
expect(block).not.toContain("B".repeat(400));
|
|
157
|
+
expect(block).not.toContain("C".repeat(400));
|
|
190
158
|
});
|
|
191
159
|
|
|
192
160
|
it("#given no matching rules #when formatting hook context #then it emits no context", () => {
|
|
@@ -5,14 +5,14 @@ import { formatAdditionalContextOutput } from "../src/hook-output.js";
|
|
|
5
5
|
describe("formatAdditionalContextOutput", () => {
|
|
6
6
|
it("#given context with outer whitespace and CRLF #when serializing hook JSON #then additional context is newline-normalized", () => {
|
|
7
7
|
// given
|
|
8
|
-
const context = "\r\n\r\
|
|
8
|
+
const context = "\r\n\r\nA1\r\nB2\rC3\r\n";
|
|
9
9
|
|
|
10
10
|
// when
|
|
11
11
|
const output = formatAdditionalContextOutput("PostToolUse", context);
|
|
12
12
|
const parsed: unknown = JSON.parse(output);
|
|
13
13
|
|
|
14
14
|
// then
|
|
15
|
-
expect(readAdditionalContext(parsed)).toBe("
|
|
15
|
+
expect(readAdditionalContext(parsed)).toBe("A1\nB2\nC3");
|
|
16
16
|
expect(output.endsWith("\n")).toBe(true);
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -40,7 +40,6 @@ describe("formatAdditionalContextOutput", () => {
|
|
|
40
40
|
expect(additionalContext.length).toBeLessThanOrEqual(32_000);
|
|
41
41
|
expect(additionalContext).toContain("first");
|
|
42
42
|
expect(additionalContext).not.toContain("last");
|
|
43
|
-
expect(additionalContext).toContain("[Truncated hook additional context to 32000 chars");
|
|
44
43
|
});
|
|
45
44
|
});
|
|
46
45
|
|
package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts
CHANGED
|
@@ -71,25 +71,11 @@ describe("Windows Git Bash bundled rule content", () => {
|
|
|
71
71
|
expect(body).toContain("alwaysApply: true");
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
-
it(
|
|
75
|
-
const body = readWindowsRuleBody();
|
|
76
|
-
|
|
77
|
-
expect(body).not.toContain('shell: "bash"');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("#given the bundled rule #when read #then it warns that bare bash often resolves to WSL System32", () => {
|
|
81
|
-
const body = readWindowsRuleBody();
|
|
82
|
-
|
|
83
|
-
expect(body).toMatch(/WSL/i);
|
|
84
|
-
expect(body).toMatch(/System32/i);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("#given the bundled rule #when read #then it prefers the git_bash MCP and the absolute Git Bash path", () => {
|
|
74
|
+
it("#given the bundled rule #when read #then it names the Git Bash runtime identifiers", () => {
|
|
88
75
|
const body = readWindowsRuleBody();
|
|
89
76
|
|
|
90
77
|
expect(body).toContain("git_bash");
|
|
91
78
|
expect(body).toContain("OMO_CODEX_GIT_BASH_PATH");
|
|
92
|
-
expect(body).toContain("C:\\Program Files\\Git\\bin\\bash.exe");
|
|
93
79
|
});
|
|
94
80
|
});
|
|
95
81
|
|
|
@@ -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 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.9) 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 5.0.0-beta.
|
|
22
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Checking Start-Work Continuation"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -26,9 +26,6 @@ describe("start-work continuation CLI", () => {
|
|
|
26
26
|
expect(result.status).toBe(0);
|
|
27
27
|
const output = parseStopHookOutput(result.stdout);
|
|
28
28
|
expect(output.decision).toBe("block");
|
|
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`");
|
|
31
|
-
expect(output.reason).toContain("Your session id in boulder.json: `codex:s1`");
|
|
32
29
|
});
|
|
33
30
|
|
|
34
31
|
it("#given valid SubagentStop stdin #when CLI runs #then stdout contains block JSON", () => {
|
package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts
CHANGED
|
@@ -58,16 +58,7 @@ describe("start-work Stop hook", () => {
|
|
|
58
58
|
const output = runStopHook(createStopInput(workspace), fs);
|
|
59
59
|
|
|
60
60
|
// then
|
|
61
|
-
|
|
62
|
-
expect(parsed.decision).toBe("block");
|
|
63
|
-
expect(parsed.reason).toContain("- Plan: `launch-plan`");
|
|
64
|
-
expect(parsed.reason).toContain(`- Plan file: \`${join(workspace, ".omo", "plans", "plan.md")}\``);
|
|
65
|
-
expect(parsed.reason).toContain(`- Boulder state: \`${join(workspace, ".omo", "boulder.json")}\``);
|
|
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`");
|
|
68
|
-
expect(parsed.reason).toContain("- Worktree: `/tmp/worktree`");
|
|
69
|
-
expect(parsed.reason).toContain(`- Ledger: \`${join(workspace, ".omo", "start-work", "ledger.jsonl")}\``);
|
|
70
|
-
expect(parsed.reason).toContain("- Your session id in boulder.json: `codex:sess_abc`");
|
|
61
|
+
expect(parseBlockOutput(output).decision).toBe("block");
|
|
71
62
|
});
|
|
72
63
|
|
|
73
64
|
it("#given active codex work and an external-blocker marker #when hook runs #then returns empty output", () => {
|
|
@@ -187,12 +178,7 @@ describe("start-work Stop hook", () => {
|
|
|
187
178
|
const output = runStopHook(createStopInput(workspace), fs);
|
|
188
179
|
|
|
189
180
|
// then
|
|
190
|
-
|
|
191
|
-
expect(parsed.decision).toBe("block");
|
|
192
|
-
expect(parsed.reason).toContain("- Remaining top-level checkboxes: `0` of `1`");
|
|
193
|
-
expect(parsed.reason).toContain("- Next incomplete task: `none (final gate pending)`");
|
|
194
|
-
expect(parsed.reason).toContain("When the remaining count is `0`, skip checkbox execution");
|
|
195
|
-
expect(parsed.reason).toContain("re-read the ledger record and verify the exact lane/SHA pair");
|
|
181
|
+
expect(parseBlockOutput(output).decision).toBe("block");
|
|
196
182
|
});
|
|
197
183
|
|
|
198
184
|
it("#given context-window pressure in transcript #when hook runs #then it does not inject continuation text", () => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
|
|
10
10
|
"timeout": 10,
|
|
11
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
11
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Checking Thread Title Hygiene"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -29,9 +29,7 @@ describe("thread title PostToolUse guidance", () => {
|
|
|
29
29
|
expect(isHookOutput(parsed)).toBe(true);
|
|
30
30
|
if (!isHookOutput(parsed)) return;
|
|
31
31
|
expect(parsed.hookSpecificOutput.hookEventName).toBe("PostToolUse");
|
|
32
|
-
expect(parsed.hookSpecificOutput.additionalContext).
|
|
33
|
-
"THREAD ID thread-123: CALL codex_app.set_thread_title NOW. USE THE REAL TASK/ROLE.",
|
|
34
|
-
);
|
|
32
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain("thread-123");
|
|
35
33
|
});
|
|
36
34
|
|
|
37
35
|
it("#given Codex reports create_thread output as a JSON string #when the hook runs #then it still extracts the thread id", () => {
|
|
@@ -59,9 +57,7 @@ describe("thread title PostToolUse guidance", () => {
|
|
|
59
57
|
// then
|
|
60
58
|
expect(isHookOutput(parsed)).toBe(true);
|
|
61
59
|
if (!isHookOutput(parsed)) return;
|
|
62
|
-
expect(parsed.hookSpecificOutput.additionalContext).
|
|
63
|
-
"THREAD ID 019ef350-ee78-72a3-bd5e-e40cebc3d814: CALL codex_app.set_thread_title NOW. USE THE REAL TASK/ROLE.",
|
|
64
|
-
);
|
|
60
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain("019ef350-ee78-72a3-bd5e-e40cebc3d814");
|
|
65
61
|
});
|
|
66
62
|
|
|
67
63
|
it("#given an unrelated tool completed #when the hook runs #then it stays silent", () => {
|
|
@@ -141,9 +137,7 @@ describe("thread title PostToolUse guidance", () => {
|
|
|
141
137
|
// then
|
|
142
138
|
expect(isHookOutput(parsed)).toBe(true);
|
|
143
139
|
if (!isHookOutput(parsed)) return;
|
|
144
|
-
expect(parsed.hookSpecificOutput.additionalContext).
|
|
145
|
-
"PENDING WORKTREE ID remote-control:env:test-worktree: WORKTREE THREAD IS NOT READY YET. DO NOT bind-thread OR SEND THE MEMBER BOOTSTRAP UNTIL A REAL THREAD ID EXISTS. THEN CALL codex_app.set_thread_title USING THE REAL TASK/ROLE.",
|
|
146
|
-
);
|
|
140
|
+
expect(parsed.hookSpecificOutput.additionalContext).toContain("remote-control:env:test-worktree");
|
|
147
141
|
});
|
|
148
142
|
});
|
|
149
143
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-telemetry",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.9",
|
|
4
4
|
"description": "Codex plugin component that emits omo-codex anonymous daily-active telemetry on SessionStart.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-ultrawork",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.9",
|
|
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",
|
|
@@ -28,7 +28,6 @@ describe("codex ultrawork hook", () => {
|
|
|
28
28
|
// then
|
|
29
29
|
expect(parsed.hookSpecificOutput.hookEventName).toBe("UserPromptSubmit");
|
|
30
30
|
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/^<ultrawork-mode>/);
|
|
31
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/First user-visible line this turn MUST be exactly:/);
|
|
32
31
|
});
|
|
33
32
|
|
|
34
33
|
it("#given Windows cwd #when hook sees ultrawork prompt #then emits directive as Codex hook JSON", () => {
|
|
@@ -174,139 +173,4 @@ describe("codex ultrawork hook", () => {
|
|
|
174
173
|
// then
|
|
175
174
|
expect(outputs).toEqual(["", "", ""]);
|
|
176
175
|
});
|
|
177
|
-
|
|
178
|
-
it("#given directive #when inspected #then keeps manual QA and cleanup invariants", () => {
|
|
179
|
-
// given
|
|
180
|
-
const payload = {
|
|
181
|
-
hook_event_name: "UserPromptSubmit",
|
|
182
|
-
prompt: "ulw",
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
// when
|
|
186
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
187
|
-
const parsed = parseHookOutput(output);
|
|
188
|
-
|
|
189
|
-
// then
|
|
190
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/# Manual-QA channels/);
|
|
191
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/TESTS ALONE NEVER PROVE DONE/);
|
|
192
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/1\. HTTP call/);
|
|
193
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/2\. Terminal \/ TUI/);
|
|
194
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/3\. Browser use/);
|
|
195
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/4\. Computer use/);
|
|
196
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/CLEANUP \(PAIRED/);
|
|
197
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/refresh current branch\/PR\/issue state/);
|
|
198
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(/preserve existing ordering\/policy/);
|
|
199
|
-
expect(parsed.hookSpecificOutput.additionalContext).toMatch(
|
|
200
|
-
/separate compatibility detection from policy changes/,
|
|
201
|
-
);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it("#given directive #when inspected #then avoids context-expensive agent polling", () => {
|
|
205
|
-
// given
|
|
206
|
-
const payload = {
|
|
207
|
-
hook_event_name: "UserPromptSubmit",
|
|
208
|
-
prompt: "ulw",
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
// when
|
|
212
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
213
|
-
const parsed = parseHookOutput(output);
|
|
214
|
-
|
|
215
|
-
// then
|
|
216
|
-
const directive = parsed.hookSpecificOutput.additionalContext;
|
|
217
|
-
expect(directive).toMatch(/multi_agent_v1\.wait_agent/);
|
|
218
|
-
expect(directive).toMatch(/Track spawned agent names locally/);
|
|
219
|
-
expect(directive).toMatch(/wait_agent[\s\S]*mailbox/);
|
|
220
|
-
expect(directive).toMatch(/WORKING:/);
|
|
221
|
-
expect(directive).toMatch(/TASK STILL ACTIVE/);
|
|
222
|
-
expect(directive).toMatch(/Treat child status as a progress signal/);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it("#given directive #when inspected #then hardens Codex subagent assignment ambiguity", () => {
|
|
226
|
-
// given
|
|
227
|
-
const payload = {
|
|
228
|
-
hook_event_name: "UserPromptSubmit",
|
|
229
|
-
prompt: "ulw",
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// when
|
|
233
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
234
|
-
const parsed = parseHookOutput(output);
|
|
235
|
-
|
|
236
|
-
// then
|
|
237
|
-
const directive = parsed.hookSpecificOutput.additionalContext;
|
|
238
|
-
expect(directive).toMatch(/TASK:/);
|
|
239
|
-
expect(directive).toMatch(/fork_context:\s*false/);
|
|
240
|
-
expect(directive).toMatch(/wait_agent[\s\S]*mailbox/);
|
|
241
|
-
expect(directive).toMatch(/TASK STILL ACTIVE/);
|
|
242
|
-
expect(directive).toMatch(/respawn.*smaller/);
|
|
243
|
-
expect(directive).toMatch(/timeout only means no new mailbox update arrived/i);
|
|
244
|
-
expect(directive).toMatch(/WORKING:/);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it("#given directive #when inspected #then blocks dependent work until spawned planners finish", () => {
|
|
248
|
-
// given
|
|
249
|
-
const payload = {
|
|
250
|
-
hook_event_name: "UserPromptSubmit",
|
|
251
|
-
prompt: "ulw",
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
// when
|
|
255
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
256
|
-
const parsed = parseHookOutput(output);
|
|
257
|
-
|
|
258
|
-
// then
|
|
259
|
-
const directive = parsed.hookSpecificOutput.additionalContext;
|
|
260
|
-
expect(directive).toMatch(/Subagent-dependent transition barrier/);
|
|
261
|
-
expect(directive).toMatch(/Spawn every independent child for the current wave first/);
|
|
262
|
-
expect(directive).toMatch(/After the wave\s+is launched[\s\S]{0,240}wait_agent[\s\S]{0,240}terminal status/);
|
|
263
|
-
expect(directive).not.toMatch(/Immediately after any `multi_agent_v1\.spawn_agent`/);
|
|
264
|
-
expect(directive).toMatch(/Do not start dependent implementation/);
|
|
265
|
-
expect(directive).toMatch(/Do not mark an `update_plan` step `completed`/);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it("#given directive #when inspected #then keeps impact-proportional sizing invariants", () => {
|
|
269
|
-
// given
|
|
270
|
-
const payload = {
|
|
271
|
-
hook_event_name: "UserPromptSubmit",
|
|
272
|
-
prompt: "ulw",
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// when
|
|
276
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
277
|
-
const parsed = parseHookOutput(output);
|
|
278
|
-
|
|
279
|
-
// then
|
|
280
|
-
const directive = parsed.hookSpecificOutput.additionalContext;
|
|
281
|
-
expect(directive).toMatch(/# Tier triage/);
|
|
282
|
-
expect(directive).toMatch(/Default is LIGHT/);
|
|
283
|
-
expect(directive).toMatch(/Take HEAVY/);
|
|
284
|
-
expect(directive).toMatch(/ratchet up only/i);
|
|
285
|
-
expect(directive).toMatch(/`plan` agent/);
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
it("#given directive #when discovery leaves known execution steps #then planning stays direct unless design uncertainty remains", () => {
|
|
289
|
-
// given
|
|
290
|
-
const payload = {
|
|
291
|
-
hook_event_name: "UserPromptSubmit",
|
|
292
|
-
prompt: "ulw",
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
// when
|
|
296
|
-
const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
|
|
297
|
-
const parsed = parseHookOutput(output);
|
|
298
|
-
|
|
299
|
-
// then
|
|
300
|
-
const directive = parsed.hookSpecificOutput.additionalContext;
|
|
301
|
-
const discoveryIndex = directive.search(/fire the first discovery wave/i);
|
|
302
|
-
const uncertaintyIndex = directive.search(/what the wave left UNDECIDED/i);
|
|
303
|
-
const directPlanIndex = directive.search(/known procedure[\s\S]*plan directly/i);
|
|
304
|
-
expect(discoveryIndex).toBeGreaterThanOrEqual(0);
|
|
305
|
-
expect(uncertaintyIndex).toBeGreaterThan(discoveryIndex);
|
|
306
|
-
expect(directPlanIndex).toBeGreaterThan(uncertaintyIndex);
|
|
307
|
-
expect(directive).toMatch(/unclear module boundaries[\s\S]*viable decompositions[\s\S]*dependency order/i);
|
|
308
|
-
expect(directive).toMatch(/A known procedure.*however many steps.*never justify a planner/is);
|
|
309
|
-
expect(directive).toMatch(/[Nn]ever spawn `plan` before the discovery wave/);
|
|
310
|
-
expect(directive).toMatch(/tier sizes\s+evidence and review, never who plans/i);
|
|
311
|
-
});
|
|
312
176
|
});
|
|
@@ -42,9 +42,7 @@ describe("ultrawork skill pointer", () => {
|
|
|
42
42
|
expect(context).toBe(buildUltraworkSkillPointer(skillFilePath));
|
|
43
43
|
expect(context.startsWith("<ultrawork-mode>")).toBe(true);
|
|
44
44
|
expect(context).toContain(skillFilePath);
|
|
45
|
-
expect(context).toContain("First user-visible line this turn MUST be exactly:");
|
|
46
45
|
expect(context).toContain("create_goal");
|
|
47
|
-
expect(context).not.toContain("Tier triage");
|
|
48
46
|
expect(Buffer.byteLength(context, "utf8")).toBeLessThan(POINTER_MAX_BYTES);
|
|
49
47
|
});
|
|
50
48
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit --with-ultrawork",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Checking Ulw-Loop Steering"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"type": "command",
|
|
21
21
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
|
|
22
22
|
"timeout": 5,
|
|
23
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
23
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Enforcing Unlimited Ulw-Loop Budget"
|
|
24
24
|
}
|
|
25
25
|
]
|
|
26
26
|
},
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"type": "command",
|
|
32
32
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use-spawn",
|
|
33
33
|
"timeout": 5,
|
|
34
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
34
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Guarding Ulw-Loop Spawns"
|
|
35
35
|
}
|
|
36
36
|
]
|
|
37
37
|
}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"type": "command",
|
|
44
44
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook stop",
|
|
45
45
|
"timeout": 10,
|
|
46
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
46
|
+
"statusMessage": "(OmO 5.0.0-beta.9) Checking Ulw-Loop Resume"
|
|
47
47
|
}
|
|
48
48
|
]
|
|
49
49
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-ulw-loop",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.9",
|
|
4
4
|
"description": "Codex plugin: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -31,7 +31,6 @@ describe("checkpointAndContinue", () => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
expect(result.next).toMatchObject({ resumed: false, goal: { id: "G002", status: "in_progress" } });
|
|
34
|
-
expect(result.next && "instruction" in result.next ? result.next.instruction.text : "").toContain("Goal: G002");
|
|
35
34
|
expect((await readUlwLoopPlan(repo)).activeGoalId).toBe("G002");
|
|
36
35
|
});
|
|
37
36
|
|
|
@@ -113,9 +113,9 @@ describe("buildCodexGoalInstruction aggregate mode", () => {
|
|
|
113
113
|
|
|
114
114
|
describe("buildCodexGoalInstruction per_story mode", () => {
|
|
115
115
|
it("uses the goal's own objective for create_goal", () => {
|
|
116
|
-
const goal = makeGoal({ objective: "
|
|
116
|
+
const goal = makeGoal({ objective: "per-story-objective-sentinel" });
|
|
117
117
|
const { text } = buildCodexGoalInstruction({ plan: makePlan({ codexGoalMode: "per_story" }), goal });
|
|
118
|
-
expect(text).toContain("
|
|
118
|
+
expect(text).toContain("per-story-objective-sentinel");
|
|
119
119
|
});
|
|
120
120
|
});
|
|
121
121
|
|