@zeph-to/cli 1.13.2 → 1.15.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/dist/agent-rules-fetch.d.ts +33 -0
- package/dist/agent-rules-fetch.d.ts.map +1 -0
- package/dist/agent-rules-fetch.js +190 -0
- package/dist/agent-rules.default.d.ts +25 -0
- package/dist/agent-rules.default.d.ts.map +1 -0
- package/dist/agent-rules.default.js +89 -0
- package/dist/agent-state.d.ts +99 -0
- package/dist/agent-state.d.ts.map +1 -0
- package/dist/agent-state.js +140 -0
- package/dist/cli.js +41 -25
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -1
- package/dist/gate.d.ts +36 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +88 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/listener.d.ts +87 -13
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +216 -93
- package/dist/remote-agents.d.ts +55 -0
- package/dist/remote-agents.d.ts.map +1 -0
- package/dist/remote-agents.js +115 -0
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +27 -150
- package/dist/wrapper.d.ts +2 -1
- package/dist/wrapper.d.ts.map +1 -1
- package/dist/wrapper.js +4 -5
- package/dist/zeph-core.generated.d.ts +7 -0
- package/dist/zeph-core.generated.d.ts.map +1 -0
- package/dist/zeph-core.generated.js +14 -0
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const fs_1 = require("fs");
|
|
5
4
|
const child_process_1 = require("child_process");
|
|
6
5
|
const zeph_hook_js_1 = require("./zeph-hook.js");
|
|
7
6
|
const errors_js_1 = require("./errors.js");
|
|
@@ -13,21 +12,10 @@ const check_update_js_1 = require("./check-update.js");
|
|
|
13
12
|
const wrapper_js_1 = require("./wrapper.js");
|
|
14
13
|
const listener_js_1 = require("./listener.js");
|
|
15
14
|
const config_js_1 = require("./config.js");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const isMuted = () => {
|
|
19
|
-
try {
|
|
20
|
-
const dir = detectProjectDir();
|
|
21
|
-
const raw = (0, child_process_1.execFileSync)('cksum', { input: dir, encoding: 'utf-8' });
|
|
22
|
-
const hash = raw.split(' ')[0];
|
|
23
|
-
return (0, fs_1.existsSync)(`/tmp/zeph-muted-${hash}`);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
};
|
|
15
|
+
const gate_js_1 = require("./gate.js");
|
|
16
|
+
const remote_agents_js_1 = require("./remote-agents.js");
|
|
29
17
|
const detectBranchAndProject = () => {
|
|
30
|
-
const dir = detectProjectDir();
|
|
18
|
+
const dir = (0, config_js_1.detectProjectDir)();
|
|
31
19
|
const project = dir.split('/').filter(Boolean).pop() ?? 'project';
|
|
32
20
|
let branch;
|
|
33
21
|
try {
|
|
@@ -67,6 +55,8 @@ const parseArgs = (argv) => {
|
|
|
67
55
|
return result;
|
|
68
56
|
};
|
|
69
57
|
// ── Output ──────────────────────────────────────────────────────
|
|
58
|
+
/** One usage line per registered remote agent — generated so help text can't drift from the table. */
|
|
59
|
+
const usageAgentLines = () => remote_agents_js_1.REMOTE_AGENTS.map((a) => ` ${`${a.subcommands[0]} [args…]`.padEnd(15)} Run '${a.binary}' in a named tmux session ('zeph-<project>')`).join('\n');
|
|
70
60
|
const printUsage = () => {
|
|
71
61
|
console.log(`Usage: zeph <command> [options]
|
|
72
62
|
|
|
@@ -80,9 +70,7 @@ Commands:
|
|
|
80
70
|
list List recent push notifications
|
|
81
71
|
dismiss <id> Dismiss a push notification (or --all)
|
|
82
72
|
test Send a test notification to verify setup
|
|
83
|
-
|
|
84
|
-
codex [args…] Run 'codex' in a named tmux session
|
|
85
|
-
gemini [args…] Run 'gemini' in a named tmux session
|
|
73
|
+
${usageAgentLines()}
|
|
86
74
|
(auto-suffixed -2/-3/… when another zeph cc is already
|
|
87
75
|
attached to the default name; any args after the
|
|
88
76
|
subcommand are forwarded verbatim, e.g.
|
|
@@ -99,6 +87,11 @@ Notify options:
|
|
|
99
87
|
--priority <p> Priority (low|normal|high|urgent) [default: normal]
|
|
100
88
|
--device <id> Target device ID
|
|
101
89
|
--session <id> AI session ID (or set ZEPH_SESSION_ID env)
|
|
90
|
+
--auto Apply the push gate before sending (honors the
|
|
91
|
+
/zeph-quiet | /zeph-loud dial; silent exit when gated)
|
|
92
|
+
--marker <m> Push Signal marker for --auto (skip|push|high)
|
|
93
|
+
--tools <n> Turn tool count for --auto [default: assume real work]
|
|
94
|
+
--nonreadonly <n> Non-read-only tool count for --auto
|
|
102
95
|
|
|
103
96
|
List options:
|
|
104
97
|
--limit <n> Number of pushes (1-20, default 5)
|
|
@@ -166,10 +159,33 @@ const createHook = (args) => {
|
|
|
166
159
|
...(baseUrl && { baseUrl }),
|
|
167
160
|
});
|
|
168
161
|
};
|
|
162
|
+
/** Parse a gate count flag; garbage input falls back to the default (never accidentally silences). */
|
|
163
|
+
const gateCount = (raw, fallback) => {
|
|
164
|
+
const n = typeof raw === 'string' ? Number(raw) : NaN;
|
|
165
|
+
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
166
|
+
};
|
|
169
167
|
const handleNotify = async (args) => {
|
|
170
168
|
const isJson = args.json === true;
|
|
171
|
-
|
|
169
|
+
const projectDir = (0, config_js_1.detectProjectDir)();
|
|
170
|
+
if ((0, gate_js_1.isMuted)(projectDir))
|
|
172
171
|
return 0;
|
|
172
|
+
// --auto: apply the shared push-gate before sending. Inputs default to
|
|
173
|
+
// GATE_DEFAULTS ("assume real work") so dumb hooks keep their historical
|
|
174
|
+
// always-push behavior in normal mode, while the /zeph-quiet | /zeph-loud
|
|
175
|
+
// dial now works for every hook-driven agent. Gated-out → silent success.
|
|
176
|
+
if (args.auto === true) {
|
|
177
|
+
const verdict = (0, gate_js_1.decidePush)({
|
|
178
|
+
toolCount: gateCount(args.tools, gate_js_1.GATE_DEFAULTS.toolCount),
|
|
179
|
+
nonReadonlyCount: gateCount(args.nonreadonly, gate_js_1.GATE_DEFAULTS.nonReadonlyCount),
|
|
180
|
+
alreadyAsked: gate_js_1.GATE_DEFAULTS.alreadyAsked,
|
|
181
|
+
marker: (0, gate_js_1.normalizeMarker)(typeof args.marker === 'string' ? args.marker : undefined),
|
|
182
|
+
pushMode: (0, gate_js_1.readPushMode)(projectDir),
|
|
183
|
+
});
|
|
184
|
+
if (!verdict.push)
|
|
185
|
+
return 0;
|
|
186
|
+
if (verdict.priority === 'high' && !args.priority)
|
|
187
|
+
args.priority = 'high';
|
|
188
|
+
}
|
|
173
189
|
const hook = createHook(args);
|
|
174
190
|
if (!hook)
|
|
175
191
|
return 3;
|
|
@@ -337,6 +353,12 @@ const main = async () => {
|
|
|
337
353
|
printUsage();
|
|
338
354
|
return 0;
|
|
339
355
|
}
|
|
356
|
+
// Remote-control subcommands (`zeph cc` / `zeph codex` / …) come from the
|
|
357
|
+
// registry — one table row per agent, no hardcoded cases. Pass the typed
|
|
358
|
+
// command token to collectPassthrough (aliases map to the same agent).
|
|
359
|
+
const remote = (0, remote_agents_js_1.findAgentBySubcommand)(command);
|
|
360
|
+
if (remote)
|
|
361
|
+
return (0, wrapper_js_1.handleAgentSession)(remote, collectPassthrough(process.argv, command));
|
|
340
362
|
switch (command) {
|
|
341
363
|
case 'install':
|
|
342
364
|
case 'setup':
|
|
@@ -357,12 +379,6 @@ const main = async () => {
|
|
|
357
379
|
return handleDismiss(args);
|
|
358
380
|
case 'test':
|
|
359
381
|
return handleTest(args);
|
|
360
|
-
case 'cc':
|
|
361
|
-
return (0, wrapper_js_1.handleAgentSession)('claude', collectPassthrough(process.argv, 'cc'));
|
|
362
|
-
case 'codex':
|
|
363
|
-
return (0, wrapper_js_1.handleAgentSession)('codex', collectPassthrough(process.argv, 'codex'));
|
|
364
|
-
case 'gemini':
|
|
365
|
-
return (0, wrapper_js_1.handleAgentSession)('gemini', collectPassthrough(process.argv, 'gemini'));
|
|
366
382
|
case 'listener':
|
|
367
383
|
return (0, listener_js_1.handleListener)(args);
|
|
368
384
|
default:
|
package/dist/config.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export interface ZephConfig {
|
|
|
8
8
|
deviceId?: string;
|
|
9
9
|
}
|
|
10
10
|
export declare const resolvedEnv: (key: string) => string | undefined;
|
|
11
|
+
export declare const PROJECT_DIR_ENV_VARS: readonly ["CLAUDE_PROJECT_DIR", "CURSOR_PROJECT_DIR", "WINDSURF_PROJECT_DIR"];
|
|
12
|
+
/** First set project-dir env (unresolved `${VAR}` placeholders ignored), else cwd. */
|
|
13
|
+
export declare const detectProjectDir: () => string;
|
|
11
14
|
export declare const loadConfig: () => ZephConfig;
|
|
12
15
|
export declare const saveConfig: (config: ZephConfig) => void;
|
|
13
16
|
export declare const VERSION: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAGlD,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,UAM7B,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU,KAAG,IAG/C,CAAC;AAEF,eAAO,MAAM,OAAO,QAOhB,CAAC"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,QAA2B,CAAC;AACnD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAGlD,CAAC;AAMF,eAAO,MAAM,oBAAoB,+EAAgF,CAAC;AAElH,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,QAAO,MAMnC,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,UAM7B,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,QAAQ,UAAU,KAAG,IAG/C,CAAC;AAEF,eAAO,MAAM,OAAO,QAOhB,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VERSION = exports.saveConfig = exports.loadConfig = exports.resolvedEnv = exports.CONFIG_FILE = exports.CONFIG_DIR = void 0;
|
|
3
|
+
exports.VERSION = exports.saveConfig = exports.loadConfig = exports.detectProjectDir = exports.PROJECT_DIR_ENV_VARS = exports.resolvedEnv = exports.CONFIG_FILE = exports.CONFIG_DIR = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const os_1 = require("os");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -11,6 +11,21 @@ const resolvedEnv = (key) => {
|
|
|
11
11
|
return val && !val.startsWith('${') ? val : undefined;
|
|
12
12
|
};
|
|
13
13
|
exports.resolvedEnv = resolvedEnv;
|
|
14
|
+
// Per-agent project-dir env vars, in precedence order. Deliberately NOT part
|
|
15
|
+
// of the remote-agent registry: Cursor/Windsurf carry project-dir envs but
|
|
16
|
+
// are not remote-controllable via tmux — the two tables have different
|
|
17
|
+
// membership.
|
|
18
|
+
exports.PROJECT_DIR_ENV_VARS = ['CLAUDE_PROJECT_DIR', 'CURSOR_PROJECT_DIR', 'WINDSURF_PROJECT_DIR'];
|
|
19
|
+
/** First set project-dir env (unresolved `${VAR}` placeholders ignored), else cwd. */
|
|
20
|
+
const detectProjectDir = () => {
|
|
21
|
+
for (const key of exports.PROJECT_DIR_ENV_VARS) {
|
|
22
|
+
const val = (0, exports.resolvedEnv)(key);
|
|
23
|
+
if (val)
|
|
24
|
+
return val;
|
|
25
|
+
}
|
|
26
|
+
return process.cwd();
|
|
27
|
+
};
|
|
28
|
+
exports.detectProjectDir = detectProjectDir;
|
|
14
29
|
const loadConfig = () => {
|
|
15
30
|
try {
|
|
16
31
|
return JSON.parse((0, fs_1.readFileSync)(exports.CONFIG_FILE, 'utf-8'));
|
package/dist/gate.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type GateMarker = 'skip' | 'push' | 'high' | 'none';
|
|
2
|
+
export type GatePushMode = 'quiet' | 'loud' | 'normal';
|
|
3
|
+
export interface GateInput {
|
|
4
|
+
/** Total tool_use blocks this turn. */
|
|
5
|
+
toolCount: number;
|
|
6
|
+
/** Tools that are NOT read-only (Read/Grep/Glob). */
|
|
7
|
+
nonReadonlyCount: number;
|
|
8
|
+
/** A zeph_ask/zeph_prompt already notified this turn. */
|
|
9
|
+
alreadyAsked: boolean;
|
|
10
|
+
marker: GateMarker;
|
|
11
|
+
pushMode: GatePushMode;
|
|
12
|
+
}
|
|
13
|
+
export interface GateVerdict {
|
|
14
|
+
push: boolean;
|
|
15
|
+
priority: 'high' | 'normal';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* "Assume real work" defaults for hooks that can't supply turn facts
|
|
19
|
+
* (most non-Claude agents pass no counts): in normal mode the push still
|
|
20
|
+
* fires — preserving the historical always-push behavior of the dumb
|
|
21
|
+
* hooks — while quiet/loud now work everywhere.
|
|
22
|
+
*/
|
|
23
|
+
export declare const GATE_DEFAULTS: {
|
|
24
|
+
readonly toolCount: 2;
|
|
25
|
+
readonly nonReadonlyCount: 1;
|
|
26
|
+
readonly alreadyAsked: false;
|
|
27
|
+
};
|
|
28
|
+
export declare const normalizeMarker: (raw: string | undefined) => GateMarker;
|
|
29
|
+
export declare const normalizePushMode: (raw: string | undefined) => GatePushMode;
|
|
30
|
+
export declare const decidePush: (input: GateInput) => GateVerdict;
|
|
31
|
+
export declare const projectHash: (dir: string) => string | null;
|
|
32
|
+
/** True when the user ran /zeph-mute for this project. */
|
|
33
|
+
export declare const isMuted: (dir: string) => boolean;
|
|
34
|
+
/** The user's session push-mode dial (/zeph-quiet | /zeph-loud), default normal. */
|
|
35
|
+
export declare const readPushMode: (dir: string) => GatePushMode;
|
|
36
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAsBA,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;AAQF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOlD,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,OAGrC,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,YAQ1C,CAAC"}
|
package/dist/gate.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readPushMode = exports.isMuted = exports.projectHash = exports.decidePush = exports.normalizePushMode = exports.normalizeMarker = exports.GATE_DEFAULTS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Push-gate decision — the portable half of the Zeph Stop-hook logic.
|
|
6
|
+
*
|
|
7
|
+
* `decidePush` is the TS twin of `plugin/hooks/gate.sh` (zeph-to/plugin).
|
|
8
|
+
* Both implementations are locked to the same semantics by the shared
|
|
9
|
+
* vector file `src/fixtures/gate-vectors.json` (vendored from the plugin
|
|
10
|
+
* repo's canonical copy via `npm run sync:plugin`): the bash side and this
|
|
11
|
+
* side run the exact same cases in their CIs, so a semantic change to one
|
|
12
|
+
* that isn't mirrored in the other fails a build. Edit them together.
|
|
13
|
+
*
|
|
14
|
+
* Ordering is contractual (encoded as named vectors):
|
|
15
|
+
* 1. alreadyAsked wins over EVERYTHING — even loud (dedup beats the dial).
|
|
16
|
+
* 2. priority is high iff marker === 'high', decided BEFORE the mode
|
|
17
|
+
* switch, so quiet+high and loud+high both push at high priority.
|
|
18
|
+
* 3. quiet → only a high marker pushes; loud → always push; normal →
|
|
19
|
+
* marker overrides the heuristic (skip → silent, push/high → push),
|
|
20
|
+
* no marker → push iff toolCount ≥ 2 AND nonReadonlyCount > 0
|
|
21
|
+
* (the B1 read-only floor).
|
|
22
|
+
*/
|
|
23
|
+
const child_process_1 = require("child_process");
|
|
24
|
+
const fs_1 = require("fs");
|
|
25
|
+
/**
|
|
26
|
+
* "Assume real work" defaults for hooks that can't supply turn facts
|
|
27
|
+
* (most non-Claude agents pass no counts): in normal mode the push still
|
|
28
|
+
* fires — preserving the historical always-push behavior of the dumb
|
|
29
|
+
* hooks — while quiet/loud now work everywhere.
|
|
30
|
+
*/
|
|
31
|
+
exports.GATE_DEFAULTS = {
|
|
32
|
+
toolCount: 2,
|
|
33
|
+
nonReadonlyCount: 1,
|
|
34
|
+
alreadyAsked: false,
|
|
35
|
+
};
|
|
36
|
+
const normalizeMarker = (raw) => raw === 'skip' || raw === 'push' || raw === 'high' ? raw : 'none';
|
|
37
|
+
exports.normalizeMarker = normalizeMarker;
|
|
38
|
+
const normalizePushMode = (raw) => raw === 'quiet' || raw === 'loud' ? raw : 'normal';
|
|
39
|
+
exports.normalizePushMode = normalizePushMode;
|
|
40
|
+
const decidePush = (input) => {
|
|
41
|
+
if (input.alreadyAsked)
|
|
42
|
+
return { push: false, priority: 'normal' };
|
|
43
|
+
const priority = input.marker === 'high' ? 'high' : 'normal';
|
|
44
|
+
if (input.pushMode === 'quiet')
|
|
45
|
+
return { push: input.marker === 'high', priority };
|
|
46
|
+
if (input.pushMode === 'loud')
|
|
47
|
+
return { push: true, priority };
|
|
48
|
+
if (input.marker === 'skip')
|
|
49
|
+
return { push: false, priority };
|
|
50
|
+
if (input.marker === 'push' || input.marker === 'high')
|
|
51
|
+
return { push: true, priority };
|
|
52
|
+
return { push: input.toolCount >= 2 && input.nonReadonlyCount > 0, priority };
|
|
53
|
+
};
|
|
54
|
+
exports.decidePush = decidePush;
|
|
55
|
+
// ── Per-project gate state (mute + push-mode dial) ───────────────
|
|
56
|
+
//
|
|
57
|
+
// The plugin's bash hooks key these tmp files off `cksum` of the project
|
|
58
|
+
// dir; shelling out to the same `cksum` here (instead of a pure-TS CRC)
|
|
59
|
+
// guarantees hash parity with every already-written file.
|
|
60
|
+
const projectHash = (dir) => {
|
|
61
|
+
try {
|
|
62
|
+
const raw = (0, child_process_1.execFileSync)('cksum', { input: dir, encoding: 'utf-8' });
|
|
63
|
+
return raw.split(' ')[0] || null;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
exports.projectHash = projectHash;
|
|
70
|
+
/** True when the user ran /zeph-mute for this project. */
|
|
71
|
+
const isMuted = (dir) => {
|
|
72
|
+
const hash = (0, exports.projectHash)(dir);
|
|
73
|
+
return hash !== null && (0, fs_1.existsSync)(`/tmp/zeph-muted-${hash}`);
|
|
74
|
+
};
|
|
75
|
+
exports.isMuted = isMuted;
|
|
76
|
+
/** The user's session push-mode dial (/zeph-quiet | /zeph-loud), default normal. */
|
|
77
|
+
const readPushMode = (dir) => {
|
|
78
|
+
const hash = (0, exports.projectHash)(dir);
|
|
79
|
+
if (!hash)
|
|
80
|
+
return 'normal';
|
|
81
|
+
try {
|
|
82
|
+
return (0, exports.normalizePushMode)((0, fs_1.readFileSync)(`/tmp/zeph-pushmode-${hash}`, 'utf-8').replace(/\s+/g, ''));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return 'normal';
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
exports.readPushMode = readPushMode;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { ZephHook } from './zeph-hook.js';
|
|
2
2
|
export { ZephError, AuthenticationError, QuotaExceededError } from './errors.js';
|
|
3
3
|
export type { ZephOptions, NotifyPayload, NotifyResult, ListParams, ListResult, DismissOneResult, DismissAllResult, PushItem } from './types.js';
|
|
4
|
+
export { decidePush, GATE_DEFAULTS, normalizeMarker, normalizePushMode } from './gate.js';
|
|
5
|
+
export type { GateInput, GateVerdict, GateMarker, GatePushMode } from './gate.js';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjJ,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC1F,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QuotaExceededError = exports.AuthenticationError = exports.ZephError = exports.ZephHook = void 0;
|
|
3
|
+
exports.normalizePushMode = exports.normalizeMarker = exports.GATE_DEFAULTS = exports.decidePush = exports.QuotaExceededError = exports.AuthenticationError = exports.ZephError = exports.ZephHook = void 0;
|
|
4
4
|
var zeph_hook_js_1 = require("./zeph-hook.js");
|
|
5
5
|
Object.defineProperty(exports, "ZephHook", { enumerable: true, get: function () { return zeph_hook_js_1.ZephHook; } });
|
|
6
6
|
var errors_js_1 = require("./errors.js");
|
|
7
7
|
Object.defineProperty(exports, "ZephError", { enumerable: true, get: function () { return errors_js_1.ZephError; } });
|
|
8
8
|
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_js_1.AuthenticationError; } });
|
|
9
9
|
Object.defineProperty(exports, "QuotaExceededError", { enumerable: true, get: function () { return errors_js_1.QuotaExceededError; } });
|
|
10
|
+
var gate_js_1 = require("./gate.js");
|
|
11
|
+
Object.defineProperty(exports, "decidePush", { enumerable: true, get: function () { return gate_js_1.decidePush; } });
|
|
12
|
+
Object.defineProperty(exports, "GATE_DEFAULTS", { enumerable: true, get: function () { return gate_js_1.GATE_DEFAULTS; } });
|
|
13
|
+
Object.defineProperty(exports, "normalizeMarker", { enumerable: true, get: function () { return gate_js_1.normalizeMarker; } });
|
|
14
|
+
Object.defineProperty(exports, "normalizePushMode", { enumerable: true, get: function () { return gate_js_1.normalizePushMode; } });
|
package/dist/listener.d.ts
CHANGED
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
* messages as new pushes are created. Reconnects with exponential
|
|
21
21
|
* backoff on transient failures; gives up on auth failures (4001/4002/4003).
|
|
22
22
|
*/
|
|
23
|
-
type AgentKind
|
|
23
|
+
import { type AgentKind, type RegisteredRemoteAgent } from './remote-agents.js';
|
|
24
|
+
import { type AgentState } from './agent-state.js';
|
|
24
25
|
interface AgentSession {
|
|
25
26
|
name: string;
|
|
26
27
|
attached: boolean;
|
|
@@ -30,6 +31,15 @@ interface AgentSession {
|
|
|
30
31
|
label?: string | null;
|
|
31
32
|
createdAt?: string;
|
|
32
33
|
lastActivityAt?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Detected agent state (wire contract — flows to the server and the
|
|
36
|
+
* phone's Agents tab). Absent when the pane can't be captured or
|
|
37
|
+
* detection is unavailable. `done` never appears here: it's derived
|
|
38
|
+
* client-side (SPEC-AGENT-AWARENESS §S1/§S6).
|
|
39
|
+
*/
|
|
40
|
+
state?: AgentState;
|
|
41
|
+
stateChangedAt?: string;
|
|
42
|
+
stateRuleId?: string;
|
|
33
43
|
}
|
|
34
44
|
export declare const AUTH_FAILURE_CODES: ReadonlySet<number>;
|
|
35
45
|
export declare const checkRateLimit: (session: string, now?: number) => boolean;
|
|
@@ -55,15 +65,78 @@ export declare const parseSessionName: (name: string) => {
|
|
|
55
65
|
project: string;
|
|
56
66
|
label: string | null;
|
|
57
67
|
} | null;
|
|
68
|
+
interface PaneInfo {
|
|
69
|
+
currentCommand: string | null;
|
|
70
|
+
startCommand: string | null;
|
|
71
|
+
currentPath: string | null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Identify the agent from the tmux pane. Prefer `pane_start_command`
|
|
75
|
+
* because the foreground process is usually `node`/`python3` (the
|
|
76
|
+
* interpreter), which doesn't tell us *what* was launched. Fall back to
|
|
77
|
+
* `pane_current_command` when start_command is empty — tmux clears
|
|
78
|
+
* start_command in some re-attach cases, especially when a pre-existing
|
|
79
|
+
* session was joined via `tmux new -A` instead of being created fresh.
|
|
80
|
+
* That fallback is safe because only the literal binaries registered in
|
|
81
|
+
* remote-agents.ts are accepted as a match.
|
|
82
|
+
*/
|
|
83
|
+
export declare const detectRemoteAgent: (info: PaneInfo) => RegisteredRemoteAgent | null;
|
|
84
|
+
/** Test hook. */
|
|
85
|
+
export declare const resetSessionStates: () => void;
|
|
58
86
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
87
|
+
* Fold one pane capture into the per-session state machine and return
|
|
88
|
+
* the wire fields for this report cycle. Exported (with `paneText`
|
|
89
|
+
* injected) so tests can drive it without tmux.
|
|
90
|
+
*
|
|
91
|
+
* Hash short-circuit: an unchanged screen skips rule evaluation but
|
|
92
|
+
* still replays the previous observation through the debounce — cheap
|
|
93
|
+
* cycles stay cheap without wedging candidate promotion.
|
|
94
|
+
*/
|
|
95
|
+
export declare const deriveSessionState: (name: string, agentKind: AgentKind, paneText: string | null, now?: number) => Pick<AgentSession, "state" | "stateChangedAt" | "stateRuleId">;
|
|
96
|
+
export interface PatternWatch {
|
|
97
|
+
sessionName: string;
|
|
98
|
+
pattern: string;
|
|
99
|
+
}
|
|
100
|
+
/** Ack payload → active watch list. Prunes fired-markers for dead watches. */
|
|
101
|
+
export declare const setPatternWatches: (raw: unknown) => void;
|
|
102
|
+
/** Test hook. */
|
|
103
|
+
export declare const resetPatternWatches: () => void;
|
|
104
|
+
export interface WatchHit {
|
|
105
|
+
sessionName: string;
|
|
106
|
+
pattern: string;
|
|
107
|
+
matchedLine: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Probe every un-fired watch whose session is live. `capture` is
|
|
111
|
+
* injectable for tests; production passes capturePaneText.
|
|
112
|
+
*/
|
|
113
|
+
export declare const collectWatchHits: (liveNames: ReadonlySet<string>, capture?: (session: string) => string | null) => WatchHit[];
|
|
114
|
+
export interface ScreenRequest {
|
|
115
|
+
subtype?: string;
|
|
116
|
+
targetDeviceId?: string;
|
|
117
|
+
sessionName?: string;
|
|
118
|
+
requestId?: string;
|
|
119
|
+
}
|
|
120
|
+
export interface ScreenSnapshot {
|
|
121
|
+
subtype: 'agent.screen.snapshot';
|
|
122
|
+
requestId: string;
|
|
123
|
+
sessionName: string;
|
|
124
|
+
content?: string;
|
|
125
|
+
truncated?: boolean;
|
|
126
|
+
error?: string;
|
|
127
|
+
capturedAt: string;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Answer a phone's screen-peek request for one of OUR sessions.
|
|
131
|
+
* Returns null when the message isn't addressed to this machine (other
|
|
132
|
+
* ephemeral traffic — clipboard, mirrors — flows through constantly).
|
|
133
|
+
*
|
|
134
|
+
* Security posture: only sessions the inventory already exposes are
|
|
135
|
+
* readable — the phone can see exactly the panes it can already send
|
|
136
|
+
* commands into, nothing else. Rate-limited with the same per-session
|
|
137
|
+
* token bucket as command injection.
|
|
65
138
|
*/
|
|
66
|
-
export declare const
|
|
139
|
+
export declare const handleScreenRequest: (req: ScreenRequest) => ScreenSnapshot | null;
|
|
67
140
|
export interface CollectResult {
|
|
68
141
|
sessions: AgentSession[];
|
|
69
142
|
/** Diagnostic notes per rejected session — surfaced under `--verbose`. */
|
|
@@ -81,11 +154,12 @@ export interface CollectResult {
|
|
|
81
154
|
export declare const collectSessionsVerbose: () => CollectResult;
|
|
82
155
|
/**
|
|
83
156
|
* Snapshot the live `zeph-*` tmux sessions on this machine, enriched
|
|
84
|
-
* with the running agent kind,
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
157
|
+
* with the running agent kind, the agent's own session id (when the
|
|
158
|
+
* registry has a resolver — currently Claude Code only), project, and
|
|
159
|
+
* tmux activity timestamps. Returns [] when tmux is unreachable or no
|
|
160
|
+
* agent sessions exist. Sessions whose pane is at a shell or running
|
|
161
|
+
* something not registered in remote-agents.ts are filtered out — the
|
|
162
|
+
* phone can't usefully address them.
|
|
89
163
|
*/
|
|
90
164
|
export declare const collectSessions: () => AgentSession[];
|
|
91
165
|
/**
|
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;
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|