@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.
- package/CHANGELOG.md +17 -0
- package/README.md +17 -7
- package/dist/commands.d.ts +2 -0
- package/dist/commands.js +31 -39
- package/dist/commands.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +5 -9
- package/dist/config.js.map +1 -1
- package/dist/credentials.d.ts +54 -3
- package/dist/credentials.js +237 -18
- package/dist/credentials.js.map +1 -1
- package/dist/file-lock.js +15 -6
- package/dist/file-lock.js.map +1 -1
- package/dist/hook-adapter.d.ts +6 -2
- package/dist/hook-adapter.js +110 -29
- package/dist/hook-adapter.js.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/hooks.js.map +1 -1
- package/dist/install-hooks.d.ts +50 -21
- package/dist/install-hooks.js +141 -57
- package/dist/install-hooks.js.map +1 -1
- package/dist/native-skills.js +5 -10
- package/dist/native-skills.js.map +1 -1
- package/dist/opencode-plugin.d.ts +7 -2
- package/dist/opencode-plugin.js +142 -4
- package/dist/opencode-plugin.js.map +1 -1
- package/dist/platform.d.ts +73 -0
- package/dist/platform.js +143 -0
- package/dist/platform.js.map +1 -0
- package/dist/ui/config-view.js +5 -1
- package/dist/ui/config-view.js.map +1 -1
- package/package.json +3 -3
- package/src/commands.test.ts +100 -26
- package/src/commands.ts +49 -36
- package/src/config.ts +11 -9
- package/src/credentials.test.ts +291 -0
- package/src/credentials.ts +274 -17
- package/src/file-lock.ts +34 -9
- package/src/hook-adapter.test.ts +136 -0
- package/src/hook-adapter.ts +120 -28
- package/src/hooks.test.ts +27 -1
- package/src/hooks.ts +2 -1
- package/src/install-hooks.test.ts +174 -33
- package/src/install-hooks.ts +186 -54
- package/src/native-skills.ts +5 -10
- package/src/opencode-plugin.ts +148 -3
- package/src/platform.test.ts +152 -0
- package/src/platform.ts +173 -0
- package/src/ui/config-view.ts +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
|
9
9
|
and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
|
10
10
|
|
|
11
|
+
## [1.1.0](https://github.com/Raidiant-io/notifai/compare/v1.0.1...v1.1.0) (2026-08-13)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **cli:** support Windows and Linux harness workflows ([779ab6b](https://github.com/Raidiant-io/notifai/commit/779ab6b075900a7a431b809ddcb715fd80836688))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **cli:** cover Windows terminal behavior ([cda7abd](https://github.com/Raidiant-io/notifai/commit/cda7abd134744b2cac44204dd3eb1b20b9038edc))
|
|
22
|
+
* **cli:** isolate Codex hooks and reply routing ([#1](https://github.com/Raidiant-io/notifai/issues/1)) ([d060b6a](https://github.com/Raidiant-io/notifai/commit/d060b6a18b5937d82f74619a6c1bc711243be26c))
|
|
23
|
+
* **cli:** keep Codex hook install on ~/.codex, ignore CODEX_HOME ([3f75f13](https://github.com/Raidiant-io/notifai/commit/3f75f131c24534d3813a336bb72422f78e24a972))
|
|
24
|
+
* **cli:** preserve Codex hook trust on reinstall ([#3](https://github.com/Raidiant-io/notifai/issues/3)) ([5e2c2f4](https://github.com/Raidiant-io/notifai/commit/5e2c2f4d618276573f810a989f41a89ab1053564))
|
|
25
|
+
* **cli:** report observed setup receipts ([99d04bb](https://github.com/Raidiant-io/notifai/commit/99d04bbd487681db3023468fbd88b77a1ba13ceb))
|
|
26
|
+
* **cli:** stabilize Linux portability checks ([1462693](https://github.com/Raidiant-io/notifai/commit/146269306ae3dfc91f3559cce802460d3e058925))
|
|
27
|
+
|
|
11
28
|
## [Unreleased]
|
|
12
29
|
|
|
13
30
|
## [1.0.1] - 2026-08-13
|
package/README.md
CHANGED
|
@@ -56,6 +56,10 @@ For a harness that cannot resume an idle agent turn, `notifai send
|
|
|
56
56
|
|
|
57
57
|
## Agent harnesses
|
|
58
58
|
|
|
59
|
+
The CLI and managed hook adapters support macOS, Linux, and Windows. Receiving
|
|
60
|
+
still requires the current iPhone or macOS Companion App; native Windows and
|
|
61
|
+
Linux Companion Apps are not shipped yet.
|
|
62
|
+
|
|
59
63
|
```sh
|
|
60
64
|
notifai hooks install
|
|
61
65
|
```
|
|
@@ -67,13 +71,19 @@ or add one it did not see. This is what lets an agent's question reach
|
|
|
67
71
|
your phone without the agent having to cooperate — no question detection,
|
|
68
72
|
no state in a context window that compaction will eat.
|
|
69
73
|
|
|
70
|
-
Every harness definition calls one stable user-level adapter
|
|
71
|
-
`~/.notifai/bin/hook-adapter
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
Every harness definition calls one stable user-level adapter under the account
|
|
75
|
+
home (`~/.notifai/bin/hook-adapter` on macOS/Linux and the corresponding user
|
|
76
|
+
profile path on Windows). Node, package manager, CLI version, checkout,
|
|
77
|
+
configuration directories, and notification preferences are resolved behind
|
|
78
|
+
it, so upgrades and configuration changes do not rewrite trusted hook
|
|
79
|
+
definitions. Windows invokes its JavaScript adapter through the registered Node
|
|
80
|
+
executable; macOS/Linux retain the POSIX adapter and its stable command bytes.
|
|
81
|
+
Claude Code Stop returns immediately into the live inbox route on macOS/Linux;
|
|
82
|
+
on Windows, where upstream exposes no inbox socket, Stop stays open and returns
|
|
83
|
+
the accepted answer through the harness continuation. The first migration may
|
|
84
|
+
require one Codex `/hooks` approval; later repairs keep the same identity.
|
|
85
|
+
Codex's Stop definition omits its timeout so the host default remains
|
|
86
|
+
authoritative; prompt-submit and session-end retain fixed short limits.
|
|
77
87
|
|
|
78
88
|
`notifai doctor` compares Codex trust on a best-effort basis against Codex's
|
|
79
89
|
current persisted representation. Notifai never writes that trust store;
|
package/dist/commands.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ export interface CommandDeps {
|
|
|
61
61
|
hookAdapterHome?: string;
|
|
62
62
|
/** Test seam; production uses this process's Node and CLI paths. */
|
|
63
63
|
hookInstallTarget?: HookAdapterTarget;
|
|
64
|
+
/** Test seam; production uses process.platform for adapter format and quoting. */
|
|
65
|
+
hookPlatform?: NodeJS.Platform;
|
|
64
66
|
/** Test seam; production uses fetch against base_url. */
|
|
65
67
|
clientFactory?: (baseUrl: string, bearer: string | null, options?: ClientOptions) => ApiClient;
|
|
66
68
|
/** Test seam for bounded polling without wall-clock sleeps. */
|
package/dist/commands.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
3
2
|
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
4
3
|
import os from 'node:os';
|
|
5
4
|
import path from 'node:path';
|
|
@@ -7,7 +6,7 @@ import { parse as parseToml, stringify as stringifyToml } from 'smol-toml';
|
|
|
7
6
|
import { CAPABILITIES_V1, QUESTION_TEXT_MAX_LENGTH, REPLY_MAX_QUESTIONS, REPLY_MAX_WINDOW_SECONDS, validateDraft, } from '@raidiant/notifai-protocol';
|
|
8
7
|
import { sha256Hex } from '@raidiant/notifai-protocol/node';
|
|
9
8
|
import { ApiCallError, NetworkError, createClient, isRetryableReplyPollError, } from './client.js';
|
|
10
|
-
import { BOOLEAN_CONFIG_KEYS, CONFIG_KEYS, LOG_LEVELS, NUMERIC_CONFIG_KEYS, configBounds, configDefaultValue, findProjectConfigPath, personalProjectConfigPath, globalConfigPath, loadConfig, sessionConfigPath, } from './config.js';
|
|
9
|
+
import { BOOLEAN_CONFIG_KEYS, CONFIG_KEYS, LOG_LEVELS, NUMERIC_CONFIG_KEYS, configBounds, configDefaultValue, findProjectConfigPath, personalProjectConfigPath, globalConfigPath, loadConfig, sessionConfigPath, stateDir, } from './config.js';
|
|
11
10
|
import { acceptedValues, configInfo } from './config-schema.js';
|
|
12
11
|
import { packageVersion, skillsSource } from './release.js';
|
|
13
12
|
import { atomicWriteFileSync } from './atomic-file.js';
|
|
@@ -23,6 +22,7 @@ import { codexWakeRoute, inspectCodexResume, } from './codex-wake.js';
|
|
|
23
22
|
import { inspectHookAdapter, installHookAdapter, isNpxAdapterTarget, } from './hook-adapter.js';
|
|
24
23
|
import { isOurOpencodePlugin, opencodePluginSource, } from './opencode-plugin.js';
|
|
25
24
|
import { CHOICE_USAGE, buildDraft, formatReceipt, parseChoices, receiptExitCode, slugify, } from './send.js';
|
|
25
|
+
import { openUrl } from './platform.js';
|
|
26
26
|
/** The invocation's logger, or one that discards everything. */
|
|
27
27
|
export function log(deps) {
|
|
28
28
|
return deps.logger ?? nullLogger();
|
|
@@ -1128,6 +1128,8 @@ function stopWakeRoute(deps, harness, sessionId, cwd) {
|
|
|
1128
1128
|
if (sessionId === undefined)
|
|
1129
1129
|
return undefined;
|
|
1130
1130
|
if (harness === 'claude-code') {
|
|
1131
|
+
if ((deps.hookPlatform ?? process.platform) === 'win32')
|
|
1132
|
+
return undefined;
|
|
1131
1133
|
return claudeWakeRoute({
|
|
1132
1134
|
sessionId,
|
|
1133
1135
|
cwd,
|
|
@@ -1316,7 +1318,7 @@ export function askCommand(deps, question, flags) {
|
|
|
1316
1318
|
const { active, contested } = resolveActiveHarness(deps.env, deps.cwd, now);
|
|
1317
1319
|
let sessionId;
|
|
1318
1320
|
if (active !== null) {
|
|
1319
|
-
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome);
|
|
1321
|
+
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
1320
1322
|
const activeInstalled = installations.some((installation) => installation.harness === active.harness);
|
|
1321
1323
|
if (!activeInstalled) {
|
|
1322
1324
|
for (const line of diagnoseActiveHarnessSession(active, 'not-installed', installations, contested)) {
|
|
@@ -1518,11 +1520,11 @@ function activeQuestionRouteProblems(deps, active, installations) {
|
|
|
1518
1520
|
}
|
|
1519
1521
|
}
|
|
1520
1522
|
}
|
|
1521
|
-
for (const problem of inspectHookAdapter(deps.hookAdapterHome).problems) {
|
|
1523
|
+
for (const problem of inspectHookAdapter(deps.hookAdapterHome, deps.hookPlatform).problems) {
|
|
1522
1524
|
problems.push(problem);
|
|
1523
1525
|
}
|
|
1524
1526
|
for (const installation of matching)
|
|
1525
|
-
problems.push(...stopShapeProblems(installation));
|
|
1527
|
+
problems.push(...stopShapeProblems(installation, deps.hookPlatform));
|
|
1526
1528
|
problems.push(...codexTrustProblems(matching, deps.env));
|
|
1527
1529
|
return [...new Set(problems)];
|
|
1528
1530
|
}
|
|
@@ -1574,7 +1576,7 @@ function diagnoseActiveHarnessSession(active, problem, installations, contested
|
|
|
1574
1576
|
* checked after a prompt before assuming that a new session is required.
|
|
1575
1577
|
*/
|
|
1576
1578
|
function diagnoseMissingSession(deps) {
|
|
1577
|
-
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome);
|
|
1579
|
+
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
1578
1580
|
if (installations.length === 0) {
|
|
1579
1581
|
return [
|
|
1580
1582
|
'Could not tell which harness session this is: no Notifai hooks are installed for this project.',
|
|
@@ -1687,16 +1689,18 @@ export function hooksInstallCommand(deps, flags) {
|
|
|
1687
1689
|
return EXIT.usage;
|
|
1688
1690
|
const adapterTarget = resolveHookAdapterTarget(deps, flags);
|
|
1689
1691
|
const scriptPath = flags.scriptPath ?? fileHookInstallTarget(adapterTarget)?.scriptPath ?? process.argv[1] ?? 'notifai';
|
|
1692
|
+
const hookPlatform = deps.hookPlatform ?? process.platform;
|
|
1693
|
+
const nodePath = adapterTarget.execPath;
|
|
1690
1694
|
let adapterPath;
|
|
1691
1695
|
try {
|
|
1692
|
-
adapterPath = installHookAdapter(adapterTarget, deps.hookAdapterHome).path;
|
|
1696
|
+
adapterPath = installHookAdapter(adapterTarget, deps.hookAdapterHome, hookPlatform).path;
|
|
1693
1697
|
}
|
|
1694
1698
|
catch (err) {
|
|
1695
1699
|
deps.io.err(`Could not prepare the stable hook adapter: ${String(err)}`);
|
|
1696
1700
|
return EXIT.failed;
|
|
1697
1701
|
}
|
|
1698
1702
|
const wantGlobal = flags.global === true;
|
|
1699
|
-
const existing = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome).filter((installation) => installation.harness === harness);
|
|
1703
|
+
const existing = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform).filter((installation) => installation.harness === harness);
|
|
1700
1704
|
const otherScope = existing.filter((installation) => installation.global !== wantGlobal);
|
|
1701
1705
|
if (!wantGlobal && otherScope.some((installation) => installation.global)) {
|
|
1702
1706
|
const globalFile = otherScope.find((installation) => installation.global)?.file;
|
|
@@ -1708,13 +1712,15 @@ export function hooksInstallCommand(deps, flags) {
|
|
|
1708
1712
|
return EXIT.failed;
|
|
1709
1713
|
}
|
|
1710
1714
|
}
|
|
1711
|
-
const file = settingsFile(harness, wantGlobal, deps.cwd, deps.env);
|
|
1715
|
+
const file = settingsFile(harness, wantGlobal, deps.cwd, deps.env, hookPlatform);
|
|
1712
1716
|
// OpenCode's adapter is a generated plugin module rather than a handler
|
|
1713
1717
|
// merged into a settings document, so it owns the whole file.
|
|
1714
1718
|
if (harness === 'opencode') {
|
|
1715
1719
|
return installOpencodePlugin(deps, file, {
|
|
1716
1720
|
adapterPath,
|
|
1717
1721
|
timeoutSeconds: BLOCKING_STOP_TIMEOUT_SECONDS,
|
|
1722
|
+
platform: hookPlatform,
|
|
1723
|
+
nodePath,
|
|
1718
1724
|
});
|
|
1719
1725
|
}
|
|
1720
1726
|
if (harness === 'cursor') {
|
|
@@ -1724,6 +1730,8 @@ export function hooksInstallCommand(deps, flags) {
|
|
|
1724
1730
|
const result = mergeCursorHooks(document, buildCursorHookConfig({
|
|
1725
1731
|
adapterPath,
|
|
1726
1732
|
harness: 'cursor',
|
|
1733
|
+
platform: hookPlatform,
|
|
1734
|
+
nodePath,
|
|
1727
1735
|
}), scriptPath);
|
|
1728
1736
|
applyPlan(file, result.document);
|
|
1729
1737
|
return result;
|
|
@@ -1745,6 +1753,8 @@ export function hooksInstallCommand(deps, flags) {
|
|
|
1745
1753
|
const result = mergeHooks(document, buildHookConfig({
|
|
1746
1754
|
adapterPath,
|
|
1747
1755
|
harness,
|
|
1756
|
+
platform: hookPlatform,
|
|
1757
|
+
nodePath,
|
|
1748
1758
|
}), scriptPath);
|
|
1749
1759
|
applyPlan(file, result.document);
|
|
1750
1760
|
return result;
|
|
@@ -1818,7 +1828,7 @@ export function hooksUninstallCommand(deps, flags) {
|
|
|
1818
1828
|
if (!harness)
|
|
1819
1829
|
return EXIT.usage;
|
|
1820
1830
|
const scriptPath = flags.scriptPath ?? process.argv[1] ?? 'notifai';
|
|
1821
|
-
const file = settingsFile(harness, flags.global ?? false, deps.cwd, deps.env);
|
|
1831
|
+
const file = settingsFile(harness, flags.global ?? false, deps.cwd, deps.env, deps.hookPlatform);
|
|
1822
1832
|
if (harness === 'opencode') {
|
|
1823
1833
|
try {
|
|
1824
1834
|
return withTargetFileLock(file, () => {
|
|
@@ -2515,9 +2525,7 @@ function setupProofPath(deps) {
|
|
|
2515
2525
|
// the resolved absolute path is still a stable local identity for it.
|
|
2516
2526
|
}
|
|
2517
2527
|
const digest = createHash('sha256').update(projectDir).digest('hex').slice(0, 32);
|
|
2518
|
-
|
|
2519
|
-
const base = xdg && xdg !== '' ? xdg : path.join(os.homedir(), '.local', 'state');
|
|
2520
|
-
return path.join(base, 'notifai', 'setup-proofs', `${digest}.json`);
|
|
2528
|
+
return path.join(stateDir(deps.env), 'setup-proofs', `${digest}.json`);
|
|
2521
2529
|
}
|
|
2522
2530
|
function readSetupProof(deps) {
|
|
2523
2531
|
const file = setupProofPath(deps);
|
|
@@ -2816,6 +2824,7 @@ async function runSetupProof(deps) {
|
|
|
2816
2824
|
const observed = observedCompanionReceipt(snapshot, proof.device_id);
|
|
2817
2825
|
if (observed) {
|
|
2818
2826
|
spinner?.stop(`Receipt observed from ${observed.delivery.device_name}`);
|
|
2827
|
+
deps.io.out(`Companion Receipt (the app's delivery confirmation) observed from ${observed.delivery.device_name}.`);
|
|
2819
2828
|
return 'closed';
|
|
2820
2829
|
}
|
|
2821
2830
|
lastError = null;
|
|
@@ -3559,7 +3568,7 @@ function remedyLine(state) {
|
|
|
3559
3568
|
* is, is each check's own call (`HookCheck`).
|
|
3560
3569
|
*/
|
|
3561
3570
|
function hookStates(deps) {
|
|
3562
|
-
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome);
|
|
3571
|
+
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
3563
3572
|
const active = activeHarnessSession(deps.env, deps.cwd, (deps.now ?? Date.now)());
|
|
3564
3573
|
const config = loadLoggedConfig(deps, { cwd: deps.cwd, env: deps.env });
|
|
3565
3574
|
const settings = {
|
|
@@ -3647,12 +3656,12 @@ function hookStates(deps) {
|
|
|
3647
3656
|
* hashes into `trusted_hash`, and an untrusted handler is simply not run.
|
|
3648
3657
|
* - Everything else blocks its turn and needs a ceiling above the wait.
|
|
3649
3658
|
*/
|
|
3650
|
-
function stopShapeProblems(installation) {
|
|
3659
|
+
function stopShapeProblems(installation, platform = process.platform) {
|
|
3651
3660
|
if (installation.harness === 'codex')
|
|
3652
3661
|
return [];
|
|
3653
3662
|
const problems = [];
|
|
3654
3663
|
for (const handler of installation.handlers.filter((entry) => handlerEvent(entry.command) === 'stop')) {
|
|
3655
|
-
if (installation.harness === 'claude-code') {
|
|
3664
|
+
if (installation.harness === 'claude-code' && platform !== 'win32') {
|
|
3656
3665
|
if (handler.async !== true) {
|
|
3657
3666
|
problems.push(`${installation.file} declares a blocking Stop handler; the Claude Code wake route needs \`async: true\` so the turn ends while the waiter runs`);
|
|
3658
3667
|
}
|
|
@@ -3669,7 +3678,7 @@ function stopShapeProblems(installation) {
|
|
|
3669
3678
|
}
|
|
3670
3679
|
function hookChecks(deps) {
|
|
3671
3680
|
const checks = [];
|
|
3672
|
-
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome);
|
|
3681
|
+
const installations = findInstallations(deps.cwd, deps.env, deps.hookAdapterHome, deps.hookPlatform);
|
|
3673
3682
|
// Not having hooks is a setup someone chose, not a fault: `send` works
|
|
3674
3683
|
// without them. A setup that cannot work is what deserves to go red.
|
|
3675
3684
|
if (installations.length === 0) {
|
|
@@ -3766,7 +3775,7 @@ function hookChecks(deps) {
|
|
|
3766
3775
|
: `${stale.join('; ')} — rerun \`notifai hooks install\` to drop ${stale.length === 1 ? 'it' : 'them'}`,
|
|
3767
3776
|
});
|
|
3768
3777
|
const adapterProblems = installations.flatMap((installation) => (installation.problems ?? []).map((problem) => `${installation.file}: ${problem}`));
|
|
3769
|
-
const sharedAdapter = inspectHookAdapter(deps.hookAdapterHome);
|
|
3778
|
+
const sharedAdapter = inspectHookAdapter(deps.hookAdapterHome, deps.hookPlatform);
|
|
3770
3779
|
adapterProblems.push(...sharedAdapter.problems);
|
|
3771
3780
|
if (adapterProblems.length > 0) {
|
|
3772
3781
|
checks.push({
|
|
@@ -3794,7 +3803,7 @@ function hookChecks(deps) {
|
|
|
3794
3803
|
},
|
|
3795
3804
|
}),
|
|
3796
3805
|
});
|
|
3797
|
-
const shapeProblems = installations.flatMap((installation) => stopShapeProblems(installation).map((problem) => `${problem} — run \`notifai hooks install --harness ${installation.harness}${installation.global ? ' --global' : ''}\``));
|
|
3806
|
+
const shapeProblems = installations.flatMap((installation) => stopShapeProblems(installation, deps.hookPlatform).map((problem) => `${problem} — run \`notifai hooks install --harness ${installation.harness}${installation.global ? ' --global' : ''}\``));
|
|
3798
3807
|
checks.push({
|
|
3799
3808
|
name: 'hooks (stop shape)',
|
|
3800
3809
|
ok: shapeProblems.length === 0,
|
|
@@ -3963,7 +3972,7 @@ function wakeRouteCheck(deps, active, activeInstallations) {
|
|
|
3963
3972
|
if (active.harness === 'claude-code') {
|
|
3964
3973
|
const readiness = inspectClaudeInbox({
|
|
3965
3974
|
pid: deps.claudeSourcePid ?? claudeSessionPid(deps.env),
|
|
3966
|
-
platform: process.platform,
|
|
3975
|
+
platform: deps.hookPlatform ?? process.platform,
|
|
3967
3976
|
readDescriptor: deps.claudeWake?.readDescriptor ?? systemClaudeWakeAdapters(deps.env).readDescriptor,
|
|
3968
3977
|
socketExists: (socketPath) => existsSync(socketPath),
|
|
3969
3978
|
});
|
|
@@ -3978,7 +3987,7 @@ function wakeRouteCheck(deps, active, activeInstallations) {
|
|
|
3978
3987
|
}
|
|
3979
3988
|
if (active.harness === 'codex') {
|
|
3980
3989
|
const readiness = inspectCodexResume(deps.env, {
|
|
3981
|
-
platform: process.platform,
|
|
3990
|
+
platform: deps.hookPlatform ?? process.platform,
|
|
3982
3991
|
directoryExists: (directory) => existsSync(directory),
|
|
3983
3992
|
});
|
|
3984
3993
|
return {
|
|
@@ -4133,24 +4142,7 @@ export function realIo(env = process.env) {
|
|
|
4133
4142
|
return log.error(message);
|
|
4134
4143
|
}
|
|
4135
4144
|
},
|
|
4136
|
-
openUrl
|
|
4137
|
-
try {
|
|
4138
|
-
if (process.platform === 'darwin') {
|
|
4139
|
-
spawn('open', [url], { stdio: 'ignore', detached: true }).unref();
|
|
4140
|
-
}
|
|
4141
|
-
else if (process.platform === 'win32') {
|
|
4142
|
-
// `start` is a cmd builtin; spawn('start', …) cannot work on Windows.
|
|
4143
|
-
// Empty title argument keeps URLs with special characters intact.
|
|
4144
|
-
spawn('cmd', ['/c', 'start', '', url], { stdio: 'ignore', detached: true }).unref();
|
|
4145
|
-
}
|
|
4146
|
-
else {
|
|
4147
|
-
spawn('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
|
|
4148
|
-
}
|
|
4149
|
-
}
|
|
4150
|
-
catch {
|
|
4151
|
-
// Browser opening is best-effort; the URL is printed anyway.
|
|
4152
|
-
}
|
|
4153
|
-
},
|
|
4145
|
+
openUrl,
|
|
4154
4146
|
};
|
|
4155
4147
|
}
|
|
4156
4148
|
//# sourceMappingURL=commands.js.map
|