@zeph-to/cli 1.24.0 → 1.25.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
@@ -43,6 +43,12 @@ on *every* notification. For notifications only, with no phone control,
43
43
  `npx @zeph-to/cli install` is a lighter alternative that skips the global
44
44
  binary.
45
45
 
46
+ Once installed, the hooks fire in **every** session of each configured
47
+ agent — `zeph cc` is the phone-control bridge, not the notification
48
+ switch. Turn the volume down without uninstalling: `/zeph-quiet --global`
49
+ (blockers only, all projects), `/zeph-mute` (silence, current project),
50
+ `/zeph-status` (what's in effect). See [Mute & push mode](#mute--push-mode).
51
+
46
52
  `~/.zeph/config.json` is the single source of truth — the CLI, the MCP
47
53
  server, the plugin hooks, and the listener all read it. You never need
48
54
  `ZEPH_API_KEY`-style env vars for a normal setup; they exist as overrides
@@ -363,7 +369,7 @@ zeph notify --title "Hello" --json
363
369
  | `--priority <p>` | Priority: `low`, `normal`, `high`, `urgent` |
364
370
  | `--device <id>` | Target device ID |
365
371
  | `--session <id>` | AI session ID so the push threads into that session's chat (or `ZEPH_SESSION_ID` env) |
366
- | `--auto` | Apply the push gate before sending — honors the `/zeph-quiet` / `/zeph-loud` push-mode dial; gated-out exits silently with code 0 |
372
+ | `--auto` | Apply the push gate before sending — honors the `/zeph-quiet` / `/zeph-loud` push-mode dial, per project or machine-wide (`--global`); gated-out exits silently with code 0 |
367
373
  | `--marker <m>` | Push Signal marker for `--auto`: `skip`, `push`, `high` |
368
374
  | `--tools <n>`, `--nonreadonly <n>` | Turn tool counts feeding `--auto`'s heuristic (defaults assume real work) |
369
375
 
@@ -401,23 +407,45 @@ code 3 instead of looping forever — fix the key and restart.
401
407
  | `--json` | Output JSON format |
402
408
  | `--version` | Print version |
403
409
 
404
- ### Mute
410
+ ### Mute & push mode
405
411
 
406
- Mute is project-scoped (uses project directory hash). Created by Claude
407
- Code `/zeph-mute` command.
412
+ Both live as state files under `${XDG_STATE_HOME:-~/.local/state}/zeph`,
413
+ keyed by a `cksum` hash of the project directory. Claude Code's
414
+ `/zeph-mute` / `/zeph-quiet` / `/zeph-loud` / `/zeph-normal` write them;
415
+ the CLI reads them (mute on every `notify`, push mode on `--auto`).
408
416
 
409
417
  Notifications are silently skipped when a mute file exists for the
410
418
  current project:
411
419
 
412
420
  ```bash
413
- # Mute (created by /zeph-mute in Claude Code plugin)
414
- HASH=$(echo -n "$PROJECT_DIR" | cksum | cut -d' ' -f1)
415
- touch /tmp/zeph-muted-$HASH
421
+ STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/zeph"
422
+ HASH=$(printf '%s' "$PROJECT_DIR" | cksum | cut -d' ' -f1)
423
+
424
+ # Mute (created by /zeph-mute in the Claude Code plugin)
425
+ mkdir -p "$STATE_DIR" && touch "$STATE_DIR/muted-$HASH"
416
426
 
417
427
  # Unmute
418
- rm /tmp/zeph-muted-$HASH
428
+ rm -f "$STATE_DIR/muted-$HASH"
419
429
  ```
420
430
 
431
+ Push mode is a one-word file (`quiet` / `loud` / `normal`) resolved in
432
+ this order — first hit wins:
433
+
434
+ | Order | File | Set by |
435
+ |-------|------|--------|
436
+ | 1 | `$STATE_DIR/pushmode-<hash>` | `/zeph-quiet` · `/zeph-loud` · `/zeph-normal` |
437
+ | 2 | `/tmp/zeph-pushmode-<hash>` | older versions (honored only when you own the file) |
438
+ | 3 | `$STATE_DIR/pushmode-default` | `/zeph-quiet --global` — the machine-wide default |
439
+ | 4 | *(none)* | `normal` |
440
+
441
+ So `/zeph-quiet --global` quiets every project that has no dial of its
442
+ own, and a per-project dial always overrides it. Mute has no `-default`
443
+ form on purpose: it is keyed on presence, not content, so a global mute
444
+ could never be lifted for a single project.
445
+
446
+ Legacy `/tmp/zeph-muted-<hash>` files are still honored when owned by the
447
+ current user (the state dir moved out of world-writable `/tmp`).
448
+
421
449
  The CLI checks `CLAUDE_PROJECT_DIR`, `CURSOR_PROJECT_DIR`,
422
450
  `WINDSURF_PROJECT_DIR`, and falls back to `cwd`.
423
451
 
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAEX,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,UACS,CAAC;AAEpE,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,YACR,CAAC;AAErD,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,KAAG,WAW7C,CAAC;AAeF,eAAO,MAAM,QAAQ,QAAO,MACoD,CAAC;AAmBjF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOlD,CAAC;AAWF,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAA4C,CAAC;AAE7F;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAG1B,CAAC;AAEnB,0DAA0D;AAC1D,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,OAGrC,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,YAU1C,CAAC"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAEX,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,UACS,CAAC;AAEpE,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,GAAG,SAAS,KAAG,YACR,CAAC;AAErD,eAAO,MAAM,UAAU,GAAI,OAAO,SAAS,KAAG,WAW7C,CAAC;AAeF,eAAO,MAAM,QAAQ,QAAO,MACoD,CAAC;AA2BjF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOlD,CAAC;AAWF,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAA4C,CAAC;AAE7F;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAG1B,CAAC;AAEnB,0DAA0D;AAC1D,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,OAGrC,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,YAU1C,CAAC"}
package/dist/gate.js CHANGED
@@ -78,13 +78,23 @@ const ownedByCurrentUser = (path) => {
78
78
  return false;
79
79
  }
80
80
  };
81
- /** Resolve a state file: current location first, then user-owned legacy /tmp. */
81
+ /**
82
+ * Resolve a state file: current location first, then user-owned legacy /tmp,
83
+ * then — for `pushmode` only — the machine-wide default written by
84
+ * `/zeph-quiet --global`. Mirrors plugin/hooks/gate.sh zeph_state_present,
85
+ * including the deliberate absence of a global mute (see the comment there).
86
+ */
82
87
  const findStateFile = (kind, hash) => {
83
88
  const current = (0, path_1.join)((0, exports.stateDir)(), `${kind}-${hash}`);
84
89
  if ((0, fs_1.existsSync)(current))
85
90
  return current;
86
91
  const legacy = `/tmp/zeph-${kind}-${hash}`;
87
- return ownedByCurrentUser(legacy) ? legacy : null;
92
+ if (ownedByCurrentUser(legacy))
93
+ return legacy;
94
+ if (kind !== 'pushmode')
95
+ return null;
96
+ const globalDefault = (0, path_1.join)((0, exports.stateDir)(), 'pushmode-default');
97
+ return (0, fs_1.existsSync)(globalDefault) ? globalDefault : null;
88
98
  };
89
99
  const projectHash = (dir) => {
90
100
  try {
@@ -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;;;;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"}
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,CA4G1F,CAAC"}
package/dist/installer.js CHANGED
@@ -485,6 +485,15 @@ const handleInstall = async (args) => {
485
485
  console.log('\n Testing connection...');
486
486
  await testConnection(apiKey, baseUrl);
487
487
  console.log('\n Done! Restart your agents.\n');
488
+ // The single most-reported surprise: pushes are not scoped to `zeph cc`.
489
+ // Hooks fire for every session of every configured agent, so say it here —
490
+ // at the moment the hooks get installed — together with the volume dials.
491
+ console.log(' Notifications now fire for EVERY session of each agent above');
492
+ console.log(' (not only sessions launched with `zeph cc`). Dial the volume');
493
+ console.log(' any time — in Claude Code:');
494
+ console.log(' /zeph-quiet --global only blockers + high-priority, all projects');
495
+ console.log(' /zeph-mute full silence, current project');
496
+ console.log(' /zeph-status show what is in effect\n');
488
497
  return 0;
489
498
  };
490
499
  exports.handleInstall = handleInstall;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeph-to/cli",
3
- "version": "1.24.0",
3
+ "version": "1.25.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",