@zeph-to/cli 1.19.3 → 1.21.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.
@@ -157,6 +157,16 @@ export interface ScreenSnapshot {
157
157
  * token bucket as command injection.
158
158
  */
159
159
  export declare const handleScreenRequest: (req: ScreenRequest) => ScreenSnapshot | null;
160
+ /**
161
+ * After the phone injects keys, push fresh frames instead of waiting for its
162
+ * next screen request — the phone's post-tap re-pull raced the key landing
163
+ * (its timer starts at tap time, the key lands a REST+WS hop later), so it
164
+ * often re-captured the pre-keypress screen and the next update was a full
165
+ * auto-refresh period away. Unsolicited frames carry no requestId; the phone
166
+ * matches them by deviceId + sessionName. A newer tap cancels pending
167
+ * captures so a burst of arrow presses yields frames after the LAST press.
168
+ */
169
+ export declare const scheduleInjectSnapshots: (sessionName: string, send: (data: Record<string, unknown>) => void, delays?: number[]) => void;
160
170
  export interface CollectResult {
161
171
  sessions: AgentSession[];
162
172
  /** Diagnostic notes per rejected session — surfaced under `--verbose`. */
@@ -221,6 +231,9 @@ interface HandlePushDeps {
221
231
  downloadAttachments?: (pushId: string, files: PushFileAttachment[]) => Promise<string[]>;
222
232
  /** Pane cwd lookup for the remote-origin marker (ADR-0002). */
223
233
  paneCwd?: (session: string) => string | null;
234
+ /** Fired after a successful named-key injection so the WS loop can push
235
+ * fresh screen frames to the phone (scheduleInjectSnapshots). */
236
+ onKeysInjected?: (session: string) => void;
224
237
  }
225
238
  /**
226
239
  * Record a successful phone→pane text injection so a prompt-submit hook
@@ -253,6 +266,17 @@ export declare const gcAttachments: (now?: number, dir?: string, ttl?: number) =
253
266
  export declare const handlePush: (push: PushItem, deps?: HandlePushDeps) => Promise<boolean>;
254
267
  export declare const computeBackoff: (attempt: number) => number;
255
268
  export declare const computeListenerDeviceId: (host?: string) => string;
269
+ /**
270
+ * A user who only set ZEPH_API_KEY (no `zeph login`, no config file) gets the
271
+ * prod socket by default — mirroring the DEFAULT_API_BASE fallback for REST.
272
+ * The default only applies when the base URL is also the prod default: with a
273
+ * custom base URL, silently pointing the listener at the prod socket while
274
+ * REST talks to another stage would split the device across environments, so
275
+ * that combination still errors loudly.
276
+ */
277
+ export declare const resolveWsUrl: (args: Record<string, string | boolean>, config: {
278
+ wsUrl?: string;
279
+ }, baseUrl: string) => string | null;
256
280
  export declare const handleListener: (args: Record<string, string | boolean>) => Promise<number>;
257
281
  export {};
258
282
  //# sourceMappingURL=listener.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAUH,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACzG,OAAO,EAAiD,KAAK,UAAU,EAA4C,MAAM,kBAAkB,CAAC;AAoC5I,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,UAAU,YAAY;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,YAAY,EAAE,KAAG,MAS7C,CAAC;AAEnB;6BAC6B;AAC7B,eAAO,MAAM,iBAAiB,GAC1B,aAAa,MAAM,EACnB,qBAAqB,MAAM,GAAG,IAAI,EAClC,cAAc,MAAM,EACpB,OAAO,MAAM,KACd,OAEoD,CAAC;AAYxD,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAA+B,CAAC;AAenF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,MAAK,MAAmB,KAAG,OAgB1E,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,IAO7D,CAAC;AAiCF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,KAAG,MAAM,EAAE,GAAG,IAQvD,CAAC;AA0CF;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,QAAO,IAG5C,CAAC;AA8NF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAK3F,CAAC;AAEF,UAAU,QAAQ;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiDD;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,QAAQ,KAAG,qBAAqB,GAAG,IAGhE,CAAC;AA0BZ,iBAAiB;AACjB,eAAO,MAAM,kBAAkB,QAAO,IAErC,CAAC;AAWF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC3B,MAAM,MAAM,EACZ,WAAW,SAAS,EACpB,UAAU,MAAM,GAAG,IAAI,EACvB,MAAK,MAAmB,KACzB,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAmB/D,CAAC;AAWF,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB;AASD,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,IAWhD,CAAC;AAEF,iBAAiB;AACjB,eAAO,MAAM,mBAAmB,QAAO,IAGtC,CAAC;AAEF,MAAM,WAAW,QAAQ;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GACzB,WAAW,WAAW,CAAC,MAAM,CAAC,EAC9B,UAAS,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAsB,KAC9D,QAAQ,EAgBV,CAAC;AAWF,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,uBAAuB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,aAAa,KAAG,cAAc,GAAG,IA8BzE,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAO,aAiEzC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,QAAO,YAAY,EAAuC,CAAC;AAIvF;;;;;GAKG;AACH,UAAU,kBAAkB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,QAAQ;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;sEACkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,UAAU,cAAc;IACpB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACpD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IAC1D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAChD;AAwBD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAC1B,SAAS,MAAM,EACf,MAAM,MAAM,EACZ,MAAK,MAAM,MAAiB,KAC7B,OAUF,CAAC;AAwCF,eAAO,MAAM,oBAAoB,GAAI,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,IAE/E,CAAC;AA2FF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACtB,MAAK,MAAmB,EACxB,MAAK,MAAwB,EAC7B,MAAK,MAA0B,KAChC,MAaF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACnB,MAAM,QAAQ,EACd,OAAM,cAAmB,KAC1B,OAAO,CAAC,OAAO,CAkCjB,CAAC;AAcF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAIhD,CAAC;AA0BF,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,KAAG,MAUvD,CAAC;AA8QF,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CA+H3F,CAAC"}
1
+ {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
package/dist/listener.js CHANGED
@@ -25,7 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
25
25
  return (mod && mod.__esModule) ? mod : { "default": mod };
26
26
  };
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.handleListener = exports.computeListenerDeviceId = exports.computeBackoff = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.writeRemoteMarker = exports.collectSessions = exports.collectSessionsVerbose = exports.handleScreenRequest = exports.collectWatchHits = exports.resetPatternWatches = exports.setPatternWatches = exports.deriveSessionState = exports.resetSessionStates = exports.detectRemoteAgent = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.resolveKeys = exports.paneCurrentCommand = exports.checkRateLimit = exports.AUTH_FAILURE_CODES = exports.sessionsReportDue = exports.sessionsFingerprint = exports.SESSION_REPORT_HEARTBEAT_MS = void 0;
28
+ exports.handleListener = exports.resolveWsUrl = exports.computeListenerDeviceId = exports.computeBackoff = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.writeRemoteMarker = exports.collectSessions = exports.collectSessionsVerbose = exports.scheduleInjectSnapshots = exports.handleScreenRequest = exports.collectWatchHits = exports.resetPatternWatches = exports.setPatternWatches = exports.deriveSessionState = exports.resetSessionStates = exports.detectRemoteAgent = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.resolveKeys = exports.paneCurrentCommand = exports.checkRateLimit = exports.AUTH_FAILURE_CODES = exports.sessionsReportDue = exports.sessionsFingerprint = exports.SESSION_REPORT_HEARTBEAT_MS = void 0;
29
29
  const child_process_1 = require("child_process");
30
30
  const crypto_1 = require("crypto");
31
31
  const fs_1 = require("fs");
@@ -683,13 +683,22 @@ const handleScreenRequest = (req) => {
683
683
  if (!(0, exports.collectSessions)().some((s) => s.name === req.sessionName)) {
684
684
  return { ...base, error: 'unknown_session' };
685
685
  }
686
- const r = (0, child_process_1.spawnSync)('tmux', tmuxArgs(['capture-pane', '-p', '-t', req.sessionName, '-S', `-${SCREEN_PEEK_LINES}`]), {
686
+ const captured = capturePane(req.sessionName);
687
+ if (!captured) {
688
+ return { ...base, error: 'capture_failed' };
689
+ }
690
+ return { ...base, ...captured };
691
+ };
692
+ exports.handleScreenRequest = handleScreenRequest;
693
+ /** Raw pane capture + size cap. Shared by the request path and the
694
+ * post-injection auto-snapshot. */
695
+ const capturePane = (sessionName) => {
696
+ const r = (0, child_process_1.spawnSync)('tmux', tmuxArgs(['capture-pane', '-p', '-t', sessionName, '-S', `-${SCREEN_PEEK_LINES}`]), {
687
697
  encoding: 'utf-8',
688
698
  stdio: ['ignore', 'pipe', 'pipe'],
689
699
  });
690
- if (r.status !== 0) {
691
- return { ...base, error: 'capture_failed' };
692
- }
700
+ if (r.status !== 0)
701
+ return null;
693
702
  let content = r.stdout ?? '';
694
703
  let truncated = false;
695
704
  while (Buffer.byteLength(content, 'utf-8') > SCREEN_PEEK_MAX_BYTES) {
@@ -698,9 +707,42 @@ const handleScreenRequest = (req) => {
698
707
  content = cut > 0 ? content.slice(cut + 1) : content.slice(-SCREEN_PEEK_MAX_BYTES);
699
708
  truncated = true;
700
709
  }
701
- return { ...base, content, truncated };
710
+ return { content, truncated };
702
711
  };
703
- exports.handleScreenRequest = handleScreenRequest;
712
+ /** Delays after a key injection at which the pane is re-captured and pushed
713
+ * to the phone unsolicited. The first frame lands right after most TUI
714
+ * redraws; the second catches slow animations and is skipped when nothing
715
+ * changed since the first. */
716
+ const INJECT_SNAPSHOT_DELAYS_MS = [250, 900];
717
+ const pendingInjectSnapshots = new Map();
718
+ /**
719
+ * After the phone injects keys, push fresh frames instead of waiting for its
720
+ * next screen request — the phone's post-tap re-pull raced the key landing
721
+ * (its timer starts at tap time, the key lands a REST+WS hop later), so it
722
+ * often re-captured the pre-keypress screen and the next update was a full
723
+ * auto-refresh period away. Unsolicited frames carry no requestId; the phone
724
+ * matches them by deviceId + sessionName. A newer tap cancels pending
725
+ * captures so a burst of arrow presses yields frames after the LAST press.
726
+ */
727
+ const scheduleInjectSnapshots = (sessionName, send, delays = INJECT_SNAPSHOT_DELAYS_MS) => {
728
+ for (const t of pendingInjectSnapshots.get(sessionName) ?? [])
729
+ clearTimeout(t);
730
+ let lastContent = null;
731
+ const timers = delays.map((delay) => setTimeout(() => {
732
+ const captured = capturePane(sessionName);
733
+ if (!captured || captured.content === lastContent)
734
+ return;
735
+ lastContent = captured.content;
736
+ send({
737
+ subtype: 'agent.screen.snapshot',
738
+ sessionName,
739
+ capturedAt: new Date().toISOString(),
740
+ ...captured,
741
+ });
742
+ }, delay));
743
+ pendingInjectSnapshots.set(sessionName, timers);
744
+ };
745
+ exports.scheduleInjectSnapshots = scheduleInjectSnapshots;
704
746
  /**
705
747
  * Inventory pass that also records *why* each `zeph-*` session was
706
748
  * skipped. The verbose log uses the rejection notes to explain empty
@@ -997,7 +1039,10 @@ const handlePush = async (push, deps = {}) => {
997
1039
  log(`! ${push.agentSessionName}: unknown key(s) [${push.keys.join(' ')}] — drop`);
998
1040
  return false;
999
1041
  }
1000
- return tryInjectKeys(push.agentSessionName, tokens, deps);
1042
+ const injected = tryInjectKeys(push.agentSessionName, tokens, deps);
1043
+ if (injected)
1044
+ deps.onKeysInjected?.(push.agentSessionName);
1045
+ return injected;
1001
1046
  }
1002
1047
  // Download any attachments BEFORE injecting so the agent can read the
1003
1048
  // local paths immediately. A download-phase failure is isolated: the
@@ -1037,23 +1082,75 @@ exports.computeBackoff = computeBackoff;
1037
1082
  * time `zeph listener` rebinds). `dev_listener_<sha8(hostname)>` keeps it
1038
1083
  * human-recognisable in dev logs without leaking the raw hostname.
1039
1084
  *
1040
- * The no-arg result is pinned for the process lifetime: macOS renames the
1041
- * hostname with network changes, and a mid-run drift made the screen-peek
1042
- * check (fresh recompute) reject requests addressed to the id we CONNECTED
1043
- * with the phone targets the id the sessions were reported under, so
1044
- * every caller in one process must see the same value.
1085
+ * The no-arg result must identify the MACHINE, stably:
1086
+ * - NOT the hostname: macOS rewrites it on network changes (observed
1087
+ * flip-flopping between 'Mac' and '<name>.local' within hours), which
1088
+ * split one machine into several device rows duplicated session lists
1089
+ * on the phone, and screen-peek requests addressed to an id no live
1090
+ * process answers for.
1091
+ * - NOT a file under ~/.zeph alone: users copy ~/.zeph to a new machine
1092
+ * to carry their API key, and a copied id makes two machines answer for
1093
+ * each other.
1094
+ * So: hash the platform machine id (IOPlatformUUID / /etc/machine-id) —
1095
+ * deterministic per machine, immune to both. The sticky file is only the
1096
+ * fallback for platforms where no machine id is readable.
1045
1097
  */
1046
1098
  let processListenerDeviceId;
1099
+ const LISTENER_ID_FILE = (0, path_1.join)((0, os_1.homedir)(), '.zeph', 'listener-device-id');
1100
+ const hashListenerId = (seed) => `dev_listener_${(0, crypto_1.createHash)('sha256').update(seed).digest('hex').slice(0, 8)}`;
1101
+ const readMachineId = () => {
1102
+ try {
1103
+ if (process.platform === 'darwin') {
1104
+ const r = (0, child_process_1.spawnSync)('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice'], {
1105
+ encoding: 'utf-8',
1106
+ stdio: ['ignore', 'pipe', 'ignore'],
1107
+ });
1108
+ const m = r.stdout?.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
1109
+ if (m)
1110
+ return m[1];
1111
+ }
1112
+ if (process.platform === 'linux') {
1113
+ for (const p of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
1114
+ try {
1115
+ const v = (0, fs_1.readFileSync)(p, 'utf-8').trim();
1116
+ if (v)
1117
+ return v;
1118
+ }
1119
+ catch { /* try next */ }
1120
+ }
1121
+ }
1122
+ }
1123
+ catch { /* fall through to the sticky-file fallback */ }
1124
+ return null;
1125
+ };
1047
1126
  const computeListenerDeviceId = (host) => {
1048
- if (host !== undefined) {
1049
- const h = (0, crypto_1.createHash)('sha256').update(host).digest('hex').slice(0, 8);
1050
- return `dev_listener_${h}`;
1127
+ if (host !== undefined)
1128
+ return hashListenerId(host);
1129
+ if (processListenerDeviceId)
1130
+ return processListenerDeviceId;
1131
+ const machineId = readMachineId();
1132
+ if (machineId) {
1133
+ processListenerDeviceId = hashListenerId(machineId);
1134
+ return processListenerDeviceId;
1051
1135
  }
1052
- if (!processListenerDeviceId) {
1053
- const h = (0, crypto_1.createHash)('sha256').update((0, os_1.hostname)()).digest('hex').slice(0, 8);
1054
- processListenerDeviceId = `dev_listener_${h}`;
1136
+ // No readable machine id — pin the first hostname-derived id to a file
1137
+ // so at least hostname drift can't split this machine.
1138
+ try {
1139
+ const saved = (0, fs_1.readFileSync)(LISTENER_ID_FILE, 'utf-8').trim();
1140
+ if (/^dev_listener_[0-9a-f]{8}$/.test(saved)) {
1141
+ processListenerDeviceId = saved;
1142
+ return saved;
1143
+ }
1055
1144
  }
1056
- return processListenerDeviceId;
1145
+ catch { /* first run — fall through to compute + persist */ }
1146
+ const fresh = hashListenerId((0, os_1.hostname)());
1147
+ try {
1148
+ (0, fs_1.mkdirSync)((0, path_1.join)((0, os_1.homedir)(), '.zeph'), { recursive: true });
1149
+ (0, fs_1.writeFileSync)(LISTENER_ID_FILE, fresh);
1150
+ }
1151
+ catch { /* persistence is best-effort; in-memory pin still holds */ }
1152
+ processListenerDeviceId = fresh;
1153
+ return fresh;
1057
1154
  };
1058
1155
  exports.computeListenerDeviceId = computeListenerDeviceId;
1059
1156
  /**
@@ -1247,7 +1344,13 @@ const streamSession = (wsUrl, apiKey) => {
1247
1344
  // Fire-and-forget: handlePush is async (attachment download)
1248
1345
  // but the WS read loop must stay responsive. Errors are
1249
1346
  // logged, never thrown into the socket handler.
1250
- void (0, exports.handlePush)(m.data).catch((err) => log(`! handlePush: ${err.message}`));
1347
+ void (0, exports.handlePush)(m.data, {
1348
+ onKeysInjected: (session) => (0, exports.scheduleInjectSnapshots)(session, (data) => {
1349
+ if (sock.readyState === ws_1.default.OPEN) {
1350
+ sock.send(JSON.stringify({ type: 'ephemeral', data }));
1351
+ }
1352
+ }),
1353
+ }).catch((err) => log(`! handlePush: ${err.message}`));
1251
1354
  }
1252
1355
  if (m.type === 'ephemeral' && m.data) {
1253
1356
  // Screen peek (§S4): the phone asks for this machine's live
@@ -1286,10 +1389,21 @@ const streamSession = (wsUrl, apiKey) => {
1286
1389
  terminate: () => { ws?.terminate(); },
1287
1390
  };
1288
1391
  };
1289
- const resolveWsUrl = (args, config) => {
1392
+ const DEFAULT_WS_URL = 'wss://ws.zeph.to';
1393
+ /**
1394
+ * A user who only set ZEPH_API_KEY (no `zeph login`, no config file) gets the
1395
+ * prod socket by default — mirroring the DEFAULT_API_BASE fallback for REST.
1396
+ * The default only applies when the base URL is also the prod default: with a
1397
+ * custom base URL, silently pointing the listener at the prod socket while
1398
+ * REST talks to another stage would split the device across environments, so
1399
+ * that combination still errors loudly.
1400
+ */
1401
+ const resolveWsUrl = (args, config, baseUrl) => {
1290
1402
  const fromArg = typeof args['ws-url'] === 'string' ? args['ws-url'] : null;
1291
- return fromArg || (0, config_js_1.resolvedEnv)('ZEPH_WS_URL') || config.wsUrl || null;
1403
+ return fromArg || (0, config_js_1.resolvedEnv)('ZEPH_WS_URL') || config.wsUrl
1404
+ || (baseUrl === DEFAULT_API_BASE ? DEFAULT_WS_URL : null);
1292
1405
  };
1406
+ exports.resolveWsUrl = resolveWsUrl;
1293
1407
  // ── Singleton guard (PID file) ──────────────────────────────────────
1294
1408
  const ZEPH_DIR = (0, path_1.join)((0, os_1.homedir)(), '.zeph');
1295
1409
  const LISTENER_PID_FILE = (0, path_1.join)(ZEPH_DIR, 'listener.pid');
@@ -1360,7 +1474,7 @@ const handleListener = async (args) => {
1360
1474
  // resolution order as the rest of the CLI; falls back to the prod API.
1361
1475
  const baseUrl = args['base-url'] || (0, config_js_1.resolvedEnv)('ZEPH_BASE_URL') || config.baseUrl || DEFAULT_API_BASE;
1362
1476
  (0, exports.setAttachmentContext)({ apiKey, baseUrl });
1363
- const wsUrl = resolveWsUrl(args, config);
1477
+ const wsUrl = (0, exports.resolveWsUrl)(args, config, baseUrl);
1364
1478
  if (!wsUrl) {
1365
1479
  console.error('zeph listener: WebSocket URL not set. Either:\n' +
1366
1480
  ' • add "wsUrl": "wss://..." to ~/.zeph/config.json\n' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeph-to/cli",
3
- "version": "1.19.3",
3
+ "version": "1.21.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",