oh-my-claude-sisyphus 3.8.14 → 3.8.16

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 (150) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +9 -11
  4. package/bridge/mcp-server.cjs +180 -180
  5. package/commands/autopilot.md +2 -6
  6. package/commands/hud.md +7 -2
  7. package/commands/ralph.md +3 -3
  8. package/commands/ultrapilot.md +2 -6
  9. package/dist/__tests__/delegation-enforcement-levels.test.js +0 -1
  10. package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -1
  11. package/dist/__tests__/hooks/learner/parser.test.d.ts +5 -0
  12. package/dist/__tests__/hooks/learner/parser.test.d.ts.map +1 -0
  13. package/dist/__tests__/hooks/learner/parser.test.js +201 -0
  14. package/dist/__tests__/hooks/learner/parser.test.js.map +1 -0
  15. package/dist/__tests__/hud/cwd.test.d.ts +2 -0
  16. package/dist/__tests__/hud/cwd.test.d.ts.map +1 -0
  17. package/dist/__tests__/hud/cwd.test.js +62 -0
  18. package/dist/__tests__/hud/cwd.test.js.map +1 -0
  19. package/dist/__tests__/hud/defaults.test.d.ts +2 -0
  20. package/dist/__tests__/hud/defaults.test.d.ts.map +1 -0
  21. package/dist/__tests__/hud/defaults.test.js +21 -0
  22. package/dist/__tests__/hud/defaults.test.js.map +1 -0
  23. package/dist/__tests__/hud/render.test.d.ts +2 -0
  24. package/dist/__tests__/hud/render.test.d.ts.map +1 -0
  25. package/dist/__tests__/hud/render.test.js +141 -0
  26. package/dist/__tests__/hud/render.test.js.map +1 -0
  27. package/dist/__tests__/hud/thinking.test.d.ts +2 -0
  28. package/dist/__tests__/hud/thinking.test.d.ts.map +1 -0
  29. package/dist/__tests__/hud/thinking.test.js +32 -0
  30. package/dist/__tests__/hud/thinking.test.js.map +1 -0
  31. package/dist/__tests__/mnemosyne/parser.test.js +1 -1
  32. package/dist/__tests__/mnemosyne/parser.test.js.map +1 -1
  33. package/dist/features/continuation-enforcement.js +1 -1
  34. package/dist/features/state-manager/index.d.ts.map +1 -1
  35. package/dist/features/state-manager/index.js +7 -4
  36. package/dist/features/state-manager/index.js.map +1 -1
  37. package/dist/features/verification/example.d.ts.map +1 -1
  38. package/dist/features/verification/example.js +4 -2
  39. package/dist/features/verification/example.js.map +1 -1
  40. package/dist/hooks/bridge.d.ts.map +1 -1
  41. package/dist/hooks/bridge.js +4 -24
  42. package/dist/hooks/bridge.js.map +1 -1
  43. package/dist/hooks/index.d.ts +1 -1
  44. package/dist/hooks/index.d.ts.map +1 -1
  45. package/dist/hooks/index.js +1 -1
  46. package/dist/hooks/index.js.map +1 -1
  47. package/dist/hooks/learner/parser.d.ts.map +1 -1
  48. package/dist/hooks/learner/parser.js +12 -5
  49. package/dist/hooks/learner/parser.js.map +1 -1
  50. package/dist/hooks/mode-registry/index.d.ts +2 -0
  51. package/dist/hooks/mode-registry/index.d.ts.map +1 -1
  52. package/dist/hooks/mode-registry/index.js +8 -19
  53. package/dist/hooks/mode-registry/index.js.map +1 -1
  54. package/dist/hooks/persistent-mode/index.d.ts +1 -1
  55. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  56. package/dist/hooks/persistent-mode/index.js +5 -33
  57. package/dist/hooks/persistent-mode/index.js.map +1 -1
  58. package/dist/hooks/ralph/index.d.ts +1 -1
  59. package/dist/hooks/ralph/index.d.ts.map +1 -1
  60. package/dist/hooks/ralph/index.js +1 -1
  61. package/dist/hooks/ralph/index.js.map +1 -1
  62. package/dist/hooks/ralph/loop.d.ts +1 -9
  63. package/dist/hooks/ralph/loop.d.ts.map +1 -1
  64. package/dist/hooks/ralph/loop.js +1 -37
  65. package/dist/hooks/ralph/loop.js.map +1 -1
  66. package/dist/hooks/ralph/prd.js +1 -1
  67. package/dist/hooks/ralph/verifier.d.ts +4 -5
  68. package/dist/hooks/ralph/verifier.d.ts.map +1 -1
  69. package/dist/hooks/ralph/verifier.js +7 -10
  70. package/dist/hooks/ralph/verifier.js.map +1 -1
  71. package/dist/hooks/session-end/index.d.ts +13 -0
  72. package/dist/hooks/session-end/index.d.ts.map +1 -1
  73. package/dist/hooks/session-end/index.js +69 -0
  74. package/dist/hooks/session-end/index.js.map +1 -1
  75. package/dist/hooks/ultrawork/index.d.ts +2 -2
  76. package/dist/hooks/ultrawork/index.d.ts.map +1 -1
  77. package/dist/hooks/ultrawork/index.js +2 -46
  78. package/dist/hooks/ultrawork/index.js.map +1 -1
  79. package/dist/hud/elements/cwd.d.ts +15 -0
  80. package/dist/hud/elements/cwd.d.ts.map +1 -0
  81. package/dist/hud/elements/cwd.js +39 -0
  82. package/dist/hud/elements/cwd.js.map +1 -0
  83. package/dist/hud/elements/index.d.ts +1 -0
  84. package/dist/hud/elements/index.d.ts.map +1 -1
  85. package/dist/hud/elements/index.js +1 -0
  86. package/dist/hud/elements/index.js.map +1 -1
  87. package/dist/hud/elements/thinking.d.ts +7 -5
  88. package/dist/hud/elements/thinking.d.ts.map +1 -1
  89. package/dist/hud/elements/thinking.js +18 -6
  90. package/dist/hud/elements/thinking.js.map +1 -1
  91. package/dist/hud/index.js +5 -3
  92. package/dist/hud/index.js.map +1 -1
  93. package/dist/hud/omc-state.d.ts +1 -1
  94. package/dist/hud/omc-state.d.ts.map +1 -1
  95. package/dist/hud/omc-state.js +14 -31
  96. package/dist/hud/omc-state.js.map +1 -1
  97. package/dist/hud/render.d.ts +9 -0
  98. package/dist/hud/render.d.ts.map +1 -1
  99. package/dist/hud/render.js +27 -7
  100. package/dist/hud/render.js.map +1 -1
  101. package/dist/hud/state.d.ts +2 -2
  102. package/dist/hud/state.d.ts.map +1 -1
  103. package/dist/hud/state.js +4 -33
  104. package/dist/hud/state.js.map +1 -1
  105. package/dist/hud/transcript.d.ts +4 -1
  106. package/dist/hud/transcript.d.ts.map +1 -1
  107. package/dist/hud/transcript.js +4 -9
  108. package/dist/hud/transcript.js.map +1 -1
  109. package/dist/hud/types.d.ts +20 -1
  110. package/dist/hud/types.d.ts.map +1 -1
  111. package/dist/hud/types.js +38 -9
  112. package/dist/hud/types.js.map +1 -1
  113. package/dist/installer/hooks.d.ts +1 -1
  114. package/dist/installer/hooks.d.ts.map +1 -1
  115. package/dist/installer/hooks.js +1 -1
  116. package/docs/AGENTS.md +100 -0
  117. package/docs/ARCHITECTURE.md +11 -7
  118. package/docs/CLAUDE.md +1 -3
  119. package/docs/DELEGATION-ENFORCER.md +1 -2
  120. package/docs/MIGRATION.md +1 -1
  121. package/docs/REFERENCE.md +29 -9
  122. package/docs/SYNC-SYSTEM.md +0 -2
  123. package/package.json +1 -1
  124. package/scripts/persistent-mode.mjs +88 -61
  125. package/scripts/test-mutual-exclusion.ts +3 -3
  126. package/skills/AGENTS.md +59 -44
  127. package/skills/autopilot/SKILL.md +0 -2
  128. package/skills/cancel/SKILL.md +13 -32
  129. package/skills/ecomode/SKILL.md +0 -1
  130. package/skills/hud/SKILL.md +3 -2
  131. package/skills/ralph/SKILL.md +9 -19
  132. package/skills/ultrawork/SKILL.md +0 -1
  133. package/templates/hooks/persistent-mode.mjs +78 -40
  134. package/agents/AGENTS.md +0 -144
  135. package/dist/hooks/clear-suggestions/constants.d.ts +0 -54
  136. package/dist/hooks/clear-suggestions/constants.d.ts.map +0 -1
  137. package/dist/hooks/clear-suggestions/constants.js +0 -102
  138. package/dist/hooks/clear-suggestions/constants.js.map +0 -1
  139. package/dist/hooks/clear-suggestions/index.d.ts +0 -61
  140. package/dist/hooks/clear-suggestions/index.d.ts.map +0 -1
  141. package/dist/hooks/clear-suggestions/index.js +0 -282
  142. package/dist/hooks/clear-suggestions/index.js.map +0 -1
  143. package/dist/hooks/clear-suggestions/triggers.d.ts +0 -65
  144. package/dist/hooks/clear-suggestions/triggers.d.ts.map +0 -1
  145. package/dist/hooks/clear-suggestions/triggers.js +0 -222
  146. package/dist/hooks/clear-suggestions/triggers.js.map +0 -1
  147. package/dist/hooks/clear-suggestions/types.d.ts +0 -92
  148. package/dist/hooks/clear-suggestions/types.d.ts.map +0 -1
  149. package/dist/hooks/clear-suggestions/types.js +0 -9
  150. package/dist/hooks/clear-suggestions/types.js.map +0 -1
@@ -44,19 +44,37 @@ function writeJsonFile(path, data) {
44
44
  }
45
45
 
46
46
  /**
47
- * Read state file from local or global location, tracking the source.
47
+ * Staleness threshold for mode states (2 hours in milliseconds).
48
+ * States older than this are treated as inactive to prevent stale state
49
+ * from causing the stop hook to malfunction in new sessions.
48
50
  */
49
- function readStateFile(stateDir, globalStateDir, filename) {
50
- const localPath = join(stateDir, filename);
51
- const globalPath = join(globalStateDir, filename);
51
+ const STALE_STATE_THRESHOLD_MS = 2 * 60 * 60 * 1000; // 2 hours
52
+
53
+ /**
54
+ * Check if a state is stale based on its timestamps.
55
+ * A state is considered stale if it hasn't been updated recently.
56
+ * We check both `last_checked_at` and `started_at` - using whichever is more recent.
57
+ */
58
+ function isStaleState(state) {
59
+ if (!state) return true;
52
60
 
53
- let state = readJsonFile(localPath);
54
- if (state) return { state, path: localPath };
61
+ const lastChecked = state.last_checked_at ? new Date(state.last_checked_at).getTime() : 0;
62
+ const startedAt = state.started_at ? new Date(state.started_at).getTime() : 0;
63
+ const mostRecent = Math.max(lastChecked, startedAt);
55
64
 
56
- state = readJsonFile(globalPath);
57
- if (state) return { state, path: globalPath };
65
+ if (mostRecent === 0) return true; // No valid timestamps
58
66
 
59
- return { state: null, path: localPath }; // Default to local for new writes
67
+ const age = Date.now() - mostRecent;
68
+ return age > STALE_STATE_THRESHOLD_MS;
69
+ }
70
+
71
+ /**
72
+ * Read state file from local location only.
73
+ */
74
+ function readStateFile(stateDir, filename) {
75
+ const localPath = join(stateDir, filename);
76
+ const state = readJsonFile(localPath);
77
+ return { state, path: localPath };
60
78
  }
61
79
 
62
80
  /**
@@ -122,7 +140,6 @@ function countIncompleteTodos(sessionId, projectDir) {
122
140
  function isContextLimitStop(data) {
123
141
  const reason = (data.stop_reason || data.stopReason || '').toLowerCase();
124
142
 
125
- // Known context-limit patterns (both confirmed and defensive)
126
143
  const contextPatterns = [
127
144
  'context_limit',
128
145
  'context_window',
@@ -139,7 +156,6 @@ function isContextLimitStop(data) {
139
156
  return true;
140
157
  }
141
158
 
142
- // Also check end_turn_reason (API-level field)
143
159
  const endTurnReason = (data.end_turn_reason || data.endTurnReason || '').toLowerCase();
144
160
  if (endTurnReason && contextPatterns.some(p => endTurnReason.includes(p))) {
145
161
  return true;
@@ -173,7 +189,6 @@ async function main() {
173
189
  const directory = data.directory || process.cwd();
174
190
  const sessionId = data.sessionId || data.session_id || '';
175
191
  const stateDir = join(directory, '.omc', 'state');
176
- const globalStateDir = join(homedir(), '.omc', 'state');
177
192
 
178
193
  // CRITICAL: Never block context-limit stops.
179
194
  // Blocking these causes a deadlock where Claude Code cannot compact.
@@ -189,14 +204,14 @@ async function main() {
189
204
  return;
190
205
  }
191
206
 
192
- // Read all mode states (local-first with fallback to global)
193
- const ralph = readStateFile(stateDir, globalStateDir, 'ralph-state.json');
194
- const autopilot = readStateFile(stateDir, globalStateDir, 'autopilot-state.json');
195
- const ultrapilot = readStateFile(stateDir, globalStateDir, 'ultrapilot-state.json');
196
- const ultrawork = readStateFile(stateDir, globalStateDir, 'ultrawork-state.json');
197
- const ecomode = readStateFile(stateDir, globalStateDir, 'ecomode-state.json');
198
- const ultraqa = readStateFile(stateDir, globalStateDir, 'ultraqa-state.json');
199
- const pipeline = readStateFile(stateDir, globalStateDir, 'pipeline-state.json');
207
+ // Read all mode states (local-only)
208
+ const ralph = readStateFile(stateDir, 'ralph-state.json');
209
+ const autopilot = readStateFile(stateDir, 'autopilot-state.json');
210
+ const ultrapilot = readStateFile(stateDir, 'ultrapilot-state.json');
211
+ const ultrawork = readStateFile(stateDir, 'ultrawork-state.json');
212
+ const ecomode = readStateFile(stateDir, 'ecomode-state.json');
213
+ const ultraqa = readStateFile(stateDir, 'ultraqa-state.json');
214
+ const pipeline = readStateFile(stateDir, 'pipeline-state.json');
200
215
 
201
216
  // Swarm uses swarm-summary.json (not swarm-state.json) + marker file
202
217
  const swarmMarker = existsSync(join(stateDir, 'swarm-active.marker'));
@@ -208,34 +223,37 @@ async function main() {
208
223
  const totalIncomplete = taskCount + todoCount;
209
224
 
210
225
  // Priority 1: Ralph Loop (explicit persistence mode)
211
- if (ralph.state?.active) {
226
+ // Skip if state is stale (older than 2 hours) - prevents blocking new sessions
227
+ if (ralph.state?.active && !isStaleState(ralph.state)) {
212
228
  const iteration = ralph.state.iteration || 1;
213
229
  const maxIter = ralph.state.max_iterations || 100;
214
230
 
215
231
  if (iteration < maxIter) {
216
232
  ralph.state.iteration = iteration + 1;
233
+ ralph.state.last_checked_at = new Date().toISOString();
217
234
  writeJsonFile(ralph.path, ralph.state);
218
235
 
219
236
  console.log(JSON.stringify({
220
- continue: true,
221
- message: `[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}` : ''}`
237
+ decision: 'block',
238
+ 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}` : ''}`
222
239
  }));
223
240
  return;
224
241
  }
225
242
  }
226
243
 
227
244
  // Priority 2: Autopilot (high-level orchestration)
228
- if (autopilot.state?.active) {
245
+ if (autopilot.state?.active && !isStaleState(autopilot.state)) {
229
246
  const phase = autopilot.state.phase || 'unknown';
230
247
  if (phase !== 'complete') {
231
248
  const newCount = (autopilot.state.reinforcement_count || 0) + 1;
232
249
  if (newCount <= 20) {
233
250
  autopilot.state.reinforcement_count = newCount;
251
+ autopilot.state.last_checked_at = new Date().toISOString();
234
252
  writeJsonFile(autopilot.path, autopilot.state);
235
253
 
236
254
  console.log(JSON.stringify({
237
- continue: true,
238
- message: `[AUTOPILOT - Phase: ${phase}] Autopilot not complete. Continue working.`
255
+ decision: 'block',
256
+ 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.`
239
257
  }));
240
258
  return;
241
259
  }
@@ -243,18 +261,19 @@ async function main() {
243
261
  }
244
262
 
245
263
  // Priority 3: Ultrapilot (parallel autopilot)
246
- if (ultrapilot.state?.active) {
264
+ if (ultrapilot.state?.active && !isStaleState(ultrapilot.state)) {
247
265
  const workers = ultrapilot.state.workers || [];
248
266
  const incomplete = workers.filter(w => w.status !== 'complete' && w.status !== 'failed').length;
249
267
  if (incomplete > 0) {
250
268
  const newCount = (ultrapilot.state.reinforcement_count || 0) + 1;
251
269
  if (newCount <= 20) {
252
270
  ultrapilot.state.reinforcement_count = newCount;
271
+ ultrapilot.state.last_checked_at = new Date().toISOString();
253
272
  writeJsonFile(ultrapilot.path, ultrapilot.state);
254
273
 
255
274
  console.log(JSON.stringify({
256
- continue: true,
257
- message: `[ULTRAPILOT] ${incomplete} workers still running. Continue.`
275
+ decision: 'block',
276
+ 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.`
258
277
  }));
259
278
  return;
260
279
  }
@@ -262,17 +281,18 @@ async function main() {
262
281
  }
263
282
 
264
283
  // Priority 4: Swarm (coordinated agents with SQLite)
265
- if (swarmMarker && swarmSummary?.active) {
284
+ if (swarmMarker && swarmSummary?.active && !isStaleState(swarmSummary)) {
266
285
  const pending = (swarmSummary.tasks_pending || 0) + (swarmSummary.tasks_claimed || 0);
267
286
  if (pending > 0) {
268
287
  const newCount = (swarmSummary.reinforcement_count || 0) + 1;
269
288
  if (newCount <= 15) {
270
289
  swarmSummary.reinforcement_count = newCount;
290
+ swarmSummary.last_checked_at = new Date().toISOString();
271
291
  writeJsonFile(join(stateDir, 'swarm-summary.json'), swarmSummary);
272
292
 
273
293
  console.log(JSON.stringify({
274
- continue: true,
275
- message: `[SWARM ACTIVE] ${pending} tasks remain. Continue working.`
294
+ decision: 'block',
295
+ 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.`
276
296
  }));
277
297
  return;
278
298
  }
@@ -280,18 +300,19 @@ async function main() {
280
300
  }
281
301
 
282
302
  // Priority 5: Pipeline (sequential stages)
283
- if (pipeline.state?.active) {
303
+ if (pipeline.state?.active && !isStaleState(pipeline.state)) {
284
304
  const currentStage = pipeline.state.current_stage || 0;
285
305
  const totalStages = pipeline.state.stages?.length || 0;
286
306
  if (currentStage < totalStages) {
287
307
  const newCount = (pipeline.state.reinforcement_count || 0) + 1;
288
308
  if (newCount <= 15) {
289
309
  pipeline.state.reinforcement_count = newCount;
310
+ pipeline.state.last_checked_at = new Date().toISOString();
290
311
  writeJsonFile(pipeline.path, pipeline.state);
291
312
 
292
313
  console.log(JSON.stringify({
293
- continue: true,
294
- message: `[PIPELINE - Stage ${currentStage + 1}/${totalStages}] Pipeline not complete. Continue.`
314
+ decision: 'block',
315
+ 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.`
295
316
  }));
296
317
  return;
297
318
  }
@@ -299,16 +320,17 @@ async function main() {
299
320
  }
300
321
 
301
322
  // Priority 6: UltraQA (QA cycling)
302
- if (ultraqa.state?.active) {
323
+ if (ultraqa.state?.active && !isStaleState(ultraqa.state)) {
303
324
  const cycle = ultraqa.state.cycle || 1;
304
325
  const maxCycles = ultraqa.state.max_cycles || 10;
305
326
  if (cycle < maxCycles && !ultraqa.state.all_passing) {
306
327
  ultraqa.state.cycle = cycle + 1;
328
+ ultraqa.state.last_checked_at = new Date().toISOString();
307
329
  writeJsonFile(ultraqa.path, ultraqa.state);
308
330
 
309
331
  console.log(JSON.stringify({
310
- continue: true,
311
- message: `[ULTRAQA - Cycle ${cycle + 1}/${maxCycles}] Tests not all passing. Continue fixing.`
332
+ decision: 'block',
333
+ 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.`
312
334
  }));
313
335
  return;
314
336
  }
@@ -316,15 +338,13 @@ async function main() {
316
338
 
317
339
  // Priority 7: Ultrawork - ALWAYS continue while active (not just when tasks exist)
318
340
  // This prevents false stops from bash errors, transient failures, etc.
319
- if (ultrawork.state?.active) {
341
+ if (ultrawork.state?.active && !isStaleState(ultrawork.state)) {
320
342
  const newCount = (ultrawork.state.reinforcement_count || 0) + 1;
321
343
  const maxReinforcements = ultrawork.state.max_reinforcements || 50;
322
344
 
323
345
  if (newCount > maxReinforcements) {
324
- console.log(JSON.stringify({
325
- continue: true,
326
- reason: `[ULTRAWORK ESCAPE] Max reinforcements (${maxReinforcements}) reached. Allowing stop.`
327
- }));
346
+ // Max reinforcements reached - allow stop
347
+ console.log(JSON.stringify({ continue: true }));
328
348
  return;
329
349
  }
330
350
 
@@ -332,49 +352,56 @@ async function main() {
332
352
  ultrawork.state.last_checked_at = new Date().toISOString();
333
353
  writeJsonFile(ultrawork.path, ultrawork.state);
334
354
 
335
- // Build continuation message
336
- let reason = `[ULTRAWORK #${newCount}] Mode active - continue working.`;
355
+ let reason = `[ULTRAWORK #${newCount}/${maxReinforcements}] Mode active.`;
356
+
337
357
  if (totalIncomplete > 0) {
338
358
  const itemType = taskCount > 0 ? 'Tasks' : 'todos';
339
- reason = `[ULTRAWORK #${newCount}] ${totalIncomplete} incomplete ${itemType}. Continue working.`;
359
+ reason += ` ${totalIncomplete} incomplete ${itemType} remain. Continue working.`;
360
+ } else if (newCount >= 3) {
361
+ // Only suggest cancel after minimum iterations (guard against no-tasks-created scenario)
362
+ 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.`;
363
+ } else {
364
+ // Early iterations with no tasks yet - just tell LLM to continue
365
+ reason += ` Continue working - create Tasks to track your progress.`;
340
366
  }
367
+
341
368
  if (ultrawork.state.original_prompt) {
342
369
  reason += `\nTask: ${ultrawork.state.original_prompt}`;
343
370
  }
344
371
 
345
- console.log(JSON.stringify({
346
- continue: true,
347
- message: reason
348
- }));
372
+ console.log(JSON.stringify({ decision: 'block', reason }));
349
373
  return;
350
374
  }
351
375
 
352
376
  // Priority 8: Ecomode - ALWAYS continue while active
353
- if (ecomode.state?.active) {
377
+ if (ecomode.state?.active && !isStaleState(ecomode.state)) {
354
378
  const newCount = (ecomode.state.reinforcement_count || 0) + 1;
355
379
  const maxReinforcements = ecomode.state.max_reinforcements || 50;
356
380
 
357
381
  if (newCount > maxReinforcements) {
358
- console.log(JSON.stringify({
359
- continue: true,
360
- reason: `[ECOMODE ESCAPE] Max reinforcements (${maxReinforcements}) reached. Allowing stop.`
361
- }));
382
+ // Max reinforcements reached - allow stop
383
+ console.log(JSON.stringify({ continue: true }));
362
384
  return;
363
385
  }
364
386
 
365
387
  ecomode.state.reinforcement_count = newCount;
388
+ ecomode.state.last_checked_at = new Date().toISOString();
366
389
  writeJsonFile(ecomode.path, ecomode.state);
367
390
 
368
- let reason = `[ECOMODE #${newCount}] Mode active - continue working.`;
391
+ let reason = `[ECOMODE #${newCount}/${maxReinforcements}] Mode active.`;
392
+
369
393
  if (totalIncomplete > 0) {
370
394
  const itemType = taskCount > 0 ? 'Tasks' : 'todos';
371
- reason = `[ECOMODE #${newCount}] ${totalIncomplete} incomplete ${itemType}. Continue working.`;
395
+ reason += ` ${totalIncomplete} incomplete ${itemType} remain. Continue working.`;
396
+ } else if (newCount >= 3) {
397
+ // Only suggest cancel after minimum iterations (guard against no-tasks-created scenario)
398
+ 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.`;
399
+ } else {
400
+ // Early iterations with no tasks yet - just tell LLM to continue
401
+ reason += ` Continue working - create Tasks to track your progress.`;
372
402
  }
373
403
 
374
- console.log(JSON.stringify({
375
- continue: true,
376
- message: reason
377
- }));
404
+ console.log(JSON.stringify({ decision: 'block', reason }));
378
405
  return;
379
406
  }
380
407
 
@@ -7,7 +7,7 @@ import { mkdirSync } from 'fs';
7
7
 
8
8
  // Import the hooks
9
9
  import { startUltraQA, clearUltraQAState, isRalphLoopActive } from '../src/hooks/ultraqa/index.js';
10
- import { createRalphLoopHook, clearRalphState, isUltraQAActive } from '../src/hooks/ralph-loop/index.js';
10
+ import { createRalphLoopHook, clearRalphState, isUltraQAActive } from '../src/hooks/ralph/index.js';
11
11
 
12
12
  // Test utilities
13
13
  function printTest(testName: string, passed: boolean) {
@@ -36,7 +36,7 @@ async function runTests() {
36
36
  const ralphStarted = ralphHook.startLoop(
37
37
  'test-session-1',
38
38
  'test task',
39
- { maxIterations: 5, completionPromise: 'TASK_COMPLETE' }
39
+ { maxIterations: 5 }
40
40
  );
41
41
 
42
42
  if (!ralphStarted) {
@@ -86,7 +86,7 @@ async function runTests() {
86
86
  const ralphStarted2 = ralphHook2.startLoop(
87
87
  'test-session-4',
88
88
  'test task',
89
- { maxIterations: 5, completionPromise: 'TASK_COMPLETE' }
89
+ { maxIterations: 5 }
90
90
  );
91
91
 
92
92
  if (ralphStarted2) {
package/skills/AGENTS.md CHANGED
@@ -1,9 +1,9 @@
1
1
  <!-- Parent: ../AGENTS.md -->
2
- <!-- Generated: 2026-01-28 | Updated: 2026-01-28 -->
2
+ <!-- Generated: 2026-01-28 | Updated: 2026-01-31 -->
3
3
 
4
4
  # skills
5
5
 
6
- 32 skill definitions for workflow automation and specialized behaviors.
6
+ 37 skill definitions for workflow automation and specialized behaviors.
7
7
 
8
8
  ## Purpose
9
9
 
@@ -15,62 +15,71 @@ Skills are reusable workflow templates that can be invoked via `/oh-my-claudecod
15
15
  ## Key Files
16
16
 
17
17
  ### Execution Mode Skills
18
+
18
19
  | File | Skill | Purpose |
19
- |------|-------|---------|
20
- | `autopilot.md` | autopilot | Full autonomous execution from idea to working code |
21
- | `ultrawork.md` | ultrawork | Maximum parallel agent execution |
22
- | `ralph.md` | ralph | Persistence until verified complete |
23
- | `ultrapilot.md` | ultrapilot | Parallel autopilot with file ownership |
24
- | `swarm.md` | swarm | N coordinated agents with task claiming |
25
- | `pipeline.md` | pipeline | Sequential agent chaining |
26
- | `ecomode.md` | ecomode | Token-efficient parallel execution |
27
- | `ultraqa.md` | ultraqa | QA cycling until goal met |
20
+ |-----------|-------|---------|
21
+ | `autopilot/SKILL.md` | autopilot | Full autonomous execution from idea to working code |
22
+ | `ultrawork/SKILL.md` | ultrawork | Maximum parallel agent execution |
23
+ | `ralph/SKILL.md` | ralph | Persistence until verified complete |
24
+ | `ultrapilot/SKILL.md` | ultrapilot | Parallel autopilot with file ownership |
25
+ | `swarm/SKILL.md` | swarm | N coordinated agents with task claiming |
26
+ | `pipeline/SKILL.md` | pipeline | Sequential agent chaining |
27
+ | `ecomode/SKILL.md` | ecomode | Token-efficient parallel execution |
28
+ | `ultraqa/SKILL.md` | ultraqa | QA cycling until goal met |
28
29
 
29
30
  ### Planning Skills
31
+
30
32
  | File | Skill | Purpose |
31
- |------|-------|---------|
32
- | `plan.md` | plan | Strategic planning with interview workflow |
33
- | `ralplan.md` | ralplan | Iterative planning (Planner+Architect+Critic) |
34
- | `review.md` | review | Review plan with Critic |
35
- | `analyze.md` | analyze | Deep analysis and investigation |
36
- | `ralph-init.md` | ralph-init | Initialize PRD for structured ralph |
33
+ |-----------|-------|---------|
34
+ | `plan/SKILL.md` | plan | Strategic planning with interview workflow |
35
+ | `ralplan/SKILL.md` | ralplan | Iterative planning (Planner+Architect+Critic) |
36
+ | `review/SKILL.md` | review | Review plan with Critic |
37
+ | `analyze/SKILL.md` | analyze | Deep analysis and investigation |
38
+ | `ralph-init/SKILL.md` | ralph-init | Initialize PRD for structured ralph |
37
39
 
38
40
  ### Code Quality Skills
41
+
39
42
  | File | Skill | Purpose |
40
- |------|-------|---------|
41
- | `code-review.md` | code-review | Comprehensive code review |
42
- | `security-review.md` | security-review | Security vulnerability detection |
43
- | `tdd.md` | tdd | Test-driven development workflow |
44
- | `build-fix.md` | build-fix | Fix build and TypeScript errors |
43
+ |-----------|-------|---------|
44
+ | `code-review/SKILL.md` | code-review | Comprehensive code review |
45
+ | `security-review/SKILL.md` | security-review | Security vulnerability detection |
46
+ | `tdd/SKILL.md` | tdd | Test-driven development workflow |
47
+ | `build-fix/SKILL.md` | build-fix | Fix build and TypeScript errors |
45
48
 
46
49
  ### Exploration Skills
50
+
47
51
  | File | Skill | Purpose |
48
- |------|-------|---------|
49
- | `deepsearch.md` | deepsearch | Thorough codebase search |
50
- | `deepinit.md` | deepinit | Generate hierarchical AGENTS.md |
51
- | `research.md` | research | Parallel scientist orchestration |
52
+ |-----------|-------|---------|
53
+ | `deepsearch/SKILL.md` | deepsearch | Thorough codebase search |
54
+ | `deepinit/SKILL.md` | deepinit | Generate hierarchical AGENTS.md |
55
+ | `research/SKILL.md` | research | Parallel scientist orchestration |
52
56
 
53
57
  ### Utility Skills
58
+
54
59
  | File | Skill | Purpose |
55
- |------|-------|---------|
56
- | `learner.md` | learner | Extract reusable skill from session |
57
- | `note.md` | note | Save notes for compaction resilience |
58
- | `cancel.md` | cancel | Cancel any active OMC mode |
59
- | `hud.md` | hud | Configure HUD display |
60
- | `doctor.md` | doctor | Diagnose installation issues |
61
- | `omc-setup.md` | omc-setup | One-time setup wizard |
62
- | `mcp-setup.md` | mcp-setup | Configure MCP servers |
63
- | `help.md` | help | Usage guide |
60
+ |-----------|-------|---------|
61
+ | `orchestrate/SKILL.md` | orchestrate | Core multi-agent orchestration (always active) |
62
+ | `learner/SKILL.md` | learner | Extract reusable skill from session |
63
+ | `note/SKILL.md` | note | Save notes for compaction resilience |
64
+ | `cancel/SKILL.md` | cancel | Cancel any active OMC mode |
65
+ | `hud/SKILL.md` | hud | Configure HUD display |
66
+ | `doctor/SKILL.md` | doctor | Diagnose installation issues |
67
+ | `omc-setup/SKILL.md` | omc-setup | One-time setup wizard |
68
+ | `mcp-setup/SKILL.md` | mcp-setup | Configure MCP servers |
69
+ | `help/SKILL.md` | help | Usage guide |
70
+ | `learn-about-omc/SKILL.md` | learn-about-omc | Usage pattern analysis |
71
+ | `skill/SKILL.md` | skill | Manage local skills |
64
72
 
65
73
  ### Domain Skills
74
+
66
75
  | File | Skill | Purpose |
67
- |------|-------|---------|
68
- | `frontend-ui-ux.md` | frontend-ui-ux | Designer-developer aesthetic |
69
- | `git-master.md` | git-master | Git expertise, atomic commits |
70
- | `project-session-manager.md` | psm | Isolated dev environments |
71
- | `writer-memory.md` | writer-memory | Agentic memory for writers |
72
- | `release.md` | release | Automated release workflow |
73
- | `local-skills-setup.md` | local-skills-setup | Manage local skills |
76
+ |-----------|-------|---------|
77
+ | `frontend-ui-ux/SKILL.md` | frontend-ui-ux | Designer-developer aesthetic |
78
+ | `git-master/SKILL.md` | git-master | Git expertise, atomic commits |
79
+ | `project-session-manager/SKILL.md` | psm | Isolated dev environments |
80
+ | `writer-memory/SKILL.md` | writer-memory | Agentic memory for writers |
81
+ | `release/SKILL.md` | release | Automated release workflow |
82
+ | `local-skills-setup/SKILL.md` | local-skills-setup | Manage local skills |
74
83
 
75
84
  ## For AI Agents
76
85
 
@@ -121,10 +130,13 @@ Any configurable options.
121
130
 
122
131
  #### Creating a New Skill
123
132
 
124
- 1. Create `new-skill.md` with YAML frontmatter
133
+ 1. Create `new-skill/SKILL.md` directory and file with YAML frontmatter
125
134
  2. Define purpose, workflow, and usage
126
135
  3. Add to skill registry (auto-detected from frontmatter)
127
136
  4. Optionally add activation triggers
137
+ 5. Create corresponding `commands/new-skill.md` file (mirror)
138
+ 6. Update `docs/REFERENCE.md` (Skills section, count)
139
+ 7. If execution mode skill, also create `src/hooks/new-skill/` hook
128
140
 
129
141
  ### Common Patterns
130
142
 
@@ -148,7 +160,10 @@ Any configurable options.
148
160
 
149
161
  ### Testing Requirements
150
162
 
151
- Skills are tested via integration tests that invoke skills and verify behavior.
163
+ - Skills are verified via integration tests
164
+ - Test skill invocation with `/oh-my-claudecode:skill-name`
165
+ - Verify trigger keywords activate correct skill
166
+ - For git-related skills, follow `templates/rules/git-workflow.md`
152
167
 
153
168
  ## Dependencies
154
169
 
@@ -161,8 +161,6 @@ rm -f .omc/state/autopilot-state.json
161
161
  rm -f .omc/state/ralph-state.json
162
162
  rm -f .omc/state/ultrawork-state.json
163
163
  rm -f .omc/state/ultraqa-state.json
164
- rm -f ~/.claude/ralph-state.json
165
- rm -f ~/.claude/ultrawork-state.json
166
164
  ```
167
165
 
168
166
  This ensures clean state for future sessions.
@@ -7,6 +7,12 @@ description: Cancel any active OMC mode (autopilot, ralph, ultrawork, ecomode, u
7
7
 
8
8
  Intelligent cancellation that detects and cancels the active OMC mode.
9
9
 
10
+ **The cancel skill is the standard way to complete and exit any OMC mode.**
11
+ When the stop hook detects work is complete, it instructs the LLM to invoke
12
+ this skill for proper state cleanup. If cancel fails or is interrupted,
13
+ retry with `--force` flag, or wait for the 2-hour staleness timeout as
14
+ a last resort.
15
+
10
16
  ## What It Does
11
17
 
12
18
  Automatically detects which mode is active and cancels it:
@@ -80,9 +86,6 @@ This removes all state files:
80
86
  - `.omc/state/pipeline-state.json`
81
87
  - `.omc/state/plan-consensus.json`
82
88
  - `.omc/state/ralplan-state.json`
83
- - `~/.claude/ralph-state.json`
84
- - `~/.claude/ultrawork-state.json`
85
- - `~/.claude/ecomode-state.json`
86
89
 
87
90
  ## Implementation Steps
88
91
 
@@ -161,11 +164,6 @@ if [[ "$FORCE_MODE" == "true" ]]; then
161
164
  rm -f .omc/state/plan-consensus.json
162
165
  rm -f .omc/state/ralplan-state.json
163
166
 
164
- # Remove global state files
165
- rm -f ~/.claude/ralph-state.json
166
- rm -f ~/.claude/ultrawork-state.json
167
- rm -f ~/.claude/ecomode-state.json
168
-
169
167
  echo "All OMC modes cleared. You are free to start fresh."
170
168
  exit 0
171
169
  fi
@@ -189,13 +187,11 @@ if [[ -f .omc/state/autopilot-state.json ]]; then
189
187
  # Clean linked ultrawork first
190
188
  if [[ "$LINKED_UW" == "true" ]] && [[ -f .omc/state/ultrawork-state.json ]]; then
191
189
  rm -f .omc/state/ultrawork-state.json
192
- rm -f ~/.claude/ultrawork-state.json
193
190
  echo "Cleaned up: ultrawork (linked to ralph)"
194
191
  fi
195
192
 
196
193
  # Clean ralph
197
194
  rm -f .omc/state/ralph-state.json
198
- rm -f ~/.claude/ralph-state.json
199
195
  rm -f .omc/state/ralph-verification.json
200
196
  echo "Cleaned up: ralph"
201
197
  fi
@@ -234,14 +230,12 @@ if [[ -f .omc/state/ralph-state.json ]]; then
234
230
  # Only clear if it was linked to ralph
235
231
  if [[ "$UW_LINKED" == "true" ]]; then
236
232
  rm -f .omc/state/ultrawork-state.json
237
- rm -f ~/.claude/ultrawork-state.json
238
233
  echo "Cleaned up: ultrawork (linked to ralph)"
239
234
  fi
240
235
  fi
241
236
 
242
- # Clean ralph state (both local and global)
237
+ # Clean ralph state
243
238
  rm -f .omc/state/ralph-state.json
244
- rm -f ~/.claude/ralph-state.json
245
239
  rm -f .omc/state/ralph-plan-state.json
246
240
  rm -f .omc/state/ralph-verification.json
247
241
 
@@ -264,9 +258,8 @@ if [[ -f .omc/state/ultrawork-state.json ]]; then
264
258
  exit 1
265
259
  fi
266
260
 
267
- # Remove both local and global state
261
+ # Remove local state
268
262
  rm -f .omc/state/ultrawork-state.json
269
- rm -f ~/.claude/ultrawork-state.json
270
263
 
271
264
  echo "Ultrawork cancelled. Parallel execution mode deactivated."
272
265
  fi
@@ -314,7 +307,7 @@ fi
314
307
  if [[ "$FORCE_MODE" == "true" ]]; then
315
308
  echo "FORCE CLEAR: Removing all OMC state files..."
316
309
 
317
- mkdir -p .omc ~/.claude
310
+ mkdir -p .omc/state
318
311
 
319
312
  # Remove local state files
320
313
  rm -f .omc/state/autopilot-state.json
@@ -333,11 +326,6 @@ if [[ "$FORCE_MODE" == "true" ]]; then
333
326
  rm -f .omc/state/plan-consensus.json
334
327
  rm -f .omc/state/ralplan-state.json
335
328
 
336
- # Remove global state files
337
- rm -f ~/.claude/ralph-state.json
338
- rm -f ~/.claude/ultrawork-state.json
339
- rm -f ~/.claude/ecomode-state.json
340
-
341
329
  echo ""
342
330
  echo "All OMC modes cleared. You are free to start fresh."
343
331
  exit 0
@@ -366,13 +354,11 @@ if [[ -f .omc/state/autopilot-state.json ]]; then
366
354
  # Clean linked ultrawork first
367
355
  if [[ "$LINKED_UW" == "true" ]] && [[ -f .omc/state/ultrawork-state.json ]]; then
368
356
  rm -f .omc/state/ultrawork-state.json
369
- rm -f ~/.claude/ultrawork-state.json
370
357
  CLEANED_UP+=("ultrawork")
371
358
  fi
372
359
 
373
360
  # Clean ralph
374
361
  rm -f .omc/state/ralph-state.json
375
- rm -f ~/.claude/ralph-state.json
376
362
  rm -f .omc/state/ralph-verification.json
377
363
  CLEANED_UP+=("ralph")
378
364
  fi
@@ -420,7 +406,6 @@ if [[ -f .omc/state/ralph-state.json ]]; then
420
406
  # Only clear if it was linked to ralph
421
407
  if [[ "$UW_LINKED" == "true" ]]; then
422
408
  rm -f .omc/state/ultrawork-state.json
423
- rm -f ~/.claude/ultrawork-state.json
424
409
  echo "Cleaned up: ultrawork (linked to ralph)"
425
410
  fi
426
411
  fi
@@ -434,14 +419,12 @@ if [[ -f .omc/state/ralph-state.json ]]; then
434
419
 
435
420
  if [[ "$ECO_LINKED" == "true" ]]; then
436
421
  rm -f .omc/state/ecomode-state.json
437
- rm -f ~/.claude/ecomode-state.json
438
422
  echo "Cleaned up: ecomode (linked to ralph)"
439
423
  fi
440
424
  fi
441
425
 
442
- # Clean ralph state (both local and global)
426
+ # Clean ralph state
443
427
  rm -f .omc/state/ralph-state.json
444
- rm -f ~/.claude/ralph-state.json
445
428
  rm -f .omc/state/ralph-plan-state.json
446
429
  rm -f .omc/state/ralph-verification.json
447
430
 
@@ -464,9 +447,8 @@ if [[ -f .omc/state/ultrawork-state.json ]]; then
464
447
  echo "Clearing ultrawork state anyway..."
465
448
  fi
466
449
 
467
- # Remove both local and global state
450
+ # Remove local state
468
451
  rm -f .omc/state/ultrawork-state.json
469
- rm -f ~/.claude/ultrawork-state.json
470
452
 
471
453
  echo "Ultrawork cancelled. Parallel execution mode deactivated."
472
454
  CANCELLED_ANYTHING=true
@@ -487,9 +469,8 @@ if [[ -f .omc/state/ecomode-state.json ]]; then
487
469
  echo "Clearing ecomode state anyway..."
488
470
  fi
489
471
 
490
- # Remove both local and global state
472
+ # Remove local state
491
473
  rm -f .omc/state/ecomode-state.json
492
- rm -f ~/.claude/ecomode-state.json
493
474
 
494
475
  echo "Ecomode cancelled. Token-efficient execution mode deactivated."
495
476
  CANCELLED_ANYTHING=true
@@ -636,5 +617,5 @@ fi
636
617
  - **Dependency-aware**: Autopilot cancellation cleans up Ralph and UltraQA
637
618
  - **Link-aware**: Ralph cancellation cleans up linked Ultrawork or Ecomode
638
619
  - **Safe**: Only clears linked Ultrawork, preserves standalone Ultrawork
639
- - **Dual-location**: Clears both `.omc/` and `~/.claude/` state files
620
+ - **Local-only**: Clears state files in `.omc/state/` directory
640
621
  - **Resume-friendly**: Autopilot state is preserved for seamless resume