@zeph-to/cli 1.21.0 → 1.22.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
@@ -33,36 +33,50 @@ npx @zeph-to/cli notify --title "Hello"
33
33
 
34
34
  ## Quick Start
35
35
 
36
- ```bash
37
- # Sign in via browser — auto-fetches your API key + hook into
38
- # ~/.zeph/config.json (no copy-paste)
39
- npx @zeph-to/cli login
36
+ Install the CLI globally, then run setup:
40
37
 
41
- # Install for your AI agents (rules + hooks + MCP). Reuses the saved
42
- # config; detects Claude Code / Cursor / Windsurf / Gemini / Codex / …
43
- npx @zeph-to/cli install
38
+ ```bash
39
+ npm install -g @zeph-to/cli
40
+ zeph install
44
41
  ```
45
42
 
46
- `login` opens a browser to the Zeph web app, asks you to confirm "connect
47
- this computer", then issues a fresh API key (labelled with your hostname)
48
- and reuses or creates a hook writing both back to `~/.zeph/config.json`
49
- over a localhost loopback. No credential ever gets pasted into the
50
- terminal.
43
+ `zeph install` opens a browser sign-in on a fresh machine the web app
44
+ issues an API key + hook as a matched pair and the CLI writes them to
45
+ `~/.zeph/config.json` (no copy-paste). Then it installs rules + hooks +
46
+ MCP for every detected agent (Claude Code / Cursor / Windsurf / Gemini /
47
+ Codex / …). Safe to re-run: a saved login is reused untouched (no
48
+ prompts), so a re-run just refreshes the agent integrations. To switch
49
+ account, `zeph install --relogin` forces a fresh sign-in.
50
+
51
+ **Why global, not `npx`?** `zeph cc` (drive a session from your phone)
52
+ needs `zeph` on your `PATH`, and the agent hooks this installs are
53
+ `$(command -v zeph || npx …)` — a global binary skips an npx cold-start
54
+ on *every* notification. For notifications only, with no phone control,
55
+ `npx @zeph-to/cli install` is a lighter alternative that skips the global
56
+ binary.
51
57
 
52
- Prefer to paste credentials yourself (or on a headless box with no
53
- browser)? Skip `login` and pass them to `install` directly:
58
+ `~/.zeph/config.json` is the single source of truth the CLI, the MCP
59
+ server, the plugin hooks, and the listener all read it. You never need
60
+ `ZEPH_API_KEY`-style env vars for a normal setup; they exist as overrides
61
+ (second account, CI).
62
+
63
+ Variants:
54
64
 
55
65
  ```bash
56
- npx @zeph-to/cli install --key ak_... --hook hook_...
57
- ```
66
+ # Headless box (no browser): paste credentials from another machine's
67
+ # ~/.zeph/config.json
68
+ zeph install --key ak_... --hook hook_...
58
69
 
59
- Either way it saves to `~/.zeph/config.json`. All Zeph tools (CLI, MCP
60
- server, plugin hooks, listener) read this file.
70
+ # Skip the interactive agent picker
71
+ zeph install --only claude,cursor
61
72
 
62
- On a fresh machine `install` alone is enough: with no `--key` and no
63
- saved config it opens the same browser login automatically (headless
64
- boxes fall back to manual key entry). Pass `--only claude,cursor,…` to
65
- skip the interactive agent picker.
73
+ # Switch account force a fresh browser sign-in over a saved login
74
+ zeph install --relogin
75
+
76
+ # Refresh credentials only (no agent re-install) — assumes you already
77
+ # ran `zeph install` once; on its own it does NOT wire MCP into agents
78
+ zeph login
79
+ ```
66
80
 
67
81
  To **send** notifications:
68
82
 
package/dist/cli.js CHANGED
@@ -107,10 +107,13 @@ Login options:
107
107
 
108
108
  Install options:
109
109
  (no --key, no saved config → opens browser login automatically;
110
- headless falls back to manual key entry)
110
+ a saved login is reused untouched on re-run; headless falls back
111
+ to manual key entry)
111
112
  --key <api-key> API key (non-interactive; skips browser login)
112
113
  --hook <hook-id> Hook ID (non-interactive)
113
114
  --base-url <url> Base URL (non-interactive)
115
+ --relogin Force a fresh browser sign-in even if a login is
116
+ already saved (switch account)
114
117
  --web-url <url> Login web app URL [default: https://app.zeph.to]
115
118
  --only <agents> Comma-separated agent ids to install for
116
119
  (claude,cursor,windsurf,gemini,codex,copilot,cline,aider).
@@ -3,7 +3,12 @@ import type { Agent } from './agents.js';
3
3
  * True when install should auto-open browser login (ADR 0002): interactive
4
4
  * context with no existing credential (--key/env/config all absent).
5
5
  */
6
- export declare const shouldTriggerLogin: (nonInteractive: boolean, currentKey: string | undefined) => boolean;
6
+ /**
7
+ * Interactive install, past the `--key` path: open a browser login only when
8
+ * there's nothing saved yet, or the user explicitly asked to re-authenticate
9
+ * with `--relogin`. A plain re-run keeps the saved login untouched.
10
+ */
11
+ export declare const shouldReauth: (currentKey: string | undefined, relogin: boolean) => boolean;
7
12
  /** Exported for tests (installGemini shells out to the real `gemini` binary,
8
13
  * so the merge semantics can't be covered through it deterministically). */
9
14
  export declare const mergeJsonFile: (filePath: string, patch: Record<string, unknown>) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA4BzC;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,gBAAgB,OAAO,EAAE,YAAY,MAAM,GAAG,SAAS,KAAG,OAC7D,CAAC;AAoBjC;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;AA4FF,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAkG1F,CAAC"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA4BzC;;;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,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAkG1F,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.shouldTriggerLogin = void 0;
3
+ exports.handleInstall = 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");
@@ -19,8 +19,13 @@ const fail = (msg) => console.log(` - ${msg}`);
19
19
  * True when install should auto-open browser login (ADR 0002): interactive
20
20
  * context with no existing credential (--key/env/config all absent).
21
21
  */
22
- const shouldTriggerLogin = (nonInteractive, currentKey) => !nonInteractive && !currentKey;
23
- exports.shouldTriggerLogin = shouldTriggerLogin;
22
+ /**
23
+ * Interactive install, past the `--key` path: open a browser login only when
24
+ * there's nothing saved yet, or the user explicitly asked to re-authenticate
25
+ * with `--relogin`. A plain re-run keeps the saved login untouched.
26
+ */
27
+ const shouldReauth = (currentKey, relogin) => !currentKey || relogin;
28
+ exports.shouldReauth = shouldReauth;
24
29
  const promptInput = (question) => {
25
30
  const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
26
31
  return new Promise((resolve) => {
@@ -348,26 +353,12 @@ const testConnection = async (apiKey, baseUrl) => {
348
353
  return false;
349
354
  }
350
355
  };
351
- /** Interactive path when a credential already exists: prompt to keep/replace. */
352
- const promptExistingCredentials = async (currentKey, existing) => {
353
- if (currentKey)
354
- console.log(` Current API Key: ${currentKey.slice(0, 12)}...`);
355
- const keyInput = await promptInput(currentKey ? ' New API Key (Enter to keep): ' : ' API Key (from app > Settings > API Keys): ');
356
- const currentHook = (0, config_js_1.resolvedEnv)('ZEPH_HOOK_ID') || existing.hookId;
357
- if (currentHook)
358
- console.log(` Current Hook ID: ${currentHook}`);
359
- const hookInput = await promptInput(currentHook ? ' New Hook ID (Enter to keep, "none" to remove): ' : ' Hook ID (optional, for prompt/input): ');
360
- return {
361
- apiKey: keyInput || currentKey,
362
- hookId: hookInput === 'none' ? undefined : (hookInput || currentHook),
363
- baseUrl: existing.baseUrl,
364
- };
365
- };
366
356
  /**
367
- * Resolve API key + hook for install. Priority: --key/env/config (non-interactive
368
- * or "keep existing") brand-new interactive opens browser login (ADR 0002),
369
- * falling back to manual paste when headless. wsUrl/deviceId from a login are
370
- * persisted by runLoginFlow and re-read at config-save time.
357
+ * Resolve API key + hook for install. Priority: --key/env/config (non-interactive)
358
+ * a saved login is reused untouched on re-run otherwise a brand-new
359
+ * interactive install opens browser login (ADR 0002), falling back to manual
360
+ * paste when headless. wsUrl/deviceId from a login are persisted by
361
+ * runLoginFlow and re-read at config-save time.
371
362
  */
372
363
  const collectCredentials = async (args, installArgs, nonInteractive, existing) => {
373
364
  if (nonInteractive) {
@@ -379,8 +370,15 @@ const collectCredentials = async (args, installArgs, nonInteractive, existing) =
379
370
  }
380
371
  console.log('');
381
372
  const currentKey = (0, config_js_1.resolvedEnv)('ZEPH_API_KEY') || existing.apiKey;
382
- if (!(0, exports.shouldTriggerLogin)(nonInteractive, currentKey)) {
383
- return promptExistingCredentials(currentKey, existing);
373
+ // Re-run with a saved login: reuse it silently and move on to agent wiring.
374
+ // Switching accounts is `zeph login` or `zeph install --relogin`.
375
+ if (!(0, exports.shouldReauth)(currentKey, args.relogin === true)) {
376
+ console.log(` Using saved login (${currentKey.slice(0, 12)}…). Run \`zeph install --relogin\` to switch account.`);
377
+ return {
378
+ apiKey: currentKey,
379
+ hookId: (0, config_js_1.resolvedEnv)('ZEPH_HOOK_ID') || existing.hookId,
380
+ baseUrl: existing.baseUrl,
381
+ };
384
382
  }
385
383
  const result = await (0, login_js_1.runLoginFlow)({
386
384
  webUrl: (0, login_js_1.resolveWebUrl)(args['web-url']),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeph-to/cli",
3
- "version": "1.21.0",
3
+ "version": "1.22.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",