@zeph-to/cli 1.19.0 → 1.19.2
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 +6 -3
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +12 -2
- package/dist/listener.d.ts +12 -0
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +58 -12
- package/dist/uninstall.d.ts.map +1 -1
- package/dist/uninstall.js +11 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -102,9 +102,12 @@ tmux session via `tmux send-keys`.
|
|
|
102
102
|
[tmux session "zeph-myapp" running claude / codex / gemini]
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
The listener
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
The listener polls its tmux session inventory every 5 seconds and
|
|
106
|
+
reports it to the server whenever something changed (new session, agent
|
|
107
|
+
state transition, activity) — an unchanged inventory is re-sent only as
|
|
108
|
+
a 30-second idle heartbeat. The phone picker stays in sync with no
|
|
109
|
+
manual configuration, and an idle listener costs the backend a fraction
|
|
110
|
+
of what a fixed 5-second report cycle would.
|
|
108
111
|
|
|
109
112
|
### Remote-origin detection (sticky REMOTE mode)
|
|
110
113
|
|
package/dist/installer.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/installer.js
CHANGED
|
@@ -179,11 +179,21 @@ const installWindsurf = () => {
|
|
|
179
179
|
};
|
|
180
180
|
const installGemini = () => {
|
|
181
181
|
try {
|
|
182
|
-
|
|
182
|
+
// gemini ≥0.26 syntax: `mcp add [-s scope] <name> <command> [args…]` —
|
|
183
|
+
// the default scope is "project" (cwd-local .gemini/), so pin user
|
|
184
|
+
// scope for a machine-wide install. Older gemini CLIs only accept the
|
|
185
|
+
// legacy `mcp add zeph -- npx …` form; fall back for those.
|
|
186
|
+
(0, child_process_1.execSync)('gemini mcp add -s user zeph npx -- -y @zeph-to/mcp-server', { stdio: 'pipe' });
|
|
183
187
|
ok('MCP server added');
|
|
184
188
|
}
|
|
185
189
|
catch {
|
|
186
|
-
|
|
190
|
+
try {
|
|
191
|
+
(0, child_process_1.execSync)('gemini mcp add zeph -- npx -y @zeph-to/mcp-server', { stdio: 'pipe' });
|
|
192
|
+
ok('MCP server added (legacy gemini CLI)');
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
fail('MCP add failed. Manual: gemini mcp add -s user zeph npx -- -y @zeph-to/mcp-server');
|
|
196
|
+
}
|
|
187
197
|
}
|
|
188
198
|
try {
|
|
189
199
|
(0, exports.mergeJsonFile)((0, path_1.join)(HOME, '.gemini', 'settings.json'), templates_js_1.GEMINI_HOOKS);
|
package/dist/listener.d.ts
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { type AgentKind, type RegisteredRemoteAgent } from './remote-agents.js';
|
|
24
24
|
import { type AgentState } from './agent-state.js';
|
|
25
|
+
export declare const SESSION_REPORT_HEARTBEAT_MS = 30000;
|
|
25
26
|
interface AgentSession {
|
|
26
27
|
name: string;
|
|
27
28
|
attached: boolean;
|
|
@@ -41,6 +42,17 @@ interface AgentSession {
|
|
|
41
42
|
stateChangedAt?: string;
|
|
42
43
|
stateRuleId?: string;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Change-fingerprint for the report gate. Mirrors the server's
|
|
47
|
+
* REPORTED_SESSION_FIELDS comparison (zeph ws.ts sameReportedSessions):
|
|
48
|
+
* same fields, order-independent, undefined/null collapsed — so the
|
|
49
|
+
* client-side skip can never suppress a report the server would have
|
|
50
|
+
* treated as a change. Keep the field list in sync with the server.
|
|
51
|
+
*/
|
|
52
|
+
export declare const sessionsFingerprint: (sessions: AgentSession[]) => string;
|
|
53
|
+
/** True when this cycle's inventory must be sent: it changed, or the
|
|
54
|
+
* idle heartbeat is due. */
|
|
55
|
+
export declare const sessionsReportDue: (fingerprint: string, lastSentFingerprint: string | null, lastSentAtMs: number, nowMs: number) => boolean;
|
|
44
56
|
export declare const AUTH_FAILURE_CODES: ReadonlySet<number>;
|
|
45
57
|
export declare const checkRateLimit: (session: string, now?: number) => boolean;
|
|
46
58
|
/** Read the foreground command in the named tmux session's active pane. */
|
package/dist/listener.d.ts.map
CHANGED
|
@@ -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;
|
|
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 = void 0;
|
|
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;
|
|
29
29
|
const child_process_1 = require("child_process");
|
|
30
30
|
const crypto_1 = require("crypto");
|
|
31
31
|
const fs_1 = require("fs");
|
|
@@ -52,12 +52,43 @@ const WS_CONNECT_TIMEOUT_MS = 20_000;
|
|
|
52
52
|
// peer never replies. macOS App Nap / Wi-Fi handoff / VPN flap all
|
|
53
53
|
// surface this way. Force-terminate so the reconnect loop runs.
|
|
54
54
|
const WS_STALL_TIMEOUT_MS = 90_000;
|
|
55
|
-
// How often the listener
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// to reflect new `zeph cc` sessions within a few seconds, not half a
|
|
59
|
-
// minute.
|
|
55
|
+
// How often the listener POLLS its local tmux session inventory (and
|
|
56
|
+
// immediately on $connect). Cheap — tmux runs locally, so a change is
|
|
57
|
+
// still detected (and sent) within a few seconds.
|
|
60
58
|
const SESSION_REPORT_INTERVAL_MS = 5_000;
|
|
59
|
+
// How often an UNCHANGED inventory is re-sent. Every send costs the
|
|
60
|
+
// backend a Lambda invocation + several DynamoDB reads + a WS round
|
|
61
|
+
// trip, and an idle listener's reports are ~95% no-ops — the dominant
|
|
62
|
+
// per-user variable cost. A changed inventory still goes out on the
|
|
63
|
+
// next 5 s poll (no latency loss); this only throttles the no-ops.
|
|
64
|
+
// Kept above the server's 20 s write-through window
|
|
65
|
+
// (AGENT_SESSIONS_REFRESH_MS) so each heartbeat also refreshes
|
|
66
|
+
// agentSessionsUpdatedAt. Side effect: the ack (which carries pattern
|
|
67
|
+
// watches) arrives at this cadence while idle, so a newly-created
|
|
68
|
+
// watch can take up to 30 s to reach an idle listener.
|
|
69
|
+
exports.SESSION_REPORT_HEARTBEAT_MS = 30_000;
|
|
70
|
+
/**
|
|
71
|
+
* Change-fingerprint for the report gate. Mirrors the server's
|
|
72
|
+
* REPORTED_SESSION_FIELDS comparison (zeph ws.ts sameReportedSessions):
|
|
73
|
+
* same fields, order-independent, undefined/null collapsed — so the
|
|
74
|
+
* client-side skip can never suppress a report the server would have
|
|
75
|
+
* treated as a change. Keep the field list in sync with the server.
|
|
76
|
+
*/
|
|
77
|
+
const sessionsFingerprint = (sessions) => sessions
|
|
78
|
+
.map((s) => JSON.stringify([
|
|
79
|
+
s.name, s.attached, s.agentKind, s.agentSessionId ?? null,
|
|
80
|
+
s.project, s.label ?? null, s.createdAt ?? null,
|
|
81
|
+
s.lastActivityAt ?? null, s.state ?? null,
|
|
82
|
+
s.stateChangedAt ?? null, s.stateRuleId ?? null,
|
|
83
|
+
]))
|
|
84
|
+
.sort()
|
|
85
|
+
.join('|');
|
|
86
|
+
exports.sessionsFingerprint = sessionsFingerprint;
|
|
87
|
+
/** True when this cycle's inventory must be sent: it changed, or the
|
|
88
|
+
* idle heartbeat is due. */
|
|
89
|
+
const sessionsReportDue = (fingerprint, lastSentFingerprint, lastSentAtMs, nowMs) => fingerprint !== lastSentFingerprint ||
|
|
90
|
+
nowMs - lastSentAtMs >= exports.SESSION_REPORT_HEARTBEAT_MS;
|
|
91
|
+
exports.sessionsReportDue = sessionsReportDue;
|
|
61
92
|
// Per-session token bucket — caps a runaway/compromised sender. 30/min
|
|
62
93
|
// is generous for human-driven phone use, tight enough to block flooding.
|
|
63
94
|
const RATE_LIMIT_TOKENS = 30;
|
|
@@ -1080,22 +1111,37 @@ const streamSession = (wsUrl, apiKey) => {
|
|
|
1080
1111
|
sock.terminate();
|
|
1081
1112
|
}
|
|
1082
1113
|
}, WS_CONNECT_TIMEOUT_MS);
|
|
1114
|
+
// Report gate state — per connection on purpose: a fresh socket
|
|
1115
|
+
// must always send its first inventory (the server may have
|
|
1116
|
+
// nothing, or another listener's stale data, for this device).
|
|
1117
|
+
let lastSentFingerprint = null;
|
|
1118
|
+
let lastSentAtMs = 0;
|
|
1083
1119
|
const reportSessions = () => {
|
|
1084
1120
|
if (sock.readyState !== ws_1.default.OPEN)
|
|
1085
1121
|
return;
|
|
1086
1122
|
const { sessions, rejected } = (0, exports.collectSessionsVerbose)();
|
|
1087
|
-
|
|
1088
|
-
//
|
|
1089
|
-
//
|
|
1090
|
-
// record and the next ack prunes it locally.
|
|
1123
|
+
// Watch hits are one-shot events — they go out on every poll,
|
|
1124
|
+
// independent of the sessions-report gate below.
|
|
1125
|
+
// (§S5 v2): probe watched panes and report hits; the server
|
|
1126
|
+
// consumes the record and the next ack prunes it locally.
|
|
1091
1127
|
for (const hit of (0, exports.collectWatchHits)(new Set(sessions.map((s) => s.name)))) {
|
|
1092
1128
|
sock.send(JSON.stringify({ type: 'listener.watch.hit', data: hit }));
|
|
1093
1129
|
log(`🔔 watch hit: ${hit.sessionName} ~ /${hit.pattern}/`);
|
|
1094
1130
|
}
|
|
1095
|
-
//
|
|
1131
|
+
// Unchanged inventory + heartbeat not due → skip the send.
|
|
1132
|
+
// The 5 s local poll above still ran, so a change is never
|
|
1133
|
+
// delayed; only the no-op reports (idle listener) are culled.
|
|
1134
|
+
const fingerprint = (0, exports.sessionsFingerprint)(sessions);
|
|
1135
|
+
if (!(0, exports.sessionsReportDue)(fingerprint, lastSentFingerprint, lastSentAtMs, Date.now())) {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
sock.send(JSON.stringify({ type: 'listener.sessions', data: { sessions } }));
|
|
1139
|
+
lastSentFingerprint = fingerprint;
|
|
1140
|
+
lastSentAtMs = Date.now();
|
|
1141
|
+
// One line per send gives the user immediate feedback on
|
|
1096
1142
|
// what the phone picker will see — particularly important
|
|
1097
1143
|
// during setup, when an empty picker has no other observable
|
|
1098
|
-
// cause.
|
|
1144
|
+
// cause. (Skipped cycles stay quiet — same signal, less noise.)
|
|
1099
1145
|
const names = sessions
|
|
1100
1146
|
.map((s) => (s.state ? `${s.name}[${s.state}]` : s.name))
|
|
1101
1147
|
.join(', ') || '∅';
|
package/dist/uninstall.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../src/uninstall.ts"],"names":[],"mappings":"AAuGA;;iDAEiD;AACjD,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAWtE,CAAC;AAEF;;;gDAGgD;AAChD,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAerE,CAAC;
|
|
1
|
+
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../src/uninstall.ts"],"names":[],"mappings":"AAuGA;;iDAEiD;AACjD,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAWtE,CAAC;AAEF;;;gDAGgD;AAChD,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,EAAE,KAAK,OAAO,KAAG,MAAM,GAAG,IAerE,CAAC;AAuEF,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CA8B5F,CAAC"}
|
package/dist/uninstall.js
CHANGED
|
@@ -195,16 +195,24 @@ const AGENT_UNINSTALLERS = {
|
|
|
195
195
|
]),
|
|
196
196
|
gemini: (dry) => {
|
|
197
197
|
if (!dry) {
|
|
198
|
+
// user scope first (where the ≥0.26 installer adds it), then the
|
|
199
|
+
// legacy scope-less form for entries created by older installs.
|
|
198
200
|
try {
|
|
199
|
-
(0, child_process_1.execSync)('gemini mcp remove zeph', { stdio: 'pipe' });
|
|
201
|
+
(0, child_process_1.execSync)('gemini mcp remove -s user zeph', { stdio: 'pipe' });
|
|
200
202
|
ok('MCP server removed');
|
|
201
203
|
}
|
|
202
204
|
catch {
|
|
203
|
-
|
|
205
|
+
try {
|
|
206
|
+
(0, child_process_1.execSync)('gemini mcp remove zeph', { stdio: 'pipe' });
|
|
207
|
+
ok('MCP server removed');
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
skip('gemini MCP entry not found');
|
|
211
|
+
}
|
|
204
212
|
}
|
|
205
213
|
}
|
|
206
214
|
else {
|
|
207
|
-
skip('would run: gemini mcp remove zeph');
|
|
215
|
+
skip('would run: gemini mcp remove -s user zeph');
|
|
208
216
|
}
|
|
209
217
|
runSteps([
|
|
210
218
|
() => (0, exports.rmGeminiHook)((0, path_1.join)(HOME, '.gemini', 'settings.json'), dry),
|