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 @@
1
+ {"version":3,"file":"logging.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/logging.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin-runner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-runner.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/plugin-runner.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,202 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawn } from 'node:child_process';
3
+ import { 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
+ const RESULT_PREFIX = '__OMX_PLUGIN_RESULT__ ';
8
+ function getRunnerPath() {
9
+ // Resolve from dist after build
10
+ return join(process.cwd(), 'dist', 'hooks', 'extensibility', 'plugin-runner.js');
11
+ }
12
+ function runRunner(input) {
13
+ return new Promise((resolve) => {
14
+ const child = spawn(process.execPath, [getRunnerPath()], {
15
+ stdio: ['pipe', 'pipe', 'pipe'],
16
+ });
17
+ let stdout = '';
18
+ let stderr = '';
19
+ child.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
20
+ child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
21
+ child.on('close', (code) => {
22
+ const lines = stdout.split('\n').filter(Boolean);
23
+ const resultLine = [...lines].reverse().find((l) => l.startsWith(RESULT_PREFIX));
24
+ let result = null;
25
+ if (resultLine) {
26
+ try {
27
+ result = JSON.parse(resultLine.slice(RESULT_PREFIX.length));
28
+ }
29
+ catch {
30
+ result = null;
31
+ }
32
+ }
33
+ resolve({ stdout, stderr, code, result });
34
+ });
35
+ child.stdin.write(JSON.stringify(input));
36
+ child.stdin.end();
37
+ });
38
+ }
39
+ describe('plugin-runner', () => {
40
+ it('emits error for empty stdin', async () => {
41
+ const { result, code } = await new Promise((resolve) => {
42
+ const child = spawn(process.execPath, [getRunnerPath()], {
43
+ stdio: ['pipe', 'pipe', 'pipe'],
44
+ });
45
+ let stdout = '';
46
+ child.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
47
+ child.on('close', (exitCode) => {
48
+ const lines = stdout.split('\n').filter(Boolean);
49
+ const resultLine = [...lines].reverse().find((l) => l.startsWith(RESULT_PREFIX));
50
+ let parsed = null;
51
+ if (resultLine) {
52
+ try {
53
+ parsed = JSON.parse(resultLine.slice(RESULT_PREFIX.length));
54
+ }
55
+ catch {
56
+ parsed = null;
57
+ }
58
+ }
59
+ resolve({ result: parsed, code: exitCode });
60
+ });
61
+ child.stdin.end('');
62
+ });
63
+ assert.ok(result);
64
+ assert.equal(result.ok, false);
65
+ assert.equal(result.reason, 'empty_request');
66
+ assert.equal(code, 1);
67
+ });
68
+ it('emits error for invalid JSON', async () => {
69
+ const { result, code } = await new Promise((resolve) => {
70
+ const child = spawn(process.execPath, [getRunnerPath()], {
71
+ stdio: ['pipe', 'pipe', 'pipe'],
72
+ });
73
+ let stdout = '';
74
+ child.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
75
+ child.on('close', (exitCode) => {
76
+ const lines = stdout.split('\n').filter(Boolean);
77
+ const resultLine = [...lines].reverse().find((l) => l.startsWith(RESULT_PREFIX));
78
+ let parsed = null;
79
+ if (resultLine) {
80
+ try {
81
+ parsed = JSON.parse(resultLine.slice(RESULT_PREFIX.length));
82
+ }
83
+ catch {
84
+ parsed = null;
85
+ }
86
+ }
87
+ resolve({ result: parsed, code: exitCode });
88
+ });
89
+ child.stdin.write('not json at all');
90
+ child.stdin.end();
91
+ });
92
+ assert.ok(result);
93
+ assert.equal(result.ok, false);
94
+ assert.equal(result.reason, 'invalid_json');
95
+ assert.equal(code, 1);
96
+ });
97
+ it('emits invalid_export for plugin without onHookEvent', async () => {
98
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runner-'));
99
+ try {
100
+ const pluginPath = join(cwd, 'no-export.mjs');
101
+ await writeFile(pluginPath, 'export const x = 1;');
102
+ const { result, code } = await runRunner({
103
+ cwd,
104
+ pluginId: 'no-export',
105
+ pluginPath,
106
+ event: {
107
+ schema_version: '1',
108
+ event: 'session-start',
109
+ timestamp: new Date().toISOString(),
110
+ source: 'native',
111
+ context: {},
112
+ },
113
+ });
114
+ assert.ok(result);
115
+ assert.equal(result.ok, false);
116
+ assert.equal(result.reason, 'invalid_export');
117
+ assert.equal(code, 1);
118
+ }
119
+ finally {
120
+ await rm(cwd, { recursive: true, force: true });
121
+ }
122
+ });
123
+ it('emits ok for valid plugin', async () => {
124
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runner-'));
125
+ try {
126
+ const pluginPath = join(cwd, 'valid.mjs');
127
+ await writeFile(pluginPath, 'export async function onHookEvent(event, sdk) {}');
128
+ const { result, code } = await runRunner({
129
+ cwd,
130
+ pluginId: 'valid',
131
+ pluginPath,
132
+ event: {
133
+ schema_version: '1',
134
+ event: 'session-start',
135
+ timestamp: new Date().toISOString(),
136
+ source: 'native',
137
+ context: {},
138
+ },
139
+ });
140
+ assert.ok(result);
141
+ assert.equal(result.ok, true);
142
+ assert.equal(result.reason, 'ok');
143
+ assert.equal(result.plugin, 'valid');
144
+ assert.equal(code, 0);
145
+ }
146
+ finally {
147
+ await rm(cwd, { recursive: true, force: true });
148
+ }
149
+ });
150
+ it('emits runner_error when plugin throws', async () => {
151
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runner-'));
152
+ try {
153
+ const pluginPath = join(cwd, 'throws.mjs');
154
+ await writeFile(pluginPath, 'export function onHookEvent() { throw new Error("boom"); }');
155
+ const { result, code } = await runRunner({
156
+ cwd,
157
+ pluginId: 'throws',
158
+ pluginPath,
159
+ event: {
160
+ schema_version: '1',
161
+ event: 'session-start',
162
+ timestamp: new Date().toISOString(),
163
+ source: 'native',
164
+ context: {},
165
+ },
166
+ });
167
+ assert.ok(result);
168
+ assert.equal(result.ok, false);
169
+ assert.equal(result.reason, 'runner_error');
170
+ assert.match(String(result.error), /boom/);
171
+ assert.equal(code, 1);
172
+ }
173
+ finally {
174
+ await rm(cwd, { recursive: true, force: true });
175
+ }
176
+ });
177
+ it('derives pluginId from path when not provided', async () => {
178
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runner-'));
179
+ try {
180
+ const pluginPath = join(cwd, 'derived-name.mjs');
181
+ await writeFile(pluginPath, 'export async function onHookEvent() {}');
182
+ const { result } = await runRunner({
183
+ cwd,
184
+ pluginPath,
185
+ event: {
186
+ schema_version: '1',
187
+ event: 'session-start',
188
+ timestamp: new Date().toISOString(),
189
+ source: 'native',
190
+ context: {},
191
+ },
192
+ });
193
+ assert.ok(result);
194
+ assert.equal(result.ok, true);
195
+ assert.equal(result.plugin, 'derived-name.mjs');
196
+ }
197
+ finally {
198
+ await rm(cwd, { recursive: true, force: true });
199
+ }
200
+ });
201
+ });
202
+ //# sourceMappingURL=plugin-runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-runner.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/plugin-runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/runtime.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,117 @@
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 { dispatchHookEventRuntime } from '../runtime.js';
7
+ import { buildHookEvent } from '../events.js';
8
+ describe('dispatchHookEventRuntime', () => {
9
+ it('returns disabled when plugins env var is not set', async () => {
10
+ const originalEnv = process.env.OMX_HOOK_PLUGINS;
11
+ try {
12
+ delete process.env.OMX_HOOK_PLUGINS;
13
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
14
+ try {
15
+ const event = buildHookEvent('session-start');
16
+ const result = await dispatchHookEventRuntime({ cwd, event });
17
+ assert.equal(result.dispatched, false);
18
+ assert.equal(result.reason, 'plugins_disabled');
19
+ assert.equal(result.result.enabled, false);
20
+ assert.equal(result.result.plugin_count, 0);
21
+ }
22
+ finally {
23
+ await rm(cwd, { recursive: true, force: true });
24
+ }
25
+ }
26
+ finally {
27
+ if (originalEnv !== undefined) {
28
+ process.env.OMX_HOOK_PLUGINS = originalEnv;
29
+ }
30
+ else {
31
+ delete process.env.OMX_HOOK_PLUGINS;
32
+ }
33
+ }
34
+ });
35
+ it('dispatches when plugins are enabled', async () => {
36
+ const originalEnv = process.env.OMX_HOOK_PLUGINS;
37
+ try {
38
+ process.env.OMX_HOOK_PLUGINS = '1';
39
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
40
+ try {
41
+ const dir = join(cwd, '.omx', 'hooks');
42
+ await mkdir(dir, { recursive: true });
43
+ await writeFile(join(dir, 'rt-test.mjs'), 'export async function onHookEvent() {}');
44
+ const event = buildHookEvent('session-start');
45
+ const result = await dispatchHookEventRuntime({ cwd, event });
46
+ assert.equal(result.dispatched, true);
47
+ assert.equal(result.reason, 'ok');
48
+ assert.equal(result.result.enabled, true);
49
+ assert.equal(result.result.plugin_count, 1);
50
+ }
51
+ finally {
52
+ await rm(cwd, { recursive: true, force: true });
53
+ }
54
+ }
55
+ finally {
56
+ if (originalEnv !== undefined) {
57
+ process.env.OMX_HOOK_PLUGINS = originalEnv;
58
+ }
59
+ else {
60
+ delete process.env.OMX_HOOK_PLUGINS;
61
+ }
62
+ }
63
+ });
64
+ it('passes allowTeamWorkerSideEffects through to dispatcher', async () => {
65
+ const originalEnv = process.env.OMX_HOOK_PLUGINS;
66
+ try {
67
+ process.env.OMX_HOOK_PLUGINS = '1';
68
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
69
+ try {
70
+ const event = buildHookEvent('turn-complete');
71
+ const result = await dispatchHookEventRuntime({
72
+ cwd,
73
+ event,
74
+ allowTeamWorkerSideEffects: true,
75
+ });
76
+ assert.equal(result.dispatched, true);
77
+ assert.equal(result.result.enabled, true);
78
+ }
79
+ finally {
80
+ await rm(cwd, { recursive: true, force: true });
81
+ }
82
+ }
83
+ finally {
84
+ if (originalEnv !== undefined) {
85
+ process.env.OMX_HOOK_PLUGINS = originalEnv;
86
+ }
87
+ else {
88
+ delete process.env.OMX_HOOK_PLUGINS;
89
+ }
90
+ }
91
+ });
92
+ it('returns event name and source in result', async () => {
93
+ const originalEnv = process.env.OMX_HOOK_PLUGINS;
94
+ try {
95
+ delete process.env.OMX_HOOK_PLUGINS;
96
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
97
+ try {
98
+ const event = buildHookEvent('needs-input');
99
+ const result = await dispatchHookEventRuntime({ cwd, event });
100
+ assert.equal(result.result.event, 'needs-input');
101
+ assert.equal(result.result.source, 'derived');
102
+ }
103
+ finally {
104
+ await rm(cwd, { recursive: true, force: true });
105
+ }
106
+ }
107
+ finally {
108
+ if (originalEnv !== undefined) {
109
+ process.env.OMX_HOOK_PLUGINS = originalEnv;
110
+ }
111
+ else {
112
+ delete process.env.OMX_HOOK_PLUGINS;
113
+ }
114
+ }
115
+ });
116
+ });
117
+ //# sourceMappingURL=runtime.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.test.js","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/runtime.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sdk.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.test.d.ts","sourceRoot":"","sources":["../../../../src/hooks/extensibility/__tests__/sdk.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,277 @@
1
+ import assert from 'node:assert/strict';
2
+ import { existsSync } from 'node:fs';
3
+ import { mkdtemp, mkdir, 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 { createHookPluginSdk, clearHookPluginState } from '../sdk.js';
8
+ function makeEvent(event = 'session-start') {
9
+ return {
10
+ schema_version: '1',
11
+ event,
12
+ timestamp: '2026-01-01T00:00:00.000Z',
13
+ source: 'native',
14
+ context: {},
15
+ };
16
+ }
17
+ describe('createHookPluginSdk', () => {
18
+ describe('state', () => {
19
+ it('reads undefined for missing key', async () => {
20
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
21
+ try {
22
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
23
+ const val = await sdk.state.read('nonexistent');
24
+ assert.equal(val, undefined);
25
+ }
26
+ finally {
27
+ await rm(cwd, { recursive: true, force: true });
28
+ }
29
+ });
30
+ it('returns fallback for missing key', async () => {
31
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
32
+ try {
33
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
34
+ const val = await sdk.state.read('missing', 42);
35
+ assert.equal(val, 42);
36
+ }
37
+ finally {
38
+ await rm(cwd, { recursive: true, force: true });
39
+ }
40
+ });
41
+ it('writes and reads state', async () => {
42
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
43
+ try {
44
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
45
+ await sdk.state.write('counter', 5);
46
+ const val = await sdk.state.read('counter');
47
+ assert.equal(val, 5);
48
+ }
49
+ finally {
50
+ await rm(cwd, { recursive: true, force: true });
51
+ }
52
+ });
53
+ it('deletes state key', async () => {
54
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
55
+ try {
56
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
57
+ await sdk.state.write('key', 'value');
58
+ await sdk.state.delete('key');
59
+ const val = await sdk.state.read('key');
60
+ assert.equal(val, undefined);
61
+ }
62
+ finally {
63
+ await rm(cwd, { recursive: true, force: true });
64
+ }
65
+ });
66
+ it('delete is a no-op for nonexistent key', async () => {
67
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
68
+ try {
69
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
70
+ await sdk.state.write('keep', 'yes');
71
+ await sdk.state.delete('nonexistent');
72
+ const val = await sdk.state.read('keep');
73
+ assert.equal(val, 'yes');
74
+ }
75
+ finally {
76
+ await rm(cwd, { recursive: true, force: true });
77
+ }
78
+ });
79
+ it('reads all state', async () => {
80
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
81
+ try {
82
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
83
+ await sdk.state.write('a', 1);
84
+ await sdk.state.write('b', 'two');
85
+ const all = await sdk.state.all();
86
+ assert.deepEqual(all, { a: 1, b: 'two' });
87
+ }
88
+ finally {
89
+ await rm(cwd, { recursive: true, force: true });
90
+ }
91
+ });
92
+ it('returns empty object for all() with no state', async () => {
93
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
94
+ try {
95
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
96
+ const all = await sdk.state.all();
97
+ assert.deepEqual(all, {});
98
+ }
99
+ finally {
100
+ await rm(cwd, { recursive: true, force: true });
101
+ }
102
+ });
103
+ it('rejects empty state key', async () => {
104
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
105
+ try {
106
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
107
+ await assert.rejects(() => sdk.state.read(''), /state key is required/);
108
+ }
109
+ finally {
110
+ await rm(cwd, { recursive: true, force: true });
111
+ }
112
+ });
113
+ it('rejects state key with path traversal', async () => {
114
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
115
+ try {
116
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
117
+ await assert.rejects(() => sdk.state.read('../escape'), /invalid state key/);
118
+ }
119
+ finally {
120
+ await rm(cwd, { recursive: true, force: true });
121
+ }
122
+ });
123
+ it('rejects state key starting with /', async () => {
124
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
125
+ try {
126
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
127
+ await assert.rejects(() => sdk.state.write('/absolute', 1), /invalid state key/);
128
+ }
129
+ finally {
130
+ await rm(cwd, { recursive: true, force: true });
131
+ }
132
+ });
133
+ });
134
+ describe('log', () => {
135
+ it('exposes info, warn, error methods', async () => {
136
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
137
+ try {
138
+ const sdk = createHookPluginSdk({ cwd, pluginName: 'test', event: makeEvent() });
139
+ // These should not throw
140
+ await sdk.log.info('test info');
141
+ await sdk.log.warn('test warn');
142
+ await sdk.log.error('test error');
143
+ }
144
+ finally {
145
+ await rm(cwd, { recursive: true, force: true });
146
+ }
147
+ });
148
+ });
149
+ describe('tmux.sendKeys', () => {
150
+ it('returns side_effects_disabled when sideEffectsEnabled is false', async () => {
151
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
152
+ try {
153
+ const sdk = createHookPluginSdk({
154
+ cwd,
155
+ pluginName: 'test',
156
+ event: makeEvent(),
157
+ sideEffectsEnabled: false,
158
+ });
159
+ const result = await sdk.tmux.sendKeys({ text: 'hello' });
160
+ assert.equal(result.ok, false);
161
+ assert.equal(result.reason, 'side_effects_disabled');
162
+ }
163
+ finally {
164
+ await rm(cwd, { recursive: true, force: true });
165
+ }
166
+ });
167
+ it('returns invalid_text for empty text', async () => {
168
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
169
+ try {
170
+ const sdk = createHookPluginSdk({
171
+ cwd,
172
+ pluginName: 'test',
173
+ event: makeEvent(),
174
+ sideEffectsEnabled: true,
175
+ });
176
+ const result = await sdk.tmux.sendKeys({ text: ' ' });
177
+ assert.equal(result.ok, false);
178
+ assert.equal(result.reason, 'invalid_text');
179
+ }
180
+ finally {
181
+ await rm(cwd, { recursive: true, force: true });
182
+ }
183
+ });
184
+ it('returns loop_guard_input_marker when text contains loop marker', async () => {
185
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
186
+ const originalMarker = process.env.OMX_HOOK_PLUGIN_LOOP_MARKER;
187
+ try {
188
+ process.env.OMX_HOOK_PLUGIN_LOOP_MARKER = '[TESTMARK]';
189
+ const sdk = createHookPluginSdk({
190
+ cwd,
191
+ pluginName: 'test',
192
+ event: makeEvent(),
193
+ sideEffectsEnabled: true,
194
+ });
195
+ const result = await sdk.tmux.sendKeys({ text: 'hello [TESTMARK] world' });
196
+ assert.equal(result.ok, false);
197
+ assert.equal(result.reason, 'loop_guard_input_marker');
198
+ }
199
+ finally {
200
+ if (originalMarker === undefined) {
201
+ delete process.env.OMX_HOOK_PLUGIN_LOOP_MARKER;
202
+ }
203
+ else {
204
+ process.env.OMX_HOOK_PLUGIN_LOOP_MARKER = originalMarker;
205
+ }
206
+ await rm(cwd, { recursive: true, force: true });
207
+ }
208
+ });
209
+ it('returns target_missing when no pane is resolvable', async () => {
210
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
211
+ const originalPane = process.env.TMUX_PANE;
212
+ try {
213
+ delete process.env.TMUX_PANE;
214
+ const sdk = createHookPluginSdk({
215
+ cwd,
216
+ pluginName: 'test',
217
+ event: makeEvent(),
218
+ sideEffectsEnabled: true,
219
+ });
220
+ const result = await sdk.tmux.sendKeys({ text: 'hello' });
221
+ assert.equal(result.ok, false);
222
+ assert.equal(result.reason, 'target_missing');
223
+ }
224
+ finally {
225
+ if (originalPane !== undefined) {
226
+ process.env.TMUX_PANE = originalPane;
227
+ }
228
+ await rm(cwd, { recursive: true, force: true });
229
+ }
230
+ });
231
+ });
232
+ describe('plugin name sanitization', () => {
233
+ it('sanitizes special characters in plugin name', async () => {
234
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-sdk-'));
235
+ try {
236
+ const sdk = createHookPluginSdk({
237
+ cwd,
238
+ pluginName: 'my plugin!@#',
239
+ event: makeEvent(),
240
+ });
241
+ await sdk.state.write('test', 'value');
242
+ const val = await sdk.state.read('test');
243
+ assert.equal(val, 'value');
244
+ }
245
+ finally {
246
+ await rm(cwd, { recursive: true, force: true });
247
+ }
248
+ });
249
+ });
250
+ });
251
+ describe('clearHookPluginState', () => {
252
+ it('removes data.json and tmux.json for plugin', async () => {
253
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-clear-'));
254
+ try {
255
+ const pluginDir = join(cwd, '.omx', 'state', 'hooks', 'plugins', 'my-plugin');
256
+ await mkdir(pluginDir, { recursive: true });
257
+ await writeFile(join(pluginDir, 'data.json'), '{}');
258
+ await writeFile(join(pluginDir, 'tmux.json'), '{}');
259
+ await clearHookPluginState(cwd, 'my-plugin');
260
+ assert.equal(existsSync(join(pluginDir, 'data.json')), false);
261
+ assert.equal(existsSync(join(pluginDir, 'tmux.json')), false);
262
+ }
263
+ finally {
264
+ await rm(cwd, { recursive: true, force: true });
265
+ }
266
+ });
267
+ it('does not throw when files do not exist', async () => {
268
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-clear-'));
269
+ try {
270
+ await clearHookPluginState(cwd, 'nonexistent');
271
+ }
272
+ finally {
273
+ await rm(cwd, { recursive: true, force: true });
274
+ }
275
+ });
276
+ });
277
+ //# sourceMappingURL=sdk.test.js.map