oh-my-claude-sisyphus 3.8.15 → 3.9.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 (259) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.mcp.json +1 -1
  4. package/README.md +9 -11
  5. package/agents/analyst.md +41 -0
  6. package/agents/architect.md +45 -0
  7. package/agents/critic.md +42 -0
  8. package/agents/deep-executor.md +193 -0
  9. package/agents/planner.md +82 -0
  10. package/bridge/mcp-server.cjs +1 -1
  11. package/commands/autopilot.md +2 -6
  12. package/commands/hud.md +7 -2
  13. package/commands/ralph.md +3 -3
  14. package/commands/ultrapilot.md +2 -6
  15. package/dist/__tests__/agent-registry.test.js +1 -1
  16. package/dist/__tests__/delegation-enforcement-levels.test.js +0 -1
  17. package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -1
  18. package/dist/__tests__/hooks/learner/parser.test.d.ts +5 -0
  19. package/dist/__tests__/hooks/learner/parser.test.d.ts.map +1 -0
  20. package/dist/__tests__/hooks/learner/parser.test.js +201 -0
  21. package/dist/__tests__/hooks/learner/parser.test.js.map +1 -0
  22. package/dist/__tests__/hud/cwd.test.d.ts +2 -0
  23. package/dist/__tests__/hud/cwd.test.d.ts.map +1 -0
  24. package/dist/__tests__/hud/cwd.test.js +62 -0
  25. package/dist/__tests__/hud/cwd.test.js.map +1 -0
  26. package/dist/__tests__/hud/defaults.test.d.ts +2 -0
  27. package/dist/__tests__/hud/defaults.test.d.ts.map +1 -0
  28. package/dist/__tests__/hud/defaults.test.js +21 -0
  29. package/dist/__tests__/hud/defaults.test.js.map +1 -0
  30. package/dist/__tests__/hud/render.test.d.ts +2 -0
  31. package/dist/__tests__/hud/render.test.d.ts.map +1 -0
  32. package/dist/__tests__/hud/render.test.js +141 -0
  33. package/dist/__tests__/hud/render.test.js.map +1 -0
  34. package/dist/__tests__/hud/thinking.test.d.ts +2 -0
  35. package/dist/__tests__/hud/thinking.test.d.ts.map +1 -0
  36. package/dist/__tests__/hud/thinking.test.js +32 -0
  37. package/dist/__tests__/hud/thinking.test.js.map +1 -0
  38. package/dist/__tests__/installer.test.js +8 -8
  39. package/dist/__tests__/installer.test.js.map +1 -1
  40. package/dist/__tests__/mnemosyne/parser.test.js +1 -1
  41. package/dist/__tests__/mnemosyne/parser.test.js.map +1 -1
  42. package/dist/__tests__/omc-tools-server.test.js +2 -2
  43. package/dist/__tests__/omc-tools-server.test.js.map +1 -1
  44. package/dist/__tests__/skills.test.js +5 -4
  45. package/dist/__tests__/skills.test.js.map +1 -1
  46. package/dist/agents/deep-executor.d.ts +15 -0
  47. package/dist/agents/deep-executor.d.ts.map +1 -0
  48. package/dist/agents/deep-executor.js +47 -0
  49. package/dist/agents/deep-executor.js.map +1 -0
  50. package/dist/agents/definitions.d.ts +15 -0
  51. package/dist/agents/definitions.d.ts.map +1 -1
  52. package/dist/agents/definitions.js +25 -0
  53. package/dist/agents/definitions.js.map +1 -1
  54. package/dist/agents/index.d.ts +1 -0
  55. package/dist/agents/index.d.ts.map +1 -1
  56. package/dist/agents/index.js +1 -0
  57. package/dist/agents/index.js.map +1 -1
  58. package/dist/cli/commands/doctor-conflicts.d.ts +55 -0
  59. package/dist/cli/commands/doctor-conflicts.d.ts.map +1 -0
  60. package/dist/cli/commands/doctor-conflicts.js +261 -0
  61. package/dist/cli/commands/doctor-conflicts.js.map +1 -0
  62. package/dist/cli/index.js +16 -1
  63. package/dist/cli/index.js.map +1 -1
  64. package/dist/features/auto-update.d.ts +12 -0
  65. package/dist/features/auto-update.d.ts.map +1 -1
  66. package/dist/features/auto-update.js +4 -1
  67. package/dist/features/auto-update.js.map +1 -1
  68. package/dist/features/context-injector/types.d.ts +1 -1
  69. package/dist/features/context-injector/types.d.ts.map +1 -1
  70. package/dist/features/continuation-enforcement.js +1 -1
  71. package/dist/features/state-manager/index.d.ts.map +1 -1
  72. package/dist/features/state-manager/index.js +7 -4
  73. package/dist/features/state-manager/index.js.map +1 -1
  74. package/dist/features/verification/example.d.ts.map +1 -1
  75. package/dist/features/verification/example.js +4 -2
  76. package/dist/features/verification/example.js.map +1 -1
  77. package/dist/hooks/__tests__/bridge.test.d.ts +2 -0
  78. package/dist/hooks/__tests__/bridge.test.d.ts.map +1 -0
  79. package/dist/hooks/__tests__/bridge.test.js +199 -0
  80. package/dist/hooks/__tests__/bridge.test.js.map +1 -0
  81. package/dist/hooks/beads-context/__tests__/index.test.d.ts +2 -0
  82. package/dist/hooks/beads-context/__tests__/index.test.d.ts.map +1 -0
  83. package/dist/hooks/beads-context/__tests__/index.test.js +150 -0
  84. package/dist/hooks/beads-context/__tests__/index.test.js.map +1 -0
  85. package/dist/hooks/beads-context/constants.d.ts +3 -0
  86. package/dist/hooks/beads-context/constants.d.ts.map +1 -0
  87. package/dist/hooks/beads-context/constants.js +35 -0
  88. package/dist/hooks/beads-context/constants.js.map +1 -0
  89. package/dist/hooks/beads-context/index.d.ts +21 -0
  90. package/dist/hooks/beads-context/index.d.ts.map +1 -0
  91. package/dist/hooks/beads-context/index.js +62 -0
  92. package/dist/hooks/beads-context/index.js.map +1 -0
  93. package/dist/hooks/beads-context/types.d.ts +7 -0
  94. package/dist/hooks/beads-context/types.d.ts.map +1 -0
  95. package/dist/hooks/beads-context/types.js +2 -0
  96. package/dist/hooks/beads-context/types.js.map +1 -0
  97. package/dist/hooks/bridge.d.ts +4 -0
  98. package/dist/hooks/bridge.d.ts.map +1 -1
  99. package/dist/hooks/bridge.js +80 -47
  100. package/dist/hooks/bridge.js.map +1 -1
  101. package/dist/hooks/index.d.ts +2 -1
  102. package/dist/hooks/index.d.ts.map +1 -1
  103. package/dist/hooks/index.js +4 -1
  104. package/dist/hooks/index.js.map +1 -1
  105. package/dist/hooks/learner/parser.d.ts.map +1 -1
  106. package/dist/hooks/learner/parser.js +12 -5
  107. package/dist/hooks/learner/parser.js.map +1 -1
  108. package/dist/hooks/mode-registry/index.d.ts +2 -0
  109. package/dist/hooks/mode-registry/index.d.ts.map +1 -1
  110. package/dist/hooks/mode-registry/index.js +8 -19
  111. package/dist/hooks/mode-registry/index.js.map +1 -1
  112. package/dist/hooks/permission-handler/index.d.ts.map +1 -1
  113. package/dist/hooks/permission-handler/index.js +3 -1
  114. package/dist/hooks/permission-handler/index.js.map +1 -1
  115. package/dist/hooks/persistent-mode/index.d.ts +1 -1
  116. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  117. package/dist/hooks/persistent-mode/index.js +5 -33
  118. package/dist/hooks/persistent-mode/index.js.map +1 -1
  119. package/dist/hooks/ralph/index.d.ts +1 -1
  120. package/dist/hooks/ralph/index.d.ts.map +1 -1
  121. package/dist/hooks/ralph/index.js +1 -1
  122. package/dist/hooks/ralph/index.js.map +1 -1
  123. package/dist/hooks/ralph/loop.d.ts +1 -9
  124. package/dist/hooks/ralph/loop.d.ts.map +1 -1
  125. package/dist/hooks/ralph/loop.js +1 -37
  126. package/dist/hooks/ralph/loop.js.map +1 -1
  127. package/dist/hooks/ralph/prd.js +1 -1
  128. package/dist/hooks/ralph/verifier.d.ts +4 -5
  129. package/dist/hooks/ralph/verifier.d.ts.map +1 -1
  130. package/dist/hooks/ralph/verifier.js +7 -10
  131. package/dist/hooks/ralph/verifier.js.map +1 -1
  132. package/dist/hooks/session-end/index.d.ts +13 -0
  133. package/dist/hooks/session-end/index.d.ts.map +1 -1
  134. package/dist/hooks/session-end/index.js +69 -0
  135. package/dist/hooks/session-end/index.js.map +1 -1
  136. package/dist/hooks/setup/index.d.ts.map +1 -1
  137. package/dist/hooks/setup/index.js +12 -5
  138. package/dist/hooks/setup/index.js.map +1 -1
  139. package/dist/hooks/subagent-tracker/index.d.ts.map +1 -1
  140. package/dist/hooks/subagent-tracker/index.js +25 -9
  141. package/dist/hooks/subagent-tracker/index.js.map +1 -1
  142. package/dist/hooks/ultrawork/index.d.ts +2 -2
  143. package/dist/hooks/ultrawork/index.d.ts.map +1 -1
  144. package/dist/hooks/ultrawork/index.js +2 -46
  145. package/dist/hooks/ultrawork/index.js.map +1 -1
  146. package/dist/hud/elements/cwd.d.ts +15 -0
  147. package/dist/hud/elements/cwd.d.ts.map +1 -0
  148. package/dist/hud/elements/cwd.js +39 -0
  149. package/dist/hud/elements/cwd.js.map +1 -0
  150. package/dist/hud/elements/index.d.ts +1 -0
  151. package/dist/hud/elements/index.d.ts.map +1 -1
  152. package/dist/hud/elements/index.js +1 -0
  153. package/dist/hud/elements/index.js.map +1 -1
  154. package/dist/hud/elements/thinking.d.ts +7 -5
  155. package/dist/hud/elements/thinking.d.ts.map +1 -1
  156. package/dist/hud/elements/thinking.js +18 -6
  157. package/dist/hud/elements/thinking.js.map +1 -1
  158. package/dist/hud/index.js +5 -3
  159. package/dist/hud/index.js.map +1 -1
  160. package/dist/hud/omc-state.d.ts +1 -1
  161. package/dist/hud/omc-state.d.ts.map +1 -1
  162. package/dist/hud/omc-state.js +14 -31
  163. package/dist/hud/omc-state.js.map +1 -1
  164. package/dist/hud/render.d.ts +9 -0
  165. package/dist/hud/render.d.ts.map +1 -1
  166. package/dist/hud/render.js +27 -7
  167. package/dist/hud/render.js.map +1 -1
  168. package/dist/hud/state.d.ts +2 -2
  169. package/dist/hud/state.d.ts.map +1 -1
  170. package/dist/hud/state.js +4 -33
  171. package/dist/hud/state.js.map +1 -1
  172. package/dist/hud/transcript.d.ts +4 -1
  173. package/dist/hud/transcript.d.ts.map +1 -1
  174. package/dist/hud/transcript.js +4 -9
  175. package/dist/hud/transcript.js.map +1 -1
  176. package/dist/hud/types.d.ts +20 -1
  177. package/dist/hud/types.d.ts.map +1 -1
  178. package/dist/hud/types.js +38 -9
  179. package/dist/hud/types.js.map +1 -1
  180. package/dist/index.js +1 -1
  181. package/dist/index.js.map +1 -1
  182. package/dist/installer/__tests__/claude-md-merge.test.d.ts +6 -0
  183. package/dist/installer/__tests__/claude-md-merge.test.d.ts.map +1 -0
  184. package/dist/installer/__tests__/claude-md-merge.test.js +220 -0
  185. package/dist/installer/__tests__/claude-md-merge.test.js.map +1 -0
  186. package/dist/installer/__tests__/safe-installer.test.d.ts +6 -0
  187. package/dist/installer/__tests__/safe-installer.test.d.ts.map +1 -0
  188. package/dist/installer/__tests__/safe-installer.test.js +172 -0
  189. package/dist/installer/__tests__/safe-installer.test.js.map +1 -0
  190. package/dist/installer/hooks.d.ts +1 -1
  191. package/dist/installer/hooks.d.ts.map +1 -1
  192. package/dist/installer/hooks.js +4 -2
  193. package/dist/installer/hooks.js.map +1 -1
  194. package/dist/installer/index.d.ts +27 -1
  195. package/dist/installer/index.d.ts.map +1 -1
  196. package/dist/installer/index.js +209 -85
  197. package/dist/installer/index.js.map +1 -1
  198. package/dist/mcp/omc-tools-server.d.ts +1 -1
  199. package/dist/mcp/omc-tools-server.d.ts.map +1 -1
  200. package/dist/mcp/omc-tools-server.js +3 -3
  201. package/dist/mcp/omc-tools-server.js.map +1 -1
  202. package/dist/mcp/standalone-server.js +1 -1
  203. package/dist/mcp/standalone-server.js.map +1 -1
  204. package/dist/verification/tier-selector.d.ts +40 -0
  205. package/dist/verification/tier-selector.d.ts.map +1 -0
  206. package/dist/verification/tier-selector.js +95 -0
  207. package/dist/verification/tier-selector.js.map +1 -0
  208. package/dist/verification/tier-selector.test.d.ts +2 -0
  209. package/dist/verification/tier-selector.test.d.ts.map +1 -0
  210. package/dist/verification/tier-selector.test.js +282 -0
  211. package/dist/verification/tier-selector.test.js.map +1 -0
  212. package/docs/AGENTS.md +100 -0
  213. package/docs/ARCHITECTURE.md +11 -7
  214. package/docs/CLAUDE.md +89 -379
  215. package/docs/DELEGATION-ENFORCER.md +1 -2
  216. package/docs/MIGRATION.md +1 -1
  217. package/docs/REFERENCE.md +29 -9
  218. package/docs/SYNC-SYSTEM.md +0 -2
  219. package/docs/partials/agent-tiers.md +165 -0
  220. package/docs/partials/features.md +131 -0
  221. package/docs/partials/mode-hierarchy.md +120 -0
  222. package/docs/partials/mode-selection-guide.md +82 -0
  223. package/docs/partials/verification-tiers.md +107 -0
  224. package/docs/shared/agent-tiers.md +165 -0
  225. package/docs/shared/features.md +131 -0
  226. package/docs/shared/mode-hierarchy.md +120 -0
  227. package/docs/shared/mode-selection-guide.md +82 -0
  228. package/docs/shared/verification-tiers.md +107 -0
  229. package/package.json +4 -3
  230. package/scripts/compose-docs.mjs +44 -0
  231. package/scripts/keyword-detector.mjs +13 -3
  232. package/scripts/persistent-mode.mjs +78 -47
  233. package/scripts/test-mutual-exclusion.ts +3 -3
  234. package/skills/AGENTS.md +59 -44
  235. package/skills/autopilot/SKILL.md +0 -2
  236. package/skills/cancel/SKILL.md +13 -32
  237. package/skills/deep-executor/SKILL.md +50 -0
  238. package/skills/ecomode/SKILL.md +58 -104
  239. package/skills/hud/SKILL.md +3 -2
  240. package/skills/omc-setup/SKILL.md +197 -20
  241. package/skills/plan/SKILL.md +62 -0
  242. package/skills/project-session-manager/SKILL.md +87 -4
  243. package/skills/project-session-manager/lib/config.sh +54 -5
  244. package/skills/project-session-manager/lib/parse.sh +65 -11
  245. package/skills/project-session-manager/lib/providers/github.sh +52 -0
  246. package/skills/project-session-manager/lib/providers/interface.sh +76 -0
  247. package/skills/project-session-manager/lib/providers/jira.sh +79 -0
  248. package/skills/project-session-manager/lib/session.sh +49 -12
  249. package/skills/project-session-manager/lib/worktree.sh +37 -4
  250. package/skills/project-session-manager/psm.sh +116 -51
  251. package/skills/ralph/SKILL.md +48 -44
  252. package/skills/ultrawork/SKILL.md +56 -67
  253. package/templates/hooks/keyword-detector.mjs +21 -13
  254. package/templates/hooks/lib/stdin.mjs +62 -0
  255. package/templates/hooks/persistent-mode.mjs +75 -34
  256. package/templates/hooks/post-tool-use.mjs +8 -10
  257. package/templates/hooks/pre-tool-use.mjs +9 -6
  258. package/templates/hooks/session-start.mjs +7 -8
  259. package/agents/AGENTS.md +0 -144
@@ -9,16 +9,15 @@
9
9
  */
10
10
 
11
11
  import { existsSync, readFileSync, writeFileSync, readdirSync, mkdirSync } from 'fs';
12
- import { join } from 'path';
12
+ import { join, dirname } from 'path';
13
13
  import { homedir } from 'os';
14
+ import { fileURLToPath } from 'url';
14
15
 
15
- async function readStdin() {
16
- const chunks = [];
17
- for await (const chunk of process.stdin) {
18
- chunks.push(chunk);
19
- }
20
- return Buffer.concat(chunks).toString('utf-8');
21
- }
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = dirname(__filename);
18
+
19
+ // Dynamic import for the shared stdin module
20
+ const { readStdin } = await import(join(__dirname, 'lib', 'stdin.mjs'));
22
21
 
23
22
  function readJsonFile(path) {
24
23
  try {
@@ -43,6 +42,31 @@ function writeJsonFile(path, data) {
43
42
  }
44
43
  }
45
44
 
45
+ /**
46
+ * Staleness threshold for mode states (2 hours in milliseconds).
47
+ * States older than this are treated as inactive to prevent stale state
48
+ * from causing the stop hook to malfunction in new sessions.
49
+ */
50
+ const STALE_STATE_THRESHOLD_MS = 2 * 60 * 60 * 1000; // 2 hours
51
+
52
+ /**
53
+ * Check if a state is stale based on its timestamps.
54
+ * A state is considered stale if it hasn't been updated recently.
55
+ * We check both `last_checked_at` and `started_at` - using whichever is more recent.
56
+ */
57
+ function isStaleState(state) {
58
+ if (!state) return true;
59
+
60
+ const lastChecked = state.last_checked_at ? new Date(state.last_checked_at).getTime() : 0;
61
+ const startedAt = state.started_at ? new Date(state.started_at).getTime() : 0;
62
+ const mostRecent = Math.max(lastChecked, startedAt);
63
+
64
+ if (mostRecent === 0) return true; // No valid timestamps
65
+
66
+ const age = Date.now() - mostRecent;
67
+ return age > STALE_STATE_THRESHOLD_MS;
68
+ }
69
+
46
70
  /**
47
71
  * Read state file from local or global location, tracking the source.
48
72
  */
@@ -206,34 +230,37 @@ async function main() {
206
230
  const totalIncomplete = taskCount + todoCount;
207
231
 
208
232
  // Priority 1: Ralph Loop (explicit persistence mode)
209
- if (ralph.state?.active) {
233
+ // Skip if state is stale (older than 2 hours) - prevents blocking new sessions
234
+ if (ralph.state?.active && !isStaleState(ralph.state)) {
210
235
  const iteration = ralph.state.iteration || 1;
211
236
  const maxIter = ralph.state.max_iterations || 100;
212
237
 
213
238
  if (iteration < maxIter) {
214
239
  ralph.state.iteration = iteration + 1;
240
+ ralph.state.last_checked_at = new Date().toISOString();
215
241
  writeJsonFile(ralph.path, ralph.state);
216
242
 
217
243
  console.log(JSON.stringify({
218
244
  decision: 'block',
219
- reason: `[RALPH LOOP - ITERATION ${iteration + 1}/${maxIter}] Work is NOT done. Continue. When complete, output: <promise>${ralph.state.completion_promise || 'DONE'}</promise>\n${ralph.state.prompt ? `Task: ${ralph.state.prompt}` : ''}`
245
+ reason: `[RALPH LOOP - ITERATION ${iteration + 1}/${maxIter}] Work is NOT done. Continue working.\nWhen FULLY complete (after Architect verification), run /oh-my-claudecode:cancel to cleanly exit ralph mode and clean up all state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.\n${ralph.state.prompt ? `Task: ${ralph.state.prompt}` : ''}`
220
246
  }));
221
247
  return;
222
248
  }
223
249
  }
224
250
 
225
251
  // Priority 2: Autopilot (high-level orchestration)
226
- if (autopilot.state?.active) {
252
+ if (autopilot.state?.active && !isStaleState(autopilot.state)) {
227
253
  const phase = autopilot.state.phase || 'unknown';
228
254
  if (phase !== 'complete') {
229
255
  const newCount = (autopilot.state.reinforcement_count || 0) + 1;
230
256
  if (newCount <= 20) {
231
257
  autopilot.state.reinforcement_count = newCount;
258
+ autopilot.state.last_checked_at = new Date().toISOString();
232
259
  writeJsonFile(autopilot.path, autopilot.state);
233
260
 
234
261
  console.log(JSON.stringify({
235
262
  decision: 'block',
236
- reason: `[AUTOPILOT - Phase: ${phase}] Autopilot not complete. Continue working.`
263
+ reason: `[AUTOPILOT - Phase: ${phase}] Autopilot not complete. Continue working. When all phases are complete, run /oh-my-claudecode:cancel to cleanly exit and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.`
237
264
  }));
238
265
  return;
239
266
  }
@@ -241,18 +268,19 @@ async function main() {
241
268
  }
242
269
 
243
270
  // Priority 3: Ultrapilot (parallel autopilot)
244
- if (ultrapilot.state?.active) {
271
+ if (ultrapilot.state?.active && !isStaleState(ultrapilot.state)) {
245
272
  const workers = ultrapilot.state.workers || [];
246
273
  const incomplete = workers.filter(w => w.status !== 'complete' && w.status !== 'failed').length;
247
274
  if (incomplete > 0) {
248
275
  const newCount = (ultrapilot.state.reinforcement_count || 0) + 1;
249
276
  if (newCount <= 20) {
250
277
  ultrapilot.state.reinforcement_count = newCount;
278
+ ultrapilot.state.last_checked_at = new Date().toISOString();
251
279
  writeJsonFile(ultrapilot.path, ultrapilot.state);
252
280
 
253
281
  console.log(JSON.stringify({
254
282
  decision: 'block',
255
- reason: `[ULTRAPILOT] ${incomplete} workers still running. Continue.`
283
+ reason: `[ULTRAPILOT] ${incomplete} workers still running. Continue working. When all workers complete, run /oh-my-claudecode:cancel to cleanly exit and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.`
256
284
  }));
257
285
  return;
258
286
  }
@@ -260,17 +288,18 @@ async function main() {
260
288
  }
261
289
 
262
290
  // Priority 4: Swarm (coordinated agents with SQLite)
263
- if (swarmMarker && swarmSummary?.active) {
291
+ if (swarmMarker && swarmSummary?.active && !isStaleState(swarmSummary)) {
264
292
  const pending = (swarmSummary.tasks_pending || 0) + (swarmSummary.tasks_claimed || 0);
265
293
  if (pending > 0) {
266
294
  const newCount = (swarmSummary.reinforcement_count || 0) + 1;
267
295
  if (newCount <= 15) {
268
296
  swarmSummary.reinforcement_count = newCount;
297
+ swarmSummary.last_checked_at = new Date().toISOString();
269
298
  writeJsonFile(join(stateDir, 'swarm-summary.json'), swarmSummary);
270
299
 
271
300
  console.log(JSON.stringify({
272
301
  decision: 'block',
273
- reason: `[SWARM ACTIVE] ${pending} tasks remain. Continue working.`
302
+ reason: `[SWARM ACTIVE] ${pending} tasks remain. Continue working. When all tasks are done, run /oh-my-claudecode:cancel to cleanly exit and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.`
274
303
  }));
275
304
  return;
276
305
  }
@@ -278,18 +307,19 @@ async function main() {
278
307
  }
279
308
 
280
309
  // Priority 5: Pipeline (sequential stages)
281
- if (pipeline.state?.active) {
310
+ if (pipeline.state?.active && !isStaleState(pipeline.state)) {
282
311
  const currentStage = pipeline.state.current_stage || 0;
283
312
  const totalStages = pipeline.state.stages?.length || 0;
284
313
  if (currentStage < totalStages) {
285
314
  const newCount = (pipeline.state.reinforcement_count || 0) + 1;
286
315
  if (newCount <= 15) {
287
316
  pipeline.state.reinforcement_count = newCount;
317
+ pipeline.state.last_checked_at = new Date().toISOString();
288
318
  writeJsonFile(pipeline.path, pipeline.state);
289
319
 
290
320
  console.log(JSON.stringify({
291
321
  decision: 'block',
292
- reason: `[PIPELINE - Stage ${currentStage + 1}/${totalStages}] Pipeline not complete. Continue.`
322
+ reason: `[PIPELINE - Stage ${currentStage + 1}/${totalStages}] Pipeline not complete. Continue working. When all stages complete, run /oh-my-claudecode:cancel to cleanly exit and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.`
293
323
  }));
294
324
  return;
295
325
  }
@@ -297,16 +327,17 @@ async function main() {
297
327
  }
298
328
 
299
329
  // Priority 6: UltraQA (QA cycling)
300
- if (ultraqa.state?.active) {
330
+ if (ultraqa.state?.active && !isStaleState(ultraqa.state)) {
301
331
  const cycle = ultraqa.state.cycle || 1;
302
332
  const maxCycles = ultraqa.state.max_cycles || 10;
303
333
  if (cycle < maxCycles && !ultraqa.state.all_passing) {
304
334
  ultraqa.state.cycle = cycle + 1;
335
+ ultraqa.state.last_checked_at = new Date().toISOString();
305
336
  writeJsonFile(ultraqa.path, ultraqa.state);
306
337
 
307
338
  console.log(JSON.stringify({
308
339
  decision: 'block',
309
- reason: `[ULTRAQA - Cycle ${cycle + 1}/${maxCycles}] Tests not all passing. Continue fixing.`
340
+ reason: `[ULTRAQA - Cycle ${cycle + 1}/${maxCycles}] Tests not all passing. Continue fixing. When all tests pass, run /oh-my-claudecode:cancel to cleanly exit and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force.`
310
341
  }));
311
342
  return;
312
343
  }
@@ -314,7 +345,7 @@ async function main() {
314
345
 
315
346
  // Priority 7: Ultrawork - ALWAYS continue while active (not just when tasks exist)
316
347
  // This prevents false stops from bash errors, transient failures, etc.
317
- if (ultrawork.state?.active) {
348
+ if (ultrawork.state?.active && !isStaleState(ultrawork.state)) {
318
349
  const newCount = (ultrawork.state.reinforcement_count || 0) + 1;
319
350
  const maxReinforcements = ultrawork.state.max_reinforcements || 50;
320
351
 
@@ -328,24 +359,29 @@ async function main() {
328
359
  ultrawork.state.last_checked_at = new Date().toISOString();
329
360
  writeJsonFile(ultrawork.path, ultrawork.state);
330
361
 
331
- let reason = `[ULTRAWORK #${newCount}] Mode active - continue working.`;
362
+ let reason = `[ULTRAWORK #${newCount}/${maxReinforcements}] Mode active.`;
363
+
332
364
  if (totalIncomplete > 0) {
333
365
  const itemType = taskCount > 0 ? 'Tasks' : 'todos';
334
- reason = `[ULTRAWORK #${newCount}] ${totalIncomplete} incomplete ${itemType}. Continue working.`;
366
+ reason += ` ${totalIncomplete} incomplete ${itemType} remain. Continue working.`;
367
+ } else if (newCount >= 3) {
368
+ // Only suggest cancel after minimum iterations (guard against no-tasks-created scenario)
369
+ reason += ` If all work is complete, run /oh-my-claudecode:cancel to cleanly exit ultrawork mode and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force. Otherwise, continue working.`;
370
+ } else {
371
+ // Early iterations with no tasks yet - just tell LLM to continue
372
+ reason += ` Continue working - create Tasks to track your progress.`;
335
373
  }
374
+
336
375
  if (ultrawork.state.original_prompt) {
337
376
  reason += `\nTask: ${ultrawork.state.original_prompt}`;
338
377
  }
339
378
 
340
- console.log(JSON.stringify({
341
- decision: 'block',
342
- reason: reason
343
- }));
379
+ console.log(JSON.stringify({ decision: 'block', reason }));
344
380
  return;
345
381
  }
346
382
 
347
383
  // Priority 8: Ecomode - ALWAYS continue while active
348
- if (ecomode.state?.active) {
384
+ if (ecomode.state?.active && !isStaleState(ecomode.state)) {
349
385
  const newCount = (ecomode.state.reinforcement_count || 0) + 1;
350
386
  const maxReinforcements = ecomode.state.max_reinforcements || 50;
351
387
 
@@ -356,18 +392,23 @@ async function main() {
356
392
  }
357
393
 
358
394
  ecomode.state.reinforcement_count = newCount;
395
+ ecomode.state.last_checked_at = new Date().toISOString();
359
396
  writeJsonFile(ecomode.path, ecomode.state);
360
397
 
361
- let reason = `[ECOMODE #${newCount}] Mode active - continue working.`;
398
+ let reason = `[ECOMODE #${newCount}/${maxReinforcements}] Mode active.`;
399
+
362
400
  if (totalIncomplete > 0) {
363
401
  const itemType = taskCount > 0 ? 'Tasks' : 'todos';
364
- reason = `[ECOMODE #${newCount}] ${totalIncomplete} incomplete ${itemType}. Continue working.`;
402
+ reason += ` ${totalIncomplete} incomplete ${itemType} remain. Continue working.`;
403
+ } else if (newCount >= 3) {
404
+ // Only suggest cancel after minimum iterations (guard against no-tasks-created scenario)
405
+ reason += ` If all work is complete, run /oh-my-claudecode:cancel to cleanly exit ecomode and clean up state files. If cancel fails, retry with /oh-my-claudecode:cancel --force. Otherwise, continue working.`;
406
+ } else {
407
+ // Early iterations with no tasks yet - just tell LLM to continue
408
+ reason += ` Continue working - create Tasks to track your progress.`;
365
409
  }
366
410
 
367
- console.log(JSON.stringify({
368
- decision: 'block',
369
- reason: reason
370
- }));
411
+ console.log(JSON.stringify({ decision: 'block', reason }));
371
412
  return;
372
413
  }
373
414
 
@@ -4,7 +4,14 @@
4
4
  // Saves to .omc/notepad.md for compaction-resilient memory
5
5
 
6
6
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
7
- import { join } from 'path';
7
+ import { join, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ // Dynamic import for the shared stdin module
14
+ const { readStdin } = await import(join(__dirname, 'lib', 'stdin.mjs'));
8
15
 
9
16
  // Constants
10
17
  const NOTEPAD_TEMPLATE = '# Notepad\n' +
@@ -16,15 +23,6 @@ const NOTEPAD_TEMPLATE = '# Notepad\n' +
16
23
  '## MANUAL\n' +
17
24
  '<!-- User content. Never auto-pruned. -->\n';
18
25
 
19
- // Read all stdin
20
- async function readStdin() {
21
- const chunks = [];
22
- for await (const chunk of process.stdin) {
23
- chunks.push(chunk);
24
- }
25
- return Buffer.concat(chunks).toString('utf-8');
26
- }
27
-
28
26
  // Initialize notepad.md if needed
29
27
  function initNotepad(directory) {
30
28
  const sisyphusDir = join(directory, '.omc');
@@ -5,6 +5,14 @@
5
5
  */
6
6
 
7
7
  import * as path from 'path';
8
+ import { dirname } from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+
14
+ // Dynamic import for the shared stdin module
15
+ const { readStdin } = await import(path.join(__dirname, 'lib', 'stdin.mjs'));
8
16
 
9
17
  // Allowed path patterns (no warning)
10
18
  const ALLOWED_PATH_PATTERNS = [
@@ -70,12 +78,7 @@ This is a soft warning. Operation will proceed.`;
70
78
  }
71
79
 
72
80
  async function main() {
73
- let input = '';
74
-
75
- // Read stdin
76
- for await (const chunk of process.stdin) {
77
- input += chunk;
78
- }
81
+ const input = await readStdin();
79
82
 
80
83
  let data;
81
84
  try {
@@ -4,16 +4,15 @@
4
4
  // Cross-platform: Windows, macOS, Linux
5
5
 
6
6
  import { existsSync, readFileSync, readdirSync, writeFileSync, mkdirSync } from 'fs';
7
- import { join } from 'path';
7
+ import { join, dirname } from 'path';
8
8
  import { homedir } from 'os';
9
+ import { fileURLToPath } from 'url';
9
10
 
10
- async function readStdin() {
11
- const chunks = [];
12
- for await (const chunk of process.stdin) {
13
- chunks.push(chunk);
14
- }
15
- return Buffer.concat(chunks).toString('utf-8');
16
- }
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+
14
+ // Dynamic import for the shared stdin module
15
+ const { readStdin } = await import(join(__dirname, 'lib', 'stdin.mjs'));
17
16
 
18
17
  function readJsonFile(path) {
19
18
  try {
package/agents/AGENTS.md DELETED
@@ -1,144 +0,0 @@
1
- <!-- Parent: ../AGENTS.md -->
2
- <!-- Generated: 2026-01-28 | Updated: 2026-01-28 -->
3
-
4
- # agents (Prompt Templates)
5
-
6
- Markdown prompt templates for all 32 agents in oh-my-claudecode.
7
-
8
- ## Purpose
9
-
10
- This directory contains the prompt templates that define agent behavior. Each file is a markdown document with YAML frontmatter for metadata, loaded dynamically by `src/agents/definitions.ts`.
11
-
12
- ## Key Files
13
-
14
- | File | Agent | Model | Purpose |
15
- |------|-------|-------|---------|
16
- | `architect.md` | architect | opus | Architecture, debugging, root cause analysis |
17
- | `architect-medium.md` | architect-medium | sonnet | Moderate analysis tasks |
18
- | `architect-low.md` | architect-low | haiku | Quick code questions |
19
- | `executor.md` | executor | sonnet | Focused task implementation |
20
- | `executor-high.md` | executor-high | opus | Complex multi-file changes |
21
- | `executor-low.md` | executor-low | haiku | Simple single-file tasks |
22
- | `explore.md` | explore | haiku | Fast codebase search |
23
- | `explore-medium.md` | explore-medium | sonnet | Thorough search with reasoning |
24
- | `explore-high.md` | explore-high | opus | Architectural discovery |
25
- | `designer.md` | designer | sonnet | UI/UX, component design |
26
- | `designer-high.md` | designer-high | opus | Complex UI architecture |
27
- | `designer-low.md` | designer-low | haiku | Simple styling tweaks |
28
- | `researcher.md` | researcher | sonnet | Documentation research |
29
- | `researcher-low.md` | researcher-low | haiku | Quick doc lookups |
30
- | `writer.md` | writer | haiku | Technical documentation |
31
- | `vision.md` | vision | sonnet | Image/screenshot analysis |
32
- | `critic.md` | critic | opus | Critical plan review |
33
- | `analyst.md` | analyst | opus | Pre-planning requirements |
34
- | `planner.md` | planner | opus | Strategic planning |
35
- | `qa-tester.md` | qa-tester | sonnet | Interactive CLI testing |
36
- | `qa-tester-high.md` | qa-tester-high | opus | Production-ready QA |
37
- | `scientist.md` | scientist | sonnet | Data analysis |
38
- | `scientist-high.md` | scientist-high | opus | Complex ML/research |
39
- | `scientist-low.md` | scientist-low | haiku | Quick data inspection |
40
- | `security-reviewer.md` | security-reviewer | opus | Security audits |
41
- | `security-reviewer-low.md` | security-reviewer-low | haiku | Quick security scans |
42
- | `build-fixer.md` | build-fixer | sonnet | Build error resolution |
43
- | `build-fixer-low.md` | build-fixer-low | haiku | Simple type errors |
44
- | `tdd-guide.md` | tdd-guide | sonnet | TDD workflow |
45
- | `tdd-guide-low.md` | tdd-guide-low | haiku | Test suggestions |
46
- | `code-reviewer.md` | code-reviewer | opus | Expert code review |
47
- | `code-reviewer-low.md` | code-reviewer-low | haiku | Quick code checks |
48
-
49
- ## For AI Agents
50
-
51
- ### Working In This Directory
52
-
53
- #### Prompt Template Format
54
-
55
- Each file follows this structure:
56
- ```markdown
57
- ---
58
- name: agent-name
59
- description: Brief description of what this agent does
60
- model: opus | sonnet | haiku
61
- tools: [Read, Glob, Grep, ...]
62
- ---
63
-
64
- # Agent Name
65
-
66
- ## Role
67
- What this agent is and its expertise.
68
-
69
- ## Instructions
70
- Detailed instructions for how the agent should behave.
71
-
72
- ## Constraints
73
- What the agent should NOT do.
74
-
75
- ## Output Format
76
- How results should be formatted.
77
- ```
78
-
79
- #### Creating a New Agent Prompt
80
-
81
- 1. Create `new-agent.md` with YAML frontmatter
82
- 2. Define clear role, instructions, and constraints
83
- 3. Reference in `src/agents/definitions.ts`
84
-
85
- #### Tiered Variants
86
-
87
- For model routing, create variants with complexity-appropriate instructions:
88
-
89
- | Tier | File Suffix | Instructions Focus |
90
- |------|-------------|-------------------|
91
- | LOW (Haiku) | `-low.md` | Quick, simple tasks, minimal reasoning |
92
- | MEDIUM (Sonnet) | Base file or `-medium.md` | Standard complexity |
93
- | HIGH (Opus) | `-high.md` | Complex reasoning, deep analysis |
94
-
95
- ### Common Patterns
96
-
97
- **Frontmatter parsing** (in `definitions.ts`):
98
- ```typescript
99
- function loadAgentPrompt(agentName: string): string {
100
- const content = readFileSync(`agents/${agentName}.md`, 'utf-8');
101
- const match = content.match(/^---[\s\S]*?---\s*([\s\S]*)$/);
102
- return match ? match[1].trim() : content.trim();
103
- }
104
- ```
105
-
106
- **Tool assignment by agent type:**
107
- - Read-only: `[Read, Glob, Grep]`
108
- - Analysis: `[Read, Glob, Grep, WebSearch, WebFetch]`
109
- - Execution: `[Read, Glob, Grep, Edit, Write, Bash, TodoWrite]`
110
- - Data: `[Read, Glob, Grep, Bash, python_repl]`
111
-
112
- ### Testing Requirements
113
-
114
- Agent prompts are tested via integration tests that spawn agents and verify behavior.
115
-
116
- ## Dependencies
117
-
118
- ### Internal
119
- - Loaded by `src/agents/definitions.ts`
120
- - Referenced by skill definitions in `skills/`
121
-
122
- ### External
123
- None - pure markdown files.
124
-
125
- ## Agent Categories
126
-
127
- | Category | Agents | Common Tools |
128
- |----------|--------|--------------|
129
- | Analysis | architect, architect-medium, architect-low | Read, Glob, Grep, lsp_diagnostics |
130
- | Execution | executor, executor-low, executor-high | Read, Glob, Grep, Edit, Write, Bash, lsp_diagnostics |
131
- | Search | explore, explore-medium, explore-high | Read, Glob, Grep, ast_grep_search, lsp_document_symbols, lsp_workspace_symbols |
132
- | Research | researcher, researcher-low | WebSearch, WebFetch |
133
- | Frontend | designer, designer-low, designer-high | Edit, Write, Bash |
134
- | Docs | writer | Edit, Write |
135
- | Visual | vision | Read, Glob, Grep |
136
- | Planning | planner, analyst, critic | Read, Glob, Grep |
137
- | Testing | qa-tester, qa-tester-high | Bash, Read, Grep, Glob, TodoWrite, lsp_diagnostics |
138
- | Security | security-reviewer, security-reviewer-low | Read, Grep, Bash |
139
- | Build | build-fixer, build-fixer-low | Read, Glob, Grep, Edit, Write, Bash, lsp_diagnostics, lsp_diagnostics_directory |
140
- | TDD | tdd-guide, tdd-guide-low | Read, Grep, Glob, Bash, lsp_diagnostics |
141
- | Review | code-reviewer, code-reviewer-low | Read, Grep, Glob, Bash, lsp_diagnostics |
142
- | Data | scientist, scientist-low, scientist-high | Read, Glob, Grep, Bash, python_repl |
143
-
144
- <!-- MANUAL: -->