@moxxy/sdk 0.21.1 → 0.23.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.
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Process-independent control surface for dedicated channel runners.
3
+ *
4
+ * A dedicated channel (Slack, Telegram, …) runs as its OWN isolated runner
5
+ * subprocess that publishes a tiny status file (`channel-<name>.status.json`,
6
+ * see {@link ./channel-status}) on ready and clears it on graceful shutdown. That
7
+ * file — NOT a held child handle — is the source of truth for "is it running",
8
+ * so a channel started from anywhere (the TUI `/channels` panel, `moxxy channels
9
+ * start`, the desktop panel) is visible and stoppable from everywhere, and keeps
10
+ * running after the launcher exits.
11
+ *
12
+ * These helpers are the shared spine for those surfaces:
13
+ * - {@link spawnDedicatedChannel} — start one, detached, on its own runner.
14
+ * - {@link liveChannelStatus}/{@link listLiveChannelStatuses} — discover the
15
+ * running ones (with stale-file self-healing).
16
+ * - {@link stopDedicatedChannel} — signal one to stop.
17
+ *
18
+ * Node-only (`node:child_process`, `node:fs`) — exported from `@moxxy/sdk/server`.
19
+ */
20
+ import { type ChannelRunStatus } from './channel-status.js';
21
+ /**
22
+ * Start a channel on its own dedicated, detached runner by re-invoking this very
23
+ * moxxy binary as `moxxy <name>` with `MOXXY_DEDICATED_RUNNER=1`. The child is
24
+ * `detached` + `unref`'d with no stdio, so it OUTLIVES the launcher (the user can
25
+ * quit the TUI and the bot keeps serving) and reports itself via its status file.
26
+ *
27
+ * Returns the child pid, or undefined if the spawn produced none. Throws if the
28
+ * moxxy CLI entry can't be resolved (no `process.argv[1]`).
29
+ *
30
+ * Caller's job (this is fire-and-forget): poll {@link liveChannelStatus} to learn
31
+ * when it's ready / failed (no status file within a timeout ⇒ it died on boot —
32
+ * re-run `moxxy <name>` in the foreground to see why).
33
+ */
34
+ export declare function spawnDedicatedChannel(name: string): number | undefined;
35
+ /**
36
+ * Is `pid` a live process? `kill(pid, 0)` sends no signal — it only probes:
37
+ * - resolves ⇒ alive,
38
+ * - `ESRCH` ⇒ gone,
39
+ * - `EPERM` ⇒ alive but owned by another user (treat as alive — it exists).
40
+ */
41
+ export declare function isPidAlive(pid: number): boolean;
42
+ /**
43
+ * The status of channel `name` IF it is actually running. Reads its status file
44
+ * and verifies the pid is alive; a file whose pid is dead (the runner crashed or
45
+ * was SIGKILL'd without clearing it) is treated as not-running AND removed, so a
46
+ * stale file never masquerades as a live channel.
47
+ */
48
+ export declare function liveChannelStatus(name: string): ChannelRunStatus | null;
49
+ /**
50
+ * Every currently-running dedicated channel, discovered by scanning the moxxy
51
+ * home for status files and filtering to live pids (self-healing stale ones).
52
+ * Returns [] when the home dir doesn't exist yet.
53
+ */
54
+ export declare function listLiveChannelStatuses(): ChannelRunStatus[];
55
+ /**
56
+ * Ask channel `name` to stop by SIGTERM-ing its runner. The runner's own signal
57
+ * handler tears down gracefully and clears its status file. Returns `'stopped'`
58
+ * if a live runner was signaled, `'not-running'` if there was nothing to stop.
59
+ *
60
+ * This is a single, synchronous SIGTERM — callers that want a hard backstop poll
61
+ * {@link liveChannelStatus} afterwards and escalate (SIGKILL + {@link clearChannelStatus})
62
+ * if it ignores the term within a grace period.
63
+ */
64
+ export declare function stopDedicatedChannel(name: string): 'stopped' | 'not-running';
65
+ //# sourceMappingURL=channel-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-control.d.ts","sourceRoot":"","sources":["../src/channel-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,qBAAqB,CAAC;AAS7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAatE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQvE;AAQD;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,gBAAgB,EAAE,CAe5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAU5E"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Process-independent control surface for dedicated channel runners.
3
+ *
4
+ * A dedicated channel (Slack, Telegram, …) runs as its OWN isolated runner
5
+ * subprocess that publishes a tiny status file (`channel-<name>.status.json`,
6
+ * see {@link ./channel-status}) on ready and clears it on graceful shutdown. That
7
+ * file — NOT a held child handle — is the source of truth for "is it running",
8
+ * so a channel started from anywhere (the TUI `/channels` panel, `moxxy channels
9
+ * start`, the desktop panel) is visible and stoppable from everywhere, and keeps
10
+ * running after the launcher exits.
11
+ *
12
+ * These helpers are the shared spine for those surfaces:
13
+ * - {@link spawnDedicatedChannel} — start one, detached, on its own runner.
14
+ * - {@link liveChannelStatus}/{@link listLiveChannelStatuses} — discover the
15
+ * running ones (with stale-file self-healing).
16
+ * - {@link stopDedicatedChannel} — signal one to stop.
17
+ *
18
+ * Node-only (`node:child_process`, `node:fs`) — exported from `@moxxy/sdk/server`.
19
+ */
20
+ import { spawn } from 'node:child_process';
21
+ import { readdirSync } from 'node:fs';
22
+ import { clearChannelStatus, readChannelStatus, } from './channel-status.js';
23
+ import { moxxyHome } from './fs-utils.js';
24
+ /** Env vars that ADDRESS a runner (socket + sticky session). We scrub these from
25
+ * a spawned channel's env so `applyDedicatedRunnerEnv` (which only fills UNSET
26
+ * vars) derives the channel's OWN isolated socket/session from its name — rather
27
+ * than the channel silently inheriting and sharing the launcher's runner. */
28
+ const ADDRESSING_ENV = ['MOXXY_RUNNER_SOCKET', 'MOXXY_SESSION_ID', 'MOXXY_SESSION_SOURCE'];
29
+ /**
30
+ * Start a channel on its own dedicated, detached runner by re-invoking this very
31
+ * moxxy binary as `moxxy <name>` with `MOXXY_DEDICATED_RUNNER=1`. The child is
32
+ * `detached` + `unref`'d with no stdio, so it OUTLIVES the launcher (the user can
33
+ * quit the TUI and the bot keeps serving) and reports itself via its status file.
34
+ *
35
+ * Returns the child pid, or undefined if the spawn produced none. Throws if the
36
+ * moxxy CLI entry can't be resolved (no `process.argv[1]`).
37
+ *
38
+ * Caller's job (this is fire-and-forget): poll {@link liveChannelStatus} to learn
39
+ * when it's ready / failed (no status file within a timeout ⇒ it died on boot —
40
+ * re-run `moxxy <name>` in the foreground to see why).
41
+ */
42
+ export function spawnDedicatedChannel(name) {
43
+ const node = process.execPath; // the running Node binary (pnpm `moxxy` launches via Node)
44
+ const entry = process.argv[1]; // the resolved CLI entry (…/cli/dist/bin.js)
45
+ if (!entry) {
46
+ throw new Error('cannot start a channel: the moxxy CLI entry is unknown (process.argv[1] missing)');
47
+ }
48
+ const env = { ...process.env, MOXXY_DEDICATED_RUNNER: '1' };
49
+ for (const key of ADDRESSING_ENV)
50
+ delete env[key];
51
+ const child = spawn(node, [entry, name], { detached: true, stdio: 'ignore', env });
52
+ child.unref();
53
+ return child.pid;
54
+ }
55
+ /**
56
+ * Is `pid` a live process? `kill(pid, 0)` sends no signal — it only probes:
57
+ * - resolves ⇒ alive,
58
+ * - `ESRCH` ⇒ gone,
59
+ * - `EPERM` ⇒ alive but owned by another user (treat as alive — it exists).
60
+ */
61
+ export function isPidAlive(pid) {
62
+ if (!Number.isInteger(pid) || pid <= 0)
63
+ return false;
64
+ try {
65
+ process.kill(pid, 0);
66
+ return true;
67
+ }
68
+ catch (err) {
69
+ return err.code === 'EPERM';
70
+ }
71
+ }
72
+ /**
73
+ * The status of channel `name` IF it is actually running. Reads its status file
74
+ * and verifies the pid is alive; a file whose pid is dead (the runner crashed or
75
+ * was SIGKILL'd without clearing it) is treated as not-running AND removed, so a
76
+ * stale file never masquerades as a live channel.
77
+ */
78
+ export function liveChannelStatus(name) {
79
+ const status = readChannelStatus(name);
80
+ if (!status)
81
+ return null;
82
+ if (!isPidAlive(status.pid)) {
83
+ clearChannelStatus(name);
84
+ return null;
85
+ }
86
+ return status;
87
+ }
88
+ /** The channel name encoded in a `channel-<name>.status.json` file, or null. */
89
+ function statusFileChannelName(file) {
90
+ const m = /^channel-(.+)\.status\.json$/.exec(file);
91
+ return m ? (m[1] ?? null) : null;
92
+ }
93
+ /**
94
+ * Every currently-running dedicated channel, discovered by scanning the moxxy
95
+ * home for status files and filtering to live pids (self-healing stale ones).
96
+ * Returns [] when the home dir doesn't exist yet.
97
+ */
98
+ export function listLiveChannelStatuses() {
99
+ let files;
100
+ try {
101
+ files = readdirSync(moxxyHome());
102
+ }
103
+ catch {
104
+ return []; // no ~/.moxxy yet ⇒ nothing running
105
+ }
106
+ const live = [];
107
+ for (const file of files) {
108
+ const name = statusFileChannelName(file);
109
+ if (!name)
110
+ continue;
111
+ const status = liveChannelStatus(name);
112
+ if (status)
113
+ live.push(status);
114
+ }
115
+ return live;
116
+ }
117
+ /**
118
+ * Ask channel `name` to stop by SIGTERM-ing its runner. The runner's own signal
119
+ * handler tears down gracefully and clears its status file. Returns `'stopped'`
120
+ * if a live runner was signaled, `'not-running'` if there was nothing to stop.
121
+ *
122
+ * This is a single, synchronous SIGTERM — callers that want a hard backstop poll
123
+ * {@link liveChannelStatus} afterwards and escalate (SIGKILL + {@link clearChannelStatus})
124
+ * if it ignores the term within a grace period.
125
+ */
126
+ export function stopDedicatedChannel(name) {
127
+ const status = liveChannelStatus(name);
128
+ if (!status)
129
+ return 'not-running';
130
+ try {
131
+ process.kill(status.pid, 'SIGTERM');
132
+ }
133
+ catch {
134
+ // Raced us to exit between the liveness check and here — already stopped.
135
+ clearChannelStatus(name);
136
+ }
137
+ return 'stopped';
138
+ }
139
+ //# sourceMappingURL=channel-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-control.js","sourceRoot":"","sources":["../src/channel-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The on-disk status a dedicated channel runner publishes so an out-of-process
3
+ * supervisor (the desktop "Channels" panel) can observe it without the runner
4
+ * protocol. Written by `moxxy <channel>` when it self-hosts a dedicated runner,
5
+ * read by the desktop host; removed on graceful shutdown.
6
+ *
7
+ * It is intentionally tiny — readiness + the public ingest URL — not a mirror of
8
+ * the session. The supervisor owns liveness (it holds the child handle); this
9
+ * file is the channel's own report of "I'm up, and here's the URL to paste".
10
+ */
11
+ export interface ChannelRunStatus {
12
+ /** Channel name (e.g. `slack`, `telegram`). */
13
+ readonly name: string;
14
+ /** PID of the channel runner process. */
15
+ readonly pid: number;
16
+ /** ISO timestamp the channel reported ready. */
17
+ readonly startedAt: string;
18
+ /** The session source the runner stamped (e.g. `slack`). */
19
+ readonly source?: string;
20
+ /** Public ingest URL (e.g. Slack's Events Request URL) once the tunnel is up;
21
+ * null for channels with no inbound endpoint (Telegram long-polls). */
22
+ readonly requestUrl?: string | null;
23
+ }
24
+ /** `~/.moxxy/channel-<name>.status.json` (honors `$MOXXY_HOME`). */
25
+ export declare function channelStatusPath(name: string): string;
26
+ /** Atomically publish a channel's run status (0600 — it may carry a URL). */
27
+ export declare function writeChannelStatus(status: ChannelRunStatus): void;
28
+ /** Read a channel's published status, or null if absent/unparseable. */
29
+ export declare function readChannelStatus(name: string): ChannelRunStatus | null;
30
+ /** Remove a channel's status file (best-effort; called on graceful shutdown). */
31
+ export declare function clearChannelStatus(name: string): void;
32
+ //# sourceMappingURL=channel-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-status.d.ts","sourceRoot":"","sources":["../src/channel-status.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;4EACwE;IACxE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAEjE;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAMvE;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMrD"}
@@ -0,0 +1,29 @@
1
+ import { readFileSync, rmSync } from 'node:fs';
2
+ import { moxxyPath, writeFileAtomicSync } from './fs-utils.js';
3
+ /** `~/.moxxy/channel-<name>.status.json` (honors `$MOXXY_HOME`). */
4
+ export function channelStatusPath(name) {
5
+ return moxxyPath(`channel-${name}.status.json`);
6
+ }
7
+ /** Atomically publish a channel's run status (0600 — it may carry a URL). */
8
+ export function writeChannelStatus(status) {
9
+ writeFileAtomicSync(channelStatusPath(status.name), JSON.stringify(status), { mode: 0o600 });
10
+ }
11
+ /** Read a channel's published status, or null if absent/unparseable. */
12
+ export function readChannelStatus(name) {
13
+ try {
14
+ return JSON.parse(readFileSync(channelStatusPath(name), 'utf8'));
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ /** Remove a channel's status file (best-effort; called on graceful shutdown). */
21
+ export function clearChannelStatus(name) {
22
+ try {
23
+ rmSync(channelStatusPath(name), { force: true });
24
+ }
25
+ catch {
26
+ /* best-effort */
27
+ }
28
+ }
29
+ //# sourceMappingURL=channel-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-status.js","sourceRoot":"","sources":["../src/channel-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AA0B/D,oEAAoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,SAAS,CAAC,WAAW,IAAI,cAAc,CAAC,CAAC;AAClD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,mBAAmB,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAqB,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC;QACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;AACH,CAAC"}
package/dist/channel.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { PermissionResolver } from './permission.js';
2
2
  import type { ClientSession } from './client-session.js';
3
+ import type { SessionSource } from './event-store.js';
3
4
  /**
4
5
  * A Channel is a bidirectional surface that drives a Session: it feeds user
5
6
  * prompts in, renders assistant chunks + tool activity out, and implements a
@@ -22,6 +23,16 @@ export interface Channel<TStartOpts = unknown> {
22
23
  * resolves when the channel exits gracefully.
23
24
  */
24
25
  start(opts: TStartOpts): Promise<ChannelHandle>;
26
+ /**
27
+ * The channel's runtime "connect value" — published once running and surfaced
28
+ * by control surfaces per the channel's declared {@link ChannelConnectStep}.
29
+ * Its meaning depends on `connect.kind`: for Slack it is the Events Request URL
30
+ * the user pastes into the app (after its proxy tunnel opens); for Telegram it
31
+ * is the `https://t.me/<botname>` link of the resolved bot. Null when the
32
+ * channel has no connect value yet (still resolving) or none at all. Read by
33
+ * the dedicated-runner host and written to the channel's status file.
34
+ */
35
+ readonly requestUrl?: string | null;
25
36
  }
26
37
  export interface ChannelHandle {
27
38
  /**
@@ -121,6 +132,94 @@ export interface ChannelDef<TStartOpts = unknown> {
121
132
  * starts the channel.
122
133
  */
123
134
  readonly interactiveCommand?: string;
135
+ /**
136
+ * Declare that this channel runs on its OWN dedicated, isolated runner: a
137
+ * distinct runner socket (`channel-<name>.sock`) + a stable sticky session id
138
+ * (`moxxy-channel-<name>`), so the channel acts as its own agent thread,
139
+ * separate from whatever runner serves the desktop/TUI. NO runner-protocol
140
+ * change — one dedicated runner is still one Session. Channels that should
141
+ * operate autonomously (slack, telegram) set this; the CLI reads it generically
142
+ * (see `applyDedicatedRunnerEnv`) so no per-channel name list is needed. Any
143
+ * channel can also opt in at runtime via `--dedicated` / `MOXXY_DEDICATED_RUNNER=1`.
144
+ */
145
+ readonly dedicatedRunner?: boolean;
146
+ /**
147
+ * The {@link SessionSource} to stamp on this channel's sessions when it runs
148
+ * dedicated (persisted into the meta sidecar; surfaces filter history by it).
149
+ * Only honored alongside `dedicatedRunner`. When unset, the source falls back
150
+ * to the usual env/default resolution.
151
+ */
152
+ readonly sessionSource?: SessionSource;
153
+ /**
154
+ * Declarative config the channel needs to run (its secret fields + where they
155
+ * live in the vault, plus pairing hints). This is what a control surface — the
156
+ * TUI `/channels` panel, `moxxy channels start`, the desktop "Channels" panel —
157
+ * renders to let the user configure + start the channel WITHOUT hardcoding a
158
+ * per-channel table. The channel self-describes here; the vault keys named are
159
+ * the same ones the channel actually reads at boot (its `keys.ts`). Channels
160
+ * with no setup (web/http) omit this.
161
+ */
162
+ readonly config?: ChannelConfigDescriptor;
163
+ }
164
+ /** One secret/config input a channel exposes for a control surface to collect. */
165
+ export interface ChannelConfigField {
166
+ /** Option key (e.g. `botToken`). Stable identifier within the channel. */
167
+ readonly name: string;
168
+ /** Short human label (e.g. `Bot token`). */
169
+ readonly label: string;
170
+ /** The vault key the channel reads this value from (e.g. `slack_bot_token`). */
171
+ readonly vaultKey: string;
172
+ /** Must be present for the channel to count as "configured". */
173
+ readonly required?: boolean;
174
+ /** Treat as a secret — mask the input and never echo the stored value. */
175
+ readonly secret?: boolean;
176
+ /** Placeholder shown in an empty input (e.g. `xoxb-…`). */
177
+ readonly placeholder?: string;
178
+ /** One-line guidance on where to obtain the value. */
179
+ readonly help?: string;
180
+ }
181
+ /** What a channel declares about being configured + run from a control surface. */
182
+ export interface ChannelConfigDescriptor {
183
+ /** The fields to collect, in display order. */
184
+ readonly fields: ReadonlyArray<ChannelConfigField>;
185
+ /** The channel exposes a public ingest URL (Slack's Request URL) once started,
186
+ * so a control surface should poll for + surface it. */
187
+ readonly hasRequestUrl?: boolean;
188
+ /** Post-start pairing/setup instructions to show the user. */
189
+ readonly runHint?: string;
190
+ /** How a control surface should present the "now connect the other side" step
191
+ * once the channel is running — declaratively, so each channel renders the
192
+ * same way without per-channel UI code. See {@link ChannelConnectStep}. */
193
+ readonly connect?: ChannelConnectStep;
194
+ }
195
+ /**
196
+ * Declares how a control surface (TUI `/channels`, the desktop Channels panel)
197
+ * presents a channel's post-start "connect" step. The runtime VALUE this step
198
+ * renders is the channel's {@link Channel.requestUrl} (Slack's Request URL,
199
+ * Telegram's `t.me/<bot>` link); this descriptor only says how to render it, so
200
+ * a new channel plugs in by declaring a `kind` rather than shipping bespoke UI.
201
+ */
202
+ export interface ChannelConnectStep {
203
+ /**
204
+ * Presentation of the channel's runtime connect value:
205
+ * - `qr`: render a QR of the value plus the value itself (e.g. scan/open a
206
+ * `t.me/<bot>` link, or a mobile pairing URL).
207
+ * - `url`: show the value as a copyable URL the user pastes elsewhere
208
+ * (Slack's Events Request URL).
209
+ * - `instructions`: static `steps`, no runtime value.
210
+ */
211
+ readonly kind: 'qr' | 'url' | 'instructions';
212
+ /** Heading for the step, e.g. "Connect your Telegram". */
213
+ readonly title?: string;
214
+ /** One-line helper under the value, e.g. "Scan, or open the link and send /start". */
215
+ readonly hint?: string;
216
+ /** When true and the value is an https URL the user should OPEN (not paste),
217
+ * a control surface may show an "open externally" affordance. */
218
+ readonly openable?: boolean;
219
+ /** Label for the open affordance, e.g. "Open in Telegram". */
220
+ readonly openLabel?: string;
221
+ /** For `kind: 'instructions'` — static steps shown verbatim (no runtime value). */
222
+ readonly steps?: ReadonlyArray<string>;
124
223
  }
125
224
  export interface ChannelAvailability {
126
225
  readonly ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAgDA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB,EAAE,IAAsB;IACvE,oEAAoE;IACpE,8EAA8E;IAC9E,oEAAoE;IACpE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAa,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AA4DA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB,EAAE,IAAsB;IACvE,oEAAoE;IACpE,8EAA8E;IAC9E,oEAAoE;IACpE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAa,CAAC,CAAC;AACtC,CAAC"}
@@ -11,7 +11,7 @@ import type { SessionId } from './ids.js';
11
11
  * event (prompts, tool I/O), so that explicit opt-in is the trust boundary.
12
12
  */
13
13
  /** Originating channel of a session (persisted into the meta sidecar). */
14
- export type SessionSource = 'cli' | 'tui' | 'desktop' | 'mobile';
14
+ export type SessionSource = 'cli' | 'tui' | 'desktop' | 'mobile' | 'slack' | 'telegram';
15
15
  /**
16
16
  * The single per-session metadata record (the JSONL impl writes it to
17
17
  * `~/.moxxy/sessions/<id>.json`). ONE per session — the unit every surface
@@ -1 +1 @@
1
- {"version":3,"file":"event-store.d.ts","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-store.d.ts","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ export type { TunnelProviderDef, TunnelHandle, TunnelOpenOptions } from './tunne
21
21
  export type { EventStoreDef, EventStoreSession, EventStoreScope, EventLogLike, EventPage, SessionMeta, SessionSource, } from './event-store.js';
22
22
  export { isRetryableError, toFriendlyError, zodToJsonSchema, estimateTextTokens, type StopReason } from './provider-utils.js';
23
23
  export type { WriteFileAtomicOptions } from './fs-utils.js';
24
+ export type { ChannelRunStatus } from './channel-status.js';
24
25
  export type { CrossProcessFireLock, CrossProcessFireLockOptions } from './cross-process-lock.js';
25
26
  export { createMutex, type Mutex } from './mutex.js';
26
27
  export { createJsonFileStore, type JsonFileStore, type JsonFileStoreOptions, } from './json-file-store.js';
@@ -46,7 +47,7 @@ export type { AppContext, TurnContext, ToolCallContext, ToolResultContext, ToolC
46
47
  export type { ServiceRegistry, NamedRegistry } from './services.js';
47
48
  export type { PluginKind, PluginSpec, Plugin, PluginManifest, ResolvedPluginManifest, } from './plugin.js';
48
49
  export { startChannelWith } from './channel.js';
49
- export type { Channel, ChannelHandle, ChannelStartArgs, ChannelStartOptsBase, ChannelFactoryDeps, ChannelDef, ChannelAvailability, ChannelRegistry, ChannelSubcommand, ChannelSubcommandContext, ChannelCommandArgs, } from './channel.js';
50
+ export type { Channel, ChannelHandle, ChannelStartArgs, ChannelStartOptsBase, ChannelFactoryDeps, ChannelDef, ChannelConfigField, ChannelConfigDescriptor, ChannelConnectStep, ChannelAvailability, ChannelRegistry, ChannelSubcommand, ChannelSubcommandContext, ChannelCommandArgs, } from './channel.js';
50
51
  export type { EmbeddingProvider, EmbedderDef } from './embedding.js';
51
52
  export { CachedEmbeddingProvider } from './embedding-cache.js';
52
53
  export { defineSurface } from './surface.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,MAAM,EACN,UAAU,EACV,SAAS,EACT,QAAQ,EACR,OAAO,GACR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEjG,YAAY,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EACV,WAAW,EACX,OAAO,EACP,uBAAuB,EACvB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,YAAY,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAGvB,YAAY,EACV,YAAY,EACZ,eAAe,EACf,eAAe,EACf,aAAa,EACb,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtF,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAClF,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,eAAe,EACf,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,QAAQ,EACR,UAAU,EACV,OAAO,EACP,cAAc,EACd,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACpH,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACtF,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC9H,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACL,mBAAmB,EACnB,KAAK,aAAa,EAClB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,GACvC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,2BAA2B,EAC3B,uBAAuB,EACvB,UAAU,EACV,cAAc,EACd,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,0BAA0B,EAC1B,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,EACf,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAChC,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/F,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,YAAY,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,SAAS,EACT,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,GACf,MAAM,WAAW,CAAC;AAEnB,YAAY,EACV,UAAU,EACV,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEpE,YAAY,EACV,UAAU,EACV,UAAU,EACV,MAAM,EACN,cAAc,EACd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,YAAY,EACV,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,UAAU,EACV,kBAAkB,EAClB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,GACZ,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,YAAY,EACV,WAAW,EACX,cAAc,EACd,wBAAwB,EACxB,eAAe,EACf,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,QAAQ,EAAE,OAAO,aAAa,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,aAAa,EAAE,MAAM,CAAC,CAAC;CACrG;AAED,OAAO,EACL,YAAY,EACZ,UAAU,EACV,cAAc,EACd,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,WAAW,EACX,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE9D,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -17,5 +17,7 @@
17
17
  export { writeFileAtomic, writeFileAtomicSync, moxxyHome, moxxyPath, } from './fs-utils.js';
18
18
  export { CrossProcessFireLock } from './cross-process-lock.js';
19
19
  export { readRequestBody, bearerTokenMatches } from './http-utils.js';
20
+ export { channelStatusPath, writeChannelStatus, readChannelStatus, clearChannelStatus, } from './channel-status.js';
21
+ export { spawnDedicatedChannel, isPidAlive, liveChannelStatus, listLiveChannelStatuses, stopDedicatedChannel, } from './channel-control.js';
20
22
  export { resolveChannelToken, rotateChannelToken, bearerGuard, encodeWsBearerProtocol, tokenFromWsProtocolHeader, MOXXY_WS_SUBPROTOCOL, MOXXY_WS_BEARER_PROTOCOL_PREFIX, } from './channel-auth.js';
21
23
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAItE,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC"}
package/dist/server.js CHANGED
@@ -19,5 +19,13 @@ export { writeFileAtomic, writeFileAtomicSync, moxxyHome, moxxyPath, } from './f
19
19
  // options type is re-exported from the main barrel like other erased types.
20
20
  export { CrossProcessFireLock } from './cross-process-lock.js';
21
21
  export { readRequestBody, bearerTokenMatches } from './http-utils.js';
22
+ // Dedicated-channel run-status file: a channel publishes readiness + its public
23
+ // ingest URL so the desktop "Channels" supervisor can observe it out-of-process
24
+ // (node:fs). The `ChannelRunStatus` *type* rides the main barrel like the others.
25
+ export { channelStatusPath, writeChannelStatus, readChannelStatus, clearChannelStatus, } from './channel-status.js';
26
+ // Process-independent control of dedicated channel runners (start detached,
27
+ // discover via status files, stop) — shared by the TUI `/channels` panel and the
28
+ // `moxxy channels start|stop|status` subcommands (node:child_process + node:fs).
29
+ export { spawnDedicatedChannel, isPidAlive, liveChannelStatus, listLiveChannelStatuses, stopDedicatedChannel, } from './channel-control.js';
22
30
  export { resolveChannelToken, rotateChannelToken, bearerGuard, encodeWsBearerProtocol, tokenFromWsProtocolHeader, MOXXY_WS_SUBPROTOCOL, MOXXY_WS_BEARER_PROTOCOL_PREFIX, } from './channel-auth.js';
23
31
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,0EAA0E;AAC1E,4EAA4E;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,eAAe,CAAC;AACvB,0EAA0E;AAC1E,4EAA4E;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,4EAA4E;AAC5E,iFAAiF;AACjF,iFAAiF;AACjF,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxxy/sdk",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "Typed public surface for the moxxy framework: event types, define* factories, lifecycle hook signatures.",
5
5
  "keywords": [
6
6
  "moxxy",
@@ -0,0 +1,141 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ // `spawnDedicatedChannel` re-invokes the CLI via node:child_process — mock it so
7
+ // the test asserts the spawn shape without launching a real process. `vi.hoisted`
8
+ // makes the mock fn available to the hoisted `vi.mock` factory.
9
+ const { spawnMock } = vi.hoisted(() => ({
10
+ spawnMock: vi.fn(() => ({ pid: 4321, unref: (): void => {} })),
11
+ }));
12
+ vi.mock('node:child_process', () => ({ spawn: spawnMock }));
13
+
14
+ import {
15
+ isPidAlive,
16
+ listLiveChannelStatuses,
17
+ liveChannelStatus,
18
+ spawnDedicatedChannel,
19
+ stopDedicatedChannel,
20
+ } from './channel-control.js';
21
+ import { channelStatusPath, writeChannelStatus } from './channel-status.js';
22
+
23
+ // A pid that is essentially never alive (above the platform max) → ESRCH.
24
+ const DEAD_PID = 2_000_000_000;
25
+
26
+ let home: string;
27
+ let prevHome: string | undefined;
28
+
29
+ beforeEach(() => {
30
+ home = fs.mkdtempSync(path.join(os.tmpdir(), 'moxxy-channel-control-'));
31
+ prevHome = process.env.MOXXY_HOME;
32
+ process.env.MOXXY_HOME = home;
33
+ spawnMock.mockClear();
34
+ });
35
+
36
+ afterEach(() => {
37
+ if (prevHome === undefined) delete process.env.MOXXY_HOME;
38
+ else process.env.MOXXY_HOME = prevHome;
39
+ fs.rmSync(home, { recursive: true, force: true });
40
+ vi.restoreAllMocks();
41
+ });
42
+
43
+ describe('isPidAlive', () => {
44
+ it('is true for the current process, false for a dead/invalid pid', () => {
45
+ expect(isPidAlive(process.pid)).toBe(true);
46
+ expect(isPidAlive(DEAD_PID)).toBe(false);
47
+ expect(isPidAlive(0)).toBe(false);
48
+ expect(isPidAlive(-1)).toBe(false);
49
+ });
50
+ });
51
+
52
+ describe('liveChannelStatus', () => {
53
+ it('returns null when no status file exists', () => {
54
+ expect(liveChannelStatus('slack')).toBeNull();
55
+ });
56
+
57
+ it('returns the status when the runner pid is alive', () => {
58
+ writeChannelStatus({
59
+ name: 'slack',
60
+ pid: process.pid,
61
+ startedAt: new Date().toISOString(),
62
+ requestUrl: 'https://example.test/slack',
63
+ });
64
+ const s = liveChannelStatus('slack');
65
+ expect(s?.pid).toBe(process.pid);
66
+ expect(s?.requestUrl).toBe('https://example.test/slack');
67
+ });
68
+
69
+ it('self-heals a stale file (dead pid) — returns null AND removes it', () => {
70
+ writeChannelStatus({ name: 'ghost', pid: DEAD_PID, startedAt: new Date().toISOString() });
71
+ expect(fs.existsSync(channelStatusPath('ghost'))).toBe(true);
72
+ expect(liveChannelStatus('ghost')).toBeNull();
73
+ expect(fs.existsSync(channelStatusPath('ghost'))).toBe(false);
74
+ });
75
+ });
76
+
77
+ describe('listLiveChannelStatuses', () => {
78
+ it('returns only live channels, drops stale files, ignores unrelated files', () => {
79
+ writeChannelStatus({ name: 'slack', pid: process.pid, startedAt: new Date().toISOString() });
80
+ writeChannelStatus({ name: 'telegram', pid: process.pid, startedAt: new Date().toISOString() });
81
+ writeChannelStatus({ name: 'ghost', pid: DEAD_PID, startedAt: new Date().toISOString() });
82
+ fs.writeFileSync(path.join(home, 'vault.json'), '{}'); // unrelated file in ~/.moxxy
83
+
84
+ const names = listLiveChannelStatuses()
85
+ .map((s) => s.name)
86
+ .sort();
87
+ expect(names).toEqual(['slack', 'telegram']);
88
+ expect(fs.existsSync(channelStatusPath('ghost'))).toBe(false);
89
+ });
90
+
91
+ it('returns [] when the home dir does not exist', () => {
92
+ process.env.MOXXY_HOME = path.join(home, 'does-not-exist');
93
+ expect(listLiveChannelStatuses()).toEqual([]);
94
+ });
95
+ });
96
+
97
+ describe('stopDedicatedChannel', () => {
98
+ it('reports not-running when there is no live status', () => {
99
+ expect(stopDedicatedChannel('slack')).toBe('not-running');
100
+ });
101
+
102
+ it('SIGTERMs the live runner and reports stopped', () => {
103
+ // Intercept kill so the liveness probe (signal 0) reports alive and the
104
+ // SIGTERM is recorded rather than actually delivered.
105
+ const killSpy = vi
106
+ .spyOn(process, 'kill')
107
+ .mockImplementation(((_pid: number, _sig?: string | number) => true) as typeof process.kill);
108
+ writeChannelStatus({ name: 'slack', pid: 999_999, startedAt: new Date().toISOString() });
109
+
110
+ expect(stopDedicatedChannel('slack')).toBe('stopped');
111
+ expect(killSpy).toHaveBeenCalledWith(999_999, 'SIGTERM');
112
+ });
113
+ });
114
+
115
+ describe('spawnDedicatedChannel', () => {
116
+ it('spawns a detached, dedicated runner with a scrubbed env', () => {
117
+ process.env.MOXXY_RUNNER_SOCKET = '/tmp/should-be-scrubbed.sock';
118
+ process.env.MOXXY_SESSION_ID = 'should-be-scrubbed';
119
+ try {
120
+ const pid = spawnDedicatedChannel('slack');
121
+ expect(pid).toBe(4321);
122
+ expect(spawnMock).toHaveBeenCalledTimes(1);
123
+ const [bin, argsArg, optsArg] = spawnMock.mock.calls[0] as [
124
+ string,
125
+ string[],
126
+ { detached?: boolean; stdio?: string; env?: NodeJS.ProcessEnv },
127
+ ];
128
+ expect(bin).toBe(process.execPath);
129
+ expect(argsArg).toEqual([process.argv[1], 'slack']);
130
+ expect(optsArg.detached).toBe(true);
131
+ expect(optsArg.stdio).toBe('ignore');
132
+ // Dedicated flag set; addressing vars scrubbed so the channel isolates.
133
+ expect(optsArg.env?.MOXXY_DEDICATED_RUNNER).toBe('1');
134
+ expect(optsArg.env?.MOXXY_RUNNER_SOCKET).toBeUndefined();
135
+ expect(optsArg.env?.MOXXY_SESSION_ID).toBeUndefined();
136
+ } finally {
137
+ delete process.env.MOXXY_RUNNER_SOCKET;
138
+ delete process.env.MOXXY_SESSION_ID;
139
+ }
140
+ });
141
+ });
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Process-independent control surface for dedicated channel runners.
3
+ *
4
+ * A dedicated channel (Slack, Telegram, …) runs as its OWN isolated runner
5
+ * subprocess that publishes a tiny status file (`channel-<name>.status.json`,
6
+ * see {@link ./channel-status}) on ready and clears it on graceful shutdown. That
7
+ * file — NOT a held child handle — is the source of truth for "is it running",
8
+ * so a channel started from anywhere (the TUI `/channels` panel, `moxxy channels
9
+ * start`, the desktop panel) is visible and stoppable from everywhere, and keeps
10
+ * running after the launcher exits.
11
+ *
12
+ * These helpers are the shared spine for those surfaces:
13
+ * - {@link spawnDedicatedChannel} — start one, detached, on its own runner.
14
+ * - {@link liveChannelStatus}/{@link listLiveChannelStatuses} — discover the
15
+ * running ones (with stale-file self-healing).
16
+ * - {@link stopDedicatedChannel} — signal one to stop.
17
+ *
18
+ * Node-only (`node:child_process`, `node:fs`) — exported from `@moxxy/sdk/server`.
19
+ */
20
+
21
+ import { spawn } from 'node:child_process';
22
+ import { readdirSync } from 'node:fs';
23
+
24
+ import {
25
+ type ChannelRunStatus,
26
+ clearChannelStatus,
27
+ readChannelStatus,
28
+ } from './channel-status.js';
29
+ import { moxxyHome } from './fs-utils.js';
30
+
31
+ /** Env vars that ADDRESS a runner (socket + sticky session). We scrub these from
32
+ * a spawned channel's env so `applyDedicatedRunnerEnv` (which only fills UNSET
33
+ * vars) derives the channel's OWN isolated socket/session from its name — rather
34
+ * than the channel silently inheriting and sharing the launcher's runner. */
35
+ const ADDRESSING_ENV = ['MOXXY_RUNNER_SOCKET', 'MOXXY_SESSION_ID', 'MOXXY_SESSION_SOURCE'] as const;
36
+
37
+ /**
38
+ * Start a channel on its own dedicated, detached runner by re-invoking this very
39
+ * moxxy binary as `moxxy <name>` with `MOXXY_DEDICATED_RUNNER=1`. The child is
40
+ * `detached` + `unref`'d with no stdio, so it OUTLIVES the launcher (the user can
41
+ * quit the TUI and the bot keeps serving) and reports itself via its status file.
42
+ *
43
+ * Returns the child pid, or undefined if the spawn produced none. Throws if the
44
+ * moxxy CLI entry can't be resolved (no `process.argv[1]`).
45
+ *
46
+ * Caller's job (this is fire-and-forget): poll {@link liveChannelStatus} to learn
47
+ * when it's ready / failed (no status file within a timeout ⇒ it died on boot —
48
+ * re-run `moxxy <name>` in the foreground to see why).
49
+ */
50
+ export function spawnDedicatedChannel(name: string): number | undefined {
51
+ const node = process.execPath; // the running Node binary (pnpm `moxxy` launches via Node)
52
+ const entry = process.argv[1]; // the resolved CLI entry (…/cli/dist/bin.js)
53
+ if (!entry) {
54
+ throw new Error('cannot start a channel: the moxxy CLI entry is unknown (process.argv[1] missing)');
55
+ }
56
+
57
+ const env: NodeJS.ProcessEnv = { ...process.env, MOXXY_DEDICATED_RUNNER: '1' };
58
+ for (const key of ADDRESSING_ENV) delete env[key];
59
+
60
+ const child = spawn(node, [entry, name], { detached: true, stdio: 'ignore', env });
61
+ child.unref();
62
+ return child.pid;
63
+ }
64
+
65
+ /**
66
+ * Is `pid` a live process? `kill(pid, 0)` sends no signal — it only probes:
67
+ * - resolves ⇒ alive,
68
+ * - `ESRCH` ⇒ gone,
69
+ * - `EPERM` ⇒ alive but owned by another user (treat as alive — it exists).
70
+ */
71
+ export function isPidAlive(pid: number): boolean {
72
+ if (!Number.isInteger(pid) || pid <= 0) return false;
73
+ try {
74
+ process.kill(pid, 0);
75
+ return true;
76
+ } catch (err) {
77
+ return (err as NodeJS.ErrnoException).code === 'EPERM';
78
+ }
79
+ }
80
+
81
+ /**
82
+ * The status of channel `name` IF it is actually running. Reads its status file
83
+ * and verifies the pid is alive; a file whose pid is dead (the runner crashed or
84
+ * was SIGKILL'd without clearing it) is treated as not-running AND removed, so a
85
+ * stale file never masquerades as a live channel.
86
+ */
87
+ export function liveChannelStatus(name: string): ChannelRunStatus | null {
88
+ const status = readChannelStatus(name);
89
+ if (!status) return null;
90
+ if (!isPidAlive(status.pid)) {
91
+ clearChannelStatus(name);
92
+ return null;
93
+ }
94
+ return status;
95
+ }
96
+
97
+ /** The channel name encoded in a `channel-<name>.status.json` file, or null. */
98
+ function statusFileChannelName(file: string): string | null {
99
+ const m = /^channel-(.+)\.status\.json$/.exec(file);
100
+ return m ? (m[1] ?? null) : null;
101
+ }
102
+
103
+ /**
104
+ * Every currently-running dedicated channel, discovered by scanning the moxxy
105
+ * home for status files and filtering to live pids (self-healing stale ones).
106
+ * Returns [] when the home dir doesn't exist yet.
107
+ */
108
+ export function listLiveChannelStatuses(): ChannelRunStatus[] {
109
+ let files: string[];
110
+ try {
111
+ files = readdirSync(moxxyHome());
112
+ } catch {
113
+ return []; // no ~/.moxxy yet ⇒ nothing running
114
+ }
115
+ const live: ChannelRunStatus[] = [];
116
+ for (const file of files) {
117
+ const name = statusFileChannelName(file);
118
+ if (!name) continue;
119
+ const status = liveChannelStatus(name);
120
+ if (status) live.push(status);
121
+ }
122
+ return live;
123
+ }
124
+
125
+ /**
126
+ * Ask channel `name` to stop by SIGTERM-ing its runner. The runner's own signal
127
+ * handler tears down gracefully and clears its status file. Returns `'stopped'`
128
+ * if a live runner was signaled, `'not-running'` if there was nothing to stop.
129
+ *
130
+ * This is a single, synchronous SIGTERM — callers that want a hard backstop poll
131
+ * {@link liveChannelStatus} afterwards and escalate (SIGKILL + {@link clearChannelStatus})
132
+ * if it ignores the term within a grace period.
133
+ */
134
+ export function stopDedicatedChannel(name: string): 'stopped' | 'not-running' {
135
+ const status = liveChannelStatus(name);
136
+ if (!status) return 'not-running';
137
+ try {
138
+ process.kill(status.pid, 'SIGTERM');
139
+ } catch {
140
+ // Raced us to exit between the liveness check and here — already stopped.
141
+ clearChannelStatus(name);
142
+ }
143
+ return 'stopped';
144
+ }
@@ -0,0 +1,55 @@
1
+ import { readFileSync, rmSync } from 'node:fs';
2
+
3
+ import { moxxyPath, writeFileAtomicSync } from './fs-utils.js';
4
+
5
+ /**
6
+ * The on-disk status a dedicated channel runner publishes so an out-of-process
7
+ * supervisor (the desktop "Channels" panel) can observe it without the runner
8
+ * protocol. Written by `moxxy <channel>` when it self-hosts a dedicated runner,
9
+ * read by the desktop host; removed on graceful shutdown.
10
+ *
11
+ * It is intentionally tiny — readiness + the public ingest URL — not a mirror of
12
+ * the session. The supervisor owns liveness (it holds the child handle); this
13
+ * file is the channel's own report of "I'm up, and here's the URL to paste".
14
+ */
15
+ export interface ChannelRunStatus {
16
+ /** Channel name (e.g. `slack`, `telegram`). */
17
+ readonly name: string;
18
+ /** PID of the channel runner process. */
19
+ readonly pid: number;
20
+ /** ISO timestamp the channel reported ready. */
21
+ readonly startedAt: string;
22
+ /** The session source the runner stamped (e.g. `slack`). */
23
+ readonly source?: string;
24
+ /** Public ingest URL (e.g. Slack's Events Request URL) once the tunnel is up;
25
+ * null for channels with no inbound endpoint (Telegram long-polls). */
26
+ readonly requestUrl?: string | null;
27
+ }
28
+
29
+ /** `~/.moxxy/channel-<name>.status.json` (honors `$MOXXY_HOME`). */
30
+ export function channelStatusPath(name: string): string {
31
+ return moxxyPath(`channel-${name}.status.json`);
32
+ }
33
+
34
+ /** Atomically publish a channel's run status (0600 — it may carry a URL). */
35
+ export function writeChannelStatus(status: ChannelRunStatus): void {
36
+ writeFileAtomicSync(channelStatusPath(status.name), JSON.stringify(status), { mode: 0o600 });
37
+ }
38
+
39
+ /** Read a channel's published status, or null if absent/unparseable. */
40
+ export function readChannelStatus(name: string): ChannelRunStatus | null {
41
+ try {
42
+ return JSON.parse(readFileSync(channelStatusPath(name), 'utf8')) as ChannelRunStatus;
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ /** Remove a channel's status file (best-effort; called on graceful shutdown). */
49
+ export function clearChannelStatus(name: string): void {
50
+ try {
51
+ rmSync(channelStatusPath(name), { force: true });
52
+ } catch {
53
+ /* best-effort */
54
+ }
55
+ }
package/src/channel.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { PermissionResolver } from './permission.js';
2
2
  import type { ClientSession } from './client-session.js';
3
+ import type { SessionSource } from './event-store.js';
3
4
 
4
5
  /**
5
6
  * A Channel is a bidirectional surface that drives a Session: it feeds user
@@ -25,6 +26,17 @@ export interface Channel<TStartOpts = unknown> {
25
26
  * resolves when the channel exits gracefully.
26
27
  */
27
28
  start(opts: TStartOpts): Promise<ChannelHandle>;
29
+
30
+ /**
31
+ * The channel's runtime "connect value" — published once running and surfaced
32
+ * by control surfaces per the channel's declared {@link ChannelConnectStep}.
33
+ * Its meaning depends on `connect.kind`: for Slack it is the Events Request URL
34
+ * the user pastes into the app (after its proxy tunnel opens); for Telegram it
35
+ * is the `https://t.me/<botname>` link of the resolved bot. Null when the
36
+ * channel has no connect value yet (still resolving) or none at all. Read by
37
+ * the dedicated-runner host and written to the channel's status file.
38
+ */
39
+ readonly requestUrl?: string | null;
28
40
  }
29
41
 
30
42
  export interface ChannelHandle {
@@ -134,6 +146,97 @@ export interface ChannelDef<TStartOpts = unknown> {
134
146
  * starts the channel.
135
147
  */
136
148
  readonly interactiveCommand?: string;
149
+ /**
150
+ * Declare that this channel runs on its OWN dedicated, isolated runner: a
151
+ * distinct runner socket (`channel-<name>.sock`) + a stable sticky session id
152
+ * (`moxxy-channel-<name>`), so the channel acts as its own agent thread,
153
+ * separate from whatever runner serves the desktop/TUI. NO runner-protocol
154
+ * change — one dedicated runner is still one Session. Channels that should
155
+ * operate autonomously (slack, telegram) set this; the CLI reads it generically
156
+ * (see `applyDedicatedRunnerEnv`) so no per-channel name list is needed. Any
157
+ * channel can also opt in at runtime via `--dedicated` / `MOXXY_DEDICATED_RUNNER=1`.
158
+ */
159
+ readonly dedicatedRunner?: boolean;
160
+ /**
161
+ * The {@link SessionSource} to stamp on this channel's sessions when it runs
162
+ * dedicated (persisted into the meta sidecar; surfaces filter history by it).
163
+ * Only honored alongside `dedicatedRunner`. When unset, the source falls back
164
+ * to the usual env/default resolution.
165
+ */
166
+ readonly sessionSource?: SessionSource;
167
+ /**
168
+ * Declarative config the channel needs to run (its secret fields + where they
169
+ * live in the vault, plus pairing hints). This is what a control surface — the
170
+ * TUI `/channels` panel, `moxxy channels start`, the desktop "Channels" panel —
171
+ * renders to let the user configure + start the channel WITHOUT hardcoding a
172
+ * per-channel table. The channel self-describes here; the vault keys named are
173
+ * the same ones the channel actually reads at boot (its `keys.ts`). Channels
174
+ * with no setup (web/http) omit this.
175
+ */
176
+ readonly config?: ChannelConfigDescriptor;
177
+ }
178
+
179
+ /** One secret/config input a channel exposes for a control surface to collect. */
180
+ export interface ChannelConfigField {
181
+ /** Option key (e.g. `botToken`). Stable identifier within the channel. */
182
+ readonly name: string;
183
+ /** Short human label (e.g. `Bot token`). */
184
+ readonly label: string;
185
+ /** The vault key the channel reads this value from (e.g. `slack_bot_token`). */
186
+ readonly vaultKey: string;
187
+ /** Must be present for the channel to count as "configured". */
188
+ readonly required?: boolean;
189
+ /** Treat as a secret — mask the input and never echo the stored value. */
190
+ readonly secret?: boolean;
191
+ /** Placeholder shown in an empty input (e.g. `xoxb-…`). */
192
+ readonly placeholder?: string;
193
+ /** One-line guidance on where to obtain the value. */
194
+ readonly help?: string;
195
+ }
196
+
197
+ /** What a channel declares about being configured + run from a control surface. */
198
+ export interface ChannelConfigDescriptor {
199
+ /** The fields to collect, in display order. */
200
+ readonly fields: ReadonlyArray<ChannelConfigField>;
201
+ /** The channel exposes a public ingest URL (Slack's Request URL) once started,
202
+ * so a control surface should poll for + surface it. */
203
+ readonly hasRequestUrl?: boolean;
204
+ /** Post-start pairing/setup instructions to show the user. */
205
+ readonly runHint?: string;
206
+ /** How a control surface should present the "now connect the other side" step
207
+ * once the channel is running — declaratively, so each channel renders the
208
+ * same way without per-channel UI code. See {@link ChannelConnectStep}. */
209
+ readonly connect?: ChannelConnectStep;
210
+ }
211
+
212
+ /**
213
+ * Declares how a control surface (TUI `/channels`, the desktop Channels panel)
214
+ * presents a channel's post-start "connect" step. The runtime VALUE this step
215
+ * renders is the channel's {@link Channel.requestUrl} (Slack's Request URL,
216
+ * Telegram's `t.me/<bot>` link); this descriptor only says how to render it, so
217
+ * a new channel plugs in by declaring a `kind` rather than shipping bespoke UI.
218
+ */
219
+ export interface ChannelConnectStep {
220
+ /**
221
+ * Presentation of the channel's runtime connect value:
222
+ * - `qr`: render a QR of the value plus the value itself (e.g. scan/open a
223
+ * `t.me/<bot>` link, or a mobile pairing URL).
224
+ * - `url`: show the value as a copyable URL the user pastes elsewhere
225
+ * (Slack's Events Request URL).
226
+ * - `instructions`: static `steps`, no runtime value.
227
+ */
228
+ readonly kind: 'qr' | 'url' | 'instructions';
229
+ /** Heading for the step, e.g. "Connect your Telegram". */
230
+ readonly title?: string;
231
+ /** One-line helper under the value, e.g. "Scan, or open the link and send /start". */
232
+ readonly hint?: string;
233
+ /** When true and the value is an https URL the user should OPEN (not paste),
234
+ * a control surface may show an "open externally" affordance. */
235
+ readonly openable?: boolean;
236
+ /** Label for the open affordance, e.g. "Open in Telegram". */
237
+ readonly openLabel?: string;
238
+ /** For `kind: 'instructions'` — static steps shown verbatim (no runtime value). */
239
+ readonly steps?: ReadonlyArray<string>;
137
240
  }
138
241
 
139
242
  export interface ChannelAvailability {
@@ -13,7 +13,7 @@ import type { SessionId } from './ids.js';
13
13
  */
14
14
 
15
15
  /** Originating channel of a session (persisted into the meta sidecar). */
16
- export type SessionSource = 'cli' | 'tui' | 'desktop' | 'mobile';
16
+ export type SessionSource = 'cli' | 'tui' | 'desktop' | 'mobile' | 'slack' | 'telegram';
17
17
 
18
18
  /**
19
19
  * The single per-session metadata record (the JSONL impl writes it to
package/src/index.ts CHANGED
@@ -194,6 +194,7 @@ export type {
194
194
  // builtins and would break a browser/RN bundle. See ./server.ts.
195
195
  export { isRetryableError, toFriendlyError, zodToJsonSchema, estimateTextTokens, type StopReason } from './provider-utils.js';
196
196
  export type { WriteFileAtomicOptions } from './fs-utils.js';
197
+ export type { ChannelRunStatus } from './channel-status.js';
197
198
  export type { CrossProcessFireLock, CrossProcessFireLockOptions } from './cross-process-lock.js';
198
199
  export { createMutex, type Mutex } from './mutex.js';
199
200
  export {
@@ -372,6 +373,9 @@ export type {
372
373
  ChannelStartOptsBase,
373
374
  ChannelFactoryDeps,
374
375
  ChannelDef,
376
+ ChannelConfigField,
377
+ ChannelConfigDescriptor,
378
+ ChannelConnectStep,
375
379
  ChannelAvailability,
376
380
  ChannelRegistry,
377
381
  ChannelSubcommand,
package/src/server.ts CHANGED
@@ -25,6 +25,25 @@ export {
25
25
  // options type is re-exported from the main barrel like other erased types.
26
26
  export { CrossProcessFireLock } from './cross-process-lock.js';
27
27
  export { readRequestBody, bearerTokenMatches } from './http-utils.js';
28
+ // Dedicated-channel run-status file: a channel publishes readiness + its public
29
+ // ingest URL so the desktop "Channels" supervisor can observe it out-of-process
30
+ // (node:fs). The `ChannelRunStatus` *type* rides the main barrel like the others.
31
+ export {
32
+ channelStatusPath,
33
+ writeChannelStatus,
34
+ readChannelStatus,
35
+ clearChannelStatus,
36
+ } from './channel-status.js';
37
+ // Process-independent control of dedicated channel runners (start detached,
38
+ // discover via status files, stop) — shared by the TUI `/channels` panel and the
39
+ // `moxxy channels start|stop|status` subcommands (node:child_process + node:fs).
40
+ export {
41
+ spawnDedicatedChannel,
42
+ isPidAlive,
43
+ liveChannelStatus,
44
+ listLiveChannelStatuses,
45
+ stopDedicatedChannel,
46
+ } from './channel-control.js';
28
47
  export {
29
48
  resolveChannelToken,
30
49
  rotateChannelToken,