@zeph-to/hook-sdk 1.8.0 → 1.10.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 +283 -14
- package/dist/cli.js +33 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/installer.d.ts +7 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +84 -27
- package/dist/listener.d.ts +116 -0
- package/dist/listener.d.ts.map +1 -0
- package/dist/listener.js +878 -0
- package/dist/wrapper.d.ts +26 -0
- package/dist/wrapper.d.ts.map +1 -0
- package/dist/wrapper.js +210 -0
- package/package.json +8 -3
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zeph listener` — resident daemon that watches the user's Zeph feed
|
|
3
|
+
* over a persistent WebSocket and injects matching messages into a
|
|
4
|
+
* named tmux session via `tmux send-keys`.
|
|
5
|
+
*
|
|
6
|
+
* Solves the MCP polling-window problem: an `zeph_ask` polling cycle
|
|
7
|
+
* times out (120–600 s) and the CC/Codex session becomes unaddressable
|
|
8
|
+
* from the phone. The listener stays subscribed indefinitely and can
|
|
9
|
+
* deliver to any named tmux session at any time.
|
|
10
|
+
*
|
|
11
|
+
* Wire format: pushes with `type='agent.command'` carry the tmux
|
|
12
|
+
* session name in `agentSessionName` and the message in `body`. The
|
|
13
|
+
* "AI Agent에게 명령" sheet on the phone builds these structured
|
|
14
|
+
* pushes from the listener-reported session inventory. Other push
|
|
15
|
+
* types (Stop-hook auto-pushes, zeph_ask responses, channel
|
|
16
|
+
* broadcasts) are ignored.
|
|
17
|
+
*
|
|
18
|
+
* Transport: WebSocket against the Zeph $connect endpoint with
|
|
19
|
+
* `?apiKey=<key>`. The server fan-out pushes `{ type: 'push.new', data }`
|
|
20
|
+
* messages as new pushes are created. Reconnects with exponential
|
|
21
|
+
* backoff on transient failures; gives up on auth failures (4001/4002/4003).
|
|
22
|
+
*/
|
|
23
|
+
type AgentKind = 'claude' | 'codex' | 'gemini';
|
|
24
|
+
interface AgentSession {
|
|
25
|
+
name: string;
|
|
26
|
+
attached: boolean;
|
|
27
|
+
agentKind: AgentKind;
|
|
28
|
+
agentSessionId?: string | null;
|
|
29
|
+
project: string;
|
|
30
|
+
label?: string | null;
|
|
31
|
+
createdAt?: string;
|
|
32
|
+
lastActivityAt?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare const checkRateLimit: (session: string, now?: number) => boolean;
|
|
35
|
+
/** Read the foreground command in the named tmux session's active pane. */
|
|
36
|
+
export declare const paneCurrentCommand: (session: string) => string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Parse a `zeph-*` tmux session name into `{project, label}`. For
|
|
39
|
+
* Phase 1 the wrapper only emits `zeph-<project>` (no labels), so the
|
|
40
|
+
* whole tail becomes the project. When labels land in Phase 2 the
|
|
41
|
+
* wrapper will sidecar `{project, label}` so the listener doesn't need
|
|
42
|
+
* to guess from a name that allows dashes in project names.
|
|
43
|
+
*/
|
|
44
|
+
export declare const parseSessionName: (name: string) => {
|
|
45
|
+
project: string;
|
|
46
|
+
label: string | null;
|
|
47
|
+
} | null;
|
|
48
|
+
/**
|
|
49
|
+
* Locate the most recent Claude Code session UUID for the working
|
|
50
|
+
* directory of a tmux pane. Mirrors `mcp-server/config.ts`'s
|
|
51
|
+
* detectClaudeSessionId: CC writes per-session jsonl files at
|
|
52
|
+
* `~/.claude/projects/<projectHash>/<UUID>.jsonl` where the hash is
|
|
53
|
+
* the cwd with `/` replaced by `-`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const detectClaudeSessionId: (cwd: string) => string | null;
|
|
56
|
+
export interface CollectResult {
|
|
57
|
+
sessions: AgentSession[];
|
|
58
|
+
/** Diagnostic notes per rejected session — surfaced under `--verbose`. */
|
|
59
|
+
rejected: Array<{
|
|
60
|
+
name: string;
|
|
61
|
+
reason: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Inventory pass that also records *why* each `zeph-*` session was
|
|
66
|
+
* skipped. The verbose log uses the rejection notes to explain empty
|
|
67
|
+
* pickers (most common cause: tmux pane lost its start_command after a
|
|
68
|
+
* re-attach, and the current command is `node` rather than `claude`).
|
|
69
|
+
*/
|
|
70
|
+
export declare const collectSessionsVerbose: () => CollectResult;
|
|
71
|
+
/**
|
|
72
|
+
* Snapshot the live `zeph-*` tmux sessions on this machine, enriched
|
|
73
|
+
* with the running agent kind, CC session UUID (claude only), project,
|
|
74
|
+
* and tmux activity timestamps. Returns [] when tmux is unreachable
|
|
75
|
+
* or no agent sessions exist. Sessions whose pane is at a shell or
|
|
76
|
+
* running something other than claude/codex/gemini are filtered out
|
|
77
|
+
* — the phone can't usefully address them.
|
|
78
|
+
*/
|
|
79
|
+
export declare const collectSessions: () => AgentSession[];
|
|
80
|
+
interface PushItem {
|
|
81
|
+
pushId: string;
|
|
82
|
+
type?: string;
|
|
83
|
+
body?: string;
|
|
84
|
+
title?: string;
|
|
85
|
+
createdAt?: string;
|
|
86
|
+
isEncrypted?: boolean;
|
|
87
|
+
/** Set when type='agent.command' — tmux session name to inject into. */
|
|
88
|
+
agentSessionName?: string;
|
|
89
|
+
}
|
|
90
|
+
interface HandlePushDeps {
|
|
91
|
+
paneCommand?: (session: string) => string | null;
|
|
92
|
+
inject?: (session: string, text: string) => boolean;
|
|
93
|
+
rateLimit?: (session: string) => boolean;
|
|
94
|
+
now?: () => number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Process one push. Returns true when an injection actually fired.
|
|
98
|
+
* Exported for unit testing with mocked deps.
|
|
99
|
+
*
|
|
100
|
+
* Only acts on `type='agent.command'` pushes carrying both an
|
|
101
|
+
* `agentSessionName` (tmux session to inject into) and a non-empty
|
|
102
|
+
* `body`. Everything else (Stop-hook auto-pushes, zeph_ask responses,
|
|
103
|
+
* encrypted pushes, normal text/link/file notifications) is ignored.
|
|
104
|
+
*/
|
|
105
|
+
export declare const handlePush: (push: PushItem, deps?: HandlePushDeps) => boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Stable per-host device id for the listener. We hash the OS hostname so
|
|
108
|
+
* the same machine reuses the same DeviceRecord across listener restarts
|
|
109
|
+
* (otherwise the phone's session inventory grows a new ghost device every
|
|
110
|
+
* time `zeph listener` rebinds). `dev_listener_<sha8(hostname)>` keeps it
|
|
111
|
+
* human-recognisable in dev logs without leaking the raw hostname.
|
|
112
|
+
*/
|
|
113
|
+
export declare const computeListenerDeviceId: (host?: string) => string;
|
|
114
|
+
export declare const handleListener: (args: Record<string, string | boolean>) => Promise<number>;
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAuBH,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAG/C,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;CAC3B;AA2BD,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;AA6QF;;;;;;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;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAkB5D,CAAC;AAoEF,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,aA0DzC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,QAAO,YAAY,EAAuC,CAAC;AAIvF,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;CAC7B;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,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAgCD;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACnB,MAAM,QAAQ,EACd,OAAM,cAAmB,KAC1B,OAQF,CAAC;AA2BF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAAI,OAAM,MAAmB,KAAG,MAGnE,CAAC;AAyLF,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CA6E3F,CAAC"}
|