oh-my-opencode 4.16.3 → 4.17.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.
Files changed (177) hide show
  1. package/.agents/command/omomomo.md +1 -1
  2. package/.agents/skills/hyperplan/SKILL.md +3 -3
  3. package/.agents/skills/omomomo/SKILL.md +1 -1
  4. package/.opencode/command/omomomo.md +1 -1
  5. package/.opencode/skills/hyperplan/SKILL.md +3 -3
  6. package/.opencode/skills/pre-publish-review/SKILL.md +3 -0
  7. package/README.ja.md +4 -4
  8. package/README.ko.md +4 -4
  9. package/README.md +2 -2
  10. package/README.ru.md +4 -4
  11. package/README.zh-cn.md +4 -4
  12. package/dist/cli/index.js +179 -63
  13. package/dist/cli-node/index.js +179 -63
  14. package/dist/features/team-mode/test-support/async-test-helpers.d.ts +2 -2
  15. package/dist/index.js +121 -58
  16. package/dist/plugin/chat-message/types.d.ts +4 -0
  17. package/dist/plugin/command-execute-before.d.ts +1 -0
  18. package/dist/plugin/stop-continuation.d.ts +17 -0
  19. package/dist/skills/remove-ai-slops/SKILL.md +2 -2
  20. package/dist/skills/start-work/SKILL.md +5 -2
  21. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  22. package/dist/tui.js +71 -29
  23. package/package.json +15 -14
  24. package/packages/git-bash-mcp/package.json +27 -0
  25. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
  26. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +84 -19
  27. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  33. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  34. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
  35. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +6 -2
  36. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +6 -2
  37. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +2 -2
  38. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +6 -2
  40. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
  41. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +67 -2
  42. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  43. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +0 -13
  45. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  46. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  47. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  49. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -79
  51. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  52. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  53. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  54. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +2 -2
  56. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  57. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +6 -6
  58. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
  59. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
  60. package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +6 -4
  61. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
  62. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +2 -2
  63. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +4 -4
  64. package/packages/omo-codex/plugin/components/ultrawork/directive.md +55 -28
  65. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  66. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  67. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +55 -28
  68. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  69. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -0
  70. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -68
  71. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  72. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
  73. package/packages/omo-codex/plugin/components/ulw-loop/README.md +3 -1
  74. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +55 -28
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +6 -1
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
  77. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -2
  78. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +405 -25
  79. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +12 -1
  80. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +4 -2
  81. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +7 -0
  82. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +16 -1
  83. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -0
  84. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.d.ts +6 -0
  85. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +20 -0
  86. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +1 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +12 -9
  88. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +3 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +148 -0
  90. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.d.ts +2 -0
  91. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +209 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +25 -2
  93. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  94. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -15
  95. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +29 -27
  96. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -1
  97. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +14 -3
  98. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +10 -0
  99. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +12 -1
  100. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +4 -2
  101. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +27 -1
  102. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -0
  103. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +23 -0
  104. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +16 -9
  105. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +138 -0
  106. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +208 -0
  107. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +12 -0
  108. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +4 -1
  109. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +8 -35
  110. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +24 -13
  111. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -2
  112. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +43 -8
  113. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +55 -2
  114. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +228 -0
  115. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +193 -0
  116. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  123. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +18 -0
  126. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +17 -0
  134. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -2
  136. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  137. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  138. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  139. package/packages/omo-codex/plugin/model-catalog.json +16 -7
  140. package/packages/omo-codex/plugin/package-lock.json +13 -13
  141. package/packages/omo-codex/plugin/package.json +1 -1
  142. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
  143. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +8 -2
  144. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +2 -2
  145. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
  146. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
  147. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +8 -2
  148. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +5 -2
  149. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +55 -28
  150. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
  151. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +29 -27
  152. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  153. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  154. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +2 -2
  155. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +76 -16
  156. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
  157. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  158. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
  159. package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
  160. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  161. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
  162. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +14 -14
  163. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +11 -0
  164. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  165. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -2
  166. package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +9 -40
  167. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +4 -277
  168. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +5 -5
  169. package/packages/omo-codex/scripts/install-config.test.mjs +22 -3
  170. package/packages/omo-codex/scripts/install-dist/install-local.mjs +91 -21
  171. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
  172. package/packages/shared-skills/skills/start-work/SKILL.md +5 -2
  173. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  174. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
  175. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +0 -70
  176. package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +0 -98
  177. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
@@ -0,0 +1,228 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+
7
+ import type { PreToolUsePayload } from "../src/codex-hook.ts";
8
+ import { applySpawnGuards } from "../src/spawn-guard.ts";
9
+
10
+ let workDir: string;
11
+ let originalLimit: string | undefined;
12
+
13
+ beforeEach(async () => {
14
+ workDir = await mkdtemp(join(tmpdir(), "ulw-spawn-guard-"));
15
+ originalLimit = process.env["OMO_SPAWN_FANOUT_LIMIT"];
16
+ delete process.env["OMO_SPAWN_FANOUT_LIMIT"];
17
+ });
18
+
19
+ afterEach(async () => {
20
+ if (originalLimit === undefined) delete process.env["OMO_SPAWN_FANOUT_LIMIT"];
21
+ else process.env["OMO_SPAWN_FANOUT_LIMIT"] = originalLimit;
22
+ await rm(workDir, { recursive: true, force: true });
23
+ });
24
+
25
+ function payload(toolName: string, toolInput: Record<string, unknown>): PreToolUsePayload {
26
+ return {
27
+ hook_event_name: "PreToolUse",
28
+ session_id: "s1",
29
+ turn_id: "t1",
30
+ transcript_path: null,
31
+ cwd: workDir,
32
+ model: "gpt-5.6-sol",
33
+ permission_mode: "default",
34
+ tool_name: toolName,
35
+ tool_use_id: "tu1",
36
+ tool_input: toolInput,
37
+ };
38
+ }
39
+
40
+ function sessionDir(): string {
41
+ return join(workDir, ".omo", "ulw-loop", "s1");
42
+ }
43
+
44
+ function criterion(id: string): Record<string, unknown> {
45
+ return {
46
+ id,
47
+ scenario: `scenario ${id}`,
48
+ userModel: "happy",
49
+ expectedEvidence: "evidence",
50
+ capturedEvidence: "captured",
51
+ status: "pass",
52
+ capturedAt: "2026-07-11T00:00:00.000Z",
53
+ };
54
+ }
55
+
56
+ function writeGoals(planOverrides: Record<string, unknown> = {}): void {
57
+ mkdirSync(sessionDir(), { recursive: true });
58
+ writeFileSync(
59
+ join(sessionDir(), "goals.json"),
60
+ JSON.stringify({
61
+ version: 1,
62
+ createdAt: "2026-07-11T00:00:00.000Z",
63
+ updatedAt: "2026-07-11T00:00:00.000Z",
64
+ briefPath: ".omo/ulw-loop/s1/brief.md",
65
+ goalsPath: ".omo/ulw-loop/s1/goals.json",
66
+ ledgerPath: ".omo/ulw-loop/s1/ledger.jsonl",
67
+ codexGoalMode: "aggregate",
68
+ goals: [
69
+ {
70
+ id: "g1",
71
+ title: "Final goal",
72
+ objective: "Final goal",
73
+ status: "in_progress",
74
+ successCriteria: [criterion("C001"), criterion("C002")],
75
+ attempt: 1,
76
+ createdAt: "2026-07-11T00:00:00.000Z",
77
+ updatedAt: "2026-07-11T00:00:00.000Z",
78
+ },
79
+ ],
80
+ activeGoalId: "g1",
81
+ ...planOverrides,
82
+ }),
83
+ );
84
+ }
85
+
86
+ function deny(output: string): { permissionDecision: string; permissionDecisionReason: string } {
87
+ return JSON.parse(output).hookSpecificOutput;
88
+ }
89
+
90
+ describe("applySpawnGuards fan-out cap", () => {
91
+ it("#given spawns under the limit #when guarded #then allows and counts", () => {
92
+ writeGoals();
93
+
94
+ expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }))).toBe("");
95
+
96
+ const counter = JSON.parse(readFileSync(join(sessionDir(), "spawn-count.json"), "utf8"));
97
+ expect(counter.count).toBe(1);
98
+ });
99
+
100
+ it("#given the env limit exceeded #when guarded #then denies naming count/limit", () => {
101
+ writeGoals();
102
+ process.env["OMO_SPAWN_FANOUT_LIMIT"] = "3";
103
+
104
+ expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }))).toBe("");
105
+ expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }))).toBe("");
106
+ expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }))).toBe("");
107
+ const fourth = applySpawnGuards(payload("spawn_agent", { message: "scan" }));
108
+
109
+ const output = deny(fourth);
110
+ expect(output.permissionDecision).toBe("deny");
111
+ expect(output.permissionDecisionReason).toContain("4/3");
112
+ });
113
+
114
+ it("#given no ulw-loop session state #when guarded #then no-ops without counting", () => {
115
+ expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }))).toBe("");
116
+ });
117
+
118
+ it("#given a non-spawn tool #when guarded #then no-ops", () => {
119
+ writeGoals();
120
+
121
+ expect(applySpawnGuards(payload("create_goal", { objective: "x" }))).toBe("");
122
+ });
123
+
124
+ it("#given the observed dotted v2 token #when guarded #then it counts too", () => {
125
+ writeGoals();
126
+ process.env["OMO_SPAWN_FANOUT_LIMIT"] = "1";
127
+
128
+ expect(applySpawnGuards(payload("collaboration.spawn_agent", { message: "scan" }))).toBe("");
129
+ const second = applySpawnGuards(payload("collaborationspawn_agent", { message: "scan" }));
130
+
131
+ expect(deny(second).permissionDecisionReason).toContain("2/1");
132
+ });
133
+ });
134
+
135
+ describe("applySpawnGuards gate-artifact guard", () => {
136
+ it("#given a gate spawn by agent_type without artifacts #when guarded #then denies naming the missing path", () => {
137
+ writeGoals();
138
+
139
+ const output = applySpawnGuards(
140
+ payload("collaborationspawn_agent", { agent_type: "lazycodex-gate-reviewer", message: "final gate review" }),
141
+ );
142
+
143
+ const parsed = deny(output);
144
+ expect(parsed.permissionDecision).toBe("deny");
145
+ expect(parsed.permissionDecisionReason).toContain("missing");
146
+ expect(parsed.permissionDecisionReason).toContain("g1-code-review.md");
147
+ });
148
+
149
+ it("#given a gate spawn identified by message only #when guarded #then still denies", () => {
150
+ writeGoals();
151
+
152
+ const output = applySpawnGuards(payload("spawn_agent", { message: "run the FINAL GATE REVIEW now" }));
153
+
154
+ expect(deny(output).permissionDecision).toBe("deny");
155
+ });
156
+
157
+ it("#given v1 artifacts on disk #when the gate spawns #then allows", () => {
158
+ writeGoals();
159
+ mkdirSync(join(workDir, ".omo", "evidence"), { recursive: true });
160
+ writeFileSync(join(workDir, ".omo", "evidence", "g1-code-review.md"), "report\n");
161
+ writeFileSync(join(workDir, ".omo", "evidence", "g1-manual-qa.md"), "matrix\n");
162
+
163
+ const output = applySpawnGuards(
164
+ payload("spawn_agent", { agent_type: "lazycodex-gate-reviewer", message: "final gate review" }),
165
+ );
166
+
167
+ expect(output).toBe("");
168
+ });
169
+
170
+ it("#given a v2 plan #when the gate spawns without attempt-dir artifacts #then denies naming the attempt path", () => {
171
+ writeGoals({ evidenceLayoutVersion: 2 });
172
+ mkdirSync(join(workDir, ".omo", "evidence"), { recursive: true });
173
+ writeFileSync(join(workDir, ".omo", "evidence", "g1-code-review.md"), "stale flat report\n");
174
+
175
+ const output = applySpawnGuards(
176
+ payload("spawn_agent", { agent_type: "lazycodex-gate-reviewer", message: "final gate review" }),
177
+ );
178
+
179
+ expect(deny(output).permissionDecisionReason).toContain(".omo/evidence/ulw/s1/g1/a1/g1-code-review.md");
180
+ });
181
+
182
+ it("#given a v2 plan with attempt-dir artifacts #when the gate spawns #then allows", () => {
183
+ writeGoals({ evidenceLayoutVersion: 2 });
184
+ const attemptDir = join(workDir, ".omo", "evidence", "ulw", "s1", "g1", "a1");
185
+ mkdirSync(attemptDir, { recursive: true });
186
+ writeFileSync(join(attemptDir, "g1-code-review.md"), "report\n");
187
+ writeFileSync(join(attemptDir, "g1-manual-qa.md"), "matrix\n");
188
+
189
+ const output = applySpawnGuards(
190
+ payload("spawn_agent", { agent_type: "lazycodex-gate-reviewer", message: "final gate review" }),
191
+ );
192
+
193
+ expect(output).toBe("");
194
+ });
195
+
196
+ it("#given the final goal's criteria are not all pass #when the gate spawns #then no-ops", () => {
197
+ writeGoals({
198
+ goals: [
199
+ {
200
+ id: "g1",
201
+ title: "Final goal",
202
+ objective: "Final goal",
203
+ status: "in_progress",
204
+ successCriteria: [criterion("C001"), { ...criterion("C002"), status: "pending" }],
205
+ attempt: 1,
206
+ createdAt: "2026-07-11T00:00:00.000Z",
207
+ updatedAt: "2026-07-11T00:00:00.000Z",
208
+ },
209
+ ],
210
+ });
211
+
212
+ const output = applySpawnGuards(
213
+ payload("spawn_agent", { agent_type: "lazycodex-gate-reviewer", message: "final gate review" }),
214
+ );
215
+
216
+ expect(output).toBe("");
217
+ });
218
+
219
+ it("#given a non-gate reviewer spawn #when artifacts are missing #then never denies on the artifact rule", () => {
220
+ writeGoals();
221
+
222
+ const output = applySpawnGuards(
223
+ payload("spawn_agent", { agent_type: "lazycodex-code-reviewer", message: "review the diff" }),
224
+ );
225
+
226
+ expect(output).toBe("");
227
+ });
228
+ });
@@ -0,0 +1,193 @@
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+
7
+ import { runStopResumeHook } from "../src/stop-resume-hook.ts";
8
+
9
+ let workDir: string;
10
+
11
+ beforeEach(async () => {
12
+ workDir = await mkdtemp(join(tmpdir(), "ulw-stop-resume-"));
13
+ });
14
+
15
+ afterEach(async () => {
16
+ await rm(workDir, { recursive: true, force: true });
17
+ });
18
+
19
+ function stopPayload(overrides: Record<string, unknown> = {}): Record<string, unknown> {
20
+ return {
21
+ hook_event_name: "Stop",
22
+ session_id: "s1",
23
+ turn_id: "t1",
24
+ transcript_path: join(workDir, "transcript.jsonl"),
25
+ cwd: workDir,
26
+ model: "gpt-5.6-sol",
27
+ permission_mode: "default",
28
+ stop_hook_active: false,
29
+ ...overrides,
30
+ };
31
+ }
32
+
33
+ function sessionDir(): string {
34
+ return join(workDir, ".omo", "ulw-loop", "s1");
35
+ }
36
+
37
+ function writeGoals(goals: readonly Record<string, unknown>[], planOverrides: Record<string, unknown> = {}): void {
38
+ mkdirSync(sessionDir(), { recursive: true });
39
+ writeFileSync(
40
+ join(sessionDir(), "goals.json"),
41
+ JSON.stringify({
42
+ version: 1,
43
+ createdAt: "2026-07-11T00:00:00.000Z",
44
+ updatedAt: "2026-07-11T00:00:00.000Z",
45
+ briefPath: ".omo/ulw-loop/s1/brief.md",
46
+ goalsPath: ".omo/ulw-loop/s1/goals.json",
47
+ ledgerPath: ".omo/ulw-loop/s1/ledger.jsonl",
48
+ codexGoalMode: "aggregate",
49
+ goals,
50
+ ...planOverrides,
51
+ }),
52
+ );
53
+ writeFileSync(join(sessionDir(), "ledger.jsonl"), "");
54
+ writeFileSync(join(workDir, "transcript.jsonl"), "");
55
+ }
56
+
57
+ function writeBoulderPlan(remaining: boolean): string {
58
+ mkdirSync(join(workDir, ".omo", "plans"), { recursive: true });
59
+ writeFileSync(
60
+ join(workDir, ".omo", "plans", "p.md"),
61
+ remaining ? "## TODOs\n- [ ] pending task\n" : "## TODOs\n- [x] done task\n",
62
+ );
63
+ return ".omo/plans/p.md";
64
+ }
65
+
66
+ function pendingGoal(id = "g1", status = "pending"): Record<string, unknown> {
67
+ return {
68
+ id,
69
+ title: `Goal ${id}`,
70
+ objective: `Objective ${id}`,
71
+ status,
72
+ successCriteria: [],
73
+ attempt: 1,
74
+ createdAt: "2026-07-11T00:00:00.000Z",
75
+ updatedAt: "2026-07-11T00:00:00.000Z",
76
+ };
77
+ }
78
+
79
+ describe("runStopResumeHook", () => {
80
+ it("#given a pending goal #when the turn stops #then blocks with a resume directive", () => {
81
+ writeGoals([pendingGoal()]);
82
+
83
+ const output = runStopResumeHook(stopPayload());
84
+
85
+ const parsed = JSON.parse(output);
86
+ expect(parsed.decision).toBe("block");
87
+ expect(parsed.reason).toContain("omo ulw-loop status");
88
+ });
89
+
90
+ it("#given stop_hook_active #when the hook runs #then no-ops", () => {
91
+ writeGoals([pendingGoal()]);
92
+
93
+ expect(runStopResumeHook(stopPayload({ stop_hook_active: true }))).toBe("");
94
+ });
95
+
96
+ it("#given a malformed payload #when the hook runs #then no-ops", () => {
97
+ writeGoals([pendingGoal()]);
98
+
99
+ expect(runStopResumeHook({ hook_event_name: "Stop" })).toBe("");
100
+ });
101
+
102
+ it("#given an active boulder work with remaining plan tasks #when the hook runs #then defers to start-work-continuation", () => {
103
+ writeGoals([pendingGoal()]);
104
+ const plan = writeBoulderPlan(true);
105
+ writeFileSync(
106
+ join(workDir, ".omo", "boulder.json"),
107
+ JSON.stringify({ works: { w1: { session_ids: ["codex:s1"], status: "active", active_plan: plan } } }),
108
+ );
109
+
110
+ expect(runStopResumeHook(stopPayload())).toBe("");
111
+ });
112
+
113
+ it("#given an active boulder work whose plan is exhausted #when the hook runs #then resumes instead of deferring", () => {
114
+ writeGoals([pendingGoal()]);
115
+ const plan = writeBoulderPlan(false);
116
+ writeFileSync(
117
+ join(workDir, ".omo", "boulder.json"),
118
+ JSON.stringify({ works: { w1: { session_ids: ["codex:s1"], status: "active", active_plan: plan } } }),
119
+ );
120
+
121
+ expect(JSON.parse(runStopResumeHook(stopPayload())).decision).toBe("block");
122
+ });
123
+
124
+ it("#given a flat legacy boulder work with remaining plan tasks #when the hook runs #then still defers", () => {
125
+ writeGoals([pendingGoal()]);
126
+ const plan = writeBoulderPlan(true);
127
+ writeFileSync(
128
+ join(workDir, ".omo", "boulder.json"),
129
+ JSON.stringify({ session_ids: ["codex:s1"], status: "active", active_plan: plan }),
130
+ );
131
+
132
+ expect(runStopResumeHook(stopPayload())).toBe("");
133
+ });
134
+
135
+ it("#given a context-pressure marker in the transcript #when the hook runs #then no-ops", () => {
136
+ writeGoals([pendingGoal()]);
137
+ writeFileSync(join(workDir, "transcript.jsonl"), "note: context compacted mid-run\n");
138
+
139
+ expect(runStopResumeHook(stopPayload())).toBe("");
140
+ });
141
+
142
+ it("#given no ulw-loop state #when the hook runs #then no-ops", () => {
143
+ expect(runStopResumeHook(stopPayload())).toBe("");
144
+ });
145
+
146
+ it("#given all goals complete #when the hook runs #then no-ops", () => {
147
+ writeGoals([pendingGoal("g1", "complete"), pendingGoal("g2", "complete")]);
148
+
149
+ expect(runStopResumeHook(stopPayload())).toBe("");
150
+ });
151
+
152
+ it("#given blocked and failed goals only #when the hook runs #then no-ops", () => {
153
+ writeGoals([pendingGoal("g1", "blocked"), pendingGoal("g2", "failed")]);
154
+
155
+ expect(runStopResumeHook(stopPayload())).toBe("");
156
+ });
157
+
158
+ it("#given a static ledger #when the hook fires three times #then caps after two and marks stuck", () => {
159
+ writeGoals([pendingGoal()]);
160
+
161
+ const first = runStopResumeHook(stopPayload());
162
+ const second = runStopResumeHook(stopPayload());
163
+ const third = runStopResumeHook(stopPayload());
164
+
165
+ expect(JSON.parse(first).decision).toBe("block");
166
+ expect(JSON.parse(second).decision).toBe("block");
167
+ expect(third).toBe("");
168
+ const counter = JSON.parse(readFileSync(join(sessionDir(), "auto-resume-g1.json"), "utf8"));
169
+ expect(counter.count).toBe(2);
170
+ expect(existsSync(join(sessionDir(), "auto-resume-g1.stuck"))).toBe(true);
171
+ expect(readFileSync(join(sessionDir(), "ledger.jsonl"), "utf8")).toBe("");
172
+ });
173
+
174
+ it("#given a session id needing normalization #when the hook blocks #then the directive carries the normalized flag", () => {
175
+ writeGoals([pendingGoal()]);
176
+
177
+ const output = runStopResumeHook(stopPayload({ session_id: "s1/" }));
178
+
179
+ expect(JSON.parse(output).reason).toContain("--session-id s1");
180
+ });
181
+
182
+ it("#given ledger movement between stops #when the hook fires again #then the cap resets", () => {
183
+ writeGoals([pendingGoal()]);
184
+
185
+ runStopResumeHook(stopPayload());
186
+ runStopResumeHook(stopPayload());
187
+ appendFileSync(join(sessionDir(), "ledger.jsonl"), '{"kind":"goal_started"}\n');
188
+ const third = runStopResumeHook(stopPayload());
189
+
190
+ expect(JSON.parse(third).decision).toBe("block");
191
+ expect(existsSync(join(sessionDir(), "auto-resume-g1.stuck"))).toBe(false);
192
+ });
193
+ });
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook post-compact",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Resetting Git Bash MCP Reminder",
10
+ "statusMessage": "(OmO 4.17.0) Resetting Git Bash MCP Reminder",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-compact",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Resetting LSP Diagnostics Cache",
10
+ "statusMessage": "(OmO 4.17.0) Resetting LSP Diagnostics Cache",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-compact",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Resetting Project Rule Cache",
10
+ "statusMessage": "(OmO 4.17.0) Resetting Project Rule Cache",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-compact"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/codegraph/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Checking CodeGraph Init Guidance",
10
+ "statusMessage": "(OmO 4.17.0) Checking CodeGraph Init Guidance",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\codegraph\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/comment-checker/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 30,
10
- "statusMessage": "(OmO 4.16.3) Checking Comments",
10
+ "statusMessage": "(OmO 4.17.0) Checking Comments",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\comment-checker\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 60,
10
- "statusMessage": "(OmO 4.16.3) Checking LSP Diagnostics",
10
+ "statusMessage": "(OmO 4.17.0) Checking LSP Diagnostics",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/teammode/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 4.16.3) Checking Thread Title Hygiene",
11
+ "statusMessage": "(OmO 4.17.0) Checking Thread Title Hygiene",
12
12
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\teammode\\dist\\cli.js\" hook post-tool-use"
13
13
  }
14
14
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-tool-use",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Matching Project Rules",
10
+ "statusMessage": "(OmO 4.17.0) Matching Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Enforcing Unlimited Goal Budget",
10
+ "statusMessage": "(OmO 4.17.0) Enforcing Unlimited Goal Budget",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use"
12
12
  }
13
13
  ],
@@ -0,0 +1,18 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "^(spawn_agent|collaborationspawn_agent|collaboration\\.spawn_agent)$",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use-spawn",
10
+ "timeout": 5,
11
+ "statusMessage": "(OmO 4.17.0) Guarding Ulw-Loop Spawns",
12
+ "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use-spawn"
13
+ }
14
+ ]
15
+ }
16
+ ]
17
+ }
18
+ }
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook pre-tool-use",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Recommending Git Bash MCP",
10
+ "statusMessage": "(OmO 4.17.0) Recommending Git Bash MCP",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook pre-tool-use"
12
12
  }
13
13
  ],
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/scripts/auto-update.mjs\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Checking Auto Update",
10
+ "statusMessage": "(OmO 4.17.0) Checking Auto Update",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\scripts\\auto-update.mjs\" hook session-start"
12
12
  }
13
13
  ],
@@ -8,7 +8,7 @@
8
8
  "command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
9
9
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 4.16.3) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 4.17.0) Checking Bootstrap Provisioning"
12
12
  }
13
13
  ]
14
14
  }
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/codegraph/dist/cli.js\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Checking CodeGraph Bootstrap",
10
+ "statusMessage": "(OmO 4.17.0) Checking CodeGraph Bootstrap",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\codegraph\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook session-start",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Loading Project Rules",
10
+ "statusMessage": "(OmO 4.17.0) Loading Project Rules",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/telemetry/dist/cli.js\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.16.3) Recording Session Telemetry",
10
+ "statusMessage": "(OmO 4.17.0) Recording Session Telemetry",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\telemetry\\dist\\cli.js\" hook session-start"
12
12
  }
13
13
  ]
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Checking Start-Work Continuation",
10
+ "statusMessage": "(OmO 4.17.0) Checking Start-Work Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\start-work-continuation\\dist\\cli.js\" hook stop"
12
12
  }
13
13
  ]
@@ -0,0 +1,17 @@
1
+ {
2
+ "hooks": {
3
+ "Stop": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook stop",
9
+ "timeout": 10,
10
+ "statusMessage": "(OmO 4.17.0) Checking Ulw-Loop Resume",
11
+ "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook stop"
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ }
17
+ }
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Checking Start-Work Continuation",
10
+ "statusMessage": "(OmO 4.17.0) Checking Start-Work Continuation",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\start-work-continuation\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ]
@@ -7,11 +7,11 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.16.3) Verifying LazyCodex Executor Evidence",
10
+ "statusMessage": "(OmO 4.17.0) Verifying LazyCodex Executor Evidence",
11
11
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lazycodex-executor-verify\\dist\\cli.js\" hook subagent-stop"
12
12
  }
13
13
  ],
14
- "matcher": "^lazycodex-executor$"
14
+ "matcher": "^lazycodex-worker-(low|medium|high)$"
15
15
  }
16
16
  ]
17
17
  }