@zeph-to/cli 2.7.0 → 2.8.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/README.md +39 -1
- package/dist/ask.js +1 -1
- package/dist/cli.js +13 -0
- package/dist/config.d.ts +7 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -3
- package/dist/installer.d.ts +11 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +61 -2
- package/dist/listener-process.d.ts +1 -0
- package/dist/listener-process.d.ts.map +1 -1
- package/dist/listener-process.js +13 -5
- package/dist/listener-service.d.ts +165 -0
- package/dist/listener-service.d.ts.map +1 -0
- package/dist/listener-service.js +424 -0
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +0 -0
- package/dist/remote-hook.d.ts.map +1 -1
- package/dist/remote-hook.js +6 -3
- package/dist/uninstall.d.ts +8 -0
- package/dist/uninstall.d.ts.map +1 -1
- package/dist/uninstall.js +28 -1
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +11 -1
- package/dist/wrapper.d.ts.map +1 -1
- package/dist/wrapper.js +23 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -244,7 +244,8 @@ block here.
|
|
|
244
244
|
`zeph listener` by hand — every `zeph cc` checks the PID file and
|
|
245
245
|
skips the spawn when one is already alive, so opening a dozen
|
|
246
246
|
terminals doesn't create a dozen daemons. The daemon survives
|
|
247
|
-
between `zeph cc` invocations
|
|
247
|
+
between `zeph cc` invocations — but not a reboot, which is what the
|
|
248
|
+
login-time service below is for.
|
|
248
249
|
|
|
249
250
|
Project name resolves from `CLAUDE_PROJECT_DIR` /
|
|
250
251
|
`CURSOR_PROJECT_DIR` / `WINDSURF_PROJECT_DIR` if set, else the git
|
|
@@ -271,6 +272,43 @@ block here.
|
|
|
271
272
|
listener can't target an unnamed session that way, but you keep your
|
|
272
273
|
existing multiplexer setup.
|
|
273
274
|
|
|
275
|
+
### Starting the listener at login (macOS)
|
|
276
|
+
|
|
277
|
+
A reboot ends the daemon, and nothing starts it again until you open a
|
|
278
|
+
terminal and run `zeph cc`. Until you do, the phone shows **no agents** —
|
|
279
|
+
the machine is on, the past sessions are on disk, and the app has no one
|
|
280
|
+
to hear from.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
zeph listener --install-service
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
That registers a launchd LaunchAgent (`to.zeph.listener`) that starts the
|
|
287
|
+
listener at every login. `--uninstall-service` removes it and
|
|
288
|
+
`--service-status` shows what the installed one points at; `zeph install`
|
|
289
|
+
offers it during setup and `zeph uninstall` takes it away again.
|
|
290
|
+
|
|
291
|
+
What you get back after a reboot is your **past sessions**, ready to
|
|
292
|
+
resume from the phone — not live agents. tmux does not survive a reboot
|
|
293
|
+
either, and this doesn't try to bring those sessions back to life.
|
|
294
|
+
|
|
295
|
+
Two details worth knowing:
|
|
296
|
+
|
|
297
|
+
- It fires at **user login**, not at boot. Without automatic login, the
|
|
298
|
+
machine stays silent while it sits on the login screen.
|
|
299
|
+
- The plist bakes in absolute paths for node and the CLI, a `PATH` that
|
|
300
|
+
can reach tmux, and a UTF-8 `LANG`. launchd gives a job
|
|
301
|
+
`/usr/bin:/bin:/usr/sbin:/sbin` and no locale at all: without the PATH
|
|
302
|
+
the daemon exits 127 at every login, and without the locale tmux
|
|
303
|
+
escapes the separator the session list is split on, so every session is
|
|
304
|
+
silently dropped while everything else looks healthy. If any of that
|
|
305
|
+
drifts — a version-manager node upgrade, say — `zeph verify` names it,
|
|
306
|
+
and re-running `--install-service` repoints the plist.
|
|
307
|
+
|
|
308
|
+
With the service installed, launchd owns the process: `zeph cc` and
|
|
309
|
+
`zeph listener --stop|--restart` ask launchd rather than signalling the
|
|
310
|
+
PID, so there is never a second daemon racing the first.
|
|
311
|
+
|
|
274
312
|
### Diagnostics
|
|
275
313
|
|
|
276
314
|
The auto-spawned listener writes to three files under `~/.zeph/`:
|
package/dist/ask.js
CHANGED
|
@@ -141,7 +141,7 @@ const handleAsk = async (args) => {
|
|
|
141
141
|
// hook maps that to DENY — a command blocked for a reason that has nothing
|
|
142
142
|
// to do with the user. Every other command in cli.ts resolves env this way.
|
|
143
143
|
const apiKey = args['api-key'] || (0, config_js_1.resolvedEnv)('ZEPH_API_KEY') || config.apiKey;
|
|
144
|
-
const hookId = args.hook || (0, config_js_1.
|
|
144
|
+
const hookId = args.hook || (0, config_js_1.resolveHookId)();
|
|
145
145
|
const title = args.title || '';
|
|
146
146
|
if (!apiKey || !hookId || !title) {
|
|
147
147
|
const missing = [!title && '--title', !apiKey && 'an API key', !hookId && 'a hook id']
|
package/dist/cli.js
CHANGED
|
@@ -90,6 +90,15 @@ ${usageAgentLines()}
|
|
|
90
90
|
--restart stop it and relaunch in the background
|
|
91
91
|
(needed after an upgrade: 'npm i -g' swaps
|
|
92
92
|
the package but never the live process)
|
|
93
|
+
--install-service
|
|
94
|
+
start the listener at every login (macOS
|
|
95
|
+
launchd). Without it the daemon only exists
|
|
96
|
+
after a 'zeph cc', so a reboot leaves the
|
|
97
|
+
phone picker empty until you open a terminal
|
|
98
|
+
--uninstall-service
|
|
99
|
+
remove the login-time service
|
|
100
|
+
--service-status
|
|
101
|
+
show what the installed service points at
|
|
93
102
|
|
|
94
103
|
Notify options:
|
|
95
104
|
--title <text> Push title
|
|
@@ -126,6 +135,10 @@ Install options:
|
|
|
126
135
|
to manual key entry)
|
|
127
136
|
--key <api-key> API key (non-interactive; skips browser login)
|
|
128
137
|
--hook <hook-id> Hook ID (non-interactive)
|
|
138
|
+
--service Install the login-time listener service without
|
|
139
|
+
asking (macOS). Interactive runs offer it anyway;
|
|
140
|
+
scripted runs need this flag
|
|
141
|
+
--no-service Never install it
|
|
129
142
|
--base-url <url> Base URL (non-interactive)
|
|
130
143
|
--relogin Force a fresh browser sign-in even if a login is
|
|
131
144
|
already saved (switch account)
|
package/dist/config.d.ts
CHANGED
|
@@ -7,7 +7,13 @@ export interface ZephConfig {
|
|
|
7
7
|
wsUrl?: string;
|
|
8
8
|
deviceId?: string;
|
|
9
9
|
}
|
|
10
|
-
export declare const resolvedEnv: (key: string) => string | undefined;
|
|
10
|
+
export declare const resolvedEnv: (key: string, env?: NodeJS.ProcessEnv) => string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* The two-way hook id: `ZEPH_HOOK_ID` when it carries a real value, else
|
|
13
|
+
* `hookId` from ~/.zeph/config.json — what `zeph setup` writes. The plugin's
|
|
14
|
+
* gate.sh `zeph_hook_id` and the MCP server resolve it in the same order.
|
|
15
|
+
*/
|
|
16
|
+
export declare const resolveHookId: (env?: NodeJS.ProcessEnv) => string | undefined;
|
|
11
17
|
export declare const PROJECT_DIR_ENV_VARS: readonly ["CLAUDE_PROJECT_DIR", "CURSOR_PROJECT_DIR", "WINDSURF_PROJECT_DIR"];
|
|
12
18
|
/** First set project-dir env (unresolved `${VAR}` placeholders ignored), else cwd. */
|
|
13
19
|
export declare const detectProjectDir: () => string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,MAAK,MAAM,CAAC,UAAwB,KAAG,MAAM,GAAG,SAGxF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,MAAM,GAAG,SACrB,CAAC;AAM1D,eAAO,MAAM,oBAAoB,+EAAgF,CAAC;AAElH,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,QAAO,MAMnC,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,UAM7B,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU,KAAG,IAM/C,CAAC;AAEF,eAAO,MAAM,OAAO,QAOhB,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VERSION = exports.saveConfig = exports.loadConfig = exports.detectProjectDir = exports.PROJECT_DIR_ENV_VARS = exports.resolvedEnv = exports.CONFIG_FILE = exports.CONFIG_DIR = void 0;
|
|
3
|
+
exports.VERSION = exports.saveConfig = exports.loadConfig = exports.detectProjectDir = exports.PROJECT_DIR_ENV_VARS = exports.resolveHookId = exports.resolvedEnv = exports.CONFIG_FILE = exports.CONFIG_DIR = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const os_1 = require("os");
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
exports.CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.zeph');
|
|
8
8
|
exports.CONFIG_FILE = (0, path_1.join)(exports.CONFIG_DIR, 'config.json');
|
|
9
|
-
const resolvedEnv = (key) => {
|
|
10
|
-
const val =
|
|
9
|
+
const resolvedEnv = (key, env = process.env) => {
|
|
10
|
+
const val = env[key];
|
|
11
11
|
return val && !val.startsWith('${') ? val : undefined;
|
|
12
12
|
};
|
|
13
13
|
exports.resolvedEnv = resolvedEnv;
|
|
14
|
+
/**
|
|
15
|
+
* The two-way hook id: `ZEPH_HOOK_ID` when it carries a real value, else
|
|
16
|
+
* `hookId` from ~/.zeph/config.json — what `zeph setup` writes. The plugin's
|
|
17
|
+
* gate.sh `zeph_hook_id` and the MCP server resolve it in the same order.
|
|
18
|
+
*/
|
|
19
|
+
const resolveHookId = (env = process.env) => (0, exports.resolvedEnv)('ZEPH_HOOK_ID', env) || (0, exports.loadConfig)().hookId;
|
|
20
|
+
exports.resolveHookId = resolveHookId;
|
|
14
21
|
// Per-agent project-dir env vars, in precedence order. Deliberately NOT part
|
|
15
22
|
// of the remote-agent registry: Cursor/Windsurf carry project-dir envs but
|
|
16
23
|
// are not remote-controllable via tmux — the two tables have different
|
package/dist/installer.d.ts
CHANGED
|
@@ -18,5 +18,16 @@ export declare const mergeJsonFile: (filePath: string, patch: Record<string, unk
|
|
|
18
18
|
* unit testing.
|
|
19
19
|
*/
|
|
20
20
|
export declare const filterAgentsByIds: (detected: Agent[], only: string) => Agent[];
|
|
21
|
+
/**
|
|
22
|
+
* Whether this install should register the LaunchAgent that starts the
|
|
23
|
+
* listener at login.
|
|
24
|
+
*
|
|
25
|
+
* Interactive installs offer it and default to yes: an empty phone picker
|
|
26
|
+
* after every reboot is precisely the kind of thing a default should fix.
|
|
27
|
+
* Scripted installs (`--key`, CI, provisioning) get it only when asked —
|
|
28
|
+
* planting a background job on a machine whose operator only wanted an API
|
|
29
|
+
* key written is a surprise, not a convenience.
|
|
30
|
+
*/
|
|
31
|
+
export declare const serviceInstallChoice: (args: Record<string, string | boolean>, nonInteractive: boolean) => "yes" | "no" | "ask";
|
|
21
32
|
export declare const handleInstall: (args: Record<string, string | boolean>) => Promise<number>;
|
|
22
33
|
//# sourceMappingURL=installer.d.ts.map
|
package/dist/installer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA6BzC;;;GAGG;AACH;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,YAAY,MAAM,GAAG,SAAS,EAAE,SAAS,OAAO,KAAG,OACxD,CAAC;AAoBzB;6EAC6E;AAC7E,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAqBhF,CAAC;AAgQF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,KAAK,EAAE,EAAE,MAAM,MAAM,KAAG,KAAK,EAKxE,CAAC;AA8EF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACtC,gBAAgB,OAAO,KACtB,KAAK,GAAG,IAAI,GAAG,KAKjB,CAAC;AAgCF,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAuH1F,CAAC"}
|
package/dist/installer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleInstall = exports.filterAgentsByIds = exports.mergeJsonFile = exports.shouldReauth = void 0;
|
|
3
|
+
exports.handleInstall = exports.serviceInstallChoice = exports.filterAgentsByIds = exports.mergeJsonFile = exports.shouldReauth = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
6
|
const os_1 = require("os");
|
|
@@ -10,11 +10,13 @@ const zeph_hook_js_1 = require("./zeph-hook.js");
|
|
|
10
10
|
const config_js_1 = require("./config.js");
|
|
11
11
|
const login_js_1 = require("./login.js");
|
|
12
12
|
const agents_js_1 = require("./agents.js");
|
|
13
|
+
const listener_service_js_1 = require("./listener-service.js");
|
|
13
14
|
const templates_js_1 = require("./templates.js");
|
|
14
15
|
const HOME = (0, os_1.homedir)();
|
|
15
16
|
// ── Helpers ──────────────────────────────────────────────────────
|
|
16
17
|
const ok = (msg) => console.log(` + ${msg}`);
|
|
17
18
|
const fail = (msg) => console.log(` - ${msg}`);
|
|
19
|
+
const skipNote = (msg) => console.log(` · ${msg}`);
|
|
18
20
|
/**
|
|
19
21
|
* True when install should auto-open browser login (ADR 0002): interactive
|
|
20
22
|
* context with no existing credential (--key/env/config all absent).
|
|
@@ -392,6 +394,57 @@ const collectCredentials = async (args, installArgs, nonInteractive, existing) =
|
|
|
392
394
|
const hookInput = await promptInput(' Hook ID (optional, for prompt/input): ');
|
|
393
395
|
return { apiKey, hookId: hookInput || undefined, baseUrl: existing.baseUrl };
|
|
394
396
|
};
|
|
397
|
+
// ── Login-time service ───────────────────────────────────────────
|
|
398
|
+
/**
|
|
399
|
+
* Whether this install should register the LaunchAgent that starts the
|
|
400
|
+
* listener at login.
|
|
401
|
+
*
|
|
402
|
+
* Interactive installs offer it and default to yes: an empty phone picker
|
|
403
|
+
* after every reboot is precisely the kind of thing a default should fix.
|
|
404
|
+
* Scripted installs (`--key`, CI, provisioning) get it only when asked —
|
|
405
|
+
* planting a background job on a machine whose operator only wanted an API
|
|
406
|
+
* key written is a surprise, not a convenience.
|
|
407
|
+
*/
|
|
408
|
+
const serviceInstallChoice = (args, nonInteractive) => {
|
|
409
|
+
if (args['no-service'] === true)
|
|
410
|
+
return 'no';
|
|
411
|
+
if (!(0, listener_service_js_1.serviceSupported)())
|
|
412
|
+
return 'no';
|
|
413
|
+
if (args.service === true)
|
|
414
|
+
return 'yes';
|
|
415
|
+
return nonInteractive ? 'no' : 'ask';
|
|
416
|
+
};
|
|
417
|
+
exports.serviceInstallChoice = serviceInstallChoice;
|
|
418
|
+
/** Run the choice: ask when it should be asked, then install if wanted. */
|
|
419
|
+
const applyServiceChoice = async (choice) => {
|
|
420
|
+
if (choice === 'no')
|
|
421
|
+
return;
|
|
422
|
+
let wanted = choice === 'yes';
|
|
423
|
+
if (choice === 'ask') {
|
|
424
|
+
try {
|
|
425
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
426
|
+
wanted = await confirm({
|
|
427
|
+
message: 'Start the listener at every login? (so the phone sees this machine after a reboot)',
|
|
428
|
+
default: true,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
// Ctrl-C or no TTY — an unanswered question is not a yes.
|
|
433
|
+
wanted = false;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (!wanted) {
|
|
437
|
+
skipNote('login-time service not installed (add it later: zeph listener --install-service)');
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const result = await (0, listener_service_js_1.installService)();
|
|
441
|
+
for (const note of result.notes)
|
|
442
|
+
ok(note);
|
|
443
|
+
if (result.ok)
|
|
444
|
+
ok('listener starts at every login');
|
|
445
|
+
else
|
|
446
|
+
fail(`login-time service: ${result.reason}`);
|
|
447
|
+
};
|
|
395
448
|
// ── Main Install Flow ────────────────────────────────────────────
|
|
396
449
|
const handleInstall = async (args) => {
|
|
397
450
|
const installArgs = {
|
|
@@ -458,6 +511,9 @@ const handleInstall = async (args) => {
|
|
|
458
511
|
if (selected.length === 0) {
|
|
459
512
|
console.log(' (no agents selected — only the config file will be saved)');
|
|
460
513
|
}
|
|
514
|
+
if ((0, exports.serviceInstallChoice)(args, nonInteractive) !== 'no') {
|
|
515
|
+
console.log(' - Offer to start the listener at every login');
|
|
516
|
+
}
|
|
461
517
|
console.log(' - Test connection');
|
|
462
518
|
}
|
|
463
519
|
// 5. Save config — merge over the latest on-disk config (re-read, since a
|
|
@@ -481,7 +537,10 @@ const handleInstall = async (args) => {
|
|
|
481
537
|
if (installer)
|
|
482
538
|
installer();
|
|
483
539
|
}
|
|
484
|
-
// 7.
|
|
540
|
+
// 7. Login-time service — the only thing that makes the phone see this
|
|
541
|
+
// machine after a reboot without a terminal being opened first.
|
|
542
|
+
await applyServiceChoice((0, exports.serviceInstallChoice)(args, nonInteractive));
|
|
543
|
+
// 8. Test connection
|
|
485
544
|
console.log('\n Testing connection...');
|
|
486
545
|
await testConnection(apiKey, baseUrl);
|
|
487
546
|
console.log('\n Done! Restart your agents.\n');
|
|
@@ -2,6 +2,7 @@ export declare const LISTENER_PID_FILE: string;
|
|
|
2
2
|
/** CLI version the running daemon booted from. Absent ⇒ pre-stamp build. */
|
|
3
3
|
export declare const LISTENER_VERSION_FILE: string;
|
|
4
4
|
export declare const LISTENER_LOG_FILE: string;
|
|
5
|
+
export declare const sleep: (ms: number) => Promise<void>;
|
|
5
6
|
/**
|
|
6
7
|
* PID of the listener on record, or null when the file is missing or stale.
|
|
7
8
|
* Stale PID files (process gone) read as "no listener" so a crashed daemon
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener-process.d.ts","sourceRoot":"","sources":["../src/listener-process.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,iBAAiB,QAAiC,CAAC;AAChE,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,QAAqC,CAAC;AACxE,eAAO,MAAM,iBAAiB,QAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"listener-process.d.ts","sourceRoot":"","sources":["../src/listener-process.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,iBAAiB,QAAiC,CAAC;AAChE,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,QAAqC,CAAC;AACxE,eAAO,MAAM,iBAAiB,QAAiC,CAAC;AAEhE,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAAsD,CAAC;AAEtG;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,IAS9C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAO,MAAM,GAAG,IAMlD,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,IAItD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,KAAG,IASlD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAAO,IAQ5C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAU,KAAK,MAAM,EAAE,kBAAiB,KAAG,OAAO,CAAC,OAAO,CAqBlF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,QAAO,MAAM,GAAG,IAM1C,CAAC;AAgBF,eAAO,MAAM,wBAAwB,QAAO,IAO3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAO,OAgBxC,CAAC"}
|
package/dist/listener-process.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.spawnListenerDetached = exports.rotateListenerLogIfLarge = exports.resolveCliPath = exports.stopListener = exports.clearStaleListenerRuntime = exports.clearListenerRuntime = exports.writeListenerRuntime = exports.runningListenerVersion = exports.runningListenerPid = exports.LISTENER_LOG_FILE = exports.LISTENER_VERSION_FILE = exports.LISTENER_PID_FILE = void 0;
|
|
3
|
+
exports.spawnListenerDetached = exports.rotateListenerLogIfLarge = exports.resolveCliPath = exports.stopListener = exports.clearStaleListenerRuntime = exports.clearListenerRuntime = exports.writeListenerRuntime = exports.runningListenerVersion = exports.runningListenerPid = exports.sleep = exports.LISTENER_LOG_FILE = exports.LISTENER_VERSION_FILE = exports.LISTENER_PID_FILE = void 0;
|
|
4
4
|
const node_child_process_1 = require("node:child_process");
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
6
|
const node_os_1 = require("node:os");
|
|
@@ -28,6 +28,7 @@ exports.LISTENER_PID_FILE = (0, node_path_1.join)(ZEPH_DIR, 'listener.pid');
|
|
|
28
28
|
exports.LISTENER_VERSION_FILE = (0, node_path_1.join)(ZEPH_DIR, 'listener.version');
|
|
29
29
|
exports.LISTENER_LOG_FILE = (0, node_path_1.join)(ZEPH_DIR, 'listener.log');
|
|
30
30
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
31
|
+
exports.sleep = sleep;
|
|
31
32
|
/**
|
|
32
33
|
* PID of the listener on record, or null when the file is missing or stale.
|
|
33
34
|
* Stale PID files (process gone) read as "no listener" so a crashed daemon
|
|
@@ -121,7 +122,7 @@ const stopListener = async (pid, timeoutMs = 3_000) => {
|
|
|
121
122
|
}
|
|
122
123
|
const deadline = Date.now() + timeoutMs;
|
|
123
124
|
while (Date.now() < deadline) {
|
|
124
|
-
await sleep(50);
|
|
125
|
+
await (0, exports.sleep)(50);
|
|
125
126
|
try {
|
|
126
127
|
process.kill(pid, 0);
|
|
127
128
|
}
|
|
@@ -166,7 +167,14 @@ exports.resolveCliPath = resolveCliPath;
|
|
|
166
167
|
/**
|
|
167
168
|
* Rotate the listener log once it grows past 5 MB. The daemon runs for days
|
|
168
169
|
* and writes 2-3 lines per 5-s cycle, so without rotation the file climbs
|
|
169
|
-
* into the tens of megabytes. Keep the previous
|
|
170
|
+
* into the tens of megabytes. Keep the previous window under `.old`.
|
|
171
|
+
*
|
|
172
|
+
* Copy-truncate rather than rename, because the writer is not always ours.
|
|
173
|
+
* Under the login-time LaunchAgent, launchd opens `StandardOutPath` itself
|
|
174
|
+
* and holds that fd for the life of the job: a rename moves the directory
|
|
175
|
+
* entry and leaves launchd appending to the very same inode, now called
|
|
176
|
+
* `.old`. The log the user tails would never shrink. Emptying the file in
|
|
177
|
+
* place keeps the inode — and the fd — valid.
|
|
170
178
|
*/
|
|
171
179
|
const LISTENER_LOG_MAX_BYTES = 5 * 1024 * 1024;
|
|
172
180
|
const rotateListenerLogIfLarge = () => {
|
|
@@ -175,7 +183,8 @@ const rotateListenerLogIfLarge = () => {
|
|
|
175
183
|
return;
|
|
176
184
|
if ((0, node_fs_1.statSync)(exports.LISTENER_LOG_FILE).size <= LISTENER_LOG_MAX_BYTES)
|
|
177
185
|
return;
|
|
178
|
-
(0, node_fs_1.
|
|
186
|
+
(0, node_fs_1.copyFileSync)(exports.LISTENER_LOG_FILE, exports.LISTENER_LOG_FILE + '.old');
|
|
187
|
+
(0, node_fs_1.truncateSync)(exports.LISTENER_LOG_FILE, 0);
|
|
179
188
|
}
|
|
180
189
|
catch { /* best-effort */ }
|
|
181
190
|
};
|
|
@@ -192,7 +201,6 @@ const spawnListenerDetached = () => {
|
|
|
192
201
|
return false;
|
|
193
202
|
try {
|
|
194
203
|
(0, node_fs_1.mkdirSync)(ZEPH_DIR, { recursive: true });
|
|
195
|
-
(0, exports.rotateListenerLogIfLarge)();
|
|
196
204
|
const out = (0, node_fs_1.openSync)(exports.LISTENER_LOG_FILE, 'a');
|
|
197
205
|
const child = (0, node_child_process_1.spawn)(process.execPath, [cliPath, 'listener'], {
|
|
198
206
|
detached: true,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The listener as an OS service: a launchd LaunchAgent that starts it at user
|
|
3
|
+
* login so the phone's picker is populated without anyone opening a terminal.
|
|
4
|
+
*
|
|
5
|
+
* Until this existed, the only thing that ever started the daemon was
|
|
6
|
+
* `zeph cc` (wrapper.ts → spawnListenerDetached). After a reboot that means an
|
|
7
|
+
* empty picker until the user happens to launch an agent — the machine is
|
|
8
|
+
* online, the past sessions are on disk, and the app says "no agents".
|
|
9
|
+
*
|
|
10
|
+
* Two constraints shape this file:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Node builtins only.** wrapper.ts reads `serviceInstalled()` on the
|
|
13
|
+
* `zeph cc` hot path, and the same rule that keeps listener.ts out of
|
|
14
|
+
* wrapper.ts (ws + the crypto stack on every agent launch) applies here.
|
|
15
|
+
* listener-process.ts is the one import, and it is builtins-only too.
|
|
16
|
+
*
|
|
17
|
+
* 2. **Everything the job needs is resolved at install time and baked into
|
|
18
|
+
* the plist.** launchd hands a job `/usr/bin:/bin:/usr/sbin:/sbin` and
|
|
19
|
+
* nothing else — no shell profile, no homebrew prefix. `verifyTmux()`
|
|
20
|
+
* (listener.ts) exits 127 when tmux is not on PATH, so a plist without a
|
|
21
|
+
* baked PATH produces a service that dies at every login and is restarted
|
|
22
|
+
* forever by KeepAlive. The interpreter is baked for the same reason.
|
|
23
|
+
*/
|
|
24
|
+
/** Reverse-DNS launchd label. Lives on the user's machine once installed —
|
|
25
|
+
* renaming it orphans every plist already out there. */
|
|
26
|
+
export declare const SERVICE_LABEL = "to.zeph.listener";
|
|
27
|
+
export interface ServiceSpec {
|
|
28
|
+
readonly nodePath: string;
|
|
29
|
+
readonly cliPath: string;
|
|
30
|
+
readonly tmuxPath: string;
|
|
31
|
+
readonly logPath: string;
|
|
32
|
+
/** PATH baked into the job: tmux dir, node dir, then launchd's own. */
|
|
33
|
+
readonly pathEnv: string;
|
|
34
|
+
/** UTF-8 locale baked into the job. Always UTF-8 — see resolveServiceSpec. */
|
|
35
|
+
readonly lang: string;
|
|
36
|
+
}
|
|
37
|
+
export type SpecResolution = {
|
|
38
|
+
readonly ok: true;
|
|
39
|
+
readonly value: ServiceSpec;
|
|
40
|
+
readonly warning?: string;
|
|
41
|
+
} | {
|
|
42
|
+
readonly ok: false;
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
};
|
|
45
|
+
/** The machine facts spec resolution needs, injectable so tests describe a
|
|
46
|
+
* machine instead of inheriting the developer's own. */
|
|
47
|
+
export interface ServiceEnv {
|
|
48
|
+
readonly exists: (path: string) => boolean;
|
|
49
|
+
/** Major version of the node at `path`, or null when it won't run. */
|
|
50
|
+
readonly nodeMajor: (path: string) => number | null;
|
|
51
|
+
/** Absolute tmux path from the invoking shell's PATH, or null. */
|
|
52
|
+
readonly whichTmux: () => string | null;
|
|
53
|
+
readonly cliPath: () => string | null;
|
|
54
|
+
/** The invoking shell's LANG, or undefined when it has none. */
|
|
55
|
+
readonly lang: () => string | undefined;
|
|
56
|
+
}
|
|
57
|
+
export interface ServiceStatus {
|
|
58
|
+
readonly supported: boolean;
|
|
59
|
+
readonly installed: boolean;
|
|
60
|
+
readonly label: string;
|
|
61
|
+
readonly plistPath: string;
|
|
62
|
+
/** Read back from the installed plist — null when nothing is installed. */
|
|
63
|
+
readonly nodePath: string | null;
|
|
64
|
+
readonly cliPath: string | null;
|
|
65
|
+
readonly pathEnv: string | null;
|
|
66
|
+
readonly langEnv: string | null;
|
|
67
|
+
/** Programs the plist names that are no longer on disk. The shape a node
|
|
68
|
+
* upgrade leaves behind: registered, listed by launchctl, unable to run. */
|
|
69
|
+
readonly missing: readonly string[];
|
|
70
|
+
}
|
|
71
|
+
/** launchd only exists on macOS. Every other platform is an explicit refusal,
|
|
72
|
+
* never a quiet success. */
|
|
73
|
+
export declare const serviceSupported: () => boolean;
|
|
74
|
+
export declare const servicePlistPath: () => string;
|
|
75
|
+
export declare const serviceInstalled: () => boolean;
|
|
76
|
+
export declare const defaultServiceEnv: ServiceEnv;
|
|
77
|
+
/**
|
|
78
|
+
* Decide what to bake into the plist, or say why we can't. Nothing is written
|
|
79
|
+
* and nothing is registered — a caller that gets `ok: false` has touched
|
|
80
|
+
* nothing on the machine.
|
|
81
|
+
*/
|
|
82
|
+
export declare const resolveServiceSpec: (env?: ServiceEnv) => SpecResolution;
|
|
83
|
+
export declare const renderLaunchAgentPlist: (spec: ServiceSpec) => string;
|
|
84
|
+
/**
|
|
85
|
+
* What is registered on this machine and whether it can still run. The single
|
|
86
|
+
* source `verify`, `--service-status` and the `zeph cc` branch all read, so
|
|
87
|
+
* they can never disagree about whether a service is installed.
|
|
88
|
+
*/
|
|
89
|
+
export declare const serviceStatus: () => ServiceStatus;
|
|
90
|
+
/**
|
|
91
|
+
* Side effects the service operations need, injectable so tests can drive the
|
|
92
|
+
* launchd sequence without a launchd.
|
|
93
|
+
*/
|
|
94
|
+
export interface ServiceOpDeps {
|
|
95
|
+
readonly supported: () => boolean;
|
|
96
|
+
readonly resolveSpec: () => SpecResolution;
|
|
97
|
+
/** PID of a listener running right now, or null. */
|
|
98
|
+
readonly runningPid: () => number | null;
|
|
99
|
+
readonly stopListener: (pid: number) => Promise<boolean>;
|
|
100
|
+
readonly launchctl: (args: string[]) => {
|
|
101
|
+
ok: boolean;
|
|
102
|
+
stderr: string;
|
|
103
|
+
};
|
|
104
|
+
readonly settle: (ms: number) => Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
export type ServiceOpResult = {
|
|
107
|
+
readonly ok: true;
|
|
108
|
+
readonly notes: readonly string[];
|
|
109
|
+
} | {
|
|
110
|
+
readonly ok: false;
|
|
111
|
+
readonly reason: string;
|
|
112
|
+
readonly notes: readonly string[];
|
|
113
|
+
};
|
|
114
|
+
export declare const defaultServiceOpDeps: ServiceOpDeps;
|
|
115
|
+
/**
|
|
116
|
+
* Register the LaunchAgent and get the daemon running under it.
|
|
117
|
+
*
|
|
118
|
+
* The order is load-bearing, not incidental:
|
|
119
|
+
*
|
|
120
|
+
* - **Any listener already running is stopped first.** `handleListener` exits
|
|
121
|
+
* **0** when it finds another listener alive, and it only does so quietly
|
|
122
|
+
* under ZEPH_LISTENER_AUTOSTART, which a launchd job does not have. So a
|
|
123
|
+
* kickstart into a live `zeph cc` daemon produces a clean exit, and
|
|
124
|
+
* `KeepAlive:{SuccessfulExit:false}` reads a clean exit as "stay down" —
|
|
125
|
+
* for the whole login session. `launchctl list` shows the job; nothing runs.
|
|
126
|
+
* - **Nothing is written until the spec resolves.** A refusal leaves the
|
|
127
|
+
* machine exactly as it was.
|
|
128
|
+
* - **The daemon is confirmed alive afterwards.** Without that check the
|
|
129
|
+
* failure above ships silently.
|
|
130
|
+
*/
|
|
131
|
+
export declare const installService: (deps?: ServiceOpDeps) => Promise<ServiceOpResult>;
|
|
132
|
+
/** Unregister the job and remove the plist. Doing only one of the two leaves
|
|
133
|
+
* either a running service with no plist or a plist launchd ignores. */
|
|
134
|
+
export declare const uninstallService: (deps?: ServiceOpDeps) => Promise<ServiceOpResult>;
|
|
135
|
+
/**
|
|
136
|
+
* Stop the service until the next login.
|
|
137
|
+
*
|
|
138
|
+
* `bootout` and not `disable`: disable writes to launchd's persistent disabled
|
|
139
|
+
* database, survives logins, and leaves no obvious way back — a `--stop` that
|
|
140
|
+
* quietly becomes permanent. Session-scoped is what stopping should mean.
|
|
141
|
+
*/
|
|
142
|
+
export declare const stopService: (deps?: ServiceOpDeps) => ServiceOpResult;
|
|
143
|
+
/** Restart the service in place. `-k` kills the running instance first, so this
|
|
144
|
+
* is also how a version-drifted daemon is replaced. */
|
|
145
|
+
export declare const restartService: (deps?: ServiceOpDeps) => ServiceOpResult;
|
|
146
|
+
export interface ServiceHealthRow {
|
|
147
|
+
readonly label: string;
|
|
148
|
+
readonly state: 'pass' | 'warn' | 'fail';
|
|
149
|
+
}
|
|
150
|
+
/** The two live facts a health check can't read off the plist. */
|
|
151
|
+
export interface ServiceProbe {
|
|
152
|
+
/** Can a process started with this PATH find tmux? */
|
|
153
|
+
readonly tmuxOnPath: (pathEnv: string) => boolean;
|
|
154
|
+
/** Is launchd actually running the job right now? */
|
|
155
|
+
readonly loaded: () => boolean;
|
|
156
|
+
}
|
|
157
|
+
export declare const defaultServiceProbe: ServiceProbe;
|
|
158
|
+
/**
|
|
159
|
+
* Why this exists: every way the service breaks leaves it looking installed.
|
|
160
|
+
* `launchctl list` shows the job whether or not its interpreter still exists,
|
|
161
|
+
* and a PATH without tmux makes the daemon exit 127 at every login while the
|
|
162
|
+
* registration sits there unchanged. None of that is visible without asking.
|
|
163
|
+
*/
|
|
164
|
+
export declare const serviceHealthChecks: (status: ServiceStatus, probe?: ServiceProbe) => ServiceHealthRow[];
|
|
165
|
+
//# sourceMappingURL=listener-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener-service.d.ts","sourceRoot":"","sources":["../src/listener-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serviceHealthChecks = exports.defaultServiceProbe = exports.restartService = exports.stopService = exports.uninstallService = exports.installService = exports.defaultServiceOpDeps = exports.serviceStatus = exports.renderLaunchAgentPlist = exports.resolveServiceSpec = exports.defaultServiceEnv = exports.serviceInstalled = exports.servicePlistPath = exports.serviceSupported = exports.SERVICE_LABEL = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const listener_process_js_1 = require("./listener-process.js");
|
|
9
|
+
/**
|
|
10
|
+
* The listener as an OS service: a launchd LaunchAgent that starts it at user
|
|
11
|
+
* login so the phone's picker is populated without anyone opening a terminal.
|
|
12
|
+
*
|
|
13
|
+
* Until this existed, the only thing that ever started the daemon was
|
|
14
|
+
* `zeph cc` (wrapper.ts → spawnListenerDetached). After a reboot that means an
|
|
15
|
+
* empty picker until the user happens to launch an agent — the machine is
|
|
16
|
+
* online, the past sessions are on disk, and the app says "no agents".
|
|
17
|
+
*
|
|
18
|
+
* Two constraints shape this file:
|
|
19
|
+
*
|
|
20
|
+
* 1. **Node builtins only.** wrapper.ts reads `serviceInstalled()` on the
|
|
21
|
+
* `zeph cc` hot path, and the same rule that keeps listener.ts out of
|
|
22
|
+
* wrapper.ts (ws + the crypto stack on every agent launch) applies here.
|
|
23
|
+
* listener-process.ts is the one import, and it is builtins-only too.
|
|
24
|
+
*
|
|
25
|
+
* 2. **Everything the job needs is resolved at install time and baked into
|
|
26
|
+
* the plist.** launchd hands a job `/usr/bin:/bin:/usr/sbin:/sbin` and
|
|
27
|
+
* nothing else — no shell profile, no homebrew prefix. `verifyTmux()`
|
|
28
|
+
* (listener.ts) exits 127 when tmux is not on PATH, so a plist without a
|
|
29
|
+
* baked PATH produces a service that dies at every login and is restarted
|
|
30
|
+
* forever by KeepAlive. The interpreter is baked for the same reason.
|
|
31
|
+
*/
|
|
32
|
+
/** Reverse-DNS launchd label. Lives on the user's machine once installed —
|
|
33
|
+
* renaming it orphans every plist already out there. */
|
|
34
|
+
exports.SERVICE_LABEL = 'to.zeph.listener';
|
|
35
|
+
/** `package.json` engines floor. A node below this starts and dies. */
|
|
36
|
+
const MIN_NODE_MAJOR = 18;
|
|
37
|
+
/** What launchd itself puts on PATH. Ours is prepended, never replaces this. */
|
|
38
|
+
const LAUNCHD_BASE_PATH = ['/usr/bin', '/bin', '/usr/sbin', '/sbin'];
|
|
39
|
+
/** Interpreters to try when the CLI's own install prefix has none. */
|
|
40
|
+
const NODE_FALLBACKS = ['/opt/homebrew/bin/node', '/usr/local/bin/node'];
|
|
41
|
+
/**
|
|
42
|
+
* Locale to fall back on when the shell has none, or has a non-UTF-8 one.
|
|
43
|
+
*
|
|
44
|
+
* launchd hands a job no LANG at all. tmux then runs in the C locale and
|
|
45
|
+
* escapes every non-ASCII byte of its format output to `_` — including the
|
|
46
|
+
* U+241F separator the session inventory is split on. The daemon starts
|
|
47
|
+
* clean, tmux answers, and every session is discarded as unparseable: the
|
|
48
|
+
* phone shows nothing while `launchctl list` and the log both look healthy.
|
|
49
|
+
*/
|
|
50
|
+
const FALLBACK_LANG = 'en_US.UTF-8';
|
|
51
|
+
/** tmux locations to try when the shell can't answer `command -v`. */
|
|
52
|
+
const TMUX_FALLBACKS = ['/opt/homebrew/bin/tmux', '/usr/local/bin/tmux', '/usr/bin/tmux'];
|
|
53
|
+
/** Version-manager roots. A node under one of these is gone after the next
|
|
54
|
+
* upgrade, which silently breaks the service months later. */
|
|
55
|
+
const VERSION_MANAGER_DIRS = ['/.nvm/', '/.fnm/', '/.volta/', '/.nodenv/', '/.asdf/', '/.n/'];
|
|
56
|
+
/** launchd only exists on macOS. Every other platform is an explicit refusal,
|
|
57
|
+
* never a quiet success. */
|
|
58
|
+
const serviceSupported = () => process.platform === 'darwin';
|
|
59
|
+
exports.serviceSupported = serviceSupported;
|
|
60
|
+
const servicePlistPath = () => (0, node_path_1.join)((0, node_os_1.homedir)(), 'Library', 'LaunchAgents', `${exports.SERVICE_LABEL}.plist`);
|
|
61
|
+
exports.servicePlistPath = servicePlistPath;
|
|
62
|
+
const serviceInstalled = () => (0, node_fs_1.existsSync)((0, exports.servicePlistPath)());
|
|
63
|
+
exports.serviceInstalled = serviceInstalled;
|
|
64
|
+
/** This user's launchd GUI domain, and our job within it. Not exported: every
|
|
65
|
+
* launchctl call lives in this file, and the label is an implementation
|
|
66
|
+
* detail of that. */
|
|
67
|
+
const serviceDomain = () => `gui/${process.getuid?.() ?? 0}`;
|
|
68
|
+
const serviceTarget = () => `${serviceDomain()}/${exports.SERVICE_LABEL}`;
|
|
69
|
+
const nodeMajorOf = (path) => {
|
|
70
|
+
try {
|
|
71
|
+
const out = (0, node_child_process_1.execFileSync)(path, ['-v'], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
72
|
+
const major = Number(out.trim().replace(/^v/, '').split('.')[0]);
|
|
73
|
+
return Number.isFinite(major) ? major : null;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const whichTmuxFromShell = () => {
|
|
80
|
+
try {
|
|
81
|
+
// `/bin/sh -c` on purpose: `which` in an interactive zsh resolves the
|
|
82
|
+
// user's tmux *alias*, which is not a path we can hand to launchd.
|
|
83
|
+
const out = (0, node_child_process_1.execFileSync)('/bin/sh', ['-c', 'command -v tmux'], {
|
|
84
|
+
encoding: 'utf-8',
|
|
85
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
86
|
+
}).trim();
|
|
87
|
+
return out.startsWith('/') ? out : null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
exports.defaultServiceEnv = {
|
|
94
|
+
exists: node_fs_1.existsSync,
|
|
95
|
+
nodeMajor: nodeMajorOf,
|
|
96
|
+
whichTmux: whichTmuxFromShell,
|
|
97
|
+
cliPath: listener_process_js_1.resolveCliPath,
|
|
98
|
+
lang: () => process.env.LANG,
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The interpreter that owns the CLI's install prefix.
|
|
102
|
+
*
|
|
103
|
+
* A global install lives at `<prefix>/lib/node_modules/@zeph-to/cli/dist/cli.js`
|
|
104
|
+
* and its node is `<prefix>/bin/node`. Preferring it keeps the plist internally
|
|
105
|
+
* consistent; picking whichever node happens to exist can pair a homebrew
|
|
106
|
+
* interpreter with a `~/.local` install — a combination that works on the
|
|
107
|
+
* machine that wrote it and breaks on the next one.
|
|
108
|
+
*/
|
|
109
|
+
const prefixNodeFor = (cliPath) => {
|
|
110
|
+
const marker = '/lib/node_modules/';
|
|
111
|
+
const at = cliPath.indexOf(marker);
|
|
112
|
+
if (at < 0)
|
|
113
|
+
return null;
|
|
114
|
+
return (0, node_path_1.join)(cliPath.slice(0, at), 'bin', 'node');
|
|
115
|
+
};
|
|
116
|
+
const isVersionManaged = (nodePath) => VERSION_MANAGER_DIRS.some((dir) => nodePath.includes(dir));
|
|
117
|
+
const dedupe = (values) => [...new Set(values)];
|
|
118
|
+
/**
|
|
119
|
+
* Decide what to bake into the plist, or say why we can't. Nothing is written
|
|
120
|
+
* and nothing is registered — a caller that gets `ok: false` has touched
|
|
121
|
+
* nothing on the machine.
|
|
122
|
+
*/
|
|
123
|
+
const resolveServiceSpec = (env = exports.defaultServiceEnv) => {
|
|
124
|
+
const cliPath = env.cliPath();
|
|
125
|
+
if (!cliPath) {
|
|
126
|
+
return { ok: false, reason: 'could not resolve the zeph CLI entry (dist/cli.js) to run' };
|
|
127
|
+
}
|
|
128
|
+
const tmuxPath = env.whichTmux() ?? TMUX_FALLBACKS.find(env.exists) ?? null;
|
|
129
|
+
if (!tmuxPath) {
|
|
130
|
+
return { ok: false, reason: 'tmux not found — install tmux first (the listener drives tmux panes)' };
|
|
131
|
+
}
|
|
132
|
+
const prefixNode = prefixNodeFor(cliPath);
|
|
133
|
+
const candidates = dedupe([...(prefixNode ? [prefixNode] : []), ...NODE_FALLBACKS, process.execPath]);
|
|
134
|
+
const nodePath = candidates.find((c) => env.exists(c) && (env.nodeMajor(c) ?? 0) >= MIN_NODE_MAJOR);
|
|
135
|
+
if (!nodePath) {
|
|
136
|
+
return { ok: false, reason: `no node >= ${MIN_NODE_MAJOR} found to run the listener with` };
|
|
137
|
+
}
|
|
138
|
+
const pathEnv = dedupe([(0, node_path_1.dirname)(tmuxPath), (0, node_path_1.dirname)(nodePath), ...LAUNCHD_BASE_PATH]).join(':');
|
|
139
|
+
const shellLang = env.lang();
|
|
140
|
+
const lang = shellLang && /utf-?8$/i.test(shellLang) ? shellLang : FALLBACK_LANG;
|
|
141
|
+
const spec = { nodePath, cliPath, tmuxPath, logPath: listener_process_js_1.LISTENER_LOG_FILE, pathEnv, lang };
|
|
142
|
+
if (isVersionManaged(nodePath)) {
|
|
143
|
+
return {
|
|
144
|
+
ok: true,
|
|
145
|
+
value: spec,
|
|
146
|
+
warning: `${nodePath} belongs to a node version manager — the service will stop working ` +
|
|
147
|
+
`after a node upgrade. Re-run \`zeph listener --install-service\` if that happens ` +
|
|
148
|
+
`(\`zeph verify\` reports it).`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return { ok: true, value: spec };
|
|
152
|
+
};
|
|
153
|
+
exports.resolveServiceSpec = resolveServiceSpec;
|
|
154
|
+
const escapeXml = (value) => value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
155
|
+
const renderLaunchAgentPlist = (spec) => {
|
|
156
|
+
const s = (value) => `<string>${escapeXml(value)}</string>`;
|
|
157
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
158
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
159
|
+
<plist version="1.0">
|
|
160
|
+
<dict>
|
|
161
|
+
<key>Label</key>
|
|
162
|
+
${s(exports.SERVICE_LABEL)}
|
|
163
|
+
<key>ProgramArguments</key>
|
|
164
|
+
<array>
|
|
165
|
+
${s(spec.nodePath)}
|
|
166
|
+
${s(spec.cliPath)}
|
|
167
|
+
<string>listener</string>
|
|
168
|
+
</array>
|
|
169
|
+
<key>RunAtLoad</key>
|
|
170
|
+
<true/>
|
|
171
|
+
<key>KeepAlive</key>
|
|
172
|
+
<dict>
|
|
173
|
+
<key>SuccessfulExit</key>
|
|
174
|
+
<false/>
|
|
175
|
+
</dict>
|
|
176
|
+
<key>ThrottleInterval</key>
|
|
177
|
+
<integer>30</integer>
|
|
178
|
+
<key>StandardOutPath</key>
|
|
179
|
+
${s(spec.logPath)}
|
|
180
|
+
<key>StandardErrorPath</key>
|
|
181
|
+
${s(spec.logPath)}
|
|
182
|
+
<key>EnvironmentVariables</key>
|
|
183
|
+
<dict>
|
|
184
|
+
<key>PATH</key>
|
|
185
|
+
${s(spec.pathEnv)}
|
|
186
|
+
<key>LANG</key>
|
|
187
|
+
${s(spec.lang)}
|
|
188
|
+
<key>ZEPH_LISTENER_SERVICE</key>
|
|
189
|
+
<string>1</string>
|
|
190
|
+
</dict>
|
|
191
|
+
</dict>
|
|
192
|
+
</plist>
|
|
193
|
+
`;
|
|
194
|
+
};
|
|
195
|
+
exports.renderLaunchAgentPlist = renderLaunchAgentPlist;
|
|
196
|
+
const unescapeXml = (value) => value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
|
197
|
+
/** ProgramArguments strings, in order, from an installed plist. */
|
|
198
|
+
const readProgramArguments = (xml) => {
|
|
199
|
+
const block = /<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/.exec(xml);
|
|
200
|
+
if (!block)
|
|
201
|
+
return [];
|
|
202
|
+
return [...block[1].matchAll(/<string>([\s\S]*?)<\/string>/g)].map((m) => unescapeXml(m[1]));
|
|
203
|
+
};
|
|
204
|
+
const readEnvValue = (xml, key) => {
|
|
205
|
+
const found = new RegExp(`<key>${key}</key>\\s*<string>([\\s\\S]*?)</string>`).exec(xml);
|
|
206
|
+
return found ? unescapeXml(found[1]) : null;
|
|
207
|
+
};
|
|
208
|
+
const NOT_INSTALLED = {
|
|
209
|
+
installed: false,
|
|
210
|
+
nodePath: null,
|
|
211
|
+
cliPath: null,
|
|
212
|
+
pathEnv: null,
|
|
213
|
+
langEnv: null,
|
|
214
|
+
missing: [],
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* What is registered on this machine and whether it can still run. The single
|
|
218
|
+
* source `verify`, `--service-status` and the `zeph cc` branch all read, so
|
|
219
|
+
* they can never disagree about whether a service is installed.
|
|
220
|
+
*/
|
|
221
|
+
const serviceStatus = () => {
|
|
222
|
+
const plistPath = (0, exports.servicePlistPath)();
|
|
223
|
+
const base = { supported: (0, exports.serviceSupported)(), label: exports.SERVICE_LABEL, plistPath };
|
|
224
|
+
if (!(0, node_fs_1.existsSync)(plistPath))
|
|
225
|
+
return { ...base, ...NOT_INSTALLED };
|
|
226
|
+
let xml = '';
|
|
227
|
+
try {
|
|
228
|
+
xml = (0, node_fs_1.readFileSync)(plistPath, 'utf-8');
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// The plist is there but unreadable — installed, nothing knowable.
|
|
232
|
+
return { ...base, ...NOT_INSTALLED, installed: true };
|
|
233
|
+
}
|
|
234
|
+
const [nodePath = null, cliPath = null] = readProgramArguments(xml);
|
|
235
|
+
const missing = [nodePath, cliPath].filter((p) => !!p && !(0, node_fs_1.existsSync)(p));
|
|
236
|
+
return {
|
|
237
|
+
...base,
|
|
238
|
+
installed: true,
|
|
239
|
+
nodePath,
|
|
240
|
+
cliPath,
|
|
241
|
+
pathEnv: readEnvValue(xml, 'PATH'),
|
|
242
|
+
langEnv: readEnvValue(xml, 'LANG'),
|
|
243
|
+
missing,
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
exports.serviceStatus = serviceStatus;
|
|
247
|
+
/** How long to give launchd to get the daemon up before calling the install
|
|
248
|
+
* a failure. Generous: the daemon writes its pid file as its first act. */
|
|
249
|
+
const POST_INSTALL_SETTLE_MS = 3_000;
|
|
250
|
+
const runLaunchctl = (args) => {
|
|
251
|
+
try {
|
|
252
|
+
(0, node_child_process_1.execFileSync)('launchctl', args, { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
253
|
+
return { ok: true, stderr: '' };
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
const stderr = err.stderr?.toString().trim() ?? '';
|
|
257
|
+
return { ok: false, stderr };
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
exports.defaultServiceOpDeps = {
|
|
261
|
+
supported: exports.serviceSupported,
|
|
262
|
+
resolveSpec: () => (0, exports.resolveServiceSpec)(),
|
|
263
|
+
runningPid: listener_process_js_1.runningListenerPid,
|
|
264
|
+
stopListener: listener_process_js_1.stopListener,
|
|
265
|
+
launchctl: runLaunchctl,
|
|
266
|
+
settle: listener_process_js_1.sleep,
|
|
267
|
+
};
|
|
268
|
+
const UNSUPPORTED = 'the login-time service needs launchd — only macOS is supported today ' +
|
|
269
|
+
'(run `zeph listener` yourself, or keep using `zeph cc` to autostart it)';
|
|
270
|
+
/**
|
|
271
|
+
* Register the LaunchAgent and get the daemon running under it.
|
|
272
|
+
*
|
|
273
|
+
* The order is load-bearing, not incidental:
|
|
274
|
+
*
|
|
275
|
+
* - **Any listener already running is stopped first.** `handleListener` exits
|
|
276
|
+
* **0** when it finds another listener alive, and it only does so quietly
|
|
277
|
+
* under ZEPH_LISTENER_AUTOSTART, which a launchd job does not have. So a
|
|
278
|
+
* kickstart into a live `zeph cc` daemon produces a clean exit, and
|
|
279
|
+
* `KeepAlive:{SuccessfulExit:false}` reads a clean exit as "stay down" —
|
|
280
|
+
* for the whole login session. `launchctl list` shows the job; nothing runs.
|
|
281
|
+
* - **Nothing is written until the spec resolves.** A refusal leaves the
|
|
282
|
+
* machine exactly as it was.
|
|
283
|
+
* - **The daemon is confirmed alive afterwards.** Without that check the
|
|
284
|
+
* failure above ships silently.
|
|
285
|
+
*/
|
|
286
|
+
const installService = async (deps = exports.defaultServiceOpDeps) => {
|
|
287
|
+
const notes = [];
|
|
288
|
+
if (!deps.supported())
|
|
289
|
+
return { ok: false, reason: UNSUPPORTED, notes };
|
|
290
|
+
const spec = deps.resolveSpec();
|
|
291
|
+
if (!spec.ok)
|
|
292
|
+
return { ok: false, reason: spec.reason, notes };
|
|
293
|
+
if (spec.warning)
|
|
294
|
+
notes.push(spec.warning);
|
|
295
|
+
const running = deps.runningPid();
|
|
296
|
+
if (running !== null) {
|
|
297
|
+
await deps.stopListener(running);
|
|
298
|
+
notes.push(`stopped the listener already running (pid ${running}) so launchd can own it`);
|
|
299
|
+
}
|
|
300
|
+
// Nothing to unload before a first install — that failure is the normal path.
|
|
301
|
+
deps.launchctl(['bootout', serviceTarget()]);
|
|
302
|
+
const plistPath = (0, exports.servicePlistPath)();
|
|
303
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(plistPath), { recursive: true });
|
|
304
|
+
(0, node_fs_1.writeFileSync)(plistPath, (0, exports.renderLaunchAgentPlist)(spec.value));
|
|
305
|
+
notes.push(`wrote ${plistPath}`);
|
|
306
|
+
const bootstrap = deps.launchctl(['bootstrap', serviceDomain(), plistPath]);
|
|
307
|
+
if (!bootstrap.ok) {
|
|
308
|
+
return { ok: false, reason: `launchctl bootstrap failed: ${bootstrap.stderr || 'no detail'}`, notes };
|
|
309
|
+
}
|
|
310
|
+
// Best-effort: a job disabled by an earlier `launchctl disable` (ours never
|
|
311
|
+
// calls it, but a user's hand might have) would otherwise refuse to start.
|
|
312
|
+
deps.launchctl(['enable', serviceTarget()]);
|
|
313
|
+
const kickstart = deps.launchctl(['kickstart', '-k', serviceTarget()]);
|
|
314
|
+
if (!kickstart.ok) {
|
|
315
|
+
return { ok: false, reason: `launchctl kickstart failed: ${kickstart.stderr || 'no detail'}`, notes };
|
|
316
|
+
}
|
|
317
|
+
await deps.settle(POST_INSTALL_SETTLE_MS);
|
|
318
|
+
if (deps.runningPid() === null) {
|
|
319
|
+
return {
|
|
320
|
+
ok: false,
|
|
321
|
+
reason: `the service was registered but the listener did not stay up — see ${listener_process_js_1.LISTENER_LOG_FILE}`,
|
|
322
|
+
notes,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return { ok: true, notes };
|
|
326
|
+
};
|
|
327
|
+
exports.installService = installService;
|
|
328
|
+
/** Unregister the job and remove the plist. Doing only one of the two leaves
|
|
329
|
+
* either a running service with no plist or a plist launchd ignores. */
|
|
330
|
+
const uninstallService = async (deps = exports.defaultServiceOpDeps) => {
|
|
331
|
+
const notes = [];
|
|
332
|
+
const plistPath = (0, exports.servicePlistPath)();
|
|
333
|
+
if (!(0, node_fs_1.existsSync)(plistPath))
|
|
334
|
+
return { ok: true, notes: ['service not installed — nothing to remove'] };
|
|
335
|
+
deps.launchctl(['bootout', serviceTarget()]);
|
|
336
|
+
notes.push(`unloaded ${exports.SERVICE_LABEL}`);
|
|
337
|
+
(0, node_fs_1.rmSync)(plistPath, { force: true });
|
|
338
|
+
notes.push(`removed ${plistPath}`);
|
|
339
|
+
return { ok: true, notes };
|
|
340
|
+
};
|
|
341
|
+
exports.uninstallService = uninstallService;
|
|
342
|
+
/** One launchctl call reported as a ServiceOpResult, naming the subcommand in
|
|
343
|
+
* the failure so the user sees which step launchd refused. */
|
|
344
|
+
const askLaunchd = (deps, args, note) => {
|
|
345
|
+
const result = deps.launchctl(args);
|
|
346
|
+
if (result.ok)
|
|
347
|
+
return { ok: true, notes: [note] };
|
|
348
|
+
return { ok: false, reason: `launchctl ${args[0]} failed: ${result.stderr || 'no detail'}`, notes: [] };
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Stop the service until the next login.
|
|
352
|
+
*
|
|
353
|
+
* `bootout` and not `disable`: disable writes to launchd's persistent disabled
|
|
354
|
+
* database, survives logins, and leaves no obvious way back — a `--stop` that
|
|
355
|
+
* quietly becomes permanent. Session-scoped is what stopping should mean.
|
|
356
|
+
*/
|
|
357
|
+
const stopService = (deps = exports.defaultServiceOpDeps) => askLaunchd(deps, ['bootout', serviceTarget()], `unloaded ${exports.SERVICE_LABEL} — it comes back at the next login`);
|
|
358
|
+
exports.stopService = stopService;
|
|
359
|
+
/** Restart the service in place. `-k` kills the running instance first, so this
|
|
360
|
+
* is also how a version-drifted daemon is replaced. */
|
|
361
|
+
const restartService = (deps = exports.defaultServiceOpDeps) => askLaunchd(deps, ['kickstart', '-k', serviceTarget()], `restarted ${exports.SERVICE_LABEL}`);
|
|
362
|
+
exports.restartService = restartService;
|
|
363
|
+
const pathHasTmux = (pathEnv) => pathEnv.split(':').filter(Boolean).some((dir) => (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'tmux')));
|
|
364
|
+
const jobIsLoaded = () => runLaunchctl(['print', serviceTarget()]).ok;
|
|
365
|
+
exports.defaultServiceProbe = { tmuxOnPath: pathHasTmux, loaded: jobIsLoaded };
|
|
366
|
+
/**
|
|
367
|
+
* Why this exists: every way the service breaks leaves it looking installed.
|
|
368
|
+
* `launchctl list` shows the job whether or not its interpreter still exists,
|
|
369
|
+
* and a PATH without tmux makes the daemon exit 127 at every login while the
|
|
370
|
+
* registration sits there unchanged. None of that is visible without asking.
|
|
371
|
+
*/
|
|
372
|
+
const serviceHealthChecks = (status, probe = exports.defaultServiceProbe) => {
|
|
373
|
+
if (!status.supported)
|
|
374
|
+
return [];
|
|
375
|
+
if (!status.installed) {
|
|
376
|
+
return [
|
|
377
|
+
{
|
|
378
|
+
label: 'no login-time service — after a reboot the phone sees nothing until you run `zeph cc` '
|
|
379
|
+
+ '(add it: zeph listener --install-service)',
|
|
380
|
+
state: 'warn',
|
|
381
|
+
},
|
|
382
|
+
];
|
|
383
|
+
}
|
|
384
|
+
const rows = [{ label: `${status.label} registered`, state: 'pass' }];
|
|
385
|
+
if (status.missing.length > 0) {
|
|
386
|
+
rows.push({
|
|
387
|
+
label: `service points at ${status.missing.join(', ')} — gone. Re-run: zeph listener --install-service`,
|
|
388
|
+
state: 'fail',
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
rows.push({ label: 'service programs still exist', state: 'pass' });
|
|
393
|
+
}
|
|
394
|
+
// launchd hands the job its own bare PATH, so tmux has to come from what
|
|
395
|
+
// the plist baked in. Without it verifyTmux() exits 127 at every login.
|
|
396
|
+
if (status.pathEnv && probe.tmuxOnPath(status.pathEnv)) {
|
|
397
|
+
rows.push({ label: 'tmux reachable from the service PATH', state: 'pass' });
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
rows.push({
|
|
401
|
+
label: 'tmux NOT on the service PATH — the daemon exits 127 at login. '
|
|
402
|
+
+ 'Re-run: zeph listener --install-service',
|
|
403
|
+
state: 'fail',
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
// Without a UTF-8 LANG, tmux escapes the U+241F field separator to `_` and
|
|
407
|
+
// every session is dropped as unparseable — with nothing in the log that
|
|
408
|
+
// says so except a raw line the user has no reason to read as fatal.
|
|
409
|
+
if (status.langEnv && /utf-?8$/i.test(status.langEnv)) {
|
|
410
|
+
rows.push({ label: 'service locale is UTF-8', state: 'pass' });
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
rows.push({
|
|
414
|
+
label: 'service LANG is not UTF-8 — tmux mangles the session separator and every session is dropped. '
|
|
415
|
+
+ 'Re-run: zeph listener --install-service',
|
|
416
|
+
state: 'fail',
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
rows.push(probe.loaded()
|
|
420
|
+
? { label: 'launchd is running the job', state: 'pass' }
|
|
421
|
+
: { label: 'registered but launchd is not running it — it returns at the next login', state: 'warn' });
|
|
422
|
+
return rows;
|
|
423
|
+
};
|
|
424
|
+
exports.serviceHealthChecks = serviceHealthChecks;
|
package/dist/listener.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|
package/dist/listener.js
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-hook.d.ts","sourceRoot":"","sources":["../src/remote-hook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"remote-hook.d.ts","sourceRoot":"","sources":["../src/remote-hook.ts"],"names":[],"mappings":"AAyCA;wEACwE;AACxE,eAAO,MAAM,kBAAkB,8BAA+B,CAAC;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAoClE,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,GAAG,IAAI,eACE,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,eAAe,EACtB,OAAO,MAAM,EACb,MAAK,MAAM,CAAC,UAAwB,EACpC,MAAK,MAAM,MAAiB,KAC3B,MAAM,GAAG,IA0CX,CAAC"}
|
package/dist/remote-hook.js
CHANGED
|
@@ -31,6 +31,7 @@ exports.runRemoteHook = exports.isRemoteHookAgent = exports.REMOTE_HOOK_AGENTS =
|
|
|
31
31
|
* context and must never block a prompt.
|
|
32
32
|
*/
|
|
33
33
|
const fs_1 = require("fs");
|
|
34
|
+
const config_js_1 = require("./config.js");
|
|
34
35
|
const gate_js_1 = require("./gate.js");
|
|
35
36
|
/** Agents whose prompt-submit hooks this command serves. Claude Code is
|
|
36
37
|
* NOT here — its hook ships with the plugin (hooks/zeph-remote.sh). */
|
|
@@ -54,7 +55,7 @@ const TWO_WAY_CONTEXT = `# System note (Zeph remote-origin detect)
|
|
|
54
55
|
This user message arrived from the user's phone via Zeph agent chat (verified by the listener — exact text match). The user is driving this session remotely and is NOT at the terminal. Enter sticky REMOTE mode now (CORE_RULES Rule 9): end EVERY response with \`zeph_ask\` (buttons + free-text) until the user exits — an exit signal (done/stop/exit), or a prompt they type at the terminal, which this hook will tell you about. Plain-text questions are invisible to them.`;
|
|
55
56
|
const ONE_WAY_CONTEXT = `# System note (Zeph remote-origin detect)
|
|
56
57
|
|
|
57
|
-
This user message arrived from the user's phone via Zeph agent chat (verified by the listener — exact text match), but
|
|
58
|
+
This user message arrived from the user's phone via Zeph agent chat (verified by the listener — exact text match), but no hook id is configured (neither \`ZEPH_HOOK_ID\` nor \`hookId\` in ~/.zeph/config.json), so two-way tools (zeph_ask/zeph_prompt/zeph_input) are unavailable. Make your final message self-contained — the completion push is the user's only feedback channel. If you have not already mentioned it this session, tell the user once that running \`npx @zeph-to/cli setup\` upgrades this into a two-way remote session (buttons + text replies from the phone).`;
|
|
58
59
|
/**
|
|
59
60
|
* The first prompt a remote session's user types at the terminal. Emitted
|
|
60
61
|
* once — the state is cleared with it, so every later terminal turn is a
|
|
@@ -96,14 +97,16 @@ const runRemoteHook = (agent, stdin, env = process.env, now = Date.now) => {
|
|
|
96
97
|
// leaves the mode as it was.
|
|
97
98
|
const origin = remoteOrigin(prompt, cwd, now);
|
|
98
99
|
if (origin === 'phone') {
|
|
99
|
-
|
|
100
|
+
// Resolved on the two branches that need it, not up front — the common
|
|
101
|
+
// no-marker path never reads the config file.
|
|
102
|
+
if (!(0, config_js_1.resolveHookId)(env))
|
|
100
103
|
return emit(ONE_WAY_CONTEXT);
|
|
101
104
|
// Only a two-way session has a mode to stay in — without zeph_ask there is
|
|
102
105
|
// nothing for a later turn to be reminded of, so no state is recorded.
|
|
103
106
|
(0, gate_js_1.touchRemoteActive)(cwd, now);
|
|
104
107
|
return emit(TWO_WAY_CONTEXT);
|
|
105
108
|
}
|
|
106
|
-
if (origin === 'keyboard' &&
|
|
109
|
+
if (origin === 'keyboard' && (0, gate_js_1.isRemoteActive)(cwd, now) && (0, config_js_1.resolveHookId)(env)) {
|
|
107
110
|
(0, gate_js_1.clearRemoteActive)(cwd);
|
|
108
111
|
return emit(EXIT_CONTEXT);
|
|
109
112
|
}
|
package/dist/uninstall.d.ts
CHANGED
|
@@ -7,5 +7,13 @@ export declare const rmGeminiHook: (filePath: string, dry: boolean) => string |
|
|
|
7
7
|
* but events the user added since install survive. Exported for tests
|
|
8
8
|
* (codex is PATH-detected, same as gemini). */
|
|
9
9
|
export declare const rmCodexHook: (filePath: string, dry: boolean) => string | null;
|
|
10
|
+
/**
|
|
11
|
+
* Remove the login-time LaunchAgent, if one is installed.
|
|
12
|
+
*
|
|
13
|
+
* Async, so it does not fit the sync `Step` shape the per-agent uninstallers
|
|
14
|
+
* use — launchctl has to be waited on. Returns the same "one line or null"
|
|
15
|
+
* contract those steps do.
|
|
16
|
+
*/
|
|
17
|
+
export declare const removeServiceStep: (dry: boolean) => Promise<string | null>;
|
|
10
18
|
export declare const handleUninstall: (args: Record<string, string | boolean>) => Promise<number>;
|
|
11
19
|
//# sourceMappingURL=uninstall.d.ts.map
|
package/dist/uninstall.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../src/uninstall.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../src/uninstall.ts"],"names":[],"mappings":"AAwGA;;iDAEiD;AACjD,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAWtE,CAAC;AAEF;;;gDAGgD;AAChD,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAerE,CAAC;AAqEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAM3E,CAAC;AAIF,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAoC5F,CAAC"}
|
package/dist/uninstall.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleUninstall = exports.rmCodexHook = exports.rmGeminiHook = void 0;
|
|
3
|
+
exports.handleUninstall = exports.removeServiceStep = exports.rmCodexHook = exports.rmGeminiHook = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
6
|
const os_1 = require("os");
|
|
7
7
|
const path_1 = require("path");
|
|
8
8
|
const agents_js_1 = require("./agents.js");
|
|
9
|
+
const listener_service_js_1 = require("./listener-service.js");
|
|
9
10
|
const templates_js_1 = require("./templates.js");
|
|
10
11
|
const config_js_1 = require("./config.js");
|
|
11
12
|
const HOME = (0, os_1.homedir)();
|
|
@@ -235,6 +236,24 @@ const AGENT_UNINSTALLERS = {
|
|
|
235
236
|
() => rmAiderReadDirective((0, path_1.join)(HOME, '.aider.conf.yml'), dry),
|
|
236
237
|
]),
|
|
237
238
|
};
|
|
239
|
+
/**
|
|
240
|
+
* Remove the login-time LaunchAgent, if one is installed.
|
|
241
|
+
*
|
|
242
|
+
* Async, so it does not fit the sync `Step` shape the per-agent uninstallers
|
|
243
|
+
* use — launchctl has to be waited on. Returns the same "one line or null"
|
|
244
|
+
* contract those steps do.
|
|
245
|
+
*/
|
|
246
|
+
const removeServiceStep = async (dry) => {
|
|
247
|
+
if (!(0, listener_service_js_1.serviceInstalled)())
|
|
248
|
+
return null;
|
|
249
|
+
if (dry)
|
|
250
|
+
return `would remove the login-time service (${listener_service_js_1.SERVICE_LABEL})`;
|
|
251
|
+
const result = await (0, listener_service_js_1.uninstallService)();
|
|
252
|
+
if (!result.ok)
|
|
253
|
+
return `could not remove the login-time service: ${result.reason}`;
|
|
254
|
+
return `removed the login-time service (${listener_service_js_1.SERVICE_LABEL})`;
|
|
255
|
+
};
|
|
256
|
+
exports.removeServiceStep = removeServiceStep;
|
|
238
257
|
// ── Entry point ──────────────────────────────────────────────────
|
|
239
258
|
const handleUninstall = async (args) => {
|
|
240
259
|
const dry = args['dry-run'] === true;
|
|
@@ -248,6 +267,14 @@ const handleUninstall = async (args) => {
|
|
|
248
267
|
console.log(` ${agent.name}:`);
|
|
249
268
|
AGENT_UNINSTALLERS[agent.id]?.(dry);
|
|
250
269
|
}
|
|
270
|
+
// The LaunchAgent outlives every agent's rules, so removing it is part of
|
|
271
|
+
// uninstall and not of any one agent's teardown.
|
|
272
|
+
console.log('\n Login-time service:');
|
|
273
|
+
const serviceLine = await (0, exports.removeServiceStep)(dry);
|
|
274
|
+
if (serviceLine)
|
|
275
|
+
ok(serviceLine);
|
|
276
|
+
else
|
|
277
|
+
skip('not installed');
|
|
251
278
|
// ~/.zeph/config.json holds the API key — kept by default so a
|
|
252
279
|
// re-install doesn't need the key re-entered. --purge removes it.
|
|
253
280
|
console.log('\n Config:');
|
package/dist/verify.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,YAAY,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,YAAY,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAiFzF,CAAC"}
|
package/dist/verify.js
CHANGED
|
@@ -6,6 +6,7 @@ const os_1 = require("os");
|
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
const agents_js_1 = require("./agents.js");
|
|
8
8
|
const config_js_1 = require("./config.js");
|
|
9
|
+
const listener_service_js_1 = require("./listener-service.js");
|
|
9
10
|
const zeph_hook_js_1 = require("./zeph-hook.js");
|
|
10
11
|
const HOME = (0, os_1.homedir)();
|
|
11
12
|
const pass = (msg) => console.log(` ✓ ${msg}`);
|
|
@@ -55,7 +56,7 @@ const handleVerify = async (args) => {
|
|
|
55
56
|
console.log(' Credentials:');
|
|
56
57
|
const config = (0, config_js_1.loadConfig)();
|
|
57
58
|
const apiKey = (0, config_js_1.resolvedEnv)('ZEPH_API_KEY') || config.apiKey;
|
|
58
|
-
const hookId = (0, config_js_1.
|
|
59
|
+
const hookId = (0, config_js_1.resolveHookId)();
|
|
59
60
|
record(apiKey ? 'ZEPH_API_KEY is set' : 'ZEPH_API_KEY not set (env or ~/.zeph/config.json)', apiKey ? 'pass' : 'fail');
|
|
60
61
|
record(hookId
|
|
61
62
|
? 'ZEPH_HOOK_ID is set (two-way zeph_ask/prompt/input enabled)'
|
|
@@ -67,6 +68,15 @@ const handleVerify = async (args) => {
|
|
|
67
68
|
record((0, agents_js_1.hasCommand)('zeph')
|
|
68
69
|
? 'zeph CLI on PATH'
|
|
69
70
|
: 'zeph CLI not on PATH (hooks fall back to npx — slower first call)', (0, agents_js_1.hasCommand)('zeph') ? 'pass' : 'warn');
|
|
71
|
+
// ── Login-time service ───────────────────────────────────────
|
|
72
|
+
// Optional, so a missing one is a warning. A broken one is not: every way
|
|
73
|
+
// it breaks still looks installed from the outside.
|
|
74
|
+
const serviceRows = (0, listener_service_js_1.serviceHealthChecks)((0, listener_service_js_1.serviceStatus)());
|
|
75
|
+
if (serviceRows.length > 0) {
|
|
76
|
+
console.log('\n Login-time service:');
|
|
77
|
+
for (const row of serviceRows)
|
|
78
|
+
record(row.label, row.state);
|
|
79
|
+
}
|
|
70
80
|
// ── Per-agent config ─────────────────────────────────────────
|
|
71
81
|
console.log('\n Agents:');
|
|
72
82
|
const detected = (0, agents_js_1.detectAgents)().filter((a) => a.detected);
|
package/dist/wrapper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../src/wrapper.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,QAAO,MAapC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAA2B,CAAC;AAI9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,MAenD,CAAC;AAmCF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,IAAI,EAAE,WAAW,MAAM,KAAG,OAChC,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CAgC1D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAU,OAAO,WAAW,EAAE,QAAO,MAAM,EAAO,KAAG,OAAO,CAAC,MAAM,CAmCjG,CAAC"}
|
package/dist/wrapper.js
CHANGED
|
@@ -17,6 +17,7 @@ const path_1 = require("path");
|
|
|
17
17
|
const check_update_js_1 = require("./check-update.js");
|
|
18
18
|
const config_js_1 = require("./config.js");
|
|
19
19
|
const listener_process_js_1 = require("./listener-process.js");
|
|
20
|
+
const listener_service_js_1 = require("./listener-service.js");
|
|
20
21
|
const FALLBACK_NAME = 'project';
|
|
21
22
|
/** basename(), with a stable fallback for edge paths like `/`. */
|
|
22
23
|
const safeBasename = (path) => (0, path_1.basename)(path) || FALLBACK_NAME;
|
|
@@ -126,10 +127,29 @@ exports.listenerVersionDrifted = listenerVersionDrifted;
|
|
|
126
127
|
*/
|
|
127
128
|
const ensureListenerRunning = async () => {
|
|
128
129
|
const pid = (0, listener_process_js_1.runningListenerPid)();
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
const running = pid === null ? null : (0, listener_process_js_1.runningListenerVersion)();
|
|
131
|
+
if (pid !== null && !(0, exports.listenerVersionDrifted)(running, config_js_1.VERSION))
|
|
132
|
+
return;
|
|
133
|
+
// When the login-time service is installed, launchd owns this process.
|
|
134
|
+
// Stopping its child makes launchd start a replacement while we spawn our
|
|
135
|
+
// own, and the two race through the singleton guard in handleListener —
|
|
136
|
+
// whichever loses exits 0, and if that is launchd's child, KeepAlive
|
|
137
|
+
// either flaps it every ThrottleInterval or reads the clean exit as
|
|
138
|
+
// deliberate and gives up for the rest of the login session. Ask launchd
|
|
139
|
+
// to do it instead; `kickstart -k` replaces a drifted daemon in one step.
|
|
140
|
+
if ((0, listener_service_js_1.serviceInstalled)()) {
|
|
141
|
+
const result = (0, listener_service_js_1.restartService)();
|
|
142
|
+
if (!result.ok) {
|
|
143
|
+
console.error(`zeph: could not start the listener service — ${result.reason}`);
|
|
132
144
|
return;
|
|
145
|
+
}
|
|
146
|
+
if (pid === null)
|
|
147
|
+
console.log(`zeph: listener started by launchd (log: ${listener_process_js_1.LISTENER_LOG_FILE})`);
|
|
148
|
+
else
|
|
149
|
+
console.log(`zeph: listener ${running ?? '(pre-1.26)'} is stale — launchd restarting on ${config_js_1.VERSION}`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (pid !== null) {
|
|
133
153
|
console.log(`zeph: listener ${running ?? '(pre-1.26)'} is stale — restarting on ${config_js_1.VERSION}`);
|
|
134
154
|
await (0, listener_process_js_1.stopListener)(pid);
|
|
135
155
|
}
|