@chatlychat/cli 0.1.3 → 0.1.5

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.
Files changed (73) hide show
  1. package/dist/commands/ai.d.ts +4 -0
  2. package/dist/commands/ai.d.ts.map +1 -0
  3. package/dist/commands/ai.js +149 -0
  4. package/dist/commands/ai.js.map +1 -0
  5. package/dist/commands/common.d.ts +79 -0
  6. package/dist/commands/common.d.ts.map +1 -0
  7. package/dist/commands/common.js +194 -0
  8. package/dist/commands/common.js.map +1 -0
  9. package/dist/commands/config.d.ts +40 -0
  10. package/dist/commands/config.d.ts.map +1 -0
  11. package/dist/commands/config.js +336 -0
  12. package/dist/commands/config.js.map +1 -0
  13. package/dist/commands/insights.d.ts +5 -0
  14. package/dist/commands/insights.d.ts.map +1 -0
  15. package/dist/commands/insights.js +277 -0
  16. package/dist/commands/insights.js.map +1 -0
  17. package/dist/commands/integrations.d.ts +15 -0
  18. package/dist/commands/integrations.d.ts.map +1 -0
  19. package/dist/commands/integrations.js +256 -0
  20. package/dist/commands/integrations.js.map +1 -0
  21. package/dist/commands/resources.d.ts +19 -7
  22. package/dist/commands/resources.d.ts.map +1 -1
  23. package/dist/commands/resources.js +100 -191
  24. package/dist/commands/resources.js.map +1 -1
  25. package/dist/commands/workspace-as-code.d.ts +27 -0
  26. package/dist/commands/workspace-as-code.d.ts.map +1 -0
  27. package/dist/commands/workspace-as-code.js +377 -0
  28. package/dist/commands/workspace-as-code.js.map +1 -0
  29. package/dist/help.d.ts +25 -1
  30. package/dist/help.d.ts.map +1 -1
  31. package/dist/help.js +104 -8
  32. package/dist/help.js.map +1 -1
  33. package/dist/run.d.ts +17 -0
  34. package/dist/run.d.ts.map +1 -1
  35. package/dist/run.js +88 -41
  36. package/dist/run.js.map +1 -1
  37. package/dist/wac/__tests__/wac-fixtures.d.ts +20 -0
  38. package/dist/wac/__tests__/wac-fixtures.d.ts.map +1 -0
  39. package/dist/wac/__tests__/wac-fixtures.js +38 -0
  40. package/dist/wac/__tests__/wac-fixtures.js.map +1 -0
  41. package/dist/wac/apply.d.ts +113 -0
  42. package/dist/wac/apply.d.ts.map +1 -0
  43. package/dist/wac/apply.js +265 -0
  44. package/dist/wac/apply.js.map +1 -0
  45. package/dist/wac/diff.d.ts +137 -0
  46. package/dist/wac/diff.d.ts.map +1 -0
  47. package/dist/wac/diff.js +413 -0
  48. package/dist/wac/diff.js.map +1 -0
  49. package/dist/wac/document.d.ts +110 -0
  50. package/dist/wac/document.d.ts.map +1 -0
  51. package/dist/wac/document.js +429 -0
  52. package/dist/wac/document.js.map +1 -0
  53. package/dist/wac/render.d.ts +52 -0
  54. package/dist/wac/render.d.ts.map +1 -0
  55. package/dist/wac/render.js +156 -0
  56. package/dist/wac/render.js.map +1 -0
  57. package/dist/wac/resource-def.d.ts +116 -0
  58. package/dist/wac/resource-def.d.ts.map +1 -0
  59. package/dist/wac/resource-def.js +44 -0
  60. package/dist/wac/resource-def.js.map +1 -0
  61. package/dist/wac/resources.d.ts +104 -0
  62. package/dist/wac/resources.d.ts.map +1 -0
  63. package/dist/wac/resources.js +541 -0
  64. package/dist/wac/resources.js.map +1 -0
  65. package/dist/wac/values.d.ts +16 -0
  66. package/dist/wac/values.d.ts.map +1 -0
  67. package/dist/wac/values.js +53 -0
  68. package/dist/wac/values.js.map +1 -0
  69. package/package.json +3 -2
  70. package/dist/cli.spec.d.ts +0 -2
  71. package/dist/cli.spec.d.ts.map +0 -1
  72. package/dist/cli.spec.js +0 -226
  73. package/dist/cli.spec.js.map +0 -1
@@ -0,0 +1,377 @@
1
+ /**
2
+ * `chatly plan` and `chatly apply` — the workspace as a file.
3
+ *
4
+ * ═══ THE ASK ══════════════════════════════════════════════════════════════
5
+ *
6
+ * From the integrator who prompted it: "We wrote ~600 lines to idempotently
7
+ * upsert tools, bots, routes, cards and channel config. Offer a declarative
8
+ * `chatly.yaml` with `chatly plan` / `chatly apply` (diff, then apply; never
9
+ * deletes unless told). This is the single biggest DX win for teams that run
10
+ * more than one environment."
11
+ *
12
+ * A CLI rather than a Terraform provider, deliberately. A provider is a
13
+ * second artifact to version, publish, document and keep in step with 142
14
+ * routes, and this CLI is already on npm as `@chatlychat/cli` with a release
15
+ * pipeline. The provider is the better answer for somebody whose whole
16
+ * platform is Terraform; it is not the better answer for the next six months.
17
+ *
18
+ * ═══ THE CONTRACT ═════════════════════════════════════════════════════════
19
+ *
20
+ * plan reads the live workspace, prints a diff, WRITES NOTHING. Not one
21
+ * POST, not one PATCH. `wac.spec.ts` drives the whole path through
22
+ * a recording transport and fails if a single non-GET is issued —
23
+ * and asserts the GETs it did make, so a plan that silently stopped
24
+ * reading cannot pass the same test.
25
+ * apply makes the plan's changes. A resource on the server and absent
26
+ * from the document is REPORTED AND LEFT ALONE; `--prune` is the
27
+ * only thing that deletes, and there is no way to set it in the
28
+ * file. Default safe, as asked.
29
+ *
30
+ * ═══ YAML ═════════════════════════════════════════════════════════════════
31
+ *
32
+ * This reads JSON. `yaml` is in the lockfile only as a transitive
33
+ * devDependency of `lint-staged`, which is not reachable from `apps/cli` and
34
+ * would not ship with the published package either way, and CLAUDE.md §2
35
+ * forbids adding a dependency without explicit approval. A hand-rolled YAML
36
+ * subset was considered and rejected: indentation, quoting, anchors and
37
+ * multi-line scalars are exactly the surface where a parser that is 95%
38
+ * right produces a document that means something other than it says, which
39
+ * is worse than one that will not load.
40
+ *
41
+ * So a `.yaml` path is refused with the one-line conversion rather than
42
+ * half-parsed, and `--file -` reads stdin, which makes any converter a pipe.
43
+ * The documented filename stays `chatly.yaml` in the integrator's words and
44
+ * `chatly.json` in this implementation; when YAML is approved, `loadDocument`
45
+ * is the only function that changes.
46
+ */
47
+ import { readFileSync } from 'node:fs';
48
+ import { bool, str } from '../args.js';
49
+ import { printJson } from '../output.js';
50
+ import { harvestSecrets, renderOutcomes, writesFor, } from '../wac/apply.js';
51
+ import { buildPlan, tally } from '../wac/diff.js';
52
+ import { parseDocument } from '../wac/document.js';
53
+ import { planFooter, planForJson, renderPlan } from '../wac/render.js';
54
+ import { resourceDef } from '../wac/resources.js';
55
+ /** Looked for in order when `--file` is absent. */
56
+ const DEFAULT_FILES = ['chatly.json', 'chatly.yaml', 'chatly.yml'];
57
+ /**
58
+ * The row cap on `/v1/macros`, used to decide whether `--prune` is safe.
59
+ *
60
+ * `@PaginationExempt` routes answer a bare array with no cursor, so a list
61
+ * that comes back at exactly the cap may be truncated — and a row past the
62
+ * cap is INVISIBLE, not absent, which would make it an orphan and then a
63
+ * deletion. `diff.ts` refuses prune for a type in that state. The number is
64
+ * the handler's, and if it ever rises this becomes conservative rather than
65
+ * wrong, which is the right direction for a flag that deletes.
66
+ */
67
+ const EXEMPT_LIST_CAP = 200;
68
+ /* ── Loading ──────────────────────────────────────────────────────────── */
69
+ function readFile(path) {
70
+ try {
71
+ // `0` is stdin, so `converter | chatly plan --file -` works.
72
+ return path === '-' ? readFileSync(0, 'utf8') : readFileSync(path, 'utf8');
73
+ }
74
+ catch (err) {
75
+ throw new Error(`Cannot read ${path}: ${err instanceof Error ? err.message : String(err)}`);
76
+ }
77
+ }
78
+ function findDefault() {
79
+ for (const candidate of DEFAULT_FILES) {
80
+ try {
81
+ readFileSync(candidate, 'utf8');
82
+ return candidate;
83
+ }
84
+ catch {
85
+ continue;
86
+ }
87
+ }
88
+ throw new Error('No document found. Looked for chatly.json, chatly.yaml and chatly.yml in this ' +
89
+ 'directory.\nPass one with --file, or --file - to read stdin.\n' +
90
+ 'There is a worked example at https://chatlychat.com/docs/sdk-cli#workspace-as-code');
91
+ }
92
+ export function loadDocument(args, env = process.env) {
93
+ const path = str(args.flags, 'file') ?? findDefault();
94
+ const raw = readFile(path);
95
+ if (/\.ya?ml$/i.test(path) || /^\s*(?:version|resources)\s*:/m.test(raw)) {
96
+ /*
97
+ * Refused, not half-parsed.
98
+ *
99
+ * The second half of that test catches a YAML document passed under a
100
+ * `.json` name or through stdin, which is the shape of the mistake
101
+ * somebody makes once. A YAML file handed to `JSON.parse` fails with
102
+ * "Unexpected token v", which sends the reader looking for a syntax error
103
+ * in their own file rather than at the one sentence they need.
104
+ */
105
+ throw new Error(`${path} looks like YAML, and this CLI reads JSON.\n\n` +
106
+ 'YAML needs a parser, and adding a dependency to a published CLI is a decision this\n' +
107
+ 'repo does not make casually (CLAUDE.md §2) — `yaml` is in the monorepo lockfile only\n' +
108
+ 'as a transitive devDependency of lint-staged, so it is not something we already ship.\n' +
109
+ 'A 95%-right hand-rolled YAML subset is worse than no YAML: it loads a document that\n' +
110
+ 'means something other than what it says.\n\n' +
111
+ 'Convert it and pipe it:\n' +
112
+ ` npx js-yaml ${path} | chatly plan --file -\n` +
113
+ ' python3 -c "import sys,yaml,json;json.dump(yaml.safe_load(sys.stdin),sys.stdout)" \\\n' +
114
+ ` < ${path} | chatly plan --file -`);
115
+ }
116
+ let parsed;
117
+ try {
118
+ parsed = JSON.parse(raw);
119
+ }
120
+ catch (err) {
121
+ throw new Error(`${path} is not valid JSON: ${err instanceof Error ? err.message : '?'}`);
122
+ }
123
+ return parseDocument(parsed, env);
124
+ }
125
+ /* ── Reading the live workspace ───────────────────────────────────────── */
126
+ /**
127
+ * The live rows for every type the document mentions, and nothing else.
128
+ *
129
+ * All through `chatly.request` — the escape hatch CONTRACT.md defines — so
130
+ * auth, retries and the typed errors are the same ones every other command
131
+ * gets, and `apps/cli` still adds no HTTP of its own. Every call here is a
132
+ * GET; that is the property `wac.spec.ts` pins.
133
+ */
134
+ export async function readLive(chatly, doc) {
135
+ const out = new Map();
136
+ for (const section of doc.sections) {
137
+ const { def } = section;
138
+ if (def.list.paged) {
139
+ const rows = [];
140
+ let cursor;
141
+ /*
142
+ * Walked by hand rather than through `autoPaginate` because the loop
143
+ * needs the raw envelope: `@PaginationExempt` neighbours answer a bare
144
+ * array and this one answers `{ items, nextCursor }`, and conflating
145
+ * the two is the bug that shipped in two SDKs.
146
+ */
147
+ for (let guard = 0; guard < 200; guard += 1) {
148
+ const page = await chatly.request('GET', def.list.path, {
149
+ query: cursor === undefined ? {} : { cursor },
150
+ });
151
+ rows.push(...(page.items ?? []));
152
+ const next = page.nextCursor;
153
+ if (typeof next !== 'string' || next.length === 0 || next === cursor) {
154
+ break;
155
+ }
156
+ cursor = next;
157
+ }
158
+ out.set(def.type, { rows });
159
+ continue;
160
+ }
161
+ const answer = await chatly.request('GET', def.list.path);
162
+ const rows = Array.isArray(answer) ? answer : [];
163
+ out.set(def.type, { rows, possiblyTruncated: rows.length >= EXEMPT_LIST_CAP });
164
+ }
165
+ return out;
166
+ }
167
+ /* ── plan ─────────────────────────────────────────────────────────────── */
168
+ export async function plan(chatly, args) {
169
+ const doc = loadDocument(args);
170
+ /*
171
+ * The guard first, before a single read.
172
+ *
173
+ * It was second for one revision, which meant a staging document aimed at
174
+ * production issued nine GETs and computed a whole diff before refusing.
175
+ * Harmless here because they are reads — and exactly the ordering mistake
176
+ * that is not harmless in `apply`, where the same code shape would have
177
+ * written before checking.
178
+ */
179
+ const guard = await workspaceGuard(chatly, doc);
180
+ if (guard !== undefined) {
181
+ process.stderr.write(`${guard}\n`);
182
+ return 1;
183
+ }
184
+ const live = await readLive(chatly, doc);
185
+ const built = buildPlan(doc, live, { writeOnly: bool(args.flags, 'write-only') });
186
+ const opts = { prune: bool(args.flags, 'prune'), pruneUnsafe: built.pruneUnsafe };
187
+ if (bool(args.flags, 'json')) {
188
+ printJson(planForJson(built));
189
+ }
190
+ else {
191
+ process.stdout.write(renderPlan(built, opts));
192
+ process.stdout.write(planFooter(built, opts));
193
+ }
194
+ /*
195
+ * `--exit-code`, off by default.
196
+ *
197
+ * CI wants "is production still what the repo says" as an exit status, and
198
+ * a plan that exits 1 by default would make `chatly plan` unusable in a
199
+ * shell with `set -e` for the ordinary case of looking. So the behaviour is
200
+ * opt-in and the code is 2 — distinct from 1, which on this CLI means the
201
+ * request failed, and conflating "there is drift" with "the call errored"
202
+ * is how a drift alarm becomes a flake alarm.
203
+ */
204
+ if (bool(args.flags, 'exit-code')) {
205
+ const counts = tally(built);
206
+ return counts.create + counts.update + counts.blocked > 0 ? 2 : 0;
207
+ }
208
+ return built.items.some((i) => i.action === 'blocked') ? 1 : 0;
209
+ }
210
+ /**
211
+ * `workspace:` in the document, against the key's actual workspace.
212
+ *
213
+ * The guard that stops a staging document reaching production. It is checked
214
+ * on `plan` as well as `apply` — a plan is what somebody reads before they
215
+ * approve, so a plan computed against the wrong workspace is a worse failure
216
+ * than an apply that is refused.
217
+ *
218
+ * `whoami` is a GET, so this does not spend the no-writes property.
219
+ */
220
+ async function workspaceGuard(chatly, doc) {
221
+ if (doc.workspace === undefined) {
222
+ return undefined;
223
+ }
224
+ const me = await chatly.whoami();
225
+ if (me.workspaceId === doc.workspace) {
226
+ return undefined;
227
+ }
228
+ return (`Refusing to run: the document says \`"workspace": "${doc.workspace}"\` and this key ` +
229
+ `belongs to ${me.workspaceId}.\n` +
230
+ 'Either point --key / CHATLY_API_KEY at the right workspace, or remove the `workspace` ' +
231
+ 'line if this document is meant to be portable.');
232
+ }
233
+ /* ── apply ────────────────────────────────────────────────────────────── */
234
+ export async function apply(chatly, args) {
235
+ const doc = loadDocument(args);
236
+ const guard = await workspaceGuard(chatly, doc);
237
+ if (guard !== undefined) {
238
+ process.stderr.write(`${guard}\n`);
239
+ return 1;
240
+ }
241
+ const live = await readLive(chatly, doc);
242
+ const writeOnly = bool(args.flags, 'write-only');
243
+ const built = buildPlan(doc, live, { writeOnly });
244
+ const opts = {
245
+ prune: bool(args.flags, 'prune'),
246
+ pruneUnsafe: built.pruneUnsafe,
247
+ writeOnly,
248
+ };
249
+ if (!bool(args.flags, 'json')) {
250
+ // The plan, then the result. An apply that printed only its result would
251
+ // make the reader diff two commands' output to find out what it did.
252
+ process.stdout.write(renderPlan(built, opts));
253
+ process.stdout.write('\nApplying…\n\n');
254
+ }
255
+ const outcomes = await execute(chatly, built, opts);
256
+ if (bool(args.flags, 'json')) {
257
+ printJson({ outcomes, warnings: built.warnings });
258
+ }
259
+ else {
260
+ process.stdout.write(renderOutcomes(outcomes));
261
+ }
262
+ return outcomes.some((o) => o.state === 'failed' || o.state === 'skipped') ? 1 : 0;
263
+ }
264
+ /**
265
+ * Walk the plan and do it. Continue on failure; never cascade.
266
+ *
267
+ * Exported so `wac.spec.ts` can drive it with a scripted transport and assert
268
+ * on the requests that went over the wire — the shape CLAUDE.md insists on
269
+ * ("assert on the request, not the canned response"), since a fake transport
270
+ * that echoes whatever the caller sent agrees with the bug.
271
+ */
272
+ export async function execute(chatly, built, opts) {
273
+ const outcomes = [];
274
+ /** `type/key` → the id a create in THIS run returned. */
275
+ const refIds = new Map();
276
+ /** `type/key` that failed, so its dependents are skipped not attempted. */
277
+ const failed = new Set();
278
+ for (const item of built.items) {
279
+ const def = resourceDef(item.type);
280
+ if (def === undefined) {
281
+ continue;
282
+ }
283
+ const address = `${item.type}/${item.key}`;
284
+ if (item.action === 'noop') {
285
+ continue;
286
+ }
287
+ if (item.action === 'blocked') {
288
+ outcomes.push({ ...base(item), state: 'skipped', detail: item.reason, secrets: [] });
289
+ continue;
290
+ }
291
+ const blocker = item.dependsOn.find((d) => failed.has(d));
292
+ if (blocker !== undefined) {
293
+ outcomes.push({
294
+ ...base(item),
295
+ state: 'skipped',
296
+ detail: `${blocker} failed above, and this names it. Attempting it anyway would produce a ` +
297
+ 'second error about a missing id that points at the wrong thing.',
298
+ secrets: [],
299
+ });
300
+ failed.add(address);
301
+ continue;
302
+ }
303
+ const ops = writesFor(def, item, refIds, opts);
304
+ if (ops.length === 0) {
305
+ outcomes.push({
306
+ ...base(item),
307
+ state: 'kept',
308
+ detail: item.action === 'orphan'
309
+ ? opts.prune
310
+ ? def.remove === null
311
+ ? (def.removeBlocked ?? 'no DELETE route.')
312
+ : 'this type cannot be pruned safely on this run (see the warnings)'
313
+ : '`--prune` would delete it'
314
+ : undefined,
315
+ secrets: [],
316
+ });
317
+ continue;
318
+ }
319
+ const secrets = [];
320
+ let ok = true;
321
+ for (const op of ops) {
322
+ try {
323
+ const response = await chatly.request(op.method, op.path, op.body === undefined ? {} : { body: op.body });
324
+ secrets.push(...harvestSecrets(def, item, response));
325
+ const id = idOf(response, def);
326
+ if (id !== undefined) {
327
+ refIds.set(address, id);
328
+ }
329
+ }
330
+ catch (err) {
331
+ ok = false;
332
+ failed.add(address);
333
+ outcomes.push({
334
+ ...base(item),
335
+ state: 'failed',
336
+ detail: `${op.method} ${op.path} — ${err instanceof Error ? err.message : String(err)}`,
337
+ secrets,
338
+ });
339
+ break;
340
+ }
341
+ }
342
+ if (ok) {
343
+ outcomes.push({ ...base(item), state: 'applied', detail: undefined, secrets });
344
+ }
345
+ }
346
+ return outcomes;
347
+ }
348
+ function base(item) {
349
+ return { type: item.type, key: item.key, action: item.action };
350
+ }
351
+ /**
352
+ * The id out of a write response, for a reference a later section needs.
353
+ *
354
+ * Two levels, because `POST /v1/customer-cards` answers
355
+ * `{ card: { id }, secret }` rather than the card itself — the same envelope
356
+ * quirk that makes the secret sweep two levels deep.
357
+ */
358
+ function idOf(response, def) {
359
+ if (typeof response !== 'object' || response === null) {
360
+ return undefined;
361
+ }
362
+ const top = response;
363
+ const direct = top[def.idField];
364
+ if (typeof direct === 'string' && direct.length > 0) {
365
+ return direct;
366
+ }
367
+ for (const value of Object.values(top)) {
368
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
369
+ const nested = value[def.idField];
370
+ if (typeof nested === 'string' && nested.length > 0) {
371
+ return nested;
372
+ }
373
+ }
374
+ }
375
+ return undefined;
376
+ }
377
+ //# sourceMappingURL=workspace-as-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-as-code.js","sourceRoot":"","sources":["../../src/commands/workspace-as-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAmB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EACL,cAAc,EACd,cAAc,EACd,SAAS,GAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,KAAK,EAA+B,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAoB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAoB,MAAM,qBAAqB,CAAC;AAIpE,mDAAmD;AACnD,MAAM,aAAa,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,YAAY,CAAU,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,6EAA6E;AAE7E,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,6DAA6D;QAC7D,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9F,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,gFAAgF;QAC9E,gEAAgE;QAChE,oFAAoF,CACvF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,MAAyB,OAAO,CAAC,GAAG;IACjF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;IACtD,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACzE;;;;;;;;WAQG;QACH,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,gDAAgD;YACrD,sFAAsF;YACtF,wFAAwF;YACxF,yFAAyF;YACzF,uFAAuF;YACvF,8CAA8C;YAC9C,2BAA2B;YAC3B,iBAAiB,IAAI,2BAA2B;YAChD,0FAA0F;YAC1F,SAAS,IAAI,yBAAyB,CACzC,CAAC;IACJ,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,6EAA6E;AAE7E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAoB,EACpB,GAAgB;IAEhB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC3C,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QACxB,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,GAAmC,EAAE,CAAC;YAChD,IAAI,MAA0B,CAAC;YAC/B;;;;;eAKG;YACH,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC5C,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAgC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;oBACrF,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE;iBAC9C,CAAC,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;gBACjC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;gBAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;oBACrE,MAAM;gBACR,CAAC;gBACD,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAU,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAyC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAE7E,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,MAAoB,EAAE,IAAgB;IAC/D,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B;;;;;;;;OAQG;IACH,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QACnC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;IAElF,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;;;;OASG;IACH,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,cAAc,CAAC,MAAoB,EAAE,GAAgB;IAClE,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,CAAC,WAAW,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC;QACrC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,CACL,sDAAsD,GAAG,CAAC,SAAS,mBAAmB;QACtF,cAAc,EAAE,CAAC,WAAW,KAAK;QACjC,wFAAwF;QACxF,gDAAgD,CACjD,CAAC;AACJ,CAAC;AAED,6EAA6E;AAE7E,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,MAAoB,EAAE,IAAgB;IAChE,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QACnC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAiB;QACzB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC;QAChC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,SAAS;KACV,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QAC9B,yEAAyE;QACzE,qEAAqE;QACrE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAoB,EACpB,KAAW,EACX,IAAkB;IAElB,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,yDAAyD;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,2EAA2E;IAC3E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QAE3C,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG,IAAI,CAAC,IAAI,CAAC;gBACb,KAAK,EAAE,SAAS;gBAChB,MAAM,EACJ,GAAG,OAAO,yEAAyE;oBACnF,iEAAiE;gBACnE,OAAO,EAAE,EAAE;aACZ,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC;gBACZ,GAAG,IAAI,CAAC,IAAI,CAAC;gBACb,KAAK,EAAE,MAAM;gBACb,MAAM,EACJ,IAAI,CAAC,MAAM,KAAK,QAAQ;oBACtB,CAAC,CAAC,IAAI,CAAC,KAAK;wBACV,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI;4BACnB,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,IAAI,kBAAkB,CAAC;4BAC3C,CAAC,CAAC,kEAAkE;wBACtE,CAAC,CAAC,2BAA2B;oBAC/B,CAAC,CAAC,SAAS;gBACf,OAAO,EAAE,EAAE;aACZ,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAkB,EAAE,CAAC;QAClC,IAAI,EAAE,GAAG,IAAI,CAAC;QACd,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CACnC,EAAE,CAAC,MAAM,EACT,EAAE,CAAC,IAAI,EACP,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAC/C,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;gBACrD,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBAC/B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;oBACrB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,EAAE,GAAG,KAAK,CAAC;gBACX,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC;oBACZ,GAAG,IAAI,CAAC,IAAI,CAAC;oBACb,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,IAAI,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;oBACvF,OAAO;iBACR,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,EAAE,EAAE,CAAC;YACP,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,IAAI,CAAC,IAA2B;IACvC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,IAAI,CAAC,QAAiB,EAAE,GAAgB;IAC/C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,QAAmC,CAAC;IAChD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzE,MAAM,MAAM,GAAI,KAAiC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC/D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
package/dist/help.d.ts CHANGED
@@ -1,2 +1,26 @@
1
- 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\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\nTICKETS\n tickets list --status --queue\n tickets comments <id>\n tickets queues\n\nKNOWLEDGE + SEARCH\n search <query> Across contacts, conversations, messages, tickets, KB\n kb articles Help-centre articles\n kb article <slug>\n\nEVENTS\n events track <contact-id> <name>\n Fire a CDP event. --prop key=value, repeatable\n events list --contact-id\n\nWEBHOOKS\n webhooks deliveries --status\n webhooks redeliver <id>\n\nREPORTS\n reports overview --from --to\n reports agents\n reports sla\n\nWORKSPACE\n workspace settings\n workspace labels | inboxes | skills\n workspace team-members <team-id>\n channels list | channels get <id>\n billing usage <event-type> One meter over a window. --from --to\n billing plans\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/cli\n";
1
+ /**
2
+ * `--help`, and the one thing it has to be: complete.
3
+ *
4
+ * ── Why this is 22 sections and not 7 ─────────────────────────────────────
5
+ *
6
+ * It was 7. `run.ts`'s own docblock said a check "makes certain that every
7
+ * command documented in `--help` is reachable — a command with no help entry
8
+ * is a command nobody finds", and no such check existed: fifteen of the
9
+ * twenty-two command groups had never been mentioned here, among them `ai`,
10
+ * `billing`, `bot-routes`, `brands`, `customer-cards`, `docs-sources`,
11
+ * `email-templates`, `knowledge-gaps`, `macros` and `triggers`.
12
+ *
13
+ * A CLI's help IS its documentation. An undocumented command is an unshipped
14
+ * command, however complete its implementation — the same defect
15
+ * `check-endpoint-with-no-caller` exists for one layer down.
16
+ *
17
+ * `cli.spec.ts` now checks BOTH directions on every run: every key in
18
+ * `COMMANDS` appears here, and every command word here resolves through
19
+ * `COMMANDS` or `ALIASES`. The first half is what was missing; the second is
20
+ * what stops this file growing a promise the CLI does not keep.
21
+ *
22
+ * The convention the spec relies on: a command line starts with exactly two
23
+ * spaces and its first word is the command group.
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";
2
26
  //# sourceMappingURL=help.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,k6EAwEhB,CAAC"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,IAAI,8lMAgJhB,CAAC"}
package/dist/help.js CHANGED
@@ -1,3 +1,27 @@
1
+ /**
2
+ * `--help`, and the one thing it has to be: complete.
3
+ *
4
+ * ── Why this is 22 sections and not 7 ─────────────────────────────────────
5
+ *
6
+ * It was 7. `run.ts`'s own docblock said a check "makes certain that every
7
+ * command documented in `--help` is reachable — a command with no help entry
8
+ * is a command nobody finds", and no such check existed: fifteen of the
9
+ * twenty-two command groups had never been mentioned here, among them `ai`,
10
+ * `billing`, `bot-routes`, `brands`, `customer-cards`, `docs-sources`,
11
+ * `email-templates`, `knowledge-gaps`, `macros` and `triggers`.
12
+ *
13
+ * A CLI's help IS its documentation. An undocumented command is an unshipped
14
+ * command, however complete its implementation — the same defect
15
+ * `check-endpoint-with-no-caller` exists for one layer down.
16
+ *
17
+ * `cli.spec.ts` now checks BOTH directions on every run: every key in
18
+ * `COMMANDS` appears here, and every command word here resolves through
19
+ * `COMMANDS` or `ALIASES`. The first half is what was missing; the second is
20
+ * what stops this file growing a promise the CLI does not keep.
21
+ *
22
+ * The convention the spec relies on: a command line starts with exactly two
23
+ * spaces and its first word is the command group.
24
+ */
1
25
  export const HELP = `chatly — the Chatly command line
2
26
 
3
27
  USAGE
@@ -15,6 +39,9 @@ CONVERSATIONS
15
39
  conversations send <id> <body>
16
40
  Reply as the key's machine identity
17
41
  conversations unattended Open with no agent reply yet
42
+ conversations mood <id> Sentiment over the thread
43
+ conversations return-to-bot <id> <bot-id>
44
+ Give an open thread back to an assistant
18
45
 
19
46
  CONTACTS
20
47
  contacts list People in this workspace
@@ -22,38 +49,107 @@ CONTACTS
22
49
  contacts upsert --email --name --external-id --phone
23
50
  contacts tag <id> <tag> Add a tag
24
51
  contacts journey <id> Timeline: conversations, events, tickets
52
+ contacts cards <id> Customer-card data for this person
25
53
 
26
54
  TICKETS
27
55
  tickets list --status --queue
56
+ tickets get <id>
28
57
  tickets comments <id>
29
58
  tickets queues
59
+ tickets lineage <id> Merge and split history
60
+ tickets time <id> Time logged
61
+ tickets status-history <id>
30
62
 
31
63
  KNOWLEDGE + SEARCH
32
64
  search <query> Across contacts, conversations, messages, tickets, KB
33
65
  kb articles Help-centre articles
34
66
  kb article <slug>
67
+ kb collections
35
68
 
36
69
  EVENTS
37
70
  events track <contact-id> <name>
38
71
  Fire a CDP event. --prop key=value, repeatable
39
72
  events list --contact-id
40
73
 
41
- WEBHOOKS
74
+ BOTS + EXTERNAL AGENTS
75
+ bots list | get <id>
76
+ bots create --body. type:"external" answers with a secret, ONCE
77
+ bots update <id> --body
78
+ bots update-external <id> --body. webhookUrl, timeoutSeconds, fallbackMessage
79
+ bots rotate-secret <id> New signing secret, shown once. No overlap window
80
+ bots deliveries <id> The push ledger. --status pending|delivered|failed|dead
81
+ bots delivery <id> <delivery-id>
82
+ One delivery, with the exact signed payload
83
+ bots redeliver <id> <delivery-id>
84
+ Queue the recorded payload again, from attempt 0
85
+ bots test-delivery <id> Sign and POST a rehearsal payload; prints the response
86
+
87
+ ROUTING + AUTOMATION
88
+ bot-routes list | fields | create | update <id> | delete <id>
89
+ bot-routes resolve Dry-run the table. --body with a hypothetical visitor
90
+ triggers list | get <id> | upsert | delete <id>
91
+ brands list | get <id> | create | update <id> | delete <id>
92
+ macros list | get <id> | create | update <id> | delete <id>
93
+ email-templates templates | get <kind> | set <kind> | reset <kind>
94
+ knowledge-gaps list | triage <id>
95
+
96
+ INTEGRATIONS
42
97
  webhooks deliveries --status
98
+ webhooks delivery <id>
43
99
  webhooks redeliver <id>
100
+ webhooks endpoints Subscriptions, not traffic
101
+ webhooks events The subscribable event catalogue
102
+ webhooks schema-versions
103
+ webhooks create --url --event (repeatable). Answers with whsec_, once
104
+ webhooks pin <id> <version>
105
+ customer-cards list | create | update <id> | delete <id>
106
+ customer-cards rotate-secret <id>
107
+ Update your endpoint BEFORE calling this
108
+ docs-sources list | providers | discover | create | update <id> | delete <id>
109
+ docs-sources sync <id> --full re-reads every page
110
+ docs-sources subscribe <id> A refusal is a success: read the response
111
+ channels list | get <id> | adapters | create | update <id>
112
+ channels rotate-secret <id>
113
+
114
+ WORKSPACE AS CODE
115
+ plan Diff chatly.json against the live workspace. Reads only
116
+ apply Make the plan's changes. Never deletes unless told
117
+ --file <path> the document (- for stdin). Default: ./chatly.json
118
+ --prune also delete what the document omits
119
+ --write-only also send fields that cannot be read back
120
+ --exit-code plan only: exit 2 when there is drift
121
+
122
+ AI
123
+ ai providers | quota
124
+ ai add-provider BYOK. --body
125
+ ai test-provider <key>
126
+ ai tools | create-tool | update-tool <id> | delete-tool <id>
127
+ ai tone | set-tone | generate-tone <sample>
44
128
 
45
129
  REPORTS
46
- reports overview --from --to
47
- reports agents
48
- reports sla
130
+ reports overview --days
131
+ reports agents Means, not percentiles
132
+ reports conversations-by-day
133
+ reports sources | response-times | voice
134
+ reports attribution <dim> One of ten dimensions; an unknown one is refused
135
+ reports cohorts --weeks, NOT --days
136
+ reports themes --date. A daily snapshot; there is no regenerate
137
+ reports theme-conversations <theme-id>
138
+ reports teams | labels | sla
139
+ --from --to --days --group-by
140
+
141
+ BILLING
142
+ billing summary | plans | invoices
143
+ billing usage <event-type> One meter over a window. --from --to
144
+ billing usage-daily <event-type>
145
+ Dense: one row per UTC day, zeros included
146
+ billing usage-monthly --month
49
147
 
50
148
  WORKSPACE
51
149
  workspace settings
52
150
  workspace labels | inboxes | skills
53
151
  workspace team-members <team-id>
54
- channels list | channels get <id>
55
- billing usage <event-type> One meter over a window. --from --to
56
- billing plans
152
+ workspace key-scopes What a key may be granted
57
153
 
58
154
  RAW
59
155
  api <METHOD> <path> Any route, with auth, idempotency and retries
@@ -69,6 +165,6 @@ GLOBAL FLAGS
69
165
  --api-url <url> Point at another Chatly environment
70
166
  --help, --version
71
167
 
72
- Docs: https://chatlychat.com/docs/cli
168
+ Docs: https://chatlychat.com/docs/sdk-cli
73
169
  `;
74
170
  //# sourceMappingURL=help.js.map
package/dist/help.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwEnB,CAAC"}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJnB,CAAC"}
package/dist/run.d.ts CHANGED
@@ -7,6 +7,23 @@
7
7
  * errors are unhelpful, we feel it first.
8
8
  */
9
9
  import { ChatlyClient } from '@chatlychat/sdk-node';
10
+ import { type ParsedArgs } from './args.js';
11
+ /**
12
+ * Every authenticated command, by the word a person types.
13
+ *
14
+ * A table rather than a `switch`, for one reason that is worth the churn:
15
+ * `cli.spec.ts` can now assert that every key here appears in `--help` and
16
+ * that every command documented in `--help` is reachable. A command with no
17
+ * help entry is a command nobody finds; a help entry with no command is a
18
+ * promise the CLI breaks. The `switch` this replaced could be checked for
19
+ * neither.
20
+ *
21
+ * Singular aliases are listed explicitly rather than derived by stripping an
22
+ * `s`, so `kb`, `search`, `whoami` and `ai` cannot acquire a nonsense twin.
23
+ */
24
+ export declare const COMMANDS: Readonly<Record<string, (c: ChatlyClient, a: ParsedArgs) => Promise<number>>>;
25
+ /** Singular spellings, for the groups where typing one reads naturally. */
26
+ export declare const ALIASES: Readonly<Record<string, string>>;
10
27
  /**
11
28
  * How a client is made. Injectable for tests ONLY.
12
29
  *
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;AAsB1F;;;;;;;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,CAmFjB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAoBvE"}
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"}