oh-my-codex 0.4.0 → 0.4.2
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.
- package/README.es.md +36 -0
- package/README.ja.md +36 -0
- package/README.ko.md +36 -0
- package/README.md +13 -1
- package/README.pt.md +36 -0
- package/README.ru.md +36 -0
- package/README.vi.md +36 -0
- package/README.zh.md +39 -0
- package/bin/omx.js +2 -1
- package/dist/config/__tests__/generator-notify.test.js +3 -3
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +1 -1
- package/dist/config/generator.js +8 -8
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +427 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +432 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +3 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/emulator.d.ts +1 -1
- package/dist/hooks/emulator.js +5 -5
- package/dist/hooks/emulator.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/dispatcher.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +152 -0
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/events.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/events.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/events.test.js +117 -0
- package/dist/hooks/extensibility/__tests__/events.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/loader.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/loader.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/loader.test.js +229 -0
- package/dist/hooks/extensibility/__tests__/loader.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/logging.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/logging.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/logging.test.js +74 -0
- package/dist/hooks/extensibility/__tests__/logging.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +202 -0
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.js +117 -0
- package/dist/hooks/extensibility/__tests__/runtime.test.js.map +1 -0
- package/dist/hooks/extensibility/__tests__/sdk.test.d.ts +2 -0
- package/dist/hooks/extensibility/__tests__/sdk.test.d.ts.map +1 -0
- package/dist/hooks/extensibility/__tests__/sdk.test.js +277 -0
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -0
- package/dist/hooks/extensibility/sdk.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk.js +10 -2
- package/dist/hooks/extensibility/sdk.js.map +1 -1
- package/dist/hud/__tests__/colors.test.d.ts +2 -0
- package/dist/hud/__tests__/colors.test.d.ts.map +1 -0
- package/dist/hud/__tests__/colors.test.js +194 -0
- package/dist/hud/__tests__/colors.test.js.map +1 -0
- package/dist/hud/__tests__/render.test.d.ts +2 -0
- package/dist/hud/__tests__/render.test.d.ts.map +1 -0
- package/dist/hud/__tests__/render.test.js +449 -0
- package/dist/hud/__tests__/render.test.js.map +1 -0
- package/dist/hud/__tests__/types.test.d.ts +2 -0
- package/dist/hud/__tests__/types.test.d.ts.map +1 -0
- package/dist/hud/__tests__/types.test.js +17 -0
- package/dist/hud/__tests__/types.test.js.map +1 -0
- package/dist/team/__tests__/tmux-session.test.js +15 -1
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/orchestrator.d.ts +1 -1
- package/dist/team/orchestrator.js +1 -1
- package/dist/team/tmux-session.d.ts +8 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +28 -7
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/utils/__tests__/package.test.d.ts +2 -0
- package/dist/utils/__tests__/package.test.d.ts.map +1 -0
- package/dist/utils/__tests__/package.test.js +21 -0
- package/dist/utils/__tests__/package.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.d.ts +2 -0
- package/dist/utils/__tests__/paths.test.d.ts.map +1 -0
- package/dist/utils/__tests__/paths.test.js +117 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -0
- package/dist/verification/__tests__/verifier.test.d.ts +2 -0
- package/dist/verification/__tests__/verifier.test.d.ts.map +1 -0
- package/dist/verification/__tests__/verifier.test.js +94 -0
- package/dist/verification/__tests__/verifier.test.js.map +1 -0
- package/package.json +1 -1
- package/scripts/notify-hook.js +346 -1
- package/templates/AGENTS.md +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import { isHookPluginFeatureEnabled, dispatchHookEvent } from '../dispatcher.js';
|
|
7
|
+
import { buildHookEvent } from '../events.js';
|
|
8
|
+
describe('isHookPluginFeatureEnabled', () => {
|
|
9
|
+
it('returns true when OMX_HOOK_PLUGINS=1', () => {
|
|
10
|
+
assert.equal(isHookPluginFeatureEnabled({ OMX_HOOK_PLUGINS: '1' }), true);
|
|
11
|
+
});
|
|
12
|
+
it('returns false when env var is missing', () => {
|
|
13
|
+
assert.equal(isHookPluginFeatureEnabled({}), false);
|
|
14
|
+
});
|
|
15
|
+
it('returns false for "0"', () => {
|
|
16
|
+
assert.equal(isHookPluginFeatureEnabled({ OMX_HOOK_PLUGINS: '0' }), false);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('dispatchHookEvent', () => {
|
|
20
|
+
it('returns disabled summary when plugins are disabled', async () => {
|
|
21
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
22
|
+
try {
|
|
23
|
+
const event = buildHookEvent('session-start');
|
|
24
|
+
const result = await dispatchHookEvent(event, {
|
|
25
|
+
cwd,
|
|
26
|
+
env: {},
|
|
27
|
+
enabled: false,
|
|
28
|
+
});
|
|
29
|
+
assert.equal(result.enabled, false);
|
|
30
|
+
assert.equal(result.reason, 'disabled');
|
|
31
|
+
assert.equal(result.event, 'session-start');
|
|
32
|
+
assert.equal(result.plugin_count, 0);
|
|
33
|
+
assert.deepEqual(result.results, []);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
await rm(cwd, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
it('returns enabled summary with zero plugins when hooks dir is empty', async () => {
|
|
40
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
41
|
+
try {
|
|
42
|
+
const event = buildHookEvent('session-start');
|
|
43
|
+
const result = await dispatchHookEvent(event, {
|
|
44
|
+
cwd,
|
|
45
|
+
env: { OMX_HOOK_PLUGINS: '1' },
|
|
46
|
+
});
|
|
47
|
+
assert.equal(result.enabled, true);
|
|
48
|
+
assert.equal(result.reason, 'ok');
|
|
49
|
+
assert.equal(result.plugin_count, 0);
|
|
50
|
+
assert.deepEqual(result.results, []);
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await rm(cwd, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
it('reports invalid_export for plugins without onHookEvent', async () => {
|
|
57
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
58
|
+
try {
|
|
59
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
60
|
+
await mkdir(dir, { recursive: true });
|
|
61
|
+
await writeFile(join(dir, 'bad.mjs'), 'export const x = 1;');
|
|
62
|
+
const event = buildHookEvent('session-start');
|
|
63
|
+
const result = await dispatchHookEvent(event, {
|
|
64
|
+
cwd,
|
|
65
|
+
env: { OMX_HOOK_PLUGINS: '1' },
|
|
66
|
+
});
|
|
67
|
+
assert.equal(result.enabled, true);
|
|
68
|
+
assert.equal(result.plugin_count, 1);
|
|
69
|
+
assert.equal(result.results.length, 1);
|
|
70
|
+
assert.equal(result.results[0].ok, false);
|
|
71
|
+
assert.equal(result.results[0].status, 'invalid_export');
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await rm(cwd, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it('dispatches valid plugins successfully', async () => {
|
|
78
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
79
|
+
try {
|
|
80
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
81
|
+
await mkdir(dir, { recursive: true });
|
|
82
|
+
await writeFile(join(dir, 'good.mjs'), 'export async function onHookEvent(event, sdk) { await sdk.state.write("ran", true); }');
|
|
83
|
+
const event = buildHookEvent('session-start');
|
|
84
|
+
const result = await dispatchHookEvent(event, {
|
|
85
|
+
cwd,
|
|
86
|
+
env: { ...process.env, OMX_HOOK_PLUGINS: '1' },
|
|
87
|
+
});
|
|
88
|
+
assert.equal(result.enabled, true);
|
|
89
|
+
assert.equal(result.plugin_count, 1);
|
|
90
|
+
assert.equal(result.results.length, 1);
|
|
91
|
+
assert.equal(result.results[0].ok, true);
|
|
92
|
+
assert.equal(result.results[0].plugin, 'good');
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await rm(cwd, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it('respects explicit enabled=true option', async () => {
|
|
99
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
100
|
+
try {
|
|
101
|
+
const event = buildHookEvent('session-start');
|
|
102
|
+
const result = await dispatchHookEvent(event, {
|
|
103
|
+
cwd,
|
|
104
|
+
env: {},
|
|
105
|
+
enabled: true,
|
|
106
|
+
});
|
|
107
|
+
assert.equal(result.enabled, true);
|
|
108
|
+
assert.equal(result.plugin_count, 0);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await rm(cwd, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
it('includes source from event in summary', async () => {
|
|
115
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
116
|
+
try {
|
|
117
|
+
const event = buildHookEvent('needs-input');
|
|
118
|
+
const result = await dispatchHookEvent(event, {
|
|
119
|
+
cwd,
|
|
120
|
+
enabled: false,
|
|
121
|
+
});
|
|
122
|
+
assert.equal(result.source, 'derived');
|
|
123
|
+
assert.equal(result.event, 'needs-input');
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
await rm(cwd, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
it('disables side effects for team workers by default', async () => {
|
|
130
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-dispatch-'));
|
|
131
|
+
try {
|
|
132
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
133
|
+
await mkdir(dir, { recursive: true });
|
|
134
|
+
await writeFile(join(dir, 'se-test.mjs'), `export async function onHookEvent(event, sdk) {
|
|
135
|
+
const result = await sdk.tmux.sendKeys({ text: 'hello' });
|
|
136
|
+
await sdk.state.write('send_result', result.reason);
|
|
137
|
+
}`);
|
|
138
|
+
const event = buildHookEvent('session-start');
|
|
139
|
+
const result = await dispatchHookEvent(event, {
|
|
140
|
+
cwd,
|
|
141
|
+
env: { ...process.env, OMX_HOOK_PLUGINS: '1', OMX_TEAM_WORKER: 'worker-1' },
|
|
142
|
+
});
|
|
143
|
+
assert.equal(result.enabled, true);
|
|
144
|
+
assert.equal(result.results.length, 1);
|
|
145
|
+
assert.equal(result.results[0].ok, true);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
await rm(cwd, { recursive: true, force: true });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=dispatcher.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/dispatcher.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/events.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { isDerivedEventName, buildHookEvent, buildNativeHookEvent, buildDerivedHookEvent } from '../events.js';
|
|
4
|
+
describe('isDerivedEventName', () => {
|
|
5
|
+
it('returns true for derived events', () => {
|
|
6
|
+
assert.equal(isDerivedEventName('needs-input'), true);
|
|
7
|
+
assert.equal(isDerivedEventName('pre-tool-use'), true);
|
|
8
|
+
assert.equal(isDerivedEventName('post-tool-use'), true);
|
|
9
|
+
});
|
|
10
|
+
it('returns false for native events', () => {
|
|
11
|
+
assert.equal(isDerivedEventName('session-start'), false);
|
|
12
|
+
assert.equal(isDerivedEventName('session-end'), false);
|
|
13
|
+
assert.equal(isDerivedEventName('turn-complete'), false);
|
|
14
|
+
});
|
|
15
|
+
it('returns false for unknown events', () => {
|
|
16
|
+
assert.equal(isDerivedEventName('custom-event'), false);
|
|
17
|
+
assert.equal(isDerivedEventName(''), false);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('buildHookEvent', () => {
|
|
21
|
+
it('creates envelope with required fields', () => {
|
|
22
|
+
const envelope = buildHookEvent('session-start');
|
|
23
|
+
assert.equal(envelope.schema_version, '1');
|
|
24
|
+
assert.equal(envelope.event, 'session-start');
|
|
25
|
+
assert.equal(envelope.source, 'native');
|
|
26
|
+
assert.ok(envelope.timestamp);
|
|
27
|
+
assert.deepEqual(envelope.context, {});
|
|
28
|
+
});
|
|
29
|
+
it('auto-detects derived source for derived events', () => {
|
|
30
|
+
const envelope = buildHookEvent('needs-input');
|
|
31
|
+
assert.equal(envelope.source, 'derived');
|
|
32
|
+
assert.equal(typeof envelope.confidence, 'number');
|
|
33
|
+
});
|
|
34
|
+
it('uses explicit source when provided', () => {
|
|
35
|
+
const envelope = buildHookEvent('needs-input', { source: 'native' });
|
|
36
|
+
assert.equal(envelope.source, 'native');
|
|
37
|
+
});
|
|
38
|
+
it('includes optional fields when provided', () => {
|
|
39
|
+
const envelope = buildHookEvent('session-start', {
|
|
40
|
+
session_id: 's1',
|
|
41
|
+
thread_id: 't1',
|
|
42
|
+
turn_id: 'u1',
|
|
43
|
+
mode: 'autopilot',
|
|
44
|
+
context: { foo: 'bar' },
|
|
45
|
+
timestamp: '2026-01-01T00:00:00Z',
|
|
46
|
+
});
|
|
47
|
+
assert.equal(envelope.session_id, 's1');
|
|
48
|
+
assert.equal(envelope.thread_id, 't1');
|
|
49
|
+
assert.equal(envelope.turn_id, 'u1');
|
|
50
|
+
assert.equal(envelope.mode, 'autopilot');
|
|
51
|
+
assert.deepEqual(envelope.context, { foo: 'bar' });
|
|
52
|
+
assert.equal(envelope.timestamp, '2026-01-01T00:00:00Z');
|
|
53
|
+
});
|
|
54
|
+
it('clamps confidence to [0, 1] range', () => {
|
|
55
|
+
const low = buildHookEvent('needs-input', { confidence: -5 });
|
|
56
|
+
assert.equal(low.confidence, 0);
|
|
57
|
+
const high = buildHookEvent('needs-input', { confidence: 99 });
|
|
58
|
+
assert.equal(high.confidence, 1);
|
|
59
|
+
const normal = buildHookEvent('needs-input', { confidence: 0.75 });
|
|
60
|
+
assert.equal(normal.confidence, 0.75);
|
|
61
|
+
});
|
|
62
|
+
it('uses default confidence 0.5 for derived events without explicit confidence', () => {
|
|
63
|
+
const envelope = buildHookEvent('pre-tool-use');
|
|
64
|
+
assert.equal(envelope.confidence, 0.5);
|
|
65
|
+
});
|
|
66
|
+
it('ignores non-finite confidence values', () => {
|
|
67
|
+
const envelope = buildHookEvent('needs-input', { confidence: NaN });
|
|
68
|
+
assert.equal(envelope.confidence, 0.5);
|
|
69
|
+
});
|
|
70
|
+
it('includes parser_reason for derived events', () => {
|
|
71
|
+
const envelope = buildHookEvent('needs-input', {
|
|
72
|
+
parser_reason: 'stall detected',
|
|
73
|
+
});
|
|
74
|
+
assert.equal(envelope.parser_reason, 'stall detected');
|
|
75
|
+
});
|
|
76
|
+
it('treats non-object context as empty object', () => {
|
|
77
|
+
const envelope = buildHookEvent('session-start', {
|
|
78
|
+
context: null,
|
|
79
|
+
});
|
|
80
|
+
assert.deepEqual(envelope.context, {});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('buildNativeHookEvent', () => {
|
|
84
|
+
it('always sets source to native', () => {
|
|
85
|
+
const envelope = buildNativeHookEvent('needs-input', { key: 'val' });
|
|
86
|
+
assert.equal(envelope.source, 'native');
|
|
87
|
+
assert.deepEqual(envelope.context, { key: 'val' });
|
|
88
|
+
});
|
|
89
|
+
it('does not include confidence for native events', () => {
|
|
90
|
+
const envelope = buildNativeHookEvent('session-start');
|
|
91
|
+
assert.equal(envelope.confidence, undefined);
|
|
92
|
+
});
|
|
93
|
+
it('passes through optional fields', () => {
|
|
94
|
+
const envelope = buildNativeHookEvent('session-start', {}, {
|
|
95
|
+
session_id: 'abc',
|
|
96
|
+
});
|
|
97
|
+
assert.equal(envelope.session_id, 'abc');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('buildDerivedHookEvent', () => {
|
|
101
|
+
it('always sets source to derived', () => {
|
|
102
|
+
const envelope = buildDerivedHookEvent('session-start', { x: 1 });
|
|
103
|
+
assert.equal(envelope.source, 'derived');
|
|
104
|
+
assert.deepEqual(envelope.context, { x: 1 });
|
|
105
|
+
});
|
|
106
|
+
it('includes default confidence of 0.5', () => {
|
|
107
|
+
const envelope = buildDerivedHookEvent('custom-event');
|
|
108
|
+
assert.equal(envelope.confidence, 0.5);
|
|
109
|
+
});
|
|
110
|
+
it('allows custom confidence', () => {
|
|
111
|
+
const envelope = buildDerivedHookEvent('custom-event', {}, {
|
|
112
|
+
confidence: 0.9,
|
|
113
|
+
});
|
|
114
|
+
assert.equal(envelope.confidence, 0.9);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=events.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/events.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import { HOOK_PLUGIN_ENABLE_ENV, HOOK_PLUGIN_TIMEOUT_ENV, hooksDir, isHookPluginsEnabled, resolveHookPluginTimeoutMs, ensureHooksDir, discoverHookPlugins, validateHookPluginExport, loadHookPluginDescriptors, } from '../loader.js';
|
|
8
|
+
describe('hooksDir', () => {
|
|
9
|
+
it('returns .omx/hooks under cwd', () => {
|
|
10
|
+
assert.equal(hooksDir('/project'), join('/project', '.omx', 'hooks'));
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe('isHookPluginsEnabled', () => {
|
|
14
|
+
it('returns true for "1"', () => {
|
|
15
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: '1' }), true);
|
|
16
|
+
});
|
|
17
|
+
it('returns true for "true"', () => {
|
|
18
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: 'true' }), true);
|
|
19
|
+
});
|
|
20
|
+
it('returns true for "yes"', () => {
|
|
21
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: 'yes' }), true);
|
|
22
|
+
});
|
|
23
|
+
it('returns true for "TRUE" (case insensitive)', () => {
|
|
24
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: 'TRUE' }), true);
|
|
25
|
+
});
|
|
26
|
+
it('returns false for "0"', () => {
|
|
27
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: '0' }), false);
|
|
28
|
+
});
|
|
29
|
+
it('returns false for empty string', () => {
|
|
30
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: '' }), false);
|
|
31
|
+
});
|
|
32
|
+
it('returns false when env var is missing', () => {
|
|
33
|
+
assert.equal(isHookPluginsEnabled({}), false);
|
|
34
|
+
});
|
|
35
|
+
it('returns false for arbitrary string', () => {
|
|
36
|
+
assert.equal(isHookPluginsEnabled({ [HOOK_PLUGIN_ENABLE_ENV]: 'enabled' }), false);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('resolveHookPluginTimeoutMs', () => {
|
|
40
|
+
it('returns fallback when env var is missing', () => {
|
|
41
|
+
assert.equal(resolveHookPluginTimeoutMs({}), 1500);
|
|
42
|
+
});
|
|
43
|
+
it('returns custom fallback', () => {
|
|
44
|
+
assert.equal(resolveHookPluginTimeoutMs({}, 3000), 3000);
|
|
45
|
+
});
|
|
46
|
+
it('parses valid numeric string', () => {
|
|
47
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: '5000' }), 5000);
|
|
48
|
+
});
|
|
49
|
+
it('clamps to minimum of 100', () => {
|
|
50
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: '10' }), 100);
|
|
51
|
+
});
|
|
52
|
+
it('clamps to maximum of 60000', () => {
|
|
53
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: '999999' }), 60000);
|
|
54
|
+
});
|
|
55
|
+
it('floors fractional values', () => {
|
|
56
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: '2500.9' }), 2500);
|
|
57
|
+
});
|
|
58
|
+
it('returns fallback for non-numeric string', () => {
|
|
59
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: 'abc' }), 1500);
|
|
60
|
+
});
|
|
61
|
+
it('returns fallback for empty string', () => {
|
|
62
|
+
assert.equal(resolveHookPluginTimeoutMs({ [HOOK_PLUGIN_TIMEOUT_ENV]: '' }), 1500);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('ensureHooksDir', () => {
|
|
66
|
+
it('creates .omx/hooks directory and returns path', async () => {
|
|
67
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-ensure-'));
|
|
68
|
+
try {
|
|
69
|
+
const dir = await ensureHooksDir(cwd);
|
|
70
|
+
assert.equal(dir, join(cwd, '.omx', 'hooks'));
|
|
71
|
+
assert.ok(existsSync(dir));
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await rm(cwd, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('discoverHookPlugins', () => {
|
|
79
|
+
it('returns empty array when hooks directory does not exist', async () => {
|
|
80
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-discover-'));
|
|
81
|
+
try {
|
|
82
|
+
const plugins = await discoverHookPlugins(cwd);
|
|
83
|
+
assert.deepEqual(plugins, []);
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await rm(cwd, { recursive: true, force: true });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
it('discovers .mjs files in hooks directory', async () => {
|
|
90
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-discover-'));
|
|
91
|
+
try {
|
|
92
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
93
|
+
await mkdir(dir, { recursive: true });
|
|
94
|
+
await writeFile(join(dir, 'alpha.mjs'), 'export function onHookEvent() {}');
|
|
95
|
+
await writeFile(join(dir, 'beta.mjs'), 'export function onHookEvent() {}');
|
|
96
|
+
await writeFile(join(dir, 'readme.txt'), 'not a plugin');
|
|
97
|
+
const plugins = await discoverHookPlugins(cwd);
|
|
98
|
+
assert.equal(plugins.length, 2);
|
|
99
|
+
assert.equal(plugins[0].id, 'alpha');
|
|
100
|
+
assert.equal(plugins[0].file, 'alpha.mjs');
|
|
101
|
+
assert.equal(plugins[1].id, 'beta');
|
|
102
|
+
assert.equal(plugins[1].file, 'beta.mjs');
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await rm(cwd, { recursive: true, force: true });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
it('sorts plugins alphabetically by file name', async () => {
|
|
109
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-discover-'));
|
|
110
|
+
try {
|
|
111
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
112
|
+
await mkdir(dir, { recursive: true });
|
|
113
|
+
await writeFile(join(dir, 'z-last.mjs'), 'export function onHookEvent() {}');
|
|
114
|
+
await writeFile(join(dir, 'a-first.mjs'), 'export function onHookEvent() {}');
|
|
115
|
+
const plugins = await discoverHookPlugins(cwd);
|
|
116
|
+
assert.equal(plugins[0].file, 'a-first.mjs');
|
|
117
|
+
assert.equal(plugins[1].file, 'z-last.mjs');
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
await rm(cwd, { recursive: true, force: true });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
it('sanitizes plugin id from file name', async () => {
|
|
124
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-discover-'));
|
|
125
|
+
try {
|
|
126
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
127
|
+
await mkdir(dir, { recursive: true });
|
|
128
|
+
await writeFile(join(dir, 'My Plugin!!(v2).mjs'), 'export function onHookEvent() {}');
|
|
129
|
+
const plugins = await discoverHookPlugins(cwd);
|
|
130
|
+
assert.equal(plugins.length, 1);
|
|
131
|
+
assert.match(plugins[0].id, /^[a-z0-9_-]+$/);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
await rm(cwd, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
it('skips subdirectories', async () => {
|
|
138
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-discover-'));
|
|
139
|
+
try {
|
|
140
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
141
|
+
await mkdir(join(dir, 'subdir.mjs'), { recursive: true });
|
|
142
|
+
await writeFile(join(dir, 'real.mjs'), 'export function onHookEvent() {}');
|
|
143
|
+
const plugins = await discoverHookPlugins(cwd);
|
|
144
|
+
assert.equal(plugins.length, 1);
|
|
145
|
+
assert.equal(plugins[0].file, 'real.mjs');
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
await rm(cwd, { recursive: true, force: true });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('validateHookPluginExport', () => {
|
|
153
|
+
it('returns valid for plugin with onHookEvent export', async () => {
|
|
154
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-validate-'));
|
|
155
|
+
try {
|
|
156
|
+
const pluginPath = join(cwd, 'valid.mjs');
|
|
157
|
+
await writeFile(pluginPath, 'export function onHookEvent() {}');
|
|
158
|
+
const result = await validateHookPluginExport(pluginPath);
|
|
159
|
+
assert.equal(result.valid, true);
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
await rm(cwd, { recursive: true, force: true });
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
it('returns invalid for plugin without onHookEvent export', async () => {
|
|
166
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-validate-'));
|
|
167
|
+
try {
|
|
168
|
+
const pluginPath = join(cwd, 'invalid.mjs');
|
|
169
|
+
await writeFile(pluginPath, 'export function hello() {}');
|
|
170
|
+
const result = await validateHookPluginExport(pluginPath);
|
|
171
|
+
assert.equal(result.valid, false);
|
|
172
|
+
assert.ok(result.reason);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
await rm(cwd, { recursive: true, force: true });
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
it('returns invalid for nonexistent file', async () => {
|
|
179
|
+
const result = await validateHookPluginExport('/nonexistent/plugin.mjs');
|
|
180
|
+
assert.equal(result.valid, false);
|
|
181
|
+
assert.ok(result.reason);
|
|
182
|
+
});
|
|
183
|
+
it('returns invalid for plugin with syntax error', async () => {
|
|
184
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-validate-'));
|
|
185
|
+
try {
|
|
186
|
+
const pluginPath = join(cwd, 'broken.mjs');
|
|
187
|
+
await writeFile(pluginPath, 'export function {{{');
|
|
188
|
+
const result = await validateHookPluginExport(pluginPath);
|
|
189
|
+
assert.equal(result.valid, false);
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
await rm(cwd, { recursive: true, force: true });
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('loadHookPluginDescriptors', () => {
|
|
197
|
+
it('returns empty array when no hooks directory', async () => {
|
|
198
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-load-'));
|
|
199
|
+
try {
|
|
200
|
+
const descriptors = await loadHookPluginDescriptors(cwd);
|
|
201
|
+
assert.deepEqual(descriptors, []);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await rm(cwd, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
it('returns descriptors with validation status', async () => {
|
|
208
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-load-'));
|
|
209
|
+
try {
|
|
210
|
+
const dir = join(cwd, '.omx', 'hooks');
|
|
211
|
+
await mkdir(dir, { recursive: true });
|
|
212
|
+
await writeFile(join(dir, 'good.mjs'), 'export function onHookEvent() {}');
|
|
213
|
+
await writeFile(join(dir, 'bad.mjs'), 'export const x = 1;');
|
|
214
|
+
const descriptors = await loadHookPluginDescriptors(cwd);
|
|
215
|
+
assert.equal(descriptors.length, 2);
|
|
216
|
+
const bad = descriptors.find((d) => d.id === 'bad');
|
|
217
|
+
const good = descriptors.find((d) => d.id === 'good');
|
|
218
|
+
assert.ok(bad);
|
|
219
|
+
assert.ok(good);
|
|
220
|
+
assert.equal(bad.valid, false);
|
|
221
|
+
assert.ok(bad.reason);
|
|
222
|
+
assert.equal(good.valid, true);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
await rm(cwd, { recursive: true, force: true });
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/logging.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import { hookLogPath, appendHookPluginLog } from '../logging.js';
|
|
7
|
+
describe('hookLogPath', () => {
|
|
8
|
+
it('returns .omx/logs/hooks-<date>.jsonl path', () => {
|
|
9
|
+
const result = hookLogPath('/project', new Date('2026-03-15T12:00:00Z'));
|
|
10
|
+
assert.equal(result, join('/project', '.omx', 'logs', 'hooks-2026-03-15.jsonl'));
|
|
11
|
+
});
|
|
12
|
+
it('uses current date when no timestamp provided', () => {
|
|
13
|
+
const result = hookLogPath('/project');
|
|
14
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
15
|
+
assert.equal(result, join('/project', '.omx', 'logs', `hooks-${today}.jsonl`));
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe('appendHookPluginLog', () => {
|
|
19
|
+
it('creates log directory and appends JSONL entry', async () => {
|
|
20
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-log-'));
|
|
21
|
+
try {
|
|
22
|
+
const entry = {
|
|
23
|
+
timestamp: '2026-01-15T10:00:00.000Z',
|
|
24
|
+
event: 'session-start',
|
|
25
|
+
plugin_id: 'my-plugin',
|
|
26
|
+
status: 'ok',
|
|
27
|
+
};
|
|
28
|
+
await appendHookPluginLog(cwd, entry);
|
|
29
|
+
const logFile = hookLogPath(cwd, new Date('2026-01-15T10:00:00.000Z'));
|
|
30
|
+
const content = await readFile(logFile, 'utf-8');
|
|
31
|
+
const parsed = JSON.parse(content.trim());
|
|
32
|
+
assert.equal(parsed.timestamp, '2026-01-15T10:00:00.000Z');
|
|
33
|
+
assert.equal(parsed.event, 'session-start');
|
|
34
|
+
assert.equal(parsed.plugin_id, 'my-plugin');
|
|
35
|
+
assert.equal(parsed.status, 'ok');
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await rm(cwd, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
it('appends multiple entries as separate lines', async () => {
|
|
42
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-log-'));
|
|
43
|
+
try {
|
|
44
|
+
const ts = '2026-02-01T00:00:00.000Z';
|
|
45
|
+
await appendHookPluginLog(cwd, { timestamp: ts, event: 'e1' });
|
|
46
|
+
await appendHookPluginLog(cwd, { timestamp: ts, event: 'e2' });
|
|
47
|
+
const logFile = hookLogPath(cwd, new Date(ts));
|
|
48
|
+
const lines = (await readFile(logFile, 'utf-8')).trim().split('\n');
|
|
49
|
+
assert.equal(lines.length, 2);
|
|
50
|
+
assert.equal(JSON.parse(lines[0]).event, 'e1');
|
|
51
|
+
assert.equal(JSON.parse(lines[1]).event, 'e2');
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
await rm(cwd, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
it('uses current timestamp when entry has no timestamp', async () => {
|
|
58
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-log-'));
|
|
59
|
+
try {
|
|
60
|
+
const before = new Date().toISOString();
|
|
61
|
+
await appendHookPluginLog(cwd, { event: 'test-event' });
|
|
62
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
63
|
+
const logFile = join(cwd, '.omx', 'logs', `hooks-${today}.jsonl`);
|
|
64
|
+
const content = await readFile(logFile, 'utf-8');
|
|
65
|
+
const parsed = JSON.parse(content.trim());
|
|
66
|
+
assert.ok(parsed.timestamp >= before);
|
|
67
|
+
assert.equal(parsed.event, 'test-event');
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
await rm(cwd, { recursive: true, force: true });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=logging.test.js.map
|