oh-my-codex 0.3.9 → 0.4.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 (184) hide show
  1. package/README.md +25 -0
  2. package/dist/cli/__tests__/doctor-team.test.js +58 -0
  3. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  4. package/dist/cli/__tests__/index.test.js +9 -3
  5. package/dist/cli/__tests__/index.test.js.map +1 -1
  6. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts +2 -0
  7. package/dist/cli/__tests__/lifecycle-notifications.test.d.ts.map +1 -0
  8. package/dist/cli/__tests__/lifecycle-notifications.test.js +48 -0
  9. package/dist/cli/__tests__/lifecycle-notifications.test.js.map +1 -0
  10. package/dist/cli/doctor.js +28 -0
  11. package/dist/cli/doctor.js.map +1 -1
  12. package/dist/cli/hooks.d.ts +4 -0
  13. package/dist/cli/hooks.d.ts.map +1 -0
  14. package/dist/cli/hooks.js +201 -0
  15. package/dist/cli/hooks.js.map +1 -0
  16. package/dist/cli/index.d.ts +1 -1
  17. package/dist/cli/index.d.ts.map +1 -1
  18. package/dist/cli/index.js +181 -2
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/config/__tests__/models.test.d.ts +2 -0
  21. package/dist/config/__tests__/models.test.d.ts.map +1 -0
  22. package/dist/config/__tests__/models.test.js +69 -0
  23. package/dist/config/__tests__/models.test.js.map +1 -0
  24. package/dist/config/models.d.ts +24 -0
  25. package/dist/config/models.d.ts.map +1 -0
  26. package/dist/config/models.js +53 -0
  27. package/dist/config/models.js.map +1 -0
  28. package/dist/hooks/__tests__/notify-hook-linked-sync.test.js +6 -0
  29. package/dist/hooks/__tests__/notify-hook-linked-sync.test.js.map +1 -1
  30. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +6 -0
  31. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  32. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +224 -36
  33. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  34. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +4 -0
  35. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  36. package/dist/hooks/__tests__/tmux-hook-engine.test.js +1 -1
  37. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -1
  38. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts +2 -0
  39. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.d.ts.map +1 -0
  40. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js +153 -0
  41. package/dist/hooks/extensibility/__tests__/example-hook-plugins.test.js.map +1 -0
  42. package/dist/hooks/extensibility/dispatcher.d.ts +4 -0
  43. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -0
  44. package/dist/hooks/extensibility/dispatcher.js +223 -0
  45. package/dist/hooks/extensibility/dispatcher.js.map +1 -0
  46. package/dist/hooks/extensibility/events.d.ts +18 -0
  47. package/dist/hooks/extensibility/events.d.ts.map +1 -0
  48. package/dist/hooks/extensibility/events.js +53 -0
  49. package/dist/hooks/extensibility/events.js.map +1 -0
  50. package/dist/hooks/extensibility/index.d.ts +6 -0
  51. package/dist/hooks/extensibility/index.d.ts.map +1 -0
  52. package/dist/hooks/extensibility/index.js +6 -0
  53. package/dist/hooks/extensibility/index.js.map +1 -0
  54. package/dist/hooks/extensibility/loader.d.ts +14 -0
  55. package/dist/hooks/extensibility/loader.d.ts.map +1 -0
  56. package/dist/hooks/extensibility/loader.js +102 -0
  57. package/dist/hooks/extensibility/loader.js.map +1 -0
  58. package/dist/hooks/extensibility/logging.d.ts +4 -0
  59. package/dist/hooks/extensibility/logging.d.ts.map +1 -0
  60. package/dist/hooks/extensibility/logging.js +16 -0
  61. package/dist/hooks/extensibility/logging.js.map +1 -0
  62. package/dist/hooks/extensibility/plugin-runner.d.ts +2 -0
  63. package/dist/hooks/extensibility/plugin-runner.d.ts.map +1 -0
  64. package/dist/hooks/extensibility/plugin-runner.js +69 -0
  65. package/dist/hooks/extensibility/plugin-runner.js.map +1 -0
  66. package/dist/hooks/extensibility/runtime.d.ts +3 -0
  67. package/dist/hooks/extensibility/runtime.d.ts.map +1 -0
  68. package/dist/hooks/extensibility/runtime.js +29 -0
  69. package/dist/hooks/extensibility/runtime.js.map +1 -0
  70. package/dist/hooks/extensibility/sdk.d.ts +11 -0
  71. package/dist/hooks/extensibility/sdk.d.ts.map +1 -0
  72. package/dist/hooks/extensibility/sdk.js +240 -0
  73. package/dist/hooks/extensibility/sdk.js.map +1 -0
  74. package/dist/hooks/extensibility/types.d.ts +122 -0
  75. package/dist/hooks/extensibility/types.d.ts.map +1 -0
  76. package/dist/hooks/extensibility/types.js +2 -0
  77. package/dist/hooks/extensibility/types.js.map +1 -0
  78. package/dist/mcp/__tests__/state-paths.test.js +21 -1
  79. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  80. package/dist/mcp/__tests__/state-server-team-tools.test.js +53 -1
  81. package/dist/mcp/__tests__/state-server-team-tools.test.js.map +1 -1
  82. package/dist/mcp/state-paths.d.ts +1 -0
  83. package/dist/mcp/state-paths.d.ts.map +1 -1
  84. package/dist/mcp/state-paths.js +34 -1
  85. package/dist/mcp/state-paths.js.map +1 -1
  86. package/dist/mcp/state-server.d.ts.map +1 -1
  87. package/dist/mcp/state-server.js +46 -11
  88. package/dist/mcp/state-server.js.map +1 -1
  89. package/dist/notifications/__tests__/config.test.d.ts +2 -0
  90. package/dist/notifications/__tests__/config.test.d.ts.map +1 -0
  91. package/dist/notifications/__tests__/config.test.js +186 -0
  92. package/dist/notifications/__tests__/config.test.js.map +1 -0
  93. package/dist/notifications/__tests__/dispatcher.test.d.ts +2 -0
  94. package/dist/notifications/__tests__/dispatcher.test.d.ts.map +1 -0
  95. package/dist/notifications/__tests__/dispatcher.test.js +202 -0
  96. package/dist/notifications/__tests__/dispatcher.test.js.map +1 -0
  97. package/dist/notifications/__tests__/formatter.test.d.ts +2 -0
  98. package/dist/notifications/__tests__/formatter.test.d.ts.map +1 -0
  99. package/dist/notifications/__tests__/formatter.test.js +103 -0
  100. package/dist/notifications/__tests__/formatter.test.js.map +1 -0
  101. package/dist/notifications/__tests__/notifier.test.d.ts +2 -0
  102. package/dist/notifications/__tests__/notifier.test.d.ts.map +1 -0
  103. package/dist/notifications/__tests__/notifier.test.js +104 -0
  104. package/dist/notifications/__tests__/notifier.test.js.map +1 -0
  105. package/dist/notifications/__tests__/profiles.test.d.ts +2 -0
  106. package/dist/notifications/__tests__/profiles.test.d.ts.map +1 -0
  107. package/dist/notifications/__tests__/profiles.test.js +404 -0
  108. package/dist/notifications/__tests__/profiles.test.js.map +1 -0
  109. package/dist/notifications/__tests__/reply-listener.test.d.ts +2 -0
  110. package/dist/notifications/__tests__/reply-listener.test.d.ts.map +1 -0
  111. package/dist/notifications/__tests__/reply-listener.test.js +58 -0
  112. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -0
  113. package/dist/notifications/__tests__/session-registry.test.d.ts +2 -0
  114. package/dist/notifications/__tests__/session-registry.test.d.ts.map +1 -0
  115. package/dist/notifications/__tests__/session-registry.test.js +147 -0
  116. package/dist/notifications/__tests__/session-registry.test.js.map +1 -0
  117. package/dist/notifications/__tests__/tmux-detector.test.d.ts +2 -0
  118. package/dist/notifications/__tests__/tmux-detector.test.d.ts.map +1 -0
  119. package/dist/notifications/__tests__/tmux-detector.test.js +77 -0
  120. package/dist/notifications/__tests__/tmux-detector.test.js.map +1 -0
  121. package/dist/notifications/__tests__/tmux.test.d.ts +2 -0
  122. package/dist/notifications/__tests__/tmux.test.d.ts.map +1 -0
  123. package/dist/notifications/__tests__/tmux.test.js +90 -0
  124. package/dist/notifications/__tests__/tmux.test.js.map +1 -0
  125. package/dist/notifications/config.d.ts +44 -0
  126. package/dist/notifications/config.d.ts.map +1 -0
  127. package/dist/notifications/config.js +407 -0
  128. package/dist/notifications/config.js.map +1 -0
  129. package/dist/notifications/dispatcher.d.ts +15 -0
  130. package/dist/notifications/dispatcher.d.ts.map +1 -0
  131. package/dist/notifications/dispatcher.js +410 -0
  132. package/dist/notifications/dispatcher.js.map +1 -0
  133. package/dist/notifications/formatter.d.ts +14 -0
  134. package/dist/notifications/formatter.d.ts.map +1 -0
  135. package/dist/notifications/formatter.js +134 -0
  136. package/dist/notifications/formatter.js.map +1 -0
  137. package/dist/notifications/index.d.ts +32 -0
  138. package/dist/notifications/index.d.ts.map +1 -0
  139. package/dist/notifications/index.js +93 -0
  140. package/dist/notifications/index.js.map +1 -0
  141. package/dist/notifications/reply-listener.d.ts +47 -0
  142. package/dist/notifications/reply-listener.d.ts.map +1 -0
  143. package/dist/notifications/reply-listener.js +656 -0
  144. package/dist/notifications/reply-listener.js.map +1 -0
  145. package/dist/notifications/session-registry.d.ts +26 -0
  146. package/dist/notifications/session-registry.d.ts.map +1 -0
  147. package/dist/notifications/session-registry.js +275 -0
  148. package/dist/notifications/session-registry.js.map +1 -0
  149. package/dist/notifications/tmux-detector.d.ts +17 -0
  150. package/dist/notifications/tmux-detector.d.ts.map +1 -0
  151. package/dist/notifications/tmux-detector.js +82 -0
  152. package/dist/notifications/tmux-detector.js.map +1 -0
  153. package/dist/notifications/tmux.d.ts +28 -0
  154. package/dist/notifications/tmux.d.ts.map +1 -0
  155. package/dist/notifications/tmux.js +210 -0
  156. package/dist/notifications/tmux.js.map +1 -0
  157. package/dist/notifications/types.d.ts +181 -0
  158. package/dist/notifications/types.d.ts.map +1 -0
  159. package/dist/notifications/types.js +9 -0
  160. package/dist/notifications/types.js.map +1 -0
  161. package/dist/team/__tests__/runtime.test.js +54 -2
  162. package/dist/team/__tests__/runtime.test.js.map +1 -1
  163. package/dist/team/__tests__/state.test.js +30 -0
  164. package/dist/team/__tests__/state.test.js.map +1 -1
  165. package/dist/team/__tests__/worker-bootstrap.test.js +2 -0
  166. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  167. package/dist/team/runtime.d.ts +2 -2
  168. package/dist/team/runtime.d.ts.map +1 -1
  169. package/dist/team/runtime.js +19 -12
  170. package/dist/team/runtime.js.map +1 -1
  171. package/dist/team/state.d.ts +1 -1
  172. package/dist/team/state.d.ts.map +1 -1
  173. package/dist/team/state.js +5 -0
  174. package/dist/team/state.js.map +1 -1
  175. package/dist/team/tmux-session.d.ts.map +1 -1
  176. package/dist/team/tmux-session.js +59 -15
  177. package/dist/team/tmux-session.js.map +1 -1
  178. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  179. package/dist/team/worker-bootstrap.js +4 -0
  180. package/dist/team/worker-bootstrap.js.map +1 -1
  181. package/package.json +1 -1
  182. package/scripts/hook-derived-watcher.js +335 -0
  183. package/scripts/notify-hook.js +168 -7
  184. package/scripts/tmux-hook-engine.js +3 -2
@@ -0,0 +1,153 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFile } from 'node:fs';
3
+ import { access, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { describe, it } from 'node:test';
7
+ import { dispatchHookEvent } from '../dispatcher.js';
8
+ import { buildHookEvent } from '../events.js';
9
+ const ALL_EVENTS = [
10
+ 'session-start',
11
+ 'session-end',
12
+ 'session-idle',
13
+ 'turn-complete',
14
+ 'needs-input',
15
+ 'pre-tool-use',
16
+ 'post-tool-use',
17
+ ];
18
+ const DERIVED_EVENTS = new Set(['needs-input', 'pre-tool-use', 'post-tool-use']);
19
+ function examplePluginSource(expectedEvent) {
20
+ return `const EXPECTED_EVENT = ${JSON.stringify(expectedEvent)};
21
+
22
+ export async function onHookEvent(event, sdk) {
23
+ if (event.event !== EXPECTED_EVENT) return;
24
+ const runId = String((event.context && event.context.run_id) || 'unknown');
25
+ const seenKey = 'seen_count';
26
+ const prev = Number((await sdk.state.read(seenKey)) ?? 0);
27
+ const next = Number.isFinite(prev) ? prev + 1 : 1;
28
+ await sdk.state.write(seenKey, next);
29
+ await sdk.state.write('last_event', event.event);
30
+ await sdk.state.write('last_source', event.source);
31
+ await sdk.state.write('last_run_id', runId);
32
+ await sdk.state.write(\`run:\${runId}\`, { event: event.event, source: event.source, at: event.timestamp });
33
+ await sdk.log.info('example hook fired', {
34
+ expected: EXPECTED_EVENT,
35
+ seen_count: next,
36
+ source: event.source,
37
+ run_id: runId,
38
+ });
39
+ }
40
+ `;
41
+ }
42
+ async function setupExamplePlugins(cwd) {
43
+ const hooksDir = join(cwd, '.omx', 'hooks');
44
+ await mkdir(hooksDir, { recursive: true });
45
+ for (const eventName of ALL_EVENTS) {
46
+ const filePath = join(hooksDir, `example-${eventName}.mjs`);
47
+ await writeFile(filePath, examplePluginSource(eventName), 'utf-8');
48
+ }
49
+ }
50
+ function pluginDataPath(cwd, eventName) {
51
+ return join(cwd, '.omx', 'state', 'hooks', 'plugins', `example-${eventName}`, 'data.json');
52
+ }
53
+ async function readPluginData(cwd, eventName) {
54
+ const path = pluginDataPath(cwd, eventName);
55
+ try {
56
+ await access(path);
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ const raw = await new Promise((resolve, reject) => {
62
+ readFile(path, 'utf-8', (err, data) => {
63
+ if (err) {
64
+ reject(err);
65
+ return;
66
+ }
67
+ resolve(data);
68
+ });
69
+ });
70
+ return JSON.parse(raw);
71
+ }
72
+ describe('example hook plugins', () => {
73
+ it('dispatches only the matching example plugin for a single event', async () => {
74
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-hook-examples-'));
75
+ try {
76
+ await setupExamplePlugins(cwd);
77
+ const event = buildHookEvent('session-start', {
78
+ timestamp: '2026-01-01T00:00:00.000Z',
79
+ context: { run_id: 'run-session-start' },
80
+ });
81
+ const result = await dispatchHookEvent(event, {
82
+ cwd,
83
+ env: {
84
+ ...process.env,
85
+ OMX_HOOK_PLUGINS: '1',
86
+ },
87
+ });
88
+ assert.equal(result.enabled, true);
89
+ assert.equal(result.plugin_count, ALL_EVENTS.length);
90
+ assert.equal(result.results.length, ALL_EVENTS.length);
91
+ const matched = result.results.find((item) => item.plugin === 'example-session-start');
92
+ assert.ok(matched);
93
+ assert.equal(matched.ok, true);
94
+ for (const eventName of ALL_EVENTS) {
95
+ const data = await readPluginData(cwd, eventName);
96
+ if (eventName === 'session-start') {
97
+ assert.ok(data);
98
+ assert.equal(data.seen_count, 1);
99
+ assert.equal(data.last_event, 'session-start');
100
+ }
101
+ else {
102
+ assert.equal(data, null);
103
+ }
104
+ }
105
+ }
106
+ finally {
107
+ await rm(cwd, { recursive: true, force: true });
108
+ }
109
+ });
110
+ it('covers all example plugin event types with deterministic state assertions', async () => {
111
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-hook-examples-all-'));
112
+ try {
113
+ await setupExamplePlugins(cwd);
114
+ for (const eventName of ALL_EVENTS) {
115
+ const timestamp = `2026-01-01T00:00:00.${String(ALL_EVENTS.indexOf(eventName)).padStart(3, '0')}Z`;
116
+ const runId = `run-${eventName}`;
117
+ const envelope = buildHookEvent(eventName, {
118
+ timestamp,
119
+ context: { run_id: runId },
120
+ });
121
+ const result = await dispatchHookEvent(envelope, {
122
+ cwd,
123
+ env: {
124
+ ...process.env,
125
+ OMX_HOOK_PLUGINS: '1',
126
+ },
127
+ });
128
+ const matched = result.results.find((item) => item.plugin === `example-${eventName}`);
129
+ assert.ok(matched);
130
+ assert.equal(matched.ok, true);
131
+ }
132
+ for (const eventName of ALL_EVENTS) {
133
+ const data = await readPluginData(cwd, eventName);
134
+ const runId = `run-${eventName}`;
135
+ const expectedSource = DERIVED_EVENTS.has(eventName) ? 'derived' : 'native';
136
+ assert.ok(data);
137
+ assert.equal(data.seen_count, 1);
138
+ assert.equal(data.last_event, eventName);
139
+ assert.equal(data.last_source, expectedSource);
140
+ assert.equal(data.last_run_id, runId);
141
+ assert.deepEqual(data[`run:${runId}`], {
142
+ event: eventName,
143
+ source: expectedSource,
144
+ at: `2026-01-01T00:00:00.${String(ALL_EVENTS.indexOf(eventName)).padStart(3, '0')}Z`,
145
+ });
146
+ }
147
+ }
148
+ finally {
149
+ await rm(cwd, { recursive: true, force: true });
150
+ }
151
+ });
152
+ });
153
+ //# sourceMappingURL=example-hook-plugins.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example-hook-plugins.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/example-hook-plugins.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HookDispatchOptions, HookDispatchResult, HookEventEnvelope } from './types.js';
2
+ export declare function isHookPluginFeatureEnabled(env?: NodeJS.ProcessEnv): boolean;
3
+ export declare function dispatchHookEvent(event: HookEventEnvelope, options?: HookDispatchOptions): Promise<HookDispatchResult>;
4
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../../src/hooks/extensibility/dispatcher.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,YAAY,CAAC;AA2KpB,wBAAgB,0BAA0B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAExF;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CA8E7B"}
@@ -0,0 +1,223 @@
1
+ import { existsSync } from 'fs';
2
+ import { appendFile, mkdir } from 'fs/promises';
3
+ import { spawn } from 'child_process';
4
+ import { join } from 'path';
5
+ import { getPackageRoot } from '../../utils/package.js';
6
+ import { discoverHookPlugins, isHookPluginsEnabled, resolveHookPluginTimeoutMs, validateHookPluginExport, } from './loader.js';
7
+ const RESULT_PREFIX = '__OMX_PLUGIN_RESULT__ ';
8
+ function hooksLogPath(cwd) {
9
+ const day = new Date().toISOString().slice(0, 10);
10
+ return join(cwd, '.omx', 'logs', `hooks-${day}.jsonl`);
11
+ }
12
+ async function appendHooksLog(cwd, payload) {
13
+ await mkdir(join(cwd, '.omx', 'logs'), { recursive: true });
14
+ await appendFile(hooksLogPath(cwd), `${JSON.stringify({ timestamp: new Date().toISOString(), ...payload })}\n`).catch(() => { });
15
+ }
16
+ function isTeamWorker(env) {
17
+ return typeof env.OMX_TEAM_WORKER === 'string' && env.OMX_TEAM_WORKER.trim() !== '';
18
+ }
19
+ async function runPluginRunner(plugin, event, options, sideEffectsEnabled) {
20
+ const started = Date.now();
21
+ const runnerPath = join(getPackageRoot(), 'dist', 'hooks', 'extensibility', 'plugin-runner.js');
22
+ const timeoutMs = options.timeoutMs ?? resolveHookPluginTimeoutMs(options.env);
23
+ if (!existsSync(runnerPath)) {
24
+ const duration = Date.now() - started;
25
+ return {
26
+ plugin: plugin.id,
27
+ path: plugin.path,
28
+ file: plugin.file,
29
+ plugin_id: plugin.id,
30
+ ok: false,
31
+ status: 'runner_error',
32
+ skipped: true,
33
+ reason: 'runner_missing',
34
+ durationMs: duration,
35
+ duration_ms: duration,
36
+ };
37
+ }
38
+ return await new Promise((resolve) => {
39
+ const child = spawn(process.execPath, [runnerPath], {
40
+ cwd: options.cwd,
41
+ stdio: ['pipe', 'pipe', 'pipe'],
42
+ env: {
43
+ ...process.env,
44
+ ...(options.env || {}),
45
+ },
46
+ });
47
+ let stdout = '';
48
+ let stderr = '';
49
+ let done = false;
50
+ let timedOut = false;
51
+ const timer = setTimeout(() => {
52
+ timedOut = true;
53
+ child.kill('SIGTERM');
54
+ }, timeoutMs);
55
+ child.stdout.on('data', (chunk) => {
56
+ stdout += chunk.toString();
57
+ });
58
+ child.stderr.on('data', (chunk) => {
59
+ stderr += chunk.toString();
60
+ });
61
+ child.on('error', (error) => {
62
+ if (done)
63
+ return;
64
+ done = true;
65
+ clearTimeout(timer);
66
+ const duration = Date.now() - started;
67
+ resolve({
68
+ plugin: plugin.id,
69
+ path: plugin.path,
70
+ file: plugin.file,
71
+ plugin_id: plugin.id,
72
+ ok: false,
73
+ status: 'runner_error',
74
+ reason: 'spawn_failed',
75
+ error: error.message,
76
+ durationMs: duration,
77
+ duration_ms: duration,
78
+ });
79
+ });
80
+ child.on('close', () => {
81
+ if (done)
82
+ return;
83
+ done = true;
84
+ clearTimeout(timer);
85
+ const duration = Date.now() - started;
86
+ if (timedOut) {
87
+ resolve({
88
+ plugin: plugin.id,
89
+ path: plugin.path,
90
+ file: plugin.file,
91
+ plugin_id: plugin.id,
92
+ ok: false,
93
+ status: 'timeout',
94
+ reason: 'timeout',
95
+ durationMs: duration,
96
+ duration_ms: duration,
97
+ });
98
+ return;
99
+ }
100
+ const lines = stdout.split('\n').map((line) => line.trim()).filter(Boolean);
101
+ const rawResult = [...lines].reverse().find((line) => line.startsWith(RESULT_PREFIX));
102
+ let parsed = null;
103
+ if (rawResult) {
104
+ try {
105
+ parsed = JSON.parse(rawResult.slice(RESULT_PREFIX.length));
106
+ }
107
+ catch {
108
+ parsed = null;
109
+ }
110
+ }
111
+ if (parsed?.ok) {
112
+ resolve({
113
+ plugin: plugin.id,
114
+ path: plugin.path,
115
+ file: plugin.file,
116
+ plugin_id: plugin.id,
117
+ ok: true,
118
+ status: 'ok',
119
+ reason: parsed.reason || 'ok',
120
+ durationMs: duration,
121
+ duration_ms: duration,
122
+ });
123
+ return;
124
+ }
125
+ const reason = parsed?.reason || 'plugin_error';
126
+ resolve({
127
+ plugin: plugin.id,
128
+ path: plugin.path,
129
+ file: plugin.file,
130
+ plugin_id: plugin.id,
131
+ ok: false,
132
+ status: reason === 'invalid_export' ? 'invalid_export' : 'error',
133
+ reason,
134
+ error: parsed?.error || stderr.trim() || undefined,
135
+ durationMs: duration,
136
+ duration_ms: duration,
137
+ });
138
+ });
139
+ child.stdin.write(JSON.stringify({
140
+ cwd: options.cwd,
141
+ pluginId: plugin.id,
142
+ pluginPath: plugin.path,
143
+ event,
144
+ sideEffectsEnabled,
145
+ }));
146
+ child.stdin.end();
147
+ });
148
+ }
149
+ export function isHookPluginFeatureEnabled(env = process.env) {
150
+ return isHookPluginsEnabled(env);
151
+ }
152
+ export async function dispatchHookEvent(event, options = {}) {
153
+ const cwd = options.cwd || process.cwd();
154
+ const env = options.env || process.env;
155
+ const enabled = options.enabled ?? isHookPluginsEnabled(env);
156
+ const summary = {
157
+ enabled,
158
+ reason: enabled ? 'ok' : 'disabled',
159
+ event: event.event,
160
+ source: event.source,
161
+ plugin_count: 0,
162
+ results: [],
163
+ };
164
+ if (!enabled) {
165
+ await appendHooksLog(cwd, {
166
+ type: 'hook_dispatch',
167
+ event: event.event,
168
+ source: event.source,
169
+ enabled: false,
170
+ reason: 'plugins_disabled',
171
+ });
172
+ return summary;
173
+ }
174
+ const plugins = await discoverHookPlugins(cwd);
175
+ summary.plugin_count = plugins.length;
176
+ const inTeamWorker = isTeamWorker(env);
177
+ const allowTeamSideEffects = options.allowTeamWorkerSideEffects ?? options.allowInTeamWorker ?? false;
178
+ const sideEffectsEnabled = options.sideEffectsEnabled ?? (!inTeamWorker || allowTeamSideEffects);
179
+ for (const plugin of plugins) {
180
+ const validation = await validateHookPluginExport(plugin.path);
181
+ if (!validation.valid) {
182
+ const invalid = {
183
+ plugin: plugin.id,
184
+ path: plugin.path,
185
+ file: plugin.file,
186
+ plugin_id: plugin.id,
187
+ ok: false,
188
+ status: 'invalid_export',
189
+ reason: validation.reason || 'invalid_export',
190
+ durationMs: 0,
191
+ duration_ms: 0,
192
+ };
193
+ summary.results.push(invalid);
194
+ await appendHooksLog(cwd, {
195
+ type: 'hook_plugin_dispatch',
196
+ event: event.event,
197
+ source: event.source,
198
+ plugin: plugin.id,
199
+ file: plugin.file,
200
+ ok: false,
201
+ status: invalid.status,
202
+ reason: invalid.reason,
203
+ });
204
+ continue;
205
+ }
206
+ const result = await runPluginRunner(plugin, event, { ...options, cwd, env }, sideEffectsEnabled);
207
+ summary.results.push(result);
208
+ await appendHooksLog(cwd, {
209
+ type: 'hook_plugin_dispatch',
210
+ event: event.event,
211
+ source: event.source,
212
+ plugin: plugin.id,
213
+ file: plugin.file,
214
+ ok: result.ok,
215
+ status: result.status,
216
+ reason: result.reason,
217
+ error: result.error,
218
+ duration_ms: result.duration_ms,
219
+ });
220
+ }
221
+ return summary;
222
+ }
223
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../../src/hooks/extensibility/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { HookEventEnvelope, HookEventName, HookEventSource } from './types.js';
2
+ interface BuildHookEventOptions {
3
+ source?: HookEventSource;
4
+ timestamp?: string;
5
+ context?: Record<string, unknown>;
6
+ session_id?: string;
7
+ thread_id?: string;
8
+ turn_id?: string;
9
+ mode?: string;
10
+ confidence?: number;
11
+ parser_reason?: string;
12
+ }
13
+ export declare function isDerivedEventName(event: string): boolean;
14
+ export declare function buildHookEvent(event: HookEventName | string, options?: BuildHookEventOptions): HookEventEnvelope;
15
+ export declare function buildNativeHookEvent(event: HookEventName | string, context?: Record<string, unknown>, options?: Omit<BuildHookEventOptions, 'source' | 'confidence' | 'parser_reason' | 'context'>): HookEventEnvelope;
16
+ export declare function buildDerivedHookEvent(event: HookEventName | string, context?: Record<string, unknown>, options?: Omit<BuildHookEventOptions, 'source' | 'context'>): HookEventEnvelope;
17
+ export {};
18
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/hooks/extensibility/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIpF,UAAU,qBAAqB;IAC7B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AASD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,GAAG,MAAM,EAC7B,OAAO,GAAE,qBAA0B,GAClC,iBAAiB,CAuBnB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,GAAG,MAAM,EAC7B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,YAAY,GAAG,eAAe,GAAG,SAAS,CAAM,GAC/F,iBAAiB,CAMnB;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,GAAG,MAAM,EAC7B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,OAAO,GAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,SAAS,CAAM,GAC9D,iBAAiB,CAMnB"}
@@ -0,0 +1,53 @@
1
+ const DERIVED_EVENTS = new Set(['needs-input', 'pre-tool-use', 'post-tool-use']);
2
+ function clampConfidence(value) {
3
+ if (typeof value !== 'number' || !Number.isFinite(value))
4
+ return undefined;
5
+ if (value < 0)
6
+ return 0;
7
+ if (value > 1)
8
+ return 1;
9
+ return value;
10
+ }
11
+ export function isDerivedEventName(event) {
12
+ return DERIVED_EVENTS.has(event);
13
+ }
14
+ export function buildHookEvent(event, options = {}) {
15
+ const source = options.source || (isDerivedEventName(event) ? 'derived' : 'native');
16
+ const confidence = clampConfidence(options.confidence);
17
+ const envelope = {
18
+ schema_version: '1',
19
+ event,
20
+ timestamp: options.timestamp || new Date().toISOString(),
21
+ source,
22
+ context: options.context && typeof options.context === 'object' ? options.context : {},
23
+ };
24
+ if (options.session_id)
25
+ envelope.session_id = options.session_id;
26
+ if (options.thread_id)
27
+ envelope.thread_id = options.thread_id;
28
+ if (options.turn_id)
29
+ envelope.turn_id = options.turn_id;
30
+ if (options.mode)
31
+ envelope.mode = options.mode;
32
+ if (source === 'derived') {
33
+ envelope.confidence = confidence ?? 0.5;
34
+ if (options.parser_reason)
35
+ envelope.parser_reason = options.parser_reason;
36
+ }
37
+ return envelope;
38
+ }
39
+ export function buildNativeHookEvent(event, context = {}, options = {}) {
40
+ return buildHookEvent(event, {
41
+ ...options,
42
+ source: 'native',
43
+ context,
44
+ });
45
+ }
46
+ export function buildDerivedHookEvent(event, context = {}, options = {}) {
47
+ return buildHookEvent(event, {
48
+ ...options,
49
+ source: 'derived',
50
+ context,
51
+ });
52
+ }
53
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/hooks/extensibility/events.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAAG,IAAI,GAAG,CAAS,CAAC,aAAa,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;AAczF,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3E,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACxB,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,OAAO,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAA6B,EAC7B,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvD,MAAM,QAAQ,GAAsB;QAClC,cAAc,EAAE,GAAG;QACnB,KAAK;QACL,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACxD,MAAM;QACN,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;KACvF,CAAC;IAEF,IAAI,OAAO,CAAC,UAAU;QAAE,QAAQ,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACjE,IAAI,OAAO,CAAC,SAAS;QAAE,QAAQ,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAC9D,IAAI,OAAO,CAAC,OAAO;QAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACxD,IAAI,OAAO,CAAC,IAAI;QAAE,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,QAAQ,CAAC,UAAU,GAAG,UAAU,IAAI,GAAG,CAAC;QACxC,IAAI,OAAO,CAAC,aAAa;YAAE,QAAQ,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC5E,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAA6B,EAC7B,UAAmC,EAAE,EACrC,UAA8F,EAAE;IAEhG,OAAO,cAAc,CAAC,KAAK,EAAE;QAC3B,GAAG,OAAO;QACV,MAAM,EAAE,QAAQ;QAChB,OAAO;KACR,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAA6B,EAC7B,UAAmC,EAAE,EACrC,UAA6D,EAAE;IAE/D,OAAO,cAAc,CAAC,KAAK,EAAE;QAC3B,GAAG,OAAO;QACV,MAAM,EAAE,SAAS;QACjB,OAAO;KACR,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './types.js';
2
+ export * from './events.js';
3
+ export * from './loader.js';
4
+ export * from './dispatcher.js';
5
+ export * from './sdk.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/extensibility/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './types.js';
2
+ export * from './events.js';
3
+ export * from './loader.js';
4
+ export * from './dispatcher.js';
5
+ export * from './sdk.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/hooks/extensibility/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { HookPluginDescriptor } from './types.js';
2
+ export declare const HOOK_PLUGIN_ENABLE_ENV = "OMX_HOOK_PLUGINS";
3
+ export declare const HOOK_PLUGIN_TIMEOUT_ENV = "OMX_HOOK_PLUGIN_TIMEOUT_MS";
4
+ export declare function hooksDir(cwd: string): string;
5
+ export declare function isHookPluginsEnabled(env?: NodeJS.ProcessEnv): boolean;
6
+ export declare function resolveHookPluginTimeoutMs(env?: NodeJS.ProcessEnv, fallback?: number): number;
7
+ export declare function ensureHooksDir(cwd: string): Promise<string>;
8
+ export declare function validateHookPluginExport(pluginPath: string): Promise<{
9
+ valid: boolean;
10
+ reason?: string;
11
+ }>;
12
+ export declare function discoverHookPlugins(cwd: string): Promise<HookPluginDescriptor[]>;
13
+ export declare function loadHookPluginDescriptors(cwd: string): Promise<HookPluginDescriptor[]>;
14
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/hooks/extensibility/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,uBAAuB,+BAA+B,CAAC;AAsBpE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAGlF;AAED,wBAAgB,0BAA0B,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,SAAO,GACd,MAAM,CAER;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIjE;AAiBD,wBAAsB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAE/G;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA2BtF;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAY5F"}
@@ -0,0 +1,102 @@
1
+ import { existsSync } from 'fs';
2
+ import { mkdir, readdir, stat } from 'fs/promises';
3
+ import { basename, join } from 'path';
4
+ import { pathToFileURL } from 'url';
5
+ export const HOOK_PLUGIN_ENABLE_ENV = 'OMX_HOOK_PLUGINS';
6
+ export const HOOK_PLUGIN_TIMEOUT_ENV = 'OMX_HOOK_PLUGIN_TIMEOUT_MS';
7
+ function sanitizePluginId(fileName) {
8
+ const stem = basename(fileName, '.mjs');
9
+ const normalized = stem
10
+ .toLowerCase()
11
+ .replace(/[^a-z0-9_-]+/g, '-')
12
+ .replace(/-+/g, '-')
13
+ .replace(/^-+|-+$/g, '');
14
+ return normalized || 'plugin';
15
+ }
16
+ function readTimeout(raw, fallback) {
17
+ if (!raw)
18
+ return fallback;
19
+ const parsed = Number(raw);
20
+ if (!Number.isFinite(parsed))
21
+ return fallback;
22
+ const rounded = Math.floor(parsed);
23
+ if (rounded < 100)
24
+ return 100;
25
+ if (rounded > 60_000)
26
+ return 60_000;
27
+ return rounded;
28
+ }
29
+ export function hooksDir(cwd) {
30
+ return join(cwd, '.omx', 'hooks');
31
+ }
32
+ export function isHookPluginsEnabled(env = process.env) {
33
+ const raw = `${env[HOOK_PLUGIN_ENABLE_ENV] ?? ''}`.trim().toLowerCase();
34
+ return raw === '1' || raw === 'true' || raw === 'yes';
35
+ }
36
+ export function resolveHookPluginTimeoutMs(env = process.env, fallback = 1500) {
37
+ return readTimeout(env[HOOK_PLUGIN_TIMEOUT_ENV], fallback);
38
+ }
39
+ export async function ensureHooksDir(cwd) {
40
+ const dir = hooksDir(cwd);
41
+ await mkdir(dir, { recursive: true });
42
+ return dir;
43
+ }
44
+ async function validatePluginExport(pluginPath) {
45
+ try {
46
+ const mod = await import(`${pathToFileURL(pluginPath).href}?v=${Date.now()}`);
47
+ if (!mod || typeof mod.onHookEvent !== 'function') {
48
+ return { valid: false, reason: 'missing_onHookEvent_export' };
49
+ }
50
+ return { valid: true };
51
+ }
52
+ catch (err) {
53
+ return {
54
+ valid: false,
55
+ reason: err instanceof Error ? err.message : 'failed_to_import_plugin',
56
+ };
57
+ }
58
+ }
59
+ export async function validateHookPluginExport(pluginPath) {
60
+ return validatePluginExport(pluginPath);
61
+ }
62
+ export async function discoverHookPlugins(cwd) {
63
+ const dir = hooksDir(cwd);
64
+ if (!existsSync(dir))
65
+ return [];
66
+ const names = await readdir(dir).catch(() => []);
67
+ const plugins = [];
68
+ for (const name of names) {
69
+ if (!name.endsWith('.mjs'))
70
+ continue;
71
+ const path = join(dir, name);
72
+ const st = await stat(path).catch(() => null);
73
+ if (!st || !st.isFile())
74
+ continue;
75
+ const id = sanitizePluginId(name);
76
+ plugins.push({
77
+ id,
78
+ name: id,
79
+ file: name,
80
+ path,
81
+ filePath: path,
82
+ fileName: name,
83
+ valid: true,
84
+ });
85
+ }
86
+ plugins.sort((a, b) => a.file.localeCompare(b.file));
87
+ return plugins;
88
+ }
89
+ export async function loadHookPluginDescriptors(cwd) {
90
+ const discovered = await discoverHookPlugins(cwd);
91
+ const validated = [];
92
+ for (const plugin of discovered) {
93
+ const validation = await validatePluginExport(plugin.path);
94
+ validated.push({
95
+ ...plugin,
96
+ valid: validation.valid,
97
+ reason: validation.reason,
98
+ });
99
+ }
100
+ return validated;
101
+ }
102
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/hooks/extensibility/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HookPluginLogContext } from './types.js';
2
+ export declare function hookLogPath(cwd: string, timestamp?: Date): string;
3
+ export declare function appendHookPluginLog(cwd: string, entry: HookPluginLogContext): Promise<void>;
4
+ //# sourceMappingURL=logging.d.ts.map