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.
Files changed (101) hide show
  1. package/dist/cli/index.js +34 -31
  2. package/dist/cli/run/on-complete-hook.d.ts +2 -0
  3. package/dist/cli-node/index.js +34 -31
  4. package/package.json +1 -1
  5. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  6. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  7. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  8. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +2 -2
  9. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +2 -2
  10. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  11. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  12. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  13. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  14. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  15. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  16. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  17. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +3 -17
  18. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  19. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  20. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  21. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  22. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
  24. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +16 -23
  25. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
  26. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
  27. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
  28. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
  29. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
  30. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +37 -69
  31. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
  32. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +1 -15
  33. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  34. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  35. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +0 -3
  36. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +2 -16
  37. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  38. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +3 -9
  40. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  43. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
  45. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
  46. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  47. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
  49. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +2 -2
  50. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
  51. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +2 -35
  52. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +4 -5
  53. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  71. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  72. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  76. package/packages/omo-codex/plugin/package-lock.json +20 -20
  77. package/packages/omo-codex/plugin/package.json +1 -1
  78. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +35 -8
  79. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  80. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  81. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -24
  82. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  83. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  84. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  85. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  86. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  87. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  88. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +1 -119
  89. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  90. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  91. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  92. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  93. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  94. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +0 -3
  95. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  96. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
  97. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +35 -8
  98. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  99. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  100. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  101. 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: ["# packages", "", "## OVERVIEW", "23 sibling packages.", "", "## CONVENTIONS", "Use npm."].join("\n"),
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).toBe(
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: "Keep generated hook context readable.",
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).toBe(
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: "First line\r\n indented second line\rThird line",
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("First line\n indented second line\nThird line");
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: "Shared rule\nKeep one copy.",
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: "Shared rule\r\nKeep one copy.",
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, "Instructions from: /repo/CONTEXT.md")).toBe(1);
100
- expect(occurrenceCount(block, "Shared rule\nKeep one copy.")).toBe(1);
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: "Alpha guidance." }),
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: "Hephaestus guidance.",
98
+ body: "HEPHAESTUS_BODY_SENTINEL",
112
99
  }),
113
- loadedRule({ path: "/repo/beta.md", relativePath: "beta.md", body: "Beta guidance." }),
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("Instructions from: /repo/bundled-rules/hephaestus.md");
121
- expect(block).toContain("Hephaestus guidance.");
122
- expect(block).toContain("Alpha guidance.");
123
- expect(block).toContain("Beta guidance.");
124
- expect(block.indexOf("Hephaestus guidance.")).toBeLessThan(block.indexOf("Alpha guidance."));
125
- expect(block.indexOf("Alpha guidance.")).toBeLessThan(block.indexOf("Beta guidance."));
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("Instructions from: /repo/alpha.md");
184
- expect(block).toContain("Instructions from: /repo/beta.md");
185
- expect(block).toContain("Instructions from: /repo/gamma.md");
186
- expect(block).toContain("[Truncated. Full: alpha.md]");
187
- expect(block).toContain("[Truncated. Full: beta.md]");
188
- expect(block).toContain("[Truncated. Full: gamma.md]");
189
- expect(occurrenceCount(block, "[Truncated. Full:")).toBe(3);
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\nFirst line\r\nSecond line\rThird line\r\n";
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("First line\nSecond line\nThird line");
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
 
@@ -71,25 +71,11 @@ describe("Windows Git Bash bundled rule content", () => {
71
71
  expect(body).toContain("alwaysApply: true");
72
72
  });
73
73
 
74
- it('#given the bundled rule #when read #then it NEVER recommends bare shell:"bash"', () => {
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.8) Checking Start-Work Continuation"
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.8) Checking Start-Work Continuation"
22
+ "statusMessage": "(OmO 5.0.0-beta.9) Checking Start-Work Continuation"
23
23
  }
24
24
  ]
25
25
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-start-work-continuation",
3
- "version": "5.0.0-beta.8",
3
+ "version": "5.0.0-beta.9",
4
4
  "description": "Codex Stop hook continuation injector for omo-codex start-work plans.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -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", () => {
@@ -58,16 +58,7 @@ describe("start-work Stop hook", () => {
58
58
  const output = runStopHook(createStopInput(workspace), fs);
59
59
 
60
60
  // then
61
- const parsed = parseBlockOutput(output);
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
- const parsed = parseBlockOutput(output);
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.8) Checking Thread Title Hygiene"
11
+ "statusMessage": "(OmO 5.0.0-beta.9) Checking Thread Title Hygiene"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-teammode",
3
- "version": "5.0.0-beta.8",
3
+ "version": "5.0.0-beta.9",
4
4
  "description": "Codex team-mode hook component that keeps background thread titles descriptive after create_thread.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -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).toBe(
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).toBe(
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).toBe(
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
 
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.8) Recording Session Telemetry"
10
+ "statusMessage": "(OmO 5.0.0-beta.9) Recording Session Telemetry"
11
11
  }
12
12
  ]
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-telemetry",
3
- "version": "5.0.0-beta.8",
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",
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 5.0.0-beta.8) Checking Ultrawork Trigger"
10
+ "statusMessage": "(OmO 5.0.0-beta.9) Checking Ultrawork Trigger"
11
11
  }
12
12
  ]
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-ultrawork",
3
- "version": "5.0.0-beta.8",
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.8) Checking Ulw-Loop Steering"
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.8) Enforcing Unlimited Ulw-Loop Budget"
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.8) Guarding Ulw-Loop Spawns"
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.8) Checking Ulw-Loop Resume"
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.8",
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: "Build the auth service" });
116
+ const goal = makeGoal({ objective: "per-story-objective-sentinel" });
117
117
  const { text } = buildCodexGoalInstruction({ plan: makePlan({ codexGoalMode: "per_story" }), goal });
118
- expect(text).toContain("Build the auth service");
118
+ expect(text).toContain("per-story-objective-sentinel");
119
119
  });
120
120
  });
121
121