@zeph-to/cli 1.15.1 → 1.15.3

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.
@@ -8,6 +8,13 @@ export declare const RULES_REFRESH_INTERVAL_MS: number;
8
8
  * back to bundled rules.
9
9
  */
10
10
  export declare const validateManifest: (value: unknown) => DetectionManifest | null;
11
+ /**
12
+ * Segment-wise numeric compare of dotted date versions
13
+ * ("2026.07.04.3"). Plain string compare fails on ".10" vs ".9";
14
+ * non-numeric segments compare as equal so a malformed version can
15
+ * never crash the refresh path.
16
+ */
17
+ export declare const compareManifestVersions: (a: string, b: string) => number;
11
18
  export type ManifestSource = 'remote' | 'cache' | 'bundled';
12
19
  export declare const getActiveManifest: () => DetectionManifest;
13
20
  export declare const getActiveManifestSource: () => ManifestSource;
@@ -21,7 +28,7 @@ export declare const loadManifestFromCache: () => ManifestSource;
21
28
  export declare const rulesUrl: () => string;
22
29
  export interface RefreshResult {
23
30
  source: ManifestSource;
24
- /** 'updated' | 'not-modified' | 'invalid' | 'error' — for verbose logs. */
31
+ /** 'updated' | 'not-modified' | 'stale-ignored' | 'invalid' | 'error' — for verbose logs. */
25
32
  outcome: string;
26
33
  version?: string;
27
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-rules-fetch.d.ts","sourceRoot":"","sources":["../src/agent-rules-fetch.ts"],"names":[],"mappings":"AAeA,OAAO,EAEH,KAAK,iBAAiB,EACzB,MAAM,kBAAkB,CAAC;AAG1B,eAAO,MAAM,gBAAgB,QAAuC,CAAC;AACrE,eAAO,MAAM,yBAAyB,QAAqB,CAAC;AA6C5D;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,iBAAiB,GAAG,IAWrE,CAAC;AAIF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAK5D,eAAO,MAAM,iBAAiB,QAAO,iBAAmC,CAAC;AACzE,eAAO,MAAM,uBAAuB,QAAO,cAA8B,CAAC;AAS1E,iBAAiB;AACjB,eAAO,MAAM,mBAAmB,QAAO,IAEtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAO,cAWxC,CAAC;AAWF,eAAO,MAAM,QAAQ,QAAO,MAK3B,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAU,YAAW,OAAO,KAAa,KAAG,OAAO,CAAC,aAAa,CAsC5F,CAAC"}
1
+ {"version":3,"file":"agent-rules-fetch.d.ts","sourceRoot":"","sources":["../src/agent-rules-fetch.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEH,KAAK,iBAAiB,EACzB,MAAM,kBAAkB,CAAC;AAG1B,eAAO,MAAM,gBAAgB,QAAuC,CAAC;AACrE,eAAO,MAAM,yBAAyB,QAAqB,CAAC;AA6C5D;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,iBAAiB,GAAG,IAWrE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAU9D,CAAC;AAIF,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAK5D,eAAO,MAAM,iBAAiB,QAAO,iBAAmC,CAAC;AACzE,eAAO,MAAM,uBAAuB,QAAO,cAA8B,CAAC;AAS1E,iBAAiB;AACjB,eAAO,MAAM,mBAAmB,QAAO,IAEtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAO,cAWxC,CAAC;AAWF,eAAO,MAAM,QAAQ,QAAO,MAK3B,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,cAAc,CAAC;IACvB,6FAA6F;IAC7F,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAU,YAAW,OAAO,KAAa,KAAG,OAAO,CAAC,aAAa,CA4C5F,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.refreshManifest = exports.rulesUrl = exports.loadManifestFromCache = exports.resetActiveManifest = exports.getActiveManifestSource = exports.getActiveManifest = exports.validateManifest = exports.RULES_REFRESH_INTERVAL_MS = exports.RULES_CACHE_FILE = void 0;
3
+ exports.refreshManifest = exports.rulesUrl = exports.loadManifestFromCache = exports.resetActiveManifest = exports.getActiveManifestSource = exports.getActiveManifest = exports.compareManifestVersions = exports.validateManifest = exports.RULES_REFRESH_INTERVAL_MS = exports.RULES_CACHE_FILE = void 0;
4
4
  /**
5
5
  * OTA delivery for agent detection rules (SPEC-AGENT-AWARENESS §S7).
6
6
  *
@@ -12,6 +12,14 @@ exports.refreshManifest = exports.rulesUrl = exports.loadManifestFromCache = exp
12
12
  * hostile payload can never leave the listener without rules, and
13
13
  * `disabledRuleIds` in a fetched manifest acts as a same-day
14
14
  * kill-switch for a misfiring rule (no release, no restart).
15
+ *
16
+ * Version precedence: a fetched/cached manifest only activates when
17
+ * its version is >= the bundled one. npm publishes land in minutes
18
+ * while the server manifest ships with a full deploy, so a fresh cli
19
+ * routinely carries NEWER rules than the endpoint — without the gate,
20
+ * the older remote manifest would shadow every bundled rule fix until
21
+ * the server caught up. Server-side rollback still works: the server
22
+ * bumps the version even when reverting rule content.
15
23
  */
16
24
  const fs_1 = require("fs");
17
25
  const path_1 = require("path");
@@ -90,6 +98,26 @@ const validateManifest = (value) => {
90
98
  return value;
91
99
  };
92
100
  exports.validateManifest = validateManifest;
101
+ /**
102
+ * Segment-wise numeric compare of dotted date versions
103
+ * ("2026.07.04.3"). Plain string compare fails on ".10" vs ".9";
104
+ * non-numeric segments compare as equal so a malformed version can
105
+ * never crash the refresh path.
106
+ */
107
+ const compareManifestVersions = (a, b) => {
108
+ const as = a.split('.').map(Number);
109
+ const bs = b.split('.').map(Number);
110
+ const len = Math.max(as.length, bs.length);
111
+ for (let i = 0; i < len; i++) {
112
+ const d = (as[i] ?? 0) - (bs[i] ?? 0);
113
+ if (Number.isNaN(d))
114
+ continue;
115
+ if (d !== 0)
116
+ return d < 0 ? -1 : 1;
117
+ }
118
+ return 0;
119
+ };
120
+ exports.compareManifestVersions = compareManifestVersions;
93
121
  let activeManifest = agent_rules_default_js_1.DEFAULT_MANIFEST;
94
122
  let activeSource = 'bundled';
95
123
  const getActiveManifest = () => activeManifest;
@@ -115,7 +143,7 @@ const loadManifestFromCache = () => {
115
143
  try {
116
144
  const cache = JSON.parse((0, fs_1.readFileSync)(exports.RULES_CACHE_FILE, 'utf-8'));
117
145
  const manifest = (0, exports.validateManifest)(cache.manifest);
118
- if (manifest) {
146
+ if (manifest && (0, exports.compareManifestVersions)(manifest.version, agent_rules_default_js_1.DEFAULT_MANIFEST.version) >= 0) {
119
147
  activateManifest(manifest, 'cache');
120
148
  }
121
149
  }
@@ -180,6 +208,12 @@ const refreshManifest = async (fetchImpl = fetch) => {
180
208
  // Cache write failure is non-fatal: the manifest still
181
209
  // activates for this process lifetime.
182
210
  }
211
+ if ((0, exports.compareManifestVersions)(manifest.version, agent_rules_default_js_1.DEFAULT_MANIFEST.version) < 0) {
212
+ // Endpoint hasn't caught up to this build's bundled rules.
213
+ // Cache is still written above (the ETag stops refetch churn)
214
+ // but startup applies the same gate, so bundled stays active.
215
+ return { source: activeSource, outcome: 'stale-ignored', version: manifest.version };
216
+ }
183
217
  activateManifest(manifest, 'remote');
184
218
  return { source: 'remote', outcome: 'updated', version: manifest.version };
185
219
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-rules.default.d.ts","sourceRoot":"","sources":["../src/agent-rules.default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,eAAO,MAAM,gBAAgB,EAAE,iBAiF9B,CAAC"}
1
+ {"version":3,"file":"agent-rules.default.d.ts","sourceRoot":"","sources":["../src/agent-rules.default.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,eAAO,MAAM,gBAAgB,EAAE,iBA2F9B,CAAC"}
@@ -26,7 +26,7 @@ exports.DEFAULT_MANIFEST = void 0;
26
26
  const agent_state_js_1 = require("./agent-state.js");
27
27
  exports.DEFAULT_MANIFEST = {
28
28
  engineVersion: agent_state_js_1.ENGINE_VERSION,
29
- version: '2026.07.04.2',
29
+ version: '2026.07.04.3',
30
30
  agents: {
31
31
  claude: [
32
32
  {
@@ -81,6 +81,16 @@ exports.DEFAULT_MANIFEST = {
81
81
  priority: 780,
82
82
  regex: ['…\\s*\\((?:\\d+m )?\\d+s ·'],
83
83
  },
84
+ {
85
+ // Compact pass ("✱ Compacting conversation… (51s)")
86
+ // renders neither the interrupt hint nor a token
87
+ // counter, but the session is busy and can't take
88
+ // input — without this it reads as idle.
89
+ id: 'claude-working-compacting',
90
+ state: 'working',
91
+ priority: 770,
92
+ contains: ['compacting conversation'],
93
+ },
84
94
  {
85
95
  // Idle prompt: `❯` at line start in the tail, with no
86
96
  // dialog affordances around it.
@@ -69,6 +69,7 @@ interface PaneInfo {
69
69
  currentCommand: string | null;
70
70
  startCommand: string | null;
71
71
  currentPath: string | null;
72
+ panePid: number | null;
72
73
  }
73
74
  /**
74
75
  * Identify the agent from the tmux pane. Prefer `pane_start_command`
@@ -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
@@ -412,20 +412,22 @@ exports.parseSessionName = parseSessionName;
412
412
  const FIELD_SEP = '␟';
413
413
  const readPaneInfo = (session) => {
414
414
  const r = (0, child_process_1.spawnSync)('tmux', tmuxArgs(['display-message', '-p', '-t', session,
415
- `#{pane_current_command}${FIELD_SEP}#{pane_start_command}${FIELD_SEP}#{pane_current_path}`]), {
415
+ `#{pane_current_command}${FIELD_SEP}#{pane_start_command}${FIELD_SEP}#{pane_current_path}${FIELD_SEP}#{pane_pid}`]), {
416
416
  encoding: 'utf-8',
417
417
  stdio: ['ignore', 'pipe', 'ignore'],
418
418
  });
419
419
  if (r.status !== 0)
420
- return { currentCommand: null, startCommand: null, currentPath: null };
420
+ return { currentCommand: null, startCommand: null, currentPath: null, panePid: null };
421
421
  const parts = (r.stdout ?? '').trim().split(FIELD_SEP);
422
- if (parts.length !== 3)
423
- return { currentCommand: null, startCommand: null, currentPath: null };
424
- const [current, start, path] = parts;
422
+ if (parts.length !== 4)
423
+ return { currentCommand: null, startCommand: null, currentPath: null, panePid: null };
424
+ const [current, start, path, pid] = parts;
425
+ const parsedPid = Number(pid);
425
426
  return {
426
427
  currentCommand: current || null,
427
428
  startCommand: start || null,
428
429
  currentPath: path || null,
430
+ panePid: Number.isInteger(parsedPid) && parsedPid > 0 ? parsedPid : null,
429
431
  };
430
432
  };
431
433
  /**
@@ -681,7 +683,7 @@ const collectSessionsVerbose = () => {
681
683
  continue;
682
684
  }
683
685
  const agentSessionId = info.currentPath
684
- ? (agent.resolveSessionId?.(info.currentPath) ?? null)
686
+ ? (agent.resolveSessionId?.(info.currentPath, info.panePid ?? undefined) ?? null)
685
687
  : null;
686
688
  sessions.push({
687
689
  name,
@@ -10,11 +10,12 @@ export interface RemoteAgent {
10
10
  /** Extra pane_command basenames accepted as this agent (beyond binary). */
11
11
  paneMatchAliases?: readonly string[];
12
12
  /**
13
- * Resolve the agent's own session id from the pane's cwd.
13
+ * Resolve the agent's own session id from the pane's cwd (+ pane pid
14
+ * when the caller knows it — enables exact process-tree matching).
14
15
  * EXTENSION POINT: omitted for codex/gemini until their session-file
15
16
  * formats are confirmed — the listener then reports agentSessionId: null.
16
17
  */
17
- resolveSessionId?: (paneCwd: string) => string | null;
18
+ resolveSessionId?: (paneCwd: string, panePid?: number) => string | null;
18
19
  }
19
20
  /**
20
21
  * Locate the most recent Claude Code session UUID for the working
@@ -25,12 +26,29 @@ export interface RemoteAgent {
25
26
  * claudeSessionCache.
26
27
  */
27
28
  export declare const detectClaudeSessionId: (cwd: string) => string | null;
29
+ interface PidSessionRecord {
30
+ pid: number;
31
+ sessionId: string;
32
+ cwd: string;
33
+ }
34
+ /** Test seam for the pid-based resolver. */
35
+ export interface PidResolveDeps {
36
+ records?: PidSessionRecord[];
37
+ descendants?: Set<number>;
38
+ }
39
+ /**
40
+ * Exact resolution: the session record whose pid lives in the pane's
41
+ * process tree AND whose cwd matches (guards against OS pid reuse
42
+ * leaving a stale record pointing elsewhere). Null → caller falls back
43
+ * to the mtime heuristic.
44
+ */
45
+ export declare const detectClaudeSessionIdByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => string | null;
28
46
  declare const REMOTE_AGENT_TABLE: readonly [{
29
47
  readonly kind: "claude";
30
48
  readonly displayName: "Claude Code";
31
49
  readonly binary: "claude";
32
50
  readonly subcommands: readonly ["cc", "claude"];
33
- readonly resolveSessionId: (cwd: string) => string | null;
51
+ readonly resolveSessionId: (paneCwd: string, panePid: number | undefined) => string | null;
34
52
  }, {
35
53
  readonly kind: "codex";
36
54
  readonly displayName: "Codex CLI";
@@ -1 +1 @@
1
- {"version":3,"file":"remote-agents.d.ts","sourceRoot":"","sources":["../src/remote-agents.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,WAAW;IACxB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACzD;AAyCD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAiB5D,CAAC;AAIF,QAAA,MAAM,kBAAkB;;;;;qCArBmB,MAAM,KAAG,MAAM,GAAG,IAAI;;;;;;;;;;;EAyCtB,CAAC;AAE5C,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,8FAA8F;AAC9F,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAEtE,eAAO,MAAM,aAAa,EAAE,SAAS,qBAAqB,EAAuB,CAAC;AAElF,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,qBAAqB,GAAG,SAClB,CAAC;AAE3D,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,qBAAqB,GAAG,SAG9E,CAAC"}
1
+ {"version":3,"file":"remote-agents.d.ts","sourceRoot":"","sources":["../src/remote-agents.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,WAAW;IACxB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC3E;AAyCD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAiB5D,CAAC;AAaF,UAAU,gBAAgB;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACf;AAkDD,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC3B,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GACnC,SAAS,MAAM,EACf,SAAS,MAAM,GAAG,IAAI,EACtB,OAAM,cAAmB,KAC1B,MAAM,GAAG,IAOX,CAAC;AAIF,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;EAwBmB,CAAC;AAE5C,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,8FAA8F;AAC9F,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAEtE,eAAO,MAAM,aAAa,EAAE,SAAS,qBAAqB,EAAuB,CAAC;AAElF,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,qBAAqB,GAAG,SAClB,CAAC;AAE3D,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,KAAG,qBAAqB,GAAG,SAG9E,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.matchAgentByPaneCommand = exports.findAgentBySubcommand = exports.REMOTE_AGENTS = exports.detectClaudeSessionId = void 0;
3
+ exports.matchAgentByPaneCommand = exports.findAgentBySubcommand = exports.REMOTE_AGENTS = exports.detectClaudeSessionIdByPid = exports.detectClaudeSessionId = void 0;
4
4
  /**
5
5
  * Remote-control agent registry — the single table behind `zeph cc` /
6
6
  * `zeph codex` / `zeph gemini`, the listener's pane matching, and the
@@ -17,6 +17,7 @@ exports.matchAgentByPaneCommand = exports.findAgentBySubcommand = exports.REMOTE
17
17
  const fs_1 = require("fs");
18
18
  const os_1 = require("os");
19
19
  const path_1 = require("path");
20
+ const child_process_1 = require("child_process");
20
21
  // ── Claude Code session resolver ─────────────────────────────────
21
22
  const CLAUDE_PROJECTS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'projects');
22
23
  /**
@@ -82,6 +83,81 @@ const detectClaudeSessionId = (cwd) => {
82
83
  return sessionId;
83
84
  };
84
85
  exports.detectClaudeSessionId = detectClaudeSessionId;
86
+ // ── Claude Code pid → session resolver ───────────────────────────
87
+ //
88
+ // Claude Code maintains ~/.claude/sessions/<pid>.json with the exact
89
+ // {pid, sessionId, cwd} of every live session. Matching the tmux pane's
90
+ // process tree against these records identifies THE session running in
91
+ // that pane — immune to the identity theft the mtime heuristic suffers
92
+ // when a second `claude` opens in the same cwd (its transcript becomes
93
+ // the newest file and steals the tmux session's id).
94
+ const CLAUDE_SESSIONS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'sessions');
95
+ const readPidSessionRecords = () => {
96
+ try {
97
+ const out = [];
98
+ for (const entry of (0, fs_1.readdirSync)(CLAUDE_SESSIONS_DIR)) {
99
+ if (!/^\d+\.json$/.test(entry))
100
+ continue;
101
+ try {
102
+ const raw = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(CLAUDE_SESSIONS_DIR, entry), 'utf-8'));
103
+ if (typeof raw.pid === 'number' && typeof raw.sessionId === 'string' && typeof raw.cwd === 'string') {
104
+ out.push({ pid: raw.pid, sessionId: raw.sessionId, cwd: raw.cwd });
105
+ }
106
+ }
107
+ catch { /* partial write / corrupt — skip */ }
108
+ }
109
+ return out;
110
+ }
111
+ catch {
112
+ return []; // dir absent (older CC) — caller falls back to mtime
113
+ }
114
+ };
115
+ /** pid set of `rootPid` + all descendants, from one `ps` snapshot. */
116
+ const collectDescendantPids = (rootPid, psOutput) => {
117
+ let table = psOutput;
118
+ if (table === undefined) {
119
+ const r = (0, child_process_1.spawnSync)('ps', ['-axo', 'pid=,ppid='], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
120
+ if (r.status !== 0)
121
+ return new Set([rootPid]);
122
+ table = r.stdout ?? '';
123
+ }
124
+ const children = new Map();
125
+ for (const line of table.split('\n')) {
126
+ const m = line.trim().match(/^(\d+)\s+(\d+)$/);
127
+ if (!m)
128
+ continue;
129
+ const [pid, ppid] = [Number(m[1]), Number(m[2])];
130
+ const list = children.get(ppid) ?? [];
131
+ list.push(pid);
132
+ children.set(ppid, list);
133
+ }
134
+ const found = new Set([rootPid]);
135
+ const queue = [rootPid];
136
+ while (queue.length > 0) {
137
+ for (const child of children.get(queue.shift()) ?? []) {
138
+ if (!found.has(child)) {
139
+ found.add(child);
140
+ queue.push(child);
141
+ }
142
+ }
143
+ }
144
+ return found;
145
+ };
146
+ /**
147
+ * Exact resolution: the session record whose pid lives in the pane's
148
+ * process tree AND whose cwd matches (guards against OS pid reuse
149
+ * leaving a stale record pointing elsewhere). Null → caller falls back
150
+ * to the mtime heuristic.
151
+ */
152
+ const detectClaudeSessionIdByPid = (panePid, paneCwd, deps = {}) => {
153
+ const records = deps.records ?? readPidSessionRecords();
154
+ if (records.length === 0)
155
+ return null;
156
+ const descendants = deps.descendants ?? collectDescendantPids(panePid);
157
+ const match = records.find((r) => descendants.has(r.pid) && (paneCwd === null || r.cwd === paneCwd));
158
+ return match?.sessionId ?? null;
159
+ };
160
+ exports.detectClaudeSessionIdByPid = detectClaudeSessionIdByPid;
85
161
  // ── The registry ─────────────────────────────────────────────────
86
162
  const REMOTE_AGENT_TABLE = [
87
163
  {
@@ -89,7 +165,10 @@ const REMOTE_AGENT_TABLE = [
89
165
  displayName: 'Claude Code',
90
166
  binary: 'claude',
91
167
  subcommands: ['cc', 'claude'],
92
- resolveSessionId: exports.detectClaudeSessionId,
168
+ // Exact pid-tree match first; mtime heuristic only as fallback
169
+ // (older CC without ~/.claude/sessions, or ps failure).
170
+ resolveSessionId: (paneCwd, panePid) => (panePid !== undefined ? (0, exports.detectClaudeSessionIdByPid)(panePid, paneCwd) : null)
171
+ ?? (0, exports.detectClaudeSessionId)(paneCwd),
93
172
  },
94
173
  {
95
174
  kind: 'codex',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeph-to/cli",
3
- "version": "1.15.1",
3
+ "version": "1.15.3",
4
4
  "description": "Zeph CLI + push notification SDK for AI agents",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",