@chatlychat/cli 0.1.7 → 0.2.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,57 @@
1
+ import { type ParsedArgs } from '../args.js';
2
+ import type { ChatlyClient } from '@chatlychat/sdk-node';
3
+ export interface ListenOptions {
4
+ /** Where to POST each event. `null` prints without forwarding. */
5
+ readonly forwardTo: string | null;
6
+ readonly endpointId: string | null;
7
+ /** Client-side event filter. `null` means every event in the log. */
8
+ readonly events: ReadonlySet<string> | null;
9
+ readonly status: string | null;
10
+ /** The `whsec_…` to re-sign forwarded requests with. `null` sends unsigned. */
11
+ readonly secret: string | null;
12
+ readonly intervalMs: number;
13
+ /** How many deliveries already in the log to forward before tailing. */
14
+ readonly replay: number;
15
+ /** Rows per poll. Also the most this can see between two polls. */
16
+ readonly pageLimit: number;
17
+ readonly json: boolean;
18
+ }
19
+ export interface ListenDeps {
20
+ /** For the FORWARD leg only. API calls go through the SDK's own transport. */
21
+ readonly fetchFn: typeof fetch;
22
+ readonly now: () => number;
23
+ readonly sleep: (ms: number, signal: AbortSignal) => Promise<void>;
24
+ readonly signal: AbortSignal;
25
+ readonly out: (line: string) => void;
26
+ readonly err: (line: string) => void;
27
+ /**
28
+ * Stop after this many polls. Test-only, and the reason it exists rather
29
+ * than a timer the test races: a tail loop with no bound is not a thing a
30
+ * unit test can assert the end of.
31
+ */
32
+ readonly maxPolls?: number;
33
+ }
34
+ export interface ListenSummary {
35
+ readonly seen: number;
36
+ readonly forwarded: number;
37
+ readonly refused: number;
38
+ readonly polls: number;
39
+ }
40
+ /** Read the flags, refusing anything that cannot work, with the fix named. */
41
+ export declare function parseListenOptions(args: ParsedArgs): ListenOptions;
42
+ /**
43
+ * The tail loop, abortable, with the process boundary left to the caller.
44
+ *
45
+ * Exported so the spec can drive it with a bounded `maxPolls` and a scripted
46
+ * fetch, rather than racing a timer against a signal handler.
47
+ */
48
+ export declare function tail(chatly: ChatlyClient, opts: ListenOptions, deps: ListenDeps): Promise<ListenSummary>;
49
+ /**
50
+ * The command entry point.
51
+ *
52
+ * SIGINT and SIGTERM abort the loop rather than killing the process, so the
53
+ * summary still prints and the exit code is 0 — a developer tool stopped on
54
+ * purpose did not fail.
55
+ */
56
+ export declare function listen(chatly: ChatlyClient, args: ParsedArgs): Promise<number>;
57
+ //# sourceMappingURL=listen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../../src/commands/listen.ts"],"names":[],"mappings":"AA6EA,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AA4BzD,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,OAAO,KAAK,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAyCD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,aAAa,CAsElE;AAyLD;;;;;GAKG;AACH,wBAAsB,IAAI,CACxB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,aAAa,CAAC,CA2HxB;AAqBD;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCpF"}
@@ -0,0 +1,490 @@
1
+ /**
2
+ * `chatly listen` — watch this workspace's webhook traffic and forward it to a
3
+ * local URL.
4
+ *
5
+ * ═══ HOW A LAPTOP RECEIVES EVENTS AT ALL ══════════════════════════════════
6
+ *
7
+ * Chatly delivers webhooks by POSTing to a URL, so a machine behind NAT cannot
8
+ * be a destination. Three ways out were considered and only one of them is
9
+ * real with a `ck_` workspace key:
10
+ *
11
+ * **(a) Poll the delivery log. This is what this command does.**
12
+ * `GET /v1/webhooks/deliveries` records one row per attempt — event type,
13
+ * payload, attempt number, HTTP status, latency, error, next retry — and is
14
+ * open to a `ck_` key (`@AllowApiKey()` on `WebhookDeliveriesController`,
15
+ * `integrations:read`), keyset-paginated newest-first on `created_at`, with
16
+ * `endpointId` and `status` filters. `GET /v1/webhooks/deliveries/{id}`
17
+ * returns the exact payload we POSTed. Both verified against their handlers,
18
+ * because a route list in this repo has been wrong in both directions.
19
+ *
20
+ * **(b) Subscribe over the realtime socket. Not possible.**
21
+ * `apps/realtime/src/gateway.ts` accepts exactly two credentials in its
22
+ * handshake: an agent RS256 access token or a visitor HS256 token. A
23
+ * workspace API key is neither, and there is no key-accessible route that
24
+ * mints either one. The realtime envelope vocabulary is also not the webhook
25
+ * catalogue — it is the dashboard's own event stream, with a different shape
26
+ * and a different subscription model.
27
+ *
28
+ * **(c) Register a temporary subscription and deregister on exit. Not
29
+ * possible either, and this is the finding worth writing down.**
30
+ * `POST /v1/webhooks` carries `@AllowApiKey()`. `DELETE /v1/webhooks/{id}`
31
+ * does **not** — it is the one route on that controller without it, so a key
32
+ * gets a 403. A CLI that registered an endpoint could therefore never remove
33
+ * it, and `listen` would leak a subscription into the customer's workspace on
34
+ * every run, with no key-accessible way to disable it either (there is no
35
+ * enable/disable route; the only PATCH moves the schema pin). So **this
36
+ * command registers nothing and has nothing to clean up** — stated in its own
37
+ * startup banner, because "what did that leave behind" is the first question
38
+ * a developer tool of this shape has to answer.
39
+ *
40
+ * ═══ WHAT THIS CANNOT DO, AND THE ROUTE THAT WOULD FIX IT ═════════════════
41
+ *
42
+ * It cannot relay Chatly's OWN signature, because the server does not keep
43
+ * it. `webhook_deliveries` stores `payload` as `jsonb` and that is all: the
44
+ * signature is computed per attempt from the endpoint's secret and never
45
+ * persisted, the secret is returned by exactly one route and never read back,
46
+ * `jsonb` does not preserve key order, and the signed envelope's `id` is the
47
+ * BullMQ-era `deliveryId` which is not the delivery row's `id`. So the exact
48
+ * signed bytes are unreconstructable by construction, not by omission.
49
+ *
50
+ * What this command forwards is therefore re-signed locally with `--secret`,
51
+ * using the same construction the worker uses (`t=<unix seconds>,v1=HMAC over
52
+ * <t>.<rawBody>`), and the header is **verified with the SDK's own
53
+ * `verifyChatlySignature` before the request goes out**. That self-check is
54
+ * not ceremony: it is the one thing that catches a signer and a verifier
55
+ * drifting on construction or on timestamp unit, which is a bug this product
56
+ * has actually shipped. If it ever fails, the forward is refused rather than
57
+ * sent.
58
+ *
59
+ * A true `stripe listen` — the developer's handler seeing byte-for-byte what
60
+ * production sends — needs a server-side surface, and there are two shapes:
61
+ *
62
+ * 1. `GET /v1/webhooks/tail` as Server-Sent Events: `@AllowApiKey()`,
63
+ * `integrations:read`, emitting `{ id, type, signedBody, signature }`
64
+ * from the same `signWebhookPayload` the dispatcher uses. Best for the
65
+ * use case; needs a streaming route and a fan-out off the webhook queue.
66
+ * 2. Cheaper: add `signed_body text` and `signature text` to
67
+ * `webhook_deliveries`, return them from
68
+ * `GET /v1/webhooks/deliveries/{id}`, and this poller relays them
69
+ * untouched. One migration, two columns, no new route shape.
70
+ *
71
+ * Both are in `apps/api`, `apps/worker` and `packages/db`, so neither is done
72
+ * here. Until one lands, this command is honest about what it mints.
73
+ */
74
+ import { createHmac } from 'node:crypto';
75
+ import { verifyChatlySignature } from '@chatlychat/sdk-node';
76
+ import { bool, num, str } from '../args.js';
77
+ import { printJson } from '../output.js';
78
+ /** Deliveries remembered before the oldest id is dropped. */
79
+ const SEEN_CAP = 5_000;
80
+ const DEFAULT_INTERVAL_SECONDS = 2;
81
+ const MIN_INTERVAL_SECONDS = 1;
82
+ const DEFAULT_PAGE_LIMIT = 50;
83
+ /**
84
+ * Sign a forwarded body the way the worker signs a real delivery.
85
+ *
86
+ * Deliberately not imported from `@livechat/shared/webhook-signature`: this
87
+ * package is published and depends on `@chatlychat/sdk-node` alone, and
88
+ * `sync-sdk-repos.mjs` cannot mirror a private workspace import. `node:crypto`
89
+ * is the standard library, not a dependency.
90
+ *
91
+ * The construction is written out here so it reads beside the verification
92
+ * below, and the verification is what keeps the two honest — see this file's
93
+ * header.
94
+ */
95
+ function signForForward(body, secret, nowMs) {
96
+ const t = Math.floor(nowMs / 1000).toString();
97
+ const v1 = createHmac('sha256', secret).update(`${t}.${body}`).digest('hex');
98
+ return `t=${t},v1=${v1}`;
99
+ }
100
+ function parseEventFilter(args) {
101
+ const raw = args.flags['event'];
102
+ if (raw === undefined) {
103
+ return null;
104
+ }
105
+ const list = (Array.isArray(raw) ? raw : [String(raw)]).flatMap((v) => v
106
+ .split(',')
107
+ .map((s) => s.trim())
108
+ .filter((s) => s.length > 0));
109
+ return list.length === 0 ? null : new Set(list);
110
+ }
111
+ /** Read the flags, refusing anything that cannot work, with the fix named. */
112
+ export function parseListenOptions(args) {
113
+ const forwardTo = str(args.flags, 'forward-to') ?? null;
114
+ if (forwardTo !== null) {
115
+ let parsed = null;
116
+ try {
117
+ parsed = new URL(forwardTo);
118
+ }
119
+ catch {
120
+ parsed = null;
121
+ }
122
+ /*
123
+ * One message for both failures, because `localhost:3000` — the mistake
124
+ * everyone makes — hits the SECOND branch, not the first: the WHATWG
125
+ * parser reads `localhost:` as a SCHEME and succeeds. A test caught this
126
+ * command telling a developer who typed `localhost:3000` that the scheme
127
+ * `"localhost:"` was unsupported, which is true and useless.
128
+ */
129
+ if (parsed === null || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {
130
+ throw new Error(`--forward-to "${forwardTo}" is not an http(s) URL${parsed === null ? '' : ` (it parsed as the scheme "${parsed.protocol}")`}. Include the scheme:\n` + ' chatly listen --forward-to http://localhost:3000/webhooks');
131
+ }
132
+ }
133
+ const intervalSeconds = num(args.flags, 'interval') ?? DEFAULT_INTERVAL_SECONDS;
134
+ if (intervalSeconds < MIN_INTERVAL_SECONDS) {
135
+ throw new Error(`--interval ${String(intervalSeconds)} is below the ${String(MIN_INTERVAL_SECONDS)}s floor. ` +
136
+ 'This polls a real API on your own rate limit; a tighter loop buys nothing, because the ' +
137
+ 'delivery row is written after the attempt completes.');
138
+ }
139
+ const pageLimit = num(args.flags, 'limit') ?? DEFAULT_PAGE_LIMIT;
140
+ if (pageLimit < 1) {
141
+ throw new Error(`--limit ${String(pageLimit)} must be at least 1.`);
142
+ }
143
+ const replay = num(args.flags, 'replay') ?? 0;
144
+ if (replay < 0) {
145
+ throw new Error(`--replay ${String(replay)} cannot be negative.`);
146
+ }
147
+ if (replay > pageLimit) {
148
+ throw new Error(`--replay ${String(replay)} is more than --limit ${String(pageLimit)}, and this command ` +
149
+ 'only ever reads one page per poll. Raise --limit to match.');
150
+ }
151
+ const secret = str(args.flags, 'secret') ?? null;
152
+ if (secret !== null && !secret.startsWith('whsec_')) {
153
+ throw new Error(`--secret should be the endpoint's whsec_ signing secret (got "${secret.slice(0, 6)}…").\n` +
154
+ 'It is returned exactly once, by `chatly webhooks create`, and by no other route — if ' +
155
+ 'you no longer have it, create another endpoint.');
156
+ }
157
+ return {
158
+ forwardTo,
159
+ endpointId: str(args.flags, 'endpoint') ?? null,
160
+ events: parseEventFilter(args),
161
+ status: str(args.flags, 'status') ?? null,
162
+ secret,
163
+ intervalMs: intervalSeconds * 1000,
164
+ replay,
165
+ pageLimit,
166
+ json: bool(args.flags, 'json'),
167
+ };
168
+ }
169
+ function asRows(value) {
170
+ const items = typeof value === 'object' && value !== null ? value.items : undefined;
171
+ if (!Array.isArray(items)) {
172
+ return [];
173
+ }
174
+ return items.filter((row) => {
175
+ if (typeof row !== 'object' || row === null) {
176
+ return false;
177
+ }
178
+ const r = row;
179
+ return typeof r['id'] === 'string' && typeof r['eventType'] === 'string';
180
+ });
181
+ }
182
+ /**
183
+ * Which endpoints this will see traffic from, and the refusal when there are
184
+ * none.
185
+ *
186
+ * The empty case is the one worth getting right: a developer running
187
+ * `chatly listen` with no subscription configured sees an empty tail forever
188
+ * and concludes the command is broken, when the real answer is that no event
189
+ * has ever been dispatched to this workspace. So it is an error naming the
190
+ * command that fixes it.
191
+ */
192
+ async function resolveEndpoints(chatly, opts) {
193
+ const endpoints = await chatly.request('GET', '/v1/webhooks');
194
+ const rows = Array.isArray(endpoints) ? endpoints : [];
195
+ if (rows.length === 0) {
196
+ throw new Error('This workspace has no webhook subscriptions, so nothing is ever dispatched and the\n' +
197
+ 'delivery log this command tails will stay empty.\n\n' +
198
+ 'Create one first:\n' +
199
+ ' chatly webhooks create --url https://example.test/hook --event conversation.created\n' +
200
+ '`chatly webhooks events` lists the subscribable names.\n\n' +
201
+ 'The URL has to be one the platform can reach — it is the real destination, and this\n' +
202
+ 'command tails what was attempted against it rather than replacing it.');
203
+ }
204
+ if (opts.endpointId !== null) {
205
+ const match = rows.find((r) => r.id === opts.endpointId);
206
+ if (match === undefined) {
207
+ throw new Error(`No webhook endpoint "${opts.endpointId}" in this workspace. The ids are:\n` +
208
+ rows.map((r) => ` ${String(r.id)} ${String(r.url)}`).join('\n'));
209
+ }
210
+ return [match];
211
+ }
212
+ return rows;
213
+ }
214
+ /**
215
+ * The startup banner.
216
+ *
217
+ * It says what was registered (nothing) and what the signature is (minted
218
+ * here), because both are things a developer would otherwise have to read
219
+ * this file to find out — and the second one changes how they should read a
220
+ * passing verification in their own handler.
221
+ */
222
+ function banner(opts, endpoints, deps) {
223
+ deps.out(`Tailing ${String(endpoints.length)} webhook endpoint(s) via the delivery log, ` +
224
+ `every ${String(opts.intervalMs / 1000)}s.`);
225
+ for (const e of endpoints) {
226
+ const types = Array.isArray(e.eventTypes) ? e.eventTypes.length : 0;
227
+ deps.out(` ${String(e.id)} ${String(e.url)} ${String(types)} event type(s)` +
228
+ (e.enabled === false ? ' [DISABLED — it receives nothing]' : ''));
229
+ }
230
+ if (opts.events !== null) {
231
+ deps.out(`Filtering to: ${[...opts.events].join(', ')} ` +
232
+ '(client-side — an event no endpoint subscribes to never reaches the log at all)');
233
+ }
234
+ deps.out(opts.forwardTo === null
235
+ ? 'Printing only. Pass --forward-to http://localhost:PORT/path to POST each event on.'
236
+ : `Forwarding to ${opts.forwardTo}`);
237
+ if (opts.forwardTo !== null) {
238
+ deps.out(opts.secret === null
239
+ ? 'UNSIGNED: no --secret, so forwarded requests carry no x-livechat-signature and your ' +
240
+ "handler's verifier will reject them. Pass the endpoint's whsec_ secret."
241
+ : 'Signed locally with --secret. This is NOT the signature Chatly sent — the delivery log ' +
242
+ 'does not store one — so it proves nothing about the original request.');
243
+ }
244
+ deps.out('Registers nothing on the server; there is nothing to clean up. Ctrl-C to stop.\n');
245
+ }
246
+ /** Drop the oldest ids once the set is at its cap. Sets iterate in insertion order. */
247
+ function remember(seen, id) {
248
+ seen.add(id);
249
+ if (seen.size > SEEN_CAP) {
250
+ for (const old of seen) {
251
+ seen.delete(old);
252
+ if (seen.size <= SEEN_CAP) {
253
+ break;
254
+ }
255
+ }
256
+ }
257
+ }
258
+ /** POST one event on, verifying the header we just minted before sending it. */
259
+ async function forward(opts, deps, envelope) {
260
+ if (opts.forwardTo === null) {
261
+ return false;
262
+ }
263
+ const body = JSON.stringify(envelope);
264
+ const headers = {
265
+ 'content-type': 'application/json',
266
+ 'x-livechat-event': envelope.type,
267
+ 'x-livechat-delivery': envelope.id,
268
+ // Not a header Chatly sends. A handler that logs it can tell a replayed
269
+ // local forward from a real delivery, which matters the first time
270
+ // somebody points this at a staging environment.
271
+ 'x-chatly-cli-forwarded': '1',
272
+ };
273
+ if (opts.secret !== null) {
274
+ const nowMs = deps.now();
275
+ const signature = signForForward(body, opts.secret, nowMs);
276
+ /*
277
+ * The self-check. `verifyChatlySignature` is the code a customer runs, so
278
+ * if it disagrees with the signer four lines up, the two have drifted on
279
+ * the construction or on the timestamp unit — and forwarding anyway would
280
+ * teach the developer that their correct handler is broken.
281
+ */
282
+ const check = verifyChatlySignature({
283
+ surface: 'event_webhook',
284
+ body,
285
+ headers: { 'x-livechat-signature': signature },
286
+ secret: opts.secret,
287
+ nowMs,
288
+ });
289
+ if (!check.ok) {
290
+ deps.err(`refusing to forward ${envelope.id}: the signature this CLI minted does not verify ` +
291
+ `(${check.reason}: ${check.message}). This is a bug in chatly listen, not in your ` +
292
+ 'handler — please report it.\n');
293
+ return false;
294
+ }
295
+ headers['x-livechat-signature'] = signature;
296
+ headers['x-livechat-timestamp'] = signature.slice('t='.length, signature.indexOf(','));
297
+ }
298
+ try {
299
+ const res = await deps.fetchFn(opts.forwardTo, {
300
+ method: 'POST',
301
+ headers,
302
+ body,
303
+ signal: deps.signal,
304
+ });
305
+ if (!res.ok) {
306
+ deps.err(` ↳ ${opts.forwardTo} answered ${String(res.status)}. ` +
307
+ (res.status === 401 || res.status === 403
308
+ ? 'That is usually signature verification — check --secret matches the endpoint.\n'
309
+ : '\n'));
310
+ return false;
311
+ }
312
+ deps.out(` ↳ ${String(res.status)} from ${opts.forwardTo}`);
313
+ return true;
314
+ }
315
+ catch (err) {
316
+ const reason = err instanceof Error ? err.message : String(err);
317
+ deps.err(` ↳ ${opts.forwardTo} unreachable: ${reason}. Is your server running on that port?\n`);
318
+ return false;
319
+ }
320
+ }
321
+ /**
322
+ * The tail loop, abortable, with the process boundary left to the caller.
323
+ *
324
+ * Exported so the spec can drive it with a bounded `maxPolls` and a scripted
325
+ * fetch, rather than racing a timer against a signal handler.
326
+ */
327
+ export async function tail(chatly, opts, deps) {
328
+ const endpoints = await resolveEndpoints(chatly, opts);
329
+ banner(opts, endpoints, deps);
330
+ const query = { limit: opts.pageLimit };
331
+ if (opts.endpointId !== null) {
332
+ query['endpointId'] = opts.endpointId;
333
+ }
334
+ if (opts.status !== null) {
335
+ query['status'] = opts.status;
336
+ }
337
+ const seen = new Set();
338
+ let seenCount = 0;
339
+ let forwarded = 0;
340
+ let refused = 0;
341
+ let polls = 0;
342
+ /*
343
+ * The baseline. Without it, the first poll replays everything already in
344
+ * the log — which for a busy workspace is `--limit` surprise POSTs at a
345
+ * handler the developer just started. `--replay N` deliberately leaves the
346
+ * newest N rows unseen, which is the "show me the last few" case.
347
+ */
348
+ const firstPage = asRows(await chatly.request('GET', '/v1/webhooks/deliveries', { query }));
349
+ for (const row of firstPage.slice(opts.replay)) {
350
+ remember(seen, row.id);
351
+ }
352
+ if (opts.replay > 0) {
353
+ deps.out(`Replaying the ${String(Math.min(opts.replay, firstPage.length))} most recent.\n`);
354
+ }
355
+ const matches = (row) => opts.events === null || opts.events.has(row.eventType);
356
+ for (;;) {
357
+ if (deps.signal.aborted) {
358
+ break;
359
+ }
360
+ if (deps.maxPolls !== undefined && polls >= deps.maxPolls) {
361
+ break;
362
+ }
363
+ polls += 1;
364
+ /*
365
+ * The first poll REUSES the baseline page rather than asking again. Two
366
+ * identical requests back to back is one more than the rate limit needs
367
+ * to see, and with `--replay` the baseline page is exactly what has to be
368
+ * replayed — so there is no case where re-reading it is right.
369
+ */
370
+ const page = polls === 1
371
+ ? firstPage
372
+ : asRows(await chatly.request('GET', '/v1/webhooks/deliveries', { query }));
373
+ // Newest-first off the wire; replay in the order they happened.
374
+ const fresh = page.filter((row) => !seen.has(row.id)).reverse();
375
+ /*
376
+ * Poll 1 is exempt: it is the baseline page, not a window this loop could
377
+ * have overflowed, and with `--replay N` its `fresh` rows are new on
378
+ * purpose. From poll 2 on, a FULL page with nothing already seen on it
379
+ * means ≥ --limit deliveries landed since the last look and some are gone
380
+ * from the window.
381
+ */
382
+ if (polls > 1 && fresh.length === page.length && page.length === opts.pageLimit) {
383
+ /*
384
+ * Every row on a FULL page was new, so the window may have overflowed
385
+ * between polls and some deliveries were never seen. This command reads
386
+ * one page per poll by design — walking the cursor backwards on every
387
+ * tick would re-read the whole log — so the honest thing is to say it.
388
+ */
389
+ deps.err(`warning: all ${String(opts.pageLimit)} rows on this page were new, so events may have ` +
390
+ 'been missed between polls. Use a shorter --interval or a larger --limit.\n');
391
+ }
392
+ for (const row of fresh) {
393
+ remember(seen, row.id);
394
+ if (!matches(row)) {
395
+ continue;
396
+ }
397
+ seenCount += 1;
398
+ const detail = await chatly.request('GET', `/v1/webhooks/deliveries/${encodeURIComponent(row.id)}`);
399
+ /*
400
+ * The envelope the worker signs is `{ id, type, payload }`. `id` here
401
+ * is the DELIVERY ROW's id, not the `deliveryId` that was in the
402
+ * original signed body — that value is not stored anywhere readable. It
403
+ * is still stable per attempt, which is what a handler deduping on it
404
+ * needs.
405
+ */
406
+ const envelope = { id: row.id, type: row.eventType, payload: detail.payload };
407
+ if (opts.json) {
408
+ printJson({ ...envelope, delivery: row });
409
+ }
410
+ else {
411
+ const http = row.httpStatus === null ? '—' : String(row.httpStatus);
412
+ deps.out(`${row.eventType} ${row.id} attempt ${String(row.attempt)} ${row.status} ` +
413
+ `http ${http} ${row.createdAt}` +
414
+ (row.error === null ? '' : ` (${row.error})`));
415
+ }
416
+ if (opts.forwardTo !== null) {
417
+ if (await forward(opts, deps, envelope)) {
418
+ forwarded += 1;
419
+ }
420
+ else {
421
+ refused += 1;
422
+ }
423
+ }
424
+ }
425
+ if (deps.maxPolls !== undefined && polls >= deps.maxPolls) {
426
+ break;
427
+ }
428
+ await deps.sleep(opts.intervalMs, deps.signal);
429
+ }
430
+ return { seen: seenCount, forwarded, refused, polls };
431
+ }
432
+ /** An abortable sleep, so Ctrl-C does not wait out the poll interval. */
433
+ function sleepUntilAborted(ms, signal) {
434
+ return new Promise((resolve) => {
435
+ if (signal.aborted) {
436
+ resolve();
437
+ return;
438
+ }
439
+ const timer = setTimeout(() => {
440
+ signal.removeEventListener('abort', onAbort);
441
+ resolve();
442
+ }, ms);
443
+ function onAbort() {
444
+ clearTimeout(timer);
445
+ resolve();
446
+ }
447
+ signal.addEventListener('abort', onAbort, { once: true });
448
+ });
449
+ }
450
+ /**
451
+ * The command entry point.
452
+ *
453
+ * SIGINT and SIGTERM abort the loop rather than killing the process, so the
454
+ * summary still prints and the exit code is 0 — a developer tool stopped on
455
+ * purpose did not fail.
456
+ */
457
+ export async function listen(chatly, args) {
458
+ const opts = parseListenOptions(args);
459
+ const controller = new AbortController();
460
+ const stop = () => {
461
+ controller.abort();
462
+ };
463
+ process.once('SIGINT', stop);
464
+ process.once('SIGTERM', stop);
465
+ const deps = {
466
+ fetchFn: globalThis.fetch.bind(globalThis),
467
+ now: () => Date.now(),
468
+ sleep: sleepUntilAborted,
469
+ signal: controller.signal,
470
+ out: (line) => {
471
+ process.stdout.write(`${line}\n`);
472
+ },
473
+ err: (line) => {
474
+ process.stderr.write(line);
475
+ },
476
+ };
477
+ try {
478
+ const summary = await tail(chatly, opts, deps);
479
+ process.stdout.write(`\nStopped. ${String(summary.seen)} event(s) seen` +
480
+ (opts.forwardTo === null
481
+ ? '.\n'
482
+ : `, ${String(summary.forwarded)} forwarded, ${String(summary.refused)} not.\n`));
483
+ return 0;
484
+ }
485
+ finally {
486
+ process.off('SIGINT', stop);
487
+ process.off('SIGTERM', stop);
488
+ }
489
+ }
490
+ //# sourceMappingURL=listen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listen.js","sourceRoot":"","sources":["../../src/commands/listen.ts"],"names":[],"mappings":"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"}
package/dist/help.d.ts CHANGED
@@ -22,5 +22,5 @@
22
22
  * The convention the spec relies on: a command line starts with exactly two
23
23
  * spaces and its first word is the command group.
24
24
  */
25
- export declare const HELP = "chatly \u2014 the Chatly command line\n\nUSAGE\n chatly <command> [subcommand] [flags]\n\nAUTH\n login Store an API key in ~/.config/chatly/config.json (0600)\n logout Remove the stored key\n whoami Which workspace this key belongs to, and its scopes\n\nCONVERSATIONS\n conversations list Open conversations, newest first\n conversations get <id> One conversation\n conversations messages <id> The thread\n conversations send <id> <body>\n Reply as the key's machine identity\n conversations unattended Open with no agent reply yet\n conversations mood <id> Sentiment over the thread\n conversations return-to-bot <id> <bot-id>\n Give an open thread back to an assistant\n\nCONTACTS\n contacts list People in this workspace\n contacts get <id>\n contacts upsert --email --name --external-id --phone\n contacts tag <id> <tag> Add a tag\n contacts journey <id> Timeline: conversations, events, tickets\n contacts cards <id> Customer-card data for this person\n\nTICKETS\n tickets list --status --queue\n tickets get <id>\n tickets comments <id>\n tickets queues\n tickets lineage <id> Merge and split history\n tickets time <id> Time logged\n tickets status-history <id>\n\nKNOWLEDGE + SEARCH\n search <query> Across contacts, conversations, messages, tickets, KB\n kb articles Help-centre articles\n kb article <slug>\n kb collections\n\nEVENTS\n events track <contact-id> <name>\n Fire a CDP event. --prop key=value, repeatable\n events list --contact-id\n\nBOTS + EXTERNAL AGENTS\n bots list | get <id>\n bots create --body. type:\"external\" answers with a secret, ONCE\n bots update <id> --body\n bots update-external <id> --body. webhookUrl, timeoutSeconds, fallbackMessage\n bots rotate-secret <id> New signing secret, shown once. No overlap window\n bots deliveries <id> The push ledger. --status pending|delivered|failed|dead\n bots delivery <id> <delivery-id>\n One delivery, with the exact signed payload\n bots redeliver <id> <delivery-id>\n Queue the recorded payload again, from attempt 0\n bots test-delivery <id> Sign and POST a rehearsal payload; prints the response\n\nROUTING + AUTOMATION\n bot-routes list | fields | create | update <id> | delete <id>\n bot-routes resolve Dry-run the table. --body with a hypothetical visitor\n triggers list | get <id> | upsert | delete <id>\n brands list | get <id> | create | update <id> | delete <id>\n macros list | get <id> | create | update <id> | delete <id>\n email-templates templates | get <kind> | set <kind> | reset <kind>\n knowledge-gaps list | triage <id>\n\nINTEGRATIONS\n webhooks deliveries --status\n webhooks delivery <id>\n webhooks redeliver <id>\n webhooks endpoints Subscriptions, not traffic\n webhooks events The subscribable event catalogue\n webhooks schema-versions\n webhooks create --url --event (repeatable). Answers with whsec_, once\n webhooks pin <id> <version>\n customer-cards list | create | update <id> | delete <id>\n customer-cards rotate-secret <id>\n Update your endpoint BEFORE calling this\n docs-sources list | providers | discover | create | update <id> | delete <id>\n docs-sources sync <id> --full re-reads every page\n docs-sources subscribe <id> A refusal is a success: read the response\n channels list | get <id> | adapters | create | update <id>\n channels rotate-secret <id>\n\nWORKSPACE AS CODE\n plan Diff chatly.json against the live workspace. Reads only\n apply Make the plan's changes. Never deletes unless told\n --file <path> the document (- for stdin). Default: ./chatly.json\n --prune also delete what the document omits\n --write-only also send fields that cannot be read back\n --exit-code plan only: exit 2 when there is drift\n\nAI\n ai providers | quota\n ai add-provider BYOK. --body\n ai test-provider <key>\n ai tools | create-tool | update-tool <id> | delete-tool <id>\n ai tone | set-tone | generate-tone <sample>\n\nREPORTS\n reports overview --days\n reports agents Means, not percentiles\n reports conversations-by-day\n reports sources | response-times | voice\n reports attribution <dim> One of ten dimensions; an unknown one is refused\n reports cohorts --weeks, NOT --days\n reports themes --date. A daily snapshot; there is no regenerate\n reports theme-conversations <theme-id>\n reports teams | labels | sla\n --from --to --days --group-by\n\nBILLING\n billing summary | plans | invoices\n billing usage <event-type> One meter over a window. --from --to\n billing usage-daily <event-type>\n Dense: one row per UTC day, zeros included\n billing usage-monthly --month\n\nWORKSPACE\n workspace settings\n workspace labels | inboxes | skills\n workspace team-members <team-id>\n workspace key-scopes What a key may be granted\n\nRAW\n api <METHOD> <path> Any route, with auth, idempotency and retries\n chatly api GET /v1/feature-flags\n chatly api POST /v1/macros --body '{\"name\":\"Refund\"}'\n\nGLOBAL FLAGS\n --json Raw API response instead of a table\n --all Follow pagination to the end (list commands)\n --limit <n> Page size\n --cursor <c> Start from a cursor\n --key <ck_\u2026> Override the stored key for this call\n --api-url <url> Point at another Chatly environment\n --help, --version\n\nDocs: https://chatlychat.com/docs/sdk-cli\n";
25
+ export declare const HELP = "chatly \u2014 the Chatly command line\n\nUSAGE\n chatly <command> [subcommand] [flags]\n\nAUTH\n login Store an API key in ~/.config/chatly/config.json (0600)\n logout Remove the stored key\n whoami Which workspace this key belongs to, and its scopes\n\nCONVERSATIONS\n conversations list Open conversations, newest first\n conversations get <id> One conversation\n conversations messages <id> The thread\n conversations send <id> <body>\n Reply as the key's machine identity\n conversations unattended Open with no agent reply yet\n conversations mood <id> Sentiment over the thread\n conversations return-to-bot <id> <bot-id>\n Give an open thread back to an assistant\n\nCONTACTS\n contacts list People in this workspace\n contacts get <id>\n contacts upsert --email --name --external-id --phone\n contacts tag <id> <tag> Add a tag\n contacts journey <id> Timeline: conversations, events, tickets\n contacts cards <id> Customer-card data for this person\n\nTICKETS\n tickets list --status --queue\n tickets get <id>\n tickets comments <id>\n tickets queues\n tickets lineage <id> Merge and split history\n tickets time <id> Time logged\n tickets status-history <id>\n\nKNOWLEDGE + SEARCH\n search <query> Across contacts, conversations, messages, tickets, KB\n kb articles Help-centre articles\n kb article <slug>\n kb collections\n\nEVENTS\n events track <contact-id> <name>\n Fire a CDP event. --prop key=value, repeatable\n events list --contact-id\n\nBOTS + EXTERNAL AGENTS\n bots list | get <id>\n bots create --body. type:\"external\" answers with a secret, ONCE\n bots update <id> --body\n bots update-external <id> --body. webhookUrl, timeoutSeconds, fallbackMessage\n bots rotate-secret <id> New signing secret, shown once. No overlap window\n bots deliveries <id> The push ledger. --status pending|delivered|failed|dead\n bots delivery <id> <delivery-id>\n One delivery, with the exact signed payload\n bots redeliver <id> <delivery-id>\n Queue the recorded payload again, from attempt 0\n bots test-delivery <id> Sign and POST a rehearsal payload; prints the response\n\nROUTING + AUTOMATION\n bot-routes list | fields | create | update <id> | delete <id>\n bot-routes resolve Dry-run the table. --body with a hypothetical visitor\n triggers list | get <id> | upsert | delete <id>\n brands list | get <id> | create | update <id> | delete <id>\n macros list | get <id> | create | update <id> | delete <id>\n email-templates templates | get <kind> | set <kind> | reset <kind>\n knowledge-gaps list | triage <id>\n\nINTEGRATIONS\n webhooks deliveries --status\n webhooks delivery <id>\n webhooks redeliver <id>\n webhooks endpoints Subscriptions, not traffic\n webhooks events The subscribable event catalogue\n webhooks schema-versions\n webhooks create --url --event (repeatable). Answers with whsec_, once\n webhooks pin <id> <version>\n customer-cards list | create | update <id> | delete <id>\n customer-cards rotate-secret <id>\n Update your endpoint BEFORE calling this\n docs-sources list | providers | discover | create | update <id> | delete <id>\n docs-sources sync <id> --full re-reads every page\n docs-sources subscribe <id> A refusal is a success: read the response\n channels list | get <id> | adapters | create | update <id>\n channels rotate-secret <id>\n\nDEVELOPING AGAINST WEBHOOKS\n listen Tail this workspace's webhook deliveries and POST\n each one to a local URL. Registers nothing\n --forward-to <url> where to POST (omit to print only)\n --secret <whsec_\u2026> sign the forwarded request\n --endpoint <id> one subscription's traffic only\n --event <name> repeatable; filters client-side\n --status <s> delivered | failed | dead\n --replay <n> forward the n newest rows first\n --interval <seconds> poll interval, default 2\n\nWORKSPACE AS CODE\n plan Diff chatly.json against the live workspace. Reads only\n apply Make the plan's changes. Never deletes unless told\n --file <path> the document (- for stdin). Default: ./chatly.json\n --prune also delete what the document omits\n --write-only also send fields that cannot be read back\n --exit-code plan only: exit 2 when there is drift\n\nAI\n ai providers | quota\n ai add-provider BYOK. --body\n ai test-provider <key>\n ai tools | create-tool | update-tool <id> | delete-tool <id>\n ai tone | set-tone | generate-tone <sample>\n\nREPORTS\n reports overview --days\n reports agents Means, not percentiles\n reports conversations-by-day\n reports sources | response-times | voice\n reports attribution <dim> One of ten dimensions; an unknown one is refused\n reports cohorts --weeks, NOT --days\n reports themes --date. A daily snapshot; there is no regenerate\n reports theme-conversations <theme-id>\n reports teams | labels | sla\n --from --to --days --group-by\n\nBILLING\n billing summary | plans | invoices\n billing usage <event-type> One meter over a window. --from --to\n billing usage-daily <event-type>\n Dense: one row per UTC day, zeros included\n billing usage-monthly --month\n\nWORKSPACE\n workspace settings\n workspace labels | inboxes | skills\n workspace team-members <team-id>\n workspace key-scopes What a key may be granted\n\nRAW\n api <METHOD> <path> Any route, with auth, idempotency and retries\n chatly api GET /v1/feature-flags\n chatly api POST /v1/macros --body '{\"name\":\"Refund\"}'\n\nGLOBAL FLAGS\n --json Raw API response instead of a table\n --all Follow pagination to the end (list commands)\n --limit <n> Page size\n --cursor <c> Start from a cursor\n --key <ck_\u2026> Override the stored key for this call\n --api-url <url> Point at another Chatly environment\n --help, --version\n\nDocs: https://chatlychat.com/docs/sdk-cli\n";
26
26
  //# sourceMappingURL=help.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,IAAI,8lMAgJhB,CAAC"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,IAAI,21NA2JhB,CAAC"}
package/dist/help.js CHANGED
@@ -111,6 +111,17 @@ INTEGRATIONS
111
111
  channels list | get <id> | adapters | create | update <id>
112
112
  channels rotate-secret <id>
113
113
 
114
+ DEVELOPING AGAINST WEBHOOKS
115
+ listen Tail this workspace's webhook deliveries and POST
116
+ each one to a local URL. Registers nothing
117
+ --forward-to <url> where to POST (omit to print only)
118
+ --secret <whsec_…> sign the forwarded request
119
+ --endpoint <id> one subscription's traffic only
120
+ --event <name> repeatable; filters client-side
121
+ --status <s> delivered | failed | dead
122
+ --replay <n> forward the n newest rows first
123
+ --interval <seconds> poll interval, default 2
124
+
114
125
  WORKSPACE AS CODE
115
126
  plan Diff chatly.json against the live workspace. Reads only
116
127
  apply Make the plan's changes. Never deletes unless told
package/dist/help.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJnB,CAAC"}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2JnB,CAAC"}
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAkB,YAAY,EAAwB,MAAM,sBAAsB,CAAC;AAE1F,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAyBlE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAC7B,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CA+CpE,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBpD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,CAAC;AAIxF,wBAAsB,GAAG,CACvB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,UAAU,GAAE,aAA8B,GACzC,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAqBvE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAkB,YAAY,EAAwB,MAAM,sBAAsB,CAAC;AAE1F,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AA0BlE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAC7B,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAwDpE,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBpD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,CAAC;AAIxF,wBAAsB,GAAG,CACvB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,UAAU,GAAE,aAA8B,GACzC,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAqBvE"}
package/dist/run.js CHANGED
@@ -13,6 +13,7 @@ import * as auth from './commands/auth.js';
13
13
  import * as config from './commands/config.js';
14
14
  import * as insights from './commands/insights.js';
15
15
  import * as integrations from './commands/integrations.js';
16
+ import * as listenCmd from './commands/listen.js';
16
17
  import * as cmd from './commands/resources.js';
17
18
  import * as wac from './commands/workspace-as-code.js';
18
19
  import { resolveCredentials } from './config.js';
@@ -26,7 +27,7 @@ import { HELP } from './help.js';
26
27
  * drifts — it said `0.1.0` while the published package was `0.1.2` — so
27
28
  * `cli.spec.ts` asserts the two agree and fails if they do not.
28
29
  */
29
- const VERSION = '0.1.7';
30
+ const VERSION = '0.2.0';
30
31
  /** Commands that need no credential. Everything else resolves a key first. */
31
32
  const UNAUTHENTICATED = new Set(['login', 'logout', 'help', 'version']);
32
33
  /**
@@ -62,6 +63,15 @@ export const COMMANDS = {
62
63
  'knowledge-gaps': config.knowledgeGaps,
63
64
  // ── Integrations ──────────────────────────────────────────────────────
64
65
  webhooks: integrations.webhooks,
66
+ /*
67
+ * `listen` sits beside `webhooks` rather than under it, because it is not a
68
+ * CRUD verb on the same resource — it is the `stripe listen` equivalent, a
69
+ * long-running tail, and it is what a developer types without reading
70
+ * anything first. Read `commands/listen.ts`'s header before changing how it
71
+ * gets its events: the three possible designs are enumerated there and two
72
+ * of them are impossible with a `ck_` key.
73
+ */
74
+ listen: listenCmd.listen,
65
75
  'customer-cards': integrations.customerCards,
66
76
  'docs-sources': integrations.docsSources,
67
77
  channels: integrations.channels,
package/dist/run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatlychat/cli",
3
- "version": "0.1.7",
3
+ "version": "0.2.0",
4
4
  "description": "The Chatly command line — inspect conversations, send replies, read reports and call any API route from a terminal.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/chatlychat/chatly-cli#readme",
@@ -30,7 +30,7 @@
30
30
  "LICENSE"
31
31
  ],
32
32
  "dependencies": {
33
- "@chatlychat/sdk-node": "0.3.1"
33
+ "@chatlychat/sdk-node": "0.4.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "20.14.10",