oh-my-codex 0.4.1 → 0.4.3

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 (121) hide show
  1. package/README.es.md +36 -0
  2. package/README.ja.md +36 -0
  3. package/README.ko.md +36 -0
  4. package/README.md +13 -1
  5. package/README.pt.md +36 -0
  6. package/README.ru.md +36 -0
  7. package/README.vi.md +36 -0
  8. package/README.zh.md +39 -0
  9. package/bin/omx.js +2 -1
  10. package/dist/cli/__tests__/index.test.js +11 -0
  11. package/dist/cli/__tests__/index.test.js.map +1 -1
  12. package/dist/cli/__tests__/star-prompt.test.d.ts +2 -0
  13. package/dist/cli/__tests__/star-prompt.test.d.ts.map +1 -0
  14. package/dist/cli/__tests__/star-prompt.test.js +82 -0
  15. package/dist/cli/__tests__/star-prompt.test.js.map +1 -0
  16. package/dist/cli/__tests__/update.test.d.ts +2 -0
  17. package/dist/cli/__tests__/update.test.d.ts.map +1 -0
  18. package/dist/cli/__tests__/update.test.js +66 -0
  19. package/dist/cli/__tests__/update.test.js.map +1 -0
  20. package/dist/cli/index.d.ts +1 -1
  21. package/dist/cli/index.d.ts.map +1 -1
  22. package/dist/cli/index.js +13 -2
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/star-prompt.d.ts +11 -0
  25. package/dist/cli/star-prompt.d.ts.map +1 -0
  26. package/dist/cli/star-prompt.js +74 -0
  27. package/dist/cli/star-prompt.js.map +1 -0
  28. package/dist/cli/update.d.ts.map +1 -1
  29. package/dist/cli/update.js +7 -29
  30. package/dist/cli/update.js.map +1 -1
  31. package/dist/config/__tests__/generator-notify.test.js +3 -3
  32. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  33. package/dist/config/generator.d.ts +1 -1
  34. package/dist/config/generator.js +8 -8
  35. package/dist/config/generator.js.map +1 -1
  36. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +2 -0
  37. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +1 -0
  38. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +427 -0
  39. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -0
  40. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +17 -0
  41. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  42. package/dist/hooks/emulator.d.ts +1 -1
  43. package/dist/hooks/emulator.js +5 -5
  44. package/dist/hooks/emulator.js.map +1 -1
  45. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +2 -0
  46. package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +1 -0
  47. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +152 -0
  48. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -0
  49. package/dist/hooks/extensibility/__tests__/events.test.d.ts +2 -0
  50. package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +1 -0
  51. package/dist/hooks/extensibility/__tests__/events.test.js +117 -0
  52. package/dist/hooks/extensibility/__tests__/events.test.js.map +1 -0
  53. package/dist/hooks/extensibility/__tests__/loader.test.d.ts +2 -0
  54. package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +1 -0
  55. package/dist/hooks/extensibility/__tests__/loader.test.js +229 -0
  56. package/dist/hooks/extensibility/__tests__/loader.test.js.map +1 -0
  57. package/dist/hooks/extensibility/__tests__/logging.test.d.ts +2 -0
  58. package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +1 -0
  59. package/dist/hooks/extensibility/__tests__/logging.test.js +74 -0
  60. package/dist/hooks/extensibility/__tests__/logging.test.js.map +1 -0
  61. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +2 -0
  62. package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +1 -0
  63. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +202 -0
  64. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -0
  65. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +2 -0
  66. package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +1 -0
  67. package/dist/hooks/extensibility/__tests__/runtime.test.js +117 -0
  68. package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -0
  69. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +2 -0
  70. package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +1 -0
  71. package/dist/hooks/extensibility/__tests__/sdk.test.js +277 -0
  72. package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -0
  73. package/dist/hud/__tests__/colors.test.d.ts +2 -0
  74. package/dist/hud/__tests__/colors.test.d.ts.map +1 -0
  75. package/dist/hud/__tests__/colors.test.js +194 -0
  76. package/dist/hud/__tests__/colors.test.js.map +1 -0
  77. package/dist/hud/__tests__/render.test.d.ts +2 -0
  78. package/dist/hud/__tests__/render.test.d.ts.map +1 -0
  79. package/dist/hud/__tests__/render.test.js +449 -0
  80. package/dist/hud/__tests__/render.test.js.map +1 -0
  81. package/dist/hud/__tests__/types.test.d.ts +2 -0
  82. package/dist/hud/__tests__/types.test.d.ts.map +1 -0
  83. package/dist/hud/__tests__/types.test.js +17 -0
  84. package/dist/hud/__tests__/types.test.js.map +1 -0
  85. package/dist/notifications/__tests__/tmux-detector.test.js +69 -1
  86. package/dist/notifications/__tests__/tmux-detector.test.js.map +1 -1
  87. package/dist/notifications/reply-listener.d.ts +1 -1
  88. package/dist/notifications/reply-listener.js +1 -1
  89. package/dist/notifications/tmux-detector.d.ts +16 -0
  90. package/dist/notifications/tmux-detector.d.ts.map +1 -1
  91. package/dist/notifications/tmux-detector.js +37 -22
  92. package/dist/notifications/tmux-detector.js.map +1 -1
  93. package/dist/team/__tests__/tmux-session.test.js +61 -1
  94. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  95. package/dist/team/orchestrator.d.ts +1 -1
  96. package/dist/team/orchestrator.js +1 -1
  97. package/dist/team/runtime.d.ts.map +1 -1
  98. package/dist/team/runtime.js +14 -2
  99. package/dist/team/runtime.js.map +1 -1
  100. package/dist/team/state.d.ts +4 -0
  101. package/dist/team/state.d.ts.map +1 -1
  102. package/dist/team/state.js.map +1 -1
  103. package/dist/team/tmux-session.d.ts +14 -2
  104. package/dist/team/tmux-session.d.ts.map +1 -1
  105. package/dist/team/tmux-session.js +42 -6
  106. package/dist/team/tmux-session.js.map +1 -1
  107. package/dist/utils/__tests__/package.test.d.ts +2 -0
  108. package/dist/utils/__tests__/package.test.d.ts.map +1 -0
  109. package/dist/utils/__tests__/package.test.js +21 -0
  110. package/dist/utils/__tests__/package.test.js.map +1 -0
  111. package/dist/utils/__tests__/paths.test.d.ts +2 -0
  112. package/dist/utils/__tests__/paths.test.d.ts.map +1 -0
  113. package/dist/utils/__tests__/paths.test.js +117 -0
  114. package/dist/utils/__tests__/paths.test.js.map +1 -0
  115. package/dist/verification/__tests__/verifier.test.d.ts +2 -0
  116. package/dist/verification/__tests__/verifier.test.d.ts.map +1 -0
  117. package/dist/verification/__tests__/verifier.test.js +94 -0
  118. package/dist/verification/__tests__/verifier.test.js.map +1 -0
  119. package/package.json +1 -1
  120. package/scripts/notify-hook.js +164 -3
  121. package/templates/AGENTS.md +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verifier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.test.d.ts","sourceRoot":"","sources":["../../../src/verification/__tests__/verifier.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,94 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { getVerificationInstructions, determineTaskSize, getFixLoopInstructions, } from '../verifier.js';
4
+ describe('determineTaskSize', () => {
5
+ it('returns small for low file count and line changes', () => {
6
+ assert.equal(determineTaskSize(1, 10), 'small');
7
+ assert.equal(determineTaskSize(3, 99), 'small');
8
+ });
9
+ it('returns standard for moderate file count and line changes', () => {
10
+ assert.equal(determineTaskSize(4, 50), 'standard');
11
+ assert.equal(determineTaskSize(15, 499), 'standard');
12
+ });
13
+ it('returns large for high file count', () => {
14
+ assert.equal(determineTaskSize(16, 100), 'large');
15
+ });
16
+ it('returns large for high line changes', () => {
17
+ assert.equal(determineTaskSize(5, 500), 'large');
18
+ });
19
+ it('returns small at exact boundary (3 files, 99 lines)', () => {
20
+ assert.equal(determineTaskSize(3, 99), 'small');
21
+ });
22
+ it('returns standard when file count exceeds small threshold', () => {
23
+ assert.equal(determineTaskSize(4, 99), 'standard');
24
+ });
25
+ it('returns standard when line changes hit 100 but files are low', () => {
26
+ assert.equal(determineTaskSize(3, 100), 'standard');
27
+ });
28
+ it('returns large at exact boundary (15 files, 500 lines)', () => {
29
+ assert.equal(determineTaskSize(15, 500), 'large');
30
+ });
31
+ it('returns large when file count exceeds standard threshold', () => {
32
+ assert.equal(determineTaskSize(16, 0), 'large');
33
+ });
34
+ });
35
+ describe('getVerificationInstructions', () => {
36
+ it('includes the task description in all sizes', () => {
37
+ const desc = 'Add login button';
38
+ for (const size of ['small', 'standard', 'large']) {
39
+ const result = getVerificationInstructions(size, desc);
40
+ assert.ok(result.includes(desc), `${size} should include task description`);
41
+ }
42
+ });
43
+ it('includes Verification Protocol header for all sizes', () => {
44
+ for (const size of ['small', 'standard', 'large']) {
45
+ const result = getVerificationInstructions(size, 'task');
46
+ assert.ok(result.includes('## Verification Protocol'));
47
+ }
48
+ });
49
+ it('returns small-specific instructions', () => {
50
+ const result = getVerificationInstructions('small', 'fix typo');
51
+ assert.ok(result.includes('type checker on modified files'));
52
+ assert.ok(result.includes('PASS/FAIL'));
53
+ // Should NOT contain large/standard-specific items
54
+ assert.ok(!result.includes('Security review'));
55
+ assert.ok(!result.includes('Run linter'));
56
+ });
57
+ it('returns standard-specific instructions', () => {
58
+ const result = getVerificationInstructions('standard', 'add feature');
59
+ assert.ok(result.includes('tsc --noEmit'));
60
+ assert.ok(result.includes('Run linter'));
61
+ assert.ok(result.includes('regressions'));
62
+ // Should NOT contain large-specific items
63
+ assert.ok(!result.includes('Security review'));
64
+ assert.ok(!result.includes('Performance impact'));
65
+ });
66
+ it('returns large-specific instructions', () => {
67
+ const result = getVerificationInstructions('large', 'refactor auth');
68
+ assert.ok(result.includes('Security review'));
69
+ assert.ok(result.includes('Performance impact'));
70
+ assert.ok(result.includes('API compatibility'));
71
+ assert.ok(result.includes('confidence level'));
72
+ });
73
+ });
74
+ describe('getFixLoopInstructions', () => {
75
+ it('returns instructions with default maxRetries of 3', () => {
76
+ const result = getFixLoopInstructions();
77
+ assert.ok(result.includes('Fix-Verify Loop'));
78
+ assert.ok(result.includes('up to 3 times'));
79
+ assert.ok(result.includes('after 3 attempts'));
80
+ });
81
+ it('respects custom maxRetries', () => {
82
+ const result = getFixLoopInstructions(5);
83
+ assert.ok(result.includes('up to 5 times'));
84
+ assert.ok(result.includes('after 5 attempts'));
85
+ assert.ok(!result.includes('up to 3 times'));
86
+ });
87
+ it('includes escalation guidance', () => {
88
+ const result = getFixLoopInstructions();
89
+ assert.ok(result.includes('escalate'));
90
+ assert.ok(result.includes('What was attempted'));
91
+ assert.ok(result.includes('Recommended next steps'));
92
+ });
93
+ });
94
+ //# sourceMappingURL=verifier.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.test.js","sourceRoot":"","sources":["../../../src/verification/__tests__/verifier.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-codex",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Multi-agent orchestration layer for OpenAI Codex CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -245,11 +245,29 @@ const DEFAULT_STALL_PATTERNS = [
245
245
  'if you want',
246
246
  'would you like',
247
247
  'shall i',
248
+ 'next i can',
248
249
  'do you want me to',
249
250
  'let me know if',
251
+ 'do you want',
252
+ 'want me to',
253
+ 'let me know',
254
+ 'just let me know',
250
255
  'i can also',
256
+ 'i could also',
251
257
  'ready to proceed',
252
258
  'should i',
259
+ 'whenever you',
260
+ 'say go',
261
+ 'say yes',
262
+ 'type continue',
263
+ 'and i\'ll continue',
264
+ 'and i\'ll proceed',
265
+ 'keep driving',
266
+ 'keep pushing',
267
+ 'move forward',
268
+ 'drive forward',
269
+ 'proceed from here',
270
+ 'i\'ll continue from',
253
271
  ];
254
272
 
255
273
  function normalizeAutoNudgeConfig(raw) {
@@ -289,9 +307,16 @@ async function loadAutoNudgeConfig() {
289
307
 
290
308
  function detectStallPattern(text, patterns) {
291
309
  if (!text || typeof text !== 'string') return false;
292
- // Check the last ~500 characters (roughly last 10 lines) for stall phrases
293
- const tail = text.slice(-500).toLowerCase();
294
- return patterns.some(p => tail.includes(p.toLowerCase()));
310
+ // Broader tail window (~800 chars / ~15-20 lines) for context
311
+ const tail = text.slice(-800).toLowerCase();
312
+ const lowerPatterns = patterns.map(p => p.toLowerCase());
313
+ // Focus on last few lines where stall prompts typically appear
314
+ const lines = tail.split('\n').filter(l => l.trim());
315
+ const hotZone = lines.slice(-3).join('\n');
316
+ // Primary: check last few lines (highest signal)
317
+ if (lowerPatterns.some(p => hotZone.includes(p))) return true;
318
+ // Secondary: check broader tail window
319
+ return lowerPatterns.some(p => tail.includes(p));
295
320
  }
296
321
 
297
322
  async function capturePane(paneId, lines = 10) {
@@ -1084,6 +1109,133 @@ function parseTeamWorkerEnv(rawValue) {
1084
1109
  return { teamName: match[1], workerName: match[2] };
1085
1110
  }
1086
1111
 
1112
+ function resolveAllWorkersIdleCooldownMs() {
1113
+ const raw = safeString(process.env.OMX_TEAM_ALL_IDLE_COOLDOWN_MS || '');
1114
+ const parsed = asNumber(raw);
1115
+ // Default: 60 seconds. Guard against unreasonable values.
1116
+ if (parsed !== null && parsed >= 5_000 && parsed <= 10 * 60_000) return parsed;
1117
+ return 60_000;
1118
+ }
1119
+
1120
+ async function readWorkerStatusState(stateDir, teamName, workerName) {
1121
+ if (!workerName) return 'unknown';
1122
+ const statusPath = join(stateDir, 'team', teamName, 'workers', workerName, 'status.json');
1123
+ try {
1124
+ if (!existsSync(statusPath)) return 'unknown';
1125
+ const raw = await readFile(statusPath, 'utf-8');
1126
+ const parsed = JSON.parse(raw);
1127
+ if (parsed && typeof parsed.state === 'string') return parsed.state;
1128
+ return 'unknown';
1129
+ } catch {
1130
+ return 'unknown';
1131
+ }
1132
+ }
1133
+
1134
+ async function readTeamWorkersForIdleCheck(stateDir, teamName) {
1135
+ // Try manifest.v2.json first (preferred), then config.json
1136
+ const manifestPath = join(stateDir, 'team', teamName, 'manifest.v2.json');
1137
+ const configPath = join(stateDir, 'team', teamName, 'config.json');
1138
+ const srcPath = existsSync(manifestPath) ? manifestPath : existsSync(configPath) ? configPath : null;
1139
+ if (!srcPath) return null;
1140
+
1141
+ try {
1142
+ const raw = await readFile(srcPath, 'utf-8');
1143
+ const parsed = JSON.parse(raw);
1144
+ if (!parsed || typeof parsed !== 'object') return null;
1145
+ const workers = parsed.workers;
1146
+ if (!Array.isArray(workers) || workers.length === 0) return null;
1147
+ const tmuxSession = safeString(parsed.tmux_session || '').trim();
1148
+ return { workers, tmuxSession };
1149
+ } catch {
1150
+ return null;
1151
+ }
1152
+ }
1153
+
1154
+ async function maybeNotifyLeaderAllWorkersIdle({ cwd, stateDir, logsDir, parsedTeamWorker }) {
1155
+ const { teamName, workerName } = parsedTeamWorker;
1156
+ const nowMs = Date.now();
1157
+ const nowIso = new Date(nowMs).toISOString();
1158
+
1159
+ // Only trigger check when this worker is idle
1160
+ const myState = await readWorkerStatusState(stateDir, teamName, workerName);
1161
+ if (myState !== 'idle') return;
1162
+
1163
+ // Read team config to get worker list and leader tmux target
1164
+ const teamInfo = await readTeamWorkersForIdleCheck(stateDir, teamName);
1165
+ if (!teamInfo) return;
1166
+ const { workers, tmuxSession } = teamInfo;
1167
+ if (!tmuxSession) return;
1168
+
1169
+ // Check cooldown to prevent notification spam
1170
+ const idleStatePath = join(stateDir, 'team', teamName, 'all-workers-idle.json');
1171
+ const idleState = (await readJsonIfExists(idleStatePath, null)) || {};
1172
+ const cooldownMs = resolveAllWorkersIdleCooldownMs();
1173
+ const lastNotifiedMs = asNumber(idleState.last_notified_at_ms) ?? 0;
1174
+ if ((nowMs - lastNotifiedMs) < cooldownMs) return;
1175
+
1176
+ // Check if ALL workers are idle (or done)
1177
+ const states = await Promise.all(
1178
+ workers.map(w => readWorkerStatusState(stateDir, teamName, safeString(w && w.name ? w.name : '')))
1179
+ );
1180
+ const allIdle = states.length > 0 && states.every(s => s === 'idle' || s === 'done');
1181
+ if (!allIdle) return;
1182
+
1183
+ const N = workers.length;
1184
+ const message = `[OMX] All ${N} worker${N === 1 ? '' : 's'} idle. Ready for next instructions. ${DEFAULT_MARKER}`;
1185
+
1186
+ try {
1187
+ await runProcess('tmux', ['send-keys', '-t', tmuxSession, '-l', message], 3000);
1188
+ await new Promise(r => setTimeout(r, 100));
1189
+ await runProcess('tmux', ['send-keys', '-t', tmuxSession, 'C-m'], 3000);
1190
+ await new Promise(r => setTimeout(r, 100));
1191
+ await runProcess('tmux', ['send-keys', '-t', tmuxSession, 'C-m'], 3000);
1192
+
1193
+ // Update cooldown state (atomic: use a tmp file pattern)
1194
+ const nextIdleState = {
1195
+ ...idleState,
1196
+ last_notified_at_ms: nowMs,
1197
+ last_notified_at: nowIso,
1198
+ worker_count: N,
1199
+ };
1200
+ await writeFile(idleStatePath, JSON.stringify(nextIdleState, null, 2)).catch(() => {});
1201
+
1202
+ // Emit team event for the notification
1203
+ const eventsDir = join(stateDir, 'team', teamName, 'events');
1204
+ const eventsPath = join(eventsDir, 'events.ndjson');
1205
+ try {
1206
+ await mkdir(eventsDir, { recursive: true });
1207
+ const event = {
1208
+ event_id: `all-idle-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
1209
+ team: teamName,
1210
+ type: 'all_workers_idle',
1211
+ worker: workerName,
1212
+ worker_count: N,
1213
+ created_at: nowIso,
1214
+ };
1215
+ await appendFile(eventsPath, JSON.stringify(event) + '\n');
1216
+ } catch { /* best effort */ }
1217
+
1218
+ // Log the notification
1219
+ await logTmuxHookEvent(logsDir, {
1220
+ timestamp: nowIso,
1221
+ type: 'all_workers_idle_notification',
1222
+ team: teamName,
1223
+ tmux_target: tmuxSession,
1224
+ worker: workerName,
1225
+ worker_count: N,
1226
+ });
1227
+ } catch (err) {
1228
+ await logTmuxHookEvent(logsDir, {
1229
+ timestamp: nowIso,
1230
+ type: 'all_workers_idle_notification',
1231
+ team: teamName,
1232
+ tmux_target: tmuxSession,
1233
+ worker: workerName,
1234
+ error: err instanceof Error ? err.message : safeString(err),
1235
+ }).catch(() => {});
1236
+ }
1237
+ }
1238
+
1087
1239
  async function dispatchNativeHookEvent(cwd, eventName, payload, context = {}) {
1088
1240
  try {
1089
1241
  const { buildNativeHookEvent } = await import('../dist/hooks/extensibility/events.js');
@@ -1312,6 +1464,15 @@ async function main() {
1312
1464
  }
1313
1465
  }
1314
1466
 
1467
+ // 4.6. Notify leader when all workers are idle (worker session only)
1468
+ if (isTeamWorker && parsedTeamWorker) {
1469
+ try {
1470
+ await maybeNotifyLeaderAllWorkersIdle({ cwd, stateDir, logsDir, parsedTeamWorker });
1471
+ } catch {
1472
+ // Non-critical
1473
+ }
1474
+ }
1475
+
1315
1476
  // 5. Optional tmux prompt injection workaround (non-fatal, opt-in)
1316
1477
  // Skip for team workers - only the lead should inject prompts
1317
1478
  if (!isTeamWorker) {
@@ -44,7 +44,7 @@ For non-trivial SDK/API/framework usage, delegate to `dependency-expert` to chec
44
44
  </delegation_rules>
45
45
 
46
46
  <child_agent_protocol>
47
- Codex CLI spawns child agents via the `spawn_agent` tool (requires `collab = true`).
47
+ Codex CLI spawns child agents via the `spawn_agent` tool (requires `multi_agent = true`).
48
48
  To inject role-specific behavior, the parent MUST read the role prompt and pass it in the spawned agent message.
49
49
 
50
50
  Delegation steps: