@zeph-to/cli 2.12.1 → 2.13.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 CHANGED
@@ -200,8 +200,11 @@ block here.
200
200
  ### Setup
201
201
 
202
202
  1. **Install tmux.** The listener uses `send-keys`; the wrapper spawns
203
- named sessions. `brew install tmux` on macOS, `apt install tmux` on
204
- Debian/Ubuntu.
203
+ named sessions. `zeph install` checks for it and, on macOS with Homebrew,
204
+ offers to run `brew install tmux` for you. Elsewhere it prints the line to
205
+ run — `sudo apt install tmux` on Debian/Ubuntu, and so on — because
206
+ installing with `sudo` is not something an installer should do on your
207
+ behalf. tmux has no Windows build, so `zeph cc` needs WSL there.
205
208
 
206
209
  2. **Add `wsUrl` to `~/.zeph/config.json`** (the WebSocket endpoint of
207
210
  your Zeph backend — CDK output `WsApiUrl`):
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA+BzC;;;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;AAsCF;mEACmE;AACnE,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAQ9F,CAAC;AAmPF;;;;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"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA+BzC;;;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;AAsCF;mEACmE;AACnE,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAQ9F,CAAC;AAmPF;;;;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,CA0I1F,CAAC"}
package/dist/installer.js CHANGED
@@ -10,6 +10,7 @@ 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 tmux_install_js_1 = require("./tmux-install.js");
13
14
  const mcp_command_js_1 = require("./mcp-command.js");
14
15
  const listener_service_js_1 = require("./listener-service.js");
15
16
  const templates_js_1 = require("./templates.js");
@@ -464,7 +465,7 @@ const applyServiceChoice = async (choice) => {
464
465
  try {
465
466
  const { confirm } = await import('@inquirer/prompts');
466
467
  wanted = await confirm({
467
- message: 'Start the listener at every login? (so the phone sees this machine after a reboot)',
468
+ message: 'Start the listener at every login, so the phone sees this machine after a reboot? (enter to confirm)',
468
469
  default: true,
469
470
  });
470
471
  }
@@ -551,6 +552,7 @@ const handleInstall = async (args) => {
551
552
  if (selected.length === 0) {
552
553
  console.log(' (no agents selected — only the config file will be saved)');
553
554
  }
555
+ console.log(' - Check tmux (`zeph cc` runs agents inside it)');
554
556
  if ((0, exports.serviceInstallChoice)(args, nonInteractive) !== 'no') {
555
557
  console.log(' - Offer to start the listener at every login');
556
558
  }
@@ -577,10 +579,28 @@ const handleInstall = async (args) => {
577
579
  if (installer)
578
580
  installer();
579
581
  }
580
- // 7. Login-time service the only thing that makes the phone see this
582
+ // 7. tmux`zeph cc` is tmux or nothing, so check before claiming success.
583
+ console.log('\n Checking tmux...');
584
+ await (0, tmux_install_js_1.ensureTmux)({
585
+ plan: (0, tmux_install_js_1.planTmuxInstall)({ resolve: agents_js_1.resolveCommand, platform: process.platform }),
586
+ nonInteractive,
587
+ askConfirm: async (message) => {
588
+ try {
589
+ const { confirm } = await import('@inquirer/prompts');
590
+ return await confirm({ message, default: true });
591
+ }
592
+ catch {
593
+ // Ctrl-C or no TTY — an unanswered question is not a yes.
594
+ return false;
595
+ }
596
+ },
597
+ run: (argv) => { (0, child_process_1.execFileSync)(argv[0], argv.slice(1), { stdio: 'inherit' }); },
598
+ report: { ok, fail, note: skipNote },
599
+ });
600
+ // 8. Login-time service — the only thing that makes the phone see this
581
601
  // machine after a reboot without a terminal being opened first.
582
602
  await applyServiceChoice((0, exports.serviceInstallChoice)(args, nonInteractive));
583
- // 8. Test connection
603
+ // 9. Test connection
584
604
  console.log('\n Testing connection...');
585
605
  await testConnection(apiKey, baseUrl);
586
606
  console.log('\n Done! Restart your agents.\n');
@@ -0,0 +1,44 @@
1
+ /**
2
+ * tmux is not optional for `zeph cc` — every remote-agent subcommand runs the
3
+ * agent inside a named tmux session so the listener (and the phone picker) can
4
+ * reach it. Nothing in the install flow used to mention that, so a machine
5
+ * without tmux looked fully set up until the first `zeph cc` failed with an
6
+ * error from a program the user was never told they needed.
7
+ */
8
+ /** What this machine can do about a missing tmux. */
9
+ export type TmuxInstallPlan = {
10
+ readonly kind: 'present';
11
+ readonly path: string;
12
+ }
13
+ /** Safe to run unattended — no root, user-writable prefix. */
14
+ | {
15
+ readonly kind: 'command';
16
+ readonly run: readonly string[];
17
+ readonly label: string;
18
+ }
19
+ /** Needs root, or there is no package manager we recognise. Tell, don't do. */
20
+ | {
21
+ readonly kind: 'manual';
22
+ readonly hint: string;
23
+ };
24
+ export declare const planTmuxInstall: (deps: {
25
+ resolve: (cmd: string) => string | null;
26
+ platform: NodeJS.Platform;
27
+ }) => TmuxInstallPlan;
28
+ /**
29
+ * Act on the plan. Everything the outside world touches is injected, because
30
+ * the interesting branch — "offer, then run a package manager" — is otherwise
31
+ * only reachable through an interactive install that no test can drive.
32
+ */
33
+ export declare const ensureTmux: (deps: {
34
+ plan: TmuxInstallPlan;
35
+ nonInteractive: boolean;
36
+ askConfirm: (message: string) => Promise<boolean>;
37
+ run: (argv: readonly string[]) => void;
38
+ report: {
39
+ ok: (m: string) => void;
40
+ fail: (m: string) => void;
41
+ note: (m: string) => void;
42
+ };
43
+ }) => Promise<void>;
44
+ //# sourceMappingURL=tmux-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-install.d.ts","sourceRoot":"","sources":["../src/tmux-install.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,qDAAqD;AACrD,MAAM,MAAM,eAAe,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACrD,8DAA8D;GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACvF,+EAA+E;GAC7E;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAWzD,eAAO,MAAM,eAAe,GAAI,MAAM;IAClC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC7B,KAAG,eAoBH,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAU,MAAM;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,GAAG,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE;QAAE,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CAC7F,KAAG,OAAO,CAAC,IAAI,CAsBf,CAAC"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /**
3
+ * tmux is not optional for `zeph cc` — every remote-agent subcommand runs the
4
+ * agent inside a named tmux session so the listener (and the phone picker) can
5
+ * reach it. Nothing in the install flow used to mention that, so a machine
6
+ * without tmux looked fully set up until the first `zeph cc` failed with an
7
+ * error from a program the user was never told they needed.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ensureTmux = exports.planTmuxInstall = void 0;
11
+ /** Package managers that need root, and the line to hand the user for each. */
12
+ const ROOT_PACKAGE_MANAGERS = [
13
+ { bin: 'apt-get', hint: 'sudo apt install tmux' },
14
+ { bin: 'dnf', hint: 'sudo dnf install tmux' },
15
+ { bin: 'pacman', hint: 'sudo pacman -S tmux' },
16
+ { bin: 'zypper', hint: 'sudo zypper install tmux' },
17
+ { bin: 'apk', hint: 'sudo apk add tmux' },
18
+ ];
19
+ const planTmuxInstall = (deps) => {
20
+ const path = deps.resolve('tmux');
21
+ if (path)
22
+ return { kind: 'present', path };
23
+ // tmux has no native Windows build. `zeph cc` is POSIX-only by way of tmux,
24
+ // so point at WSL rather than at a package that cannot be installed.
25
+ if (deps.platform === 'win32') {
26
+ return { kind: 'manual', hint: '`zeph cc` needs tmux, which has no Windows build — run it under WSL' };
27
+ }
28
+ if (deps.platform === 'darwin') {
29
+ return deps.resolve('brew')
30
+ ? { kind: 'command', run: ['brew', 'install', 'tmux'], label: 'brew install tmux' }
31
+ : { kind: 'manual', hint: 'install Homebrew (brew.sh), then: brew install tmux' };
32
+ }
33
+ const rootManager = ROOT_PACKAGE_MANAGERS.find((pm) => deps.resolve(pm.bin));
34
+ if (rootManager)
35
+ return { kind: 'manual', hint: rootManager.hint };
36
+ return { kind: 'manual', hint: 'install tmux with this system\'s package manager' };
37
+ };
38
+ exports.planTmuxInstall = planTmuxInstall;
39
+ /**
40
+ * Act on the plan. Everything the outside world touches is injected, because
41
+ * the interesting branch — "offer, then run a package manager" — is otherwise
42
+ * only reachable through an interactive install that no test can drive.
43
+ */
44
+ const ensureTmux = async (deps) => {
45
+ const { plan, report } = deps;
46
+ if (plan.kind === 'present')
47
+ return report.ok(`tmux found (${plan.path})`);
48
+ if (plan.kind === 'manual')
49
+ return report.fail(`tmux not found — \`zeph cc\` needs it. ${plan.hint}`);
50
+ if (deps.nonInteractive) {
51
+ return report.note(`tmux not found — \`zeph cc\` needs it. Run: ${plan.label}`);
52
+ }
53
+ const wanted = await deps.askConfirm(`tmux is missing and \`zeph cc\` needs it — run \`${plan.label}\`? (enter to confirm)`);
54
+ if (!wanted) {
55
+ return report.note(`tmux not installed — \`zeph cc\` will not work until you run: ${plan.label}`);
56
+ }
57
+ try {
58
+ deps.run(plan.run);
59
+ report.ok('tmux installed');
60
+ }
61
+ catch {
62
+ report.fail(`\`${plan.label}\` failed — run it by hand`);
63
+ }
64
+ };
65
+ exports.ensureTmux = ensureTmux;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeph-to/cli",
3
- "version": "2.12.1",
3
+ "version": "2.13.0",
4
4
  "description": "Zeph CLI + push notification SDK for AI agents",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",