@raidiant/notifai 1.0.1 → 1.1.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 (49) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +17 -7
  3. package/dist/commands.d.ts +2 -0
  4. package/dist/commands.js +31 -39
  5. package/dist/commands.js.map +1 -1
  6. package/dist/config.d.ts +2 -2
  7. package/dist/config.js +5 -9
  8. package/dist/config.js.map +1 -1
  9. package/dist/credentials.d.ts +54 -3
  10. package/dist/credentials.js +237 -18
  11. package/dist/credentials.js.map +1 -1
  12. package/dist/file-lock.js +15 -6
  13. package/dist/file-lock.js.map +1 -1
  14. package/dist/hook-adapter.d.ts +6 -2
  15. package/dist/hook-adapter.js +110 -29
  16. package/dist/hook-adapter.js.map +1 -1
  17. package/dist/hooks.js +2 -1
  18. package/dist/hooks.js.map +1 -1
  19. package/dist/install-hooks.d.ts +50 -21
  20. package/dist/install-hooks.js +141 -57
  21. package/dist/install-hooks.js.map +1 -1
  22. package/dist/native-skills.js +5 -10
  23. package/dist/native-skills.js.map +1 -1
  24. package/dist/opencode-plugin.d.ts +7 -2
  25. package/dist/opencode-plugin.js +142 -4
  26. package/dist/opencode-plugin.js.map +1 -1
  27. package/dist/platform.d.ts +73 -0
  28. package/dist/platform.js +143 -0
  29. package/dist/platform.js.map +1 -0
  30. package/dist/ui/config-view.js +5 -1
  31. package/dist/ui/config-view.js.map +1 -1
  32. package/package.json +3 -3
  33. package/src/commands.test.ts +100 -26
  34. package/src/commands.ts +49 -36
  35. package/src/config.ts +11 -9
  36. package/src/credentials.test.ts +291 -0
  37. package/src/credentials.ts +274 -17
  38. package/src/file-lock.ts +34 -9
  39. package/src/hook-adapter.test.ts +136 -0
  40. package/src/hook-adapter.ts +120 -28
  41. package/src/hooks.test.ts +27 -1
  42. package/src/hooks.ts +2 -1
  43. package/src/install-hooks.test.ts +174 -33
  44. package/src/install-hooks.ts +186 -54
  45. package/src/native-skills.ts +5 -10
  46. package/src/opencode-plugin.ts +148 -3
  47. package/src/platform.test.ts +152 -0
  48. package/src/platform.ts +173 -0
  49. package/src/ui/config-view.ts +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -47,7 +47,11 @@ export function renderConfigList(config, options = {}) {
47
47
  }
48
48
  }
49
49
  lines.push('');
50
- lines.push(style.dim(`${glyph.arrow} ${style.code('notifai config explain <key>')} for what one of these means and how to change it.`));
50
+ const command = 'notifai config explain <key>';
51
+ const help = `${glyph.arrow} ${command} for what one of these means and how to change it.`;
52
+ for (const line of wrap(help, columns)) {
53
+ lines.push(style.dim(line.replace(command, style.code(command))));
54
+ }
51
55
  return lines;
52
56
  }
53
57
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config-view.js","sourceRoot":"","sources":["../../src/ui/config-view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-view.js","sourceRoot":"","sources":["../../src/ui/config-view.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raidiant/notifai",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Send native phone notifications from agents and local programs",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "dependencies": {
16
16
  "@clack/prompts": "^1.7.0",
17
- "@raidiant/notifai-protocol": "0.3.0",
17
+ "@raidiant/notifai-protocol": "0.4.0",
18
18
  "commander": "^14.0.0",
19
19
  "picocolors": "^1.1.1",
20
20
  "smol-toml": "^1.4.0"
@@ -54,6 +54,6 @@
54
54
  "build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.json",
55
55
  "pretest": "pnpm run build",
56
56
  "typecheck": "tsc -p tsconfig.json --noEmit",
57
- "test": "vitest run"
57
+ "test": "node ../../scripts/run-cli-tests.mjs"
58
58
  }
59
59
  }
@@ -1,4 +1,13 @@
1
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, symlinkSync, writeFileSync } from 'node:fs'
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ mkdtempSync,
5
+ readFileSync,
6
+ readdirSync,
7
+ rmSync,
8
+ symlinkSync,
9
+ writeFileSync,
10
+ } from 'node:fs'
2
11
  import os from 'node:os'
3
12
  import path from 'node:path'
4
13
  import { fileURLToPath } from 'node:url'
@@ -10,7 +19,7 @@ import type {
10
19
  SubmissionReceipt,
11
20
  SubmitNotificationRequestT,
12
21
  } from '@raidiant/notifai-protocol'
13
- import { describe, expect, it } from 'vitest'
22
+ import { afterEach, describe, expect, it } from 'vitest'
14
23
  import { ApiCallError, NetworkError, type ApiClient } from './client.js'
15
24
  import type { ClaudeWakeAdapters } from './claude-wake.js'
16
25
  import {
@@ -51,7 +60,7 @@ import {
51
60
  } from './install-hooks.js'
52
61
  import { readSessionState, writeProjectSession, writeSessionState } from './hooks.js'
53
62
  import { nativeSkills as realNativeSkills, type NativeSkill, type NativeSkills, type SkillScope } from './native-skills.js'
54
- import { CONFIG_KEYS, loadConfig, personalProjectConfigPath } from './config.js'
63
+ import { CONFIG_KEYS, loadConfig, personalProjectConfigPath, stateDir } from './config.js'
55
64
  import { createLogger, logsDiskUsage, readLogRecords } from './logging.js'
56
65
  import { hookAdapterPath, inspectHookAdapter } from './hook-adapter.js'
57
66
  import type { Tone } from './ui/theme.js'
@@ -161,6 +170,29 @@ class InteractiveIo extends CapturedIo {
161
170
  }
162
171
 
163
172
  function trustInstalledCodexHooks(cwd: string, env: NodeJS.ProcessEnv): void {
173
+ const home = env['HOME']
174
+ if (home === undefined || home === '') {
175
+ throw new Error(
176
+ 'trustInstalledCodexHooks requires env.HOME; refusing to use the real home directory',
177
+ )
178
+ }
179
+ const resolvedHome = path.resolve(home)
180
+ const tmpRoot = path.resolve(os.tmpdir())
181
+ const underTmp = resolvedHome === tmpRoot || resolvedHome.startsWith(`${tmpRoot}${path.sep}`)
182
+ if (!underTmp) {
183
+ throw new Error(
184
+ `trustInstalledCodexHooks will only write under ${tmpRoot}, not ${resolvedHome}`,
185
+ )
186
+ }
187
+ const codexHome = env['CODEX_HOME'] !== undefined && env['CODEX_HOME'] !== ''
188
+ ? path.resolve(env['CODEX_HOME'])
189
+ : path.join(resolvedHome, '.codex')
190
+ if (codexHome !== tmpRoot && !codexHome.startsWith(`${tmpRoot}${path.sep}`)) {
191
+ throw new Error(
192
+ `trustInstalledCodexHooks will only write under ${tmpRoot}, not ${codexHome}`,
193
+ )
194
+ }
195
+ const file = path.join(codexHome, 'config.toml')
164
196
  const installations = findInstallations(cwd, env).filter(
165
197
  (installation) => installation.harness === 'codex',
166
198
  )
@@ -170,9 +202,7 @@ function trustInstalledCodexHooks(cwd: string, env: NodeJS.ProcessEnv): void {
170
202
  return `[hooks.state.${JSON.stringify(key)}]\ntrusted_hash = ${JSON.stringify(codexHookIdentityHash(handler))}\n`
171
203
  }),
172
204
  )
173
- const codexHome = env['CODEX_HOME'] as string
174
- mkdirSync(codexHome, { recursive: true })
175
- const file = path.join(codexHome, 'config.toml')
205
+ mkdirSync(path.dirname(file), { recursive: true })
176
206
  // Trust lives in the same config.toml as inline [hooks]. Overwriting the
177
207
  // file would delete the global handlers this helper is trying to trust.
178
208
  const existing = existsSync(file) ? readFileSync(file, 'utf8').trimEnd() : ''
@@ -219,6 +249,7 @@ function isolatedEnv(cwd: string): NodeJS.ProcessEnv {
219
249
  HOME: home,
220
250
  CLAUDE_CONFIG_DIR: path.join(home, '.claude'),
221
251
  CODEX_HOME: path.join(home, '.codex'),
252
+ OPENCODE_CONFIG_DIR: path.join(home, '.config', 'opencode'),
222
253
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
223
254
  XDG_STATE_HOME: path.join(cwd, 'state'),
224
255
  }
@@ -1225,6 +1256,7 @@ describe('Cursor hook commands', () => {
1225
1256
  XDG_STATE_HOME: path.join(cwd, 'state'),
1226
1257
  CODEX_HOME: path.join(cwd, 'codex'),
1227
1258
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude'),
1259
+ OPENCODE_CONFIG_DIR: path.join(cwd, 'opencode'),
1228
1260
  },
1229
1261
  store: { load: () => null, save: () => {}, clear: () => {}, describe: () => 'empty store' },
1230
1262
  }
@@ -1303,7 +1335,7 @@ describe('Codex hook representation', () => {
1303
1335
  expect(io.outLines.join('\n')).toMatch(/Stop and the existing one will both fire/i)
1304
1336
  })
1305
1337
 
1306
- it('collapses a leftover hooks.json onto inline [hooks] and says both Stops will run', async () => {
1338
+ it('preserves a foreign inline Stop while collapsing our duplicate definition', async () => {
1307
1339
  const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-codex-collapse-'))
1308
1340
  const toml = writeInlineStop(cwd, 'gdh-stop')
1309
1341
  const json = path.join(cwd, '.codex', 'hooks.json')
@@ -1485,7 +1517,11 @@ describe('harness activation guidance', () => {
1485
1517
  const deps = {
1486
1518
  ...makeDeps(io, {} as ApiClient),
1487
1519
  cwd,
1488
- env: { XDG_STATE_HOME: path.join(cwd, 'state') },
1520
+ env: {
1521
+ HOME: path.join(cwd, 'home'),
1522
+ XDG_STATE_HOME: path.join(cwd, 'state'),
1523
+ OPENCODE_CONFIG_DIR: path.join(cwd, 'opencode-home'),
1524
+ },
1489
1525
  }
1490
1526
 
1491
1527
  expect(hooksInstallCommand(deps, { harness: 'opencode', execPath, scriptPath })).toBe(
@@ -2120,6 +2156,7 @@ describe('init', () => {
2120
2156
  platform: 'ios' as const,
2121
2157
  permission_status: 'authorized',
2122
2158
  registration_healthy: true,
2159
+ reply_protocol_version: 1,
2123
2160
  last_seen_at: '2026-08-05T18:00:00.000Z',
2124
2161
  }
2125
2162
 
@@ -2492,8 +2529,8 @@ describe('init', () => {
2492
2529
  )
2493
2530
  expect(wired).toEqual(['claude-code', 'codex'])
2494
2531
  expect(existsSync(path.join(cwd, '.claude', 'settings.local.json'))).toBe(true)
2495
- expect(existsSync(path.join(cwd, '.codex', 'config.toml'))).toBe(true)
2496
- expect(existsSync(path.join(cwd, '.codex', 'hooks.json'))).toBe(false)
2532
+ expect(existsSync(path.join(cwd, '.codex', 'hooks.json'))).toBe(true)
2533
+ expect(existsSync(path.join(cwd, '.codex', 'config.toml'))).toBe(false)
2497
2534
  expect(io.outLines.join('\n')).toContain('Installed claude-code hooks')
2498
2535
  expect(io.outLines.join('\n')).toContain('Installed codex hooks')
2499
2536
  })
@@ -2664,6 +2701,7 @@ describe('init', () => {
2664
2701
  XDG_STATE_HOME: path.join(cwd, 'state'),
2665
2702
  CODEX_HOME: path.join(cwd, 'codex'),
2666
2703
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude'),
2704
+ OPENCODE_CONFIG_DIR: path.join(cwd, 'opencode'),
2667
2705
  },
2668
2706
  }
2669
2707
 
@@ -2753,6 +2791,9 @@ describe('init', () => {
2753
2791
  expect(io.notes.some((n) => n.message.includes('I will wait up to 10 minutes'))).toBe(true)
2754
2792
  expect(io.spinnerEvents).toContain('stop:iPhone is ready to receive')
2755
2793
  expect(io.spinnerEvents).toContain('stop:Receipt observed from iPhone')
2794
+ expect(io.outLines.join('\n')).toContain(
2795
+ "Companion Receipt (the app's delivery confirmation) observed from iPhone.",
2796
+ )
2756
2797
  expect(io.outLines.join('\n')).toContain('All set.')
2757
2798
  expect(submitCalls).toBe(1)
2758
2799
  expect(submittedDraft?.draft.event).toBe('setup_verified')
@@ -2895,6 +2936,8 @@ describe('init', () => {
2895
2936
  expect(io.outLines.join('\n')).toContain('Next: Delivery proof')
2896
2937
  expect(io.outLines.join('\n')).toContain('Provider accepted the notification')
2897
2938
  expect(io.outLines.join('\n')).toContain('Proof may still arrive')
2939
+ const proofDir = path.join(stateDir(deps.env), 'setup-proofs')
2940
+ expect(readdirSync(proofDir).some((name) => name.endsWith('.json'))).toBe(true)
2898
2941
 
2899
2942
  io.outLines = []
2900
2943
  io.errLines = []
@@ -3304,6 +3347,27 @@ describe('an outage is not an answer', () => {
3304
3347
  describe('asking before the hooks have ever run', () => {
3305
3348
  const execPath = process.execPath
3306
3349
  const scriptPath = fileURLToPath(import.meta.url)
3350
+ const scratch: string[] = []
3351
+
3352
+ function scratchDir(prefix: string): string {
3353
+ const dir = mkdtempSync(path.join(os.tmpdir(), prefix))
3354
+ scratch.push(dir)
3355
+ return dir
3356
+ }
3357
+
3358
+ afterEach(() => {
3359
+ while (scratch.length > 0) {
3360
+ rmSync(scratch.pop()!, { recursive: true, force: true })
3361
+ }
3362
+ })
3363
+
3364
+ it('refuses to write Codex trust outside the isolated test account', () => {
3365
+ expect(() => trustInstalledCodexHooks(os.tmpdir(), {})).toThrow(/requires env.HOME/)
3366
+ expect(() => trustInstalledCodexHooks(os.tmpdir(), { HOME: path.dirname(os.tmpdir()) })).toThrow(
3367
+ /will only write under/,
3368
+ )
3369
+ expect(os.homedir()).toBe(process.env['NOTIFAI_TEST_HOME'])
3370
+ })
3307
3371
 
3308
3372
  it('names the active Codex harness instead of unrelated installed adapters', () => {
3309
3373
  const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-active-codex-missing-'))
@@ -3311,6 +3375,7 @@ describe('asking before the hooks have ever run', () => {
3311
3375
  const env = {
3312
3376
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3313
3377
  XDG_STATE_HOME: path.join(cwd, 'state'),
3378
+ HOME: path.join(cwd, 'home'),
3314
3379
  CODEX_HOME: path.join(cwd, 'codex-home'),
3315
3380
  CODEX_THREAD_ID: 'codex-current-thread',
3316
3381
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude-home'),
@@ -3335,6 +3400,7 @@ describe('asking before the hooks have ever run', () => {
3335
3400
  const env = {
3336
3401
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3337
3402
  XDG_STATE_HOME: path.join(cwd, 'state'),
3403
+ HOME: path.join(cwd, 'home'),
3338
3404
  CODEX_HOME: path.join(cwd, 'codex-home'),
3339
3405
  CODEX_THREAD_ID: 'codex-current-thread',
3340
3406
  }
@@ -3353,11 +3419,12 @@ describe('asking before the hooks have ever run', () => {
3353
3419
  })
3354
3420
 
3355
3421
  it('registers only when the active Codex thread owns the project pointer', () => {
3356
- const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-active-codex-matching-'))
3422
+ const cwd = scratchDir('notifai-active-codex-matching-')
3357
3423
  const io = new CapturedIo()
3358
3424
  const env = {
3359
3425
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3360
3426
  XDG_STATE_HOME: path.join(cwd, 'state'),
3427
+ HOME: path.join(cwd, 'home'),
3361
3428
  CODEX_HOME: path.join(cwd, 'codex-home'),
3362
3429
  CODEX_THREAD_ID: 'codex-current-thread',
3363
3430
  }
@@ -3497,11 +3564,12 @@ describe('asking before the hooks have ever run', () => {
3497
3564
  })
3498
3565
 
3499
3566
  it('makes one work-resumption commitment per offered answer part of the asking turn', () => {
3500
- const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-ask-commitment-'))
3567
+ const cwd = scratchDir('notifai-ask-commitment-')
3501
3568
  const io = new CapturedIo()
3502
3569
  const env = {
3503
3570
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3504
3571
  XDG_STATE_HOME: path.join(cwd, 'state'),
3572
+ HOME: path.join(cwd, 'home'),
3505
3573
  CODEX_HOME: path.join(cwd, 'codex-home'),
3506
3574
  CODEX_THREAD_ID: 'codex-commitment-thread',
3507
3575
  }
@@ -3532,11 +3600,12 @@ describe('asking before the hooks have ever run', () => {
3532
3600
  })
3533
3601
 
3534
3602
  it('requires a concrete fallback for free-text answers before the turn ends', () => {
3535
- const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-ask-free-text-'))
3603
+ const cwd = scratchDir('notifai-ask-free-text-')
3536
3604
  const io = new CapturedIo()
3537
3605
  const env = {
3538
3606
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3539
3607
  XDG_STATE_HOME: path.join(cwd, 'state'),
3608
+ HOME: path.join(cwd, 'home'),
3540
3609
  CODEX_HOME: path.join(cwd, 'codex-home'),
3541
3610
  CODEX_THREAD_ID: 'codex-free-text-thread',
3542
3611
  }
@@ -3555,11 +3624,12 @@ describe('asking before the hooks have ever run', () => {
3555
3624
  })
3556
3625
 
3557
3626
  it('refuses a Codex question when the installed Stop definition is no longer trusted', async () => {
3558
- const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-codex-stale-trust-'))
3627
+ const cwd = scratchDir('notifai-codex-stale-trust-')
3559
3628
  const io = new CapturedIo()
3560
3629
  const env = {
3561
3630
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3562
3631
  XDG_STATE_HOME: path.join(cwd, 'state'),
3632
+ HOME: path.join(cwd, 'home'),
3563
3633
  CODEX_HOME: path.join(cwd, 'codex-home'),
3564
3634
  CODEX_THREAD_ID: 'codex-current-thread',
3565
3635
  }
@@ -3570,7 +3640,7 @@ describe('asking before the hooks have ever run', () => {
3570
3640
  .find((installation) => installation.harness === 'codex')
3571
3641
  ?.handlers.find((handler) => handler.event === 'Stop')
3572
3642
  expect(stop).toBeDefined()
3573
- const configFile = path.join(env.CODEX_HOME, 'config.toml')
3643
+ const configFile = path.join(env.CODEX_HOME!, 'config.toml')
3574
3644
  writeFileSync(
3575
3645
  configFile,
3576
3646
  readFileSync(configFile, 'utf8').replace(codexHookIdentityHash(stop!), 'sha256:obsolete'),
@@ -3594,6 +3664,7 @@ describe('asking before the hooks have ever run', () => {
3594
3664
  const env = {
3595
3665
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3596
3666
  XDG_STATE_HOME: path.join(cwd, 'state'),
3667
+ HOME: path.join(cwd, 'home'),
3597
3668
  CODEX_HOME: path.join(cwd, 'codex-home'),
3598
3669
  CODEX_THREAD_ID: 'codex-current-thread',
3599
3670
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude-home'),
@@ -3702,7 +3773,7 @@ describe('asking before the hooks have ever run', () => {
3702
3773
  })
3703
3774
 
3704
3775
  it('rejects duplicate active Codex definitions before registration', () => {
3705
- const cwd = mkdtempSync(path.join(os.tmpdir(), 'notifai-active-codex-duplicate-'))
3776
+ const cwd = scratchDir('notifai-active-codex-duplicate-')
3706
3777
  const io = new CapturedIo()
3707
3778
  const env = {
3708
3779
  HOME: path.join(cwd, 'home'),
@@ -3713,7 +3784,8 @@ describe('asking before the hooks have ever run', () => {
3713
3784
  }
3714
3785
  const deps = { ...makeDeps(io, {} as ApiClient), cwd, env, now: () => 42 }
3715
3786
  expect(hooksInstallCommand(deps, { harness: 'codex', execPath, scriptPath })).toBe(EXIT.ok)
3716
- applyPlan(path.join(env.CODEX_HOME, 'config.toml'), {
3787
+ mkdirSync(env.CODEX_HOME!, { recursive: true })
3788
+ applyPlan(path.join(env.CODEX_HOME!, 'config.toml'), {
3717
3789
  hooks: buildHookConfig({
3718
3790
  adapterPath: hookAdapterPath(deps.hookAdapterHome),
3719
3791
  harness: 'codex',
@@ -3822,6 +3894,7 @@ describe('asking before the hooks have ever run', () => {
3822
3894
  const env = {
3823
3895
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3824
3896
  XDG_STATE_HOME: path.join(cwd, 'state'),
3897
+ HOME: path.join(cwd, 'home'),
3825
3898
  CODEX_HOME: path.join(cwd, 'codex-home'),
3826
3899
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude-home'),
3827
3900
  CLAUDECODE: '1',
@@ -3844,6 +3917,7 @@ describe('asking before the hooks have ever run', () => {
3844
3917
  XDG_CONFIG_HOME: path.join(cwd, 'config'),
3845
3918
  XDG_STATE_HOME: path.join(cwd, 'state'),
3846
3919
  CLAUDE_CONFIG_DIR: path.join(cwd, 'claude-home'),
3920
+ HOME: path.join(cwd, 'home'),
3847
3921
  CODEX_HOME: path.join(cwd, 'codex-home'),
3848
3922
  CLAUDECODE: '1',
3849
3923
  CLAUDE_CODE_SESSION_ID: 'claude-current',
@@ -4026,7 +4100,12 @@ describe('asking before the hooks have ever run', () => {
4026
4100
  ...isolatedEnv(cwd),
4027
4101
  CODEX_THREAD_ID: '9f1c2b3a-4d5e-6f70-8192-a3b4c5d6e7f8',
4028
4102
  }
4029
- const deps = { ...makeDeps(io, {} as ApiClient), cwd, env }
4103
+ const deps = {
4104
+ ...makeDeps(io, {} as ApiClient),
4105
+ cwd,
4106
+ env,
4107
+ hookPlatform: 'darwin' as NodeJS.Platform,
4108
+ }
4030
4109
  expect(hooksInstallCommand(deps, { harness: 'codex', execPath, scriptPath })).toBe(EXIT.ok)
4031
4110
 
4032
4111
  io.outLines = []
@@ -4037,14 +4116,8 @@ describe('asking before the hooks have ever run', () => {
4037
4116
  io.outLines = []
4038
4117
  await doctorCommand(deps, {})
4039
4118
  const out = io.outLines.join('\n')
4040
- if (process.platform === 'darwin') {
4041
- expect(out).toMatch(/ok\s+hooks \(wake route\)/)
4042
- expect(out).toContain('can prove a stopped thread unowned before resuming it')
4043
- } else {
4044
- // Linux has no non-blocking `flock` through Node's `open(2)` flags, so
4045
- // the gate stays shut and doctor says so rather than implying a wake.
4046
- expect(out).toContain('nothing can be resumed')
4047
- }
4119
+ expect(out).toMatch(/ok\s+hooks \(wake route\)/)
4120
+ expect(out).toContain('can prove a stopped thread unowned before resuming it')
4048
4121
  })
4049
4122
 
4050
4123
  it('documents the failing exit contract in doctor JSON', async () => {
@@ -4123,6 +4196,7 @@ describe('asking before the hooks have ever run', () => {
4123
4196
  XDG_STATE_HOME: cwd,
4124
4197
  CODEX_HOME: path.join(cwd, 'none'),
4125
4198
  CLAUDE_CONFIG_DIR: path.join(cwd, 'none'),
4199
+ OPENCODE_CONFIG_DIR: path.join(cwd, 'none'),
4126
4200
  },
4127
4201
  }
4128
4202