conduyt 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -56,6 +56,25 @@ export class ConduytClient {
56
56
  del(path) {
57
57
  return this.request("DELETE", path);
58
58
  }
59
+ /** A POST whose body comes back as text (a CSV or XLSX export), not JSON. */
60
+ async postText(path, body) {
61
+ const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
62
+ const res = await fetch(url, {
63
+ method: "POST",
64
+ headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json" },
65
+ body: body === undefined ? undefined : JSON.stringify(body),
66
+ });
67
+ const text = await res.text();
68
+ if (!res.ok) {
69
+ let msg = text.slice(0, 500);
70
+ try {
71
+ msg = JSON.parse(text).error ?? msg;
72
+ }
73
+ catch { /* keep the raw text */ }
74
+ throw new Error(`Conduyt API ${res.status}: ${msg}`);
75
+ }
76
+ return { text, filename: res.headers.get("x-report-filename"), contentType: res.headers.get("content-type") };
77
+ }
59
78
  // Stream `ai chat`'s text/event-stream response to stdout as clean answer
60
79
  // text. The server frames SSE records as `data: {"text":"..."}\n\n`, ends
61
80
  // with `data: [DONE]\n\n`, and reports in-stream failures as
package/dist/index.js CHANGED
@@ -2221,6 +2221,159 @@ ringGroups
2221
2221
  // Smart Dialing priorities: agents dial them one lead at a time, top to
2222
2222
  // bottom. Dialing settings + reorder are admin-only in the API.
2223
2223
  // ---------------------------------------------------------------------------
2224
+ // ── Custom reports: the Lead Activity grid (reporting P1, 2026-09-10) ──────────────────────────────────────────────
2225
+ const reports = program.command("reports").description("Custom reports: the Lead Activity grid (rollups, custom fields, Smart View populations, CSV/XLSX export)");
2226
+ reports
2227
+ .command("fields <entity>")
2228
+ .description("The field catalogue for a report base: columns, per-lead rollups (contacts/deals) and the account's custom fields (cf:<key>)")
2229
+ .option("--kind <kind>", "only base | rollup | custom")
2230
+ .action(run(async (client, entity, opts) => {
2231
+ const res = (await client.get(`/api/v1/reports/custom/fields?entity=${encodeURIComponent(entity)}`));
2232
+ const fields = Array.isArray(res?.fields) ? res.fields : [];
2233
+ return opts.kind ? fields.filter((f) => f.kind === opts.kind) : fields;
2234
+ }));
2235
+ reports
2236
+ .command("list")
2237
+ .description("List saved custom reports (shared and your own) with their last-run status")
2238
+ .action(run(async (client) => client.get("/api/v1/reports/custom")));
2239
+ reports
2240
+ .command("create")
2241
+ .description("Create a saved report from a JSON definition (name, entity, columns, filters, sortBy, groupBy, groupBy2, aggregate, measureField, population: { smartViewId })")
2242
+ .requiredOption("--json <definition>", "the definition as JSON (or @file)")
2243
+ .action(run(async (client, opts) => {
2244
+ const raw = opts.json.startsWith("@") ? (await import("node:fs")).readFileSync(opts.json.slice(1), "utf8") : opts.json;
2245
+ const body = JSON.parse(raw);
2246
+ if (typeof body.name !== "string" || typeof body.entity !== "string" || !Array.isArray(body.columns)) {
2247
+ throw new Error("The definition needs name, entity and columns.");
2248
+ }
2249
+ return client.post("/api/v1/reports/custom", body);
2250
+ }));
2251
+ reports
2252
+ .command("run <id>")
2253
+ .description("Run a saved report: a page of rows, the total, the metric, the chart data and (with groupBy2) the grouped rows")
2254
+ .option("--page <n>", "page number", "1")
2255
+ .option("--per-page <n>", "rows per page (1-500)", "100")
2256
+ .action(run(async (client, id, opts) => {
2257
+ assertUuid(id, "report id");
2258
+ const params = new URLSearchParams({ page: String(Math.max(1, Number(opts.page) || 1)), per_page: String(Math.min(500, Math.max(1, Number(opts.perPage) || 100))) });
2259
+ return client.post(`/api/v1/reports/custom/${id}/run?${params.toString()}`, {});
2260
+ }));
2261
+ reports
2262
+ .command("export <id>")
2263
+ .description("Export every matching row (up to 50,000) as CSV or XLSX; prints to stdout or writes --out")
2264
+ .option("--format <format>", "csv | xlsx", "csv")
2265
+ .option("--out <file>", "write the file here instead of stdout")
2266
+ .action(async (id, opts) => {
2267
+ try {
2268
+ assertUuid(id, "report id");
2269
+ const format = opts.format === "xlsx" ? "xlsx" : "csv";
2270
+ const client = new ConduytClient();
2271
+ const { text, filename } = await client.postText(`/api/v1/reports/custom/${id}/export?format=${format}`, {});
2272
+ if (opts.out) {
2273
+ (await import("node:fs")).writeFileSync(opts.out, text);
2274
+ print({ written: opts.out, bytes: Buffer.byteLength(text), filename });
2275
+ }
2276
+ else {
2277
+ process.stdout.write(text);
2278
+ }
2279
+ }
2280
+ catch (err) {
2281
+ fail(err);
2282
+ }
2283
+ });
2284
+ // ── Reporting P2 (2026-09-10): scheduled delivery of saved reports ────────────────────────────────────────────────
2285
+ reports
2286
+ .command("schedules <id>")
2287
+ .description("The scheduled deliveries on a saved report (cadence, time, formats, recipients, next/last run)")
2288
+ .action(run(async (client, id) => { assertUuid(id, "report id"); return client.get(`/api/v1/reports/custom/${id}/subscriptions`); }));
2289
+ reports
2290
+ .command("schedule <id>")
2291
+ .description("Email a saved report on a schedule (runs with your visibility)")
2292
+ .requiredOption("--cadence <cadence>", "daily | weekly | monthly")
2293
+ .requiredOption("--to <emails>", "recipient addresses, comma-separated (inside or outside the workspace)")
2294
+ .option("--at <hh:mm>", "workspace-local time, 24h", "07:00")
2295
+ .option("--weekday <n>", "weekly: 0 = Sunday … 6 = Saturday")
2296
+ .option("--monthday <n>", "monthly: 1-28")
2297
+ .option("--formats <list>", "csv,xlsx,pdf", "csv")
2298
+ .option("--timezone <zone>", "IANA zone (defaults to the workspace timezone)")
2299
+ .option("--name <name>", "a label for the schedule")
2300
+ .option("--rolling", "only records created in the period since the last run")
2301
+ .option("--paused", "create it paused")
2302
+ .action(run(async (client, id, opts) => {
2303
+ assertUuid(id, "report id");
2304
+ const [hh, mm] = opts.at.split(":").map((x) => Number(x));
2305
+ if (!Number.isInteger(hh) || hh < 0 || hh > 23 || !Number.isInteger(mm) || mm < 0 || mm > 59)
2306
+ throw new Error("--at must be hh:mm (24h)");
2307
+ const body = {
2308
+ cadence: opts.cadence, hourLocal: hh, minuteLocal: mm,
2309
+ formats: opts.formats.split(",").map((f) => f.trim()).filter(Boolean),
2310
+ recipients: opts.to.split(",").map((e) => e.trim()).filter(Boolean).map((email) => ({ email })),
2311
+ rangeMode: opts.rolling ? "rolling" : "as_saved", enabled: !opts.paused,
2312
+ };
2313
+ if (opts.weekday !== undefined)
2314
+ body.weekday = Number(opts.weekday);
2315
+ if (opts.monthday !== undefined)
2316
+ body.monthday = Number(opts.monthday);
2317
+ if (opts.timezone)
2318
+ body.timezone = opts.timezone;
2319
+ if (opts.name)
2320
+ body.name = opts.name;
2321
+ return client.post(`/api/v1/reports/custom/${id}/subscriptions`, body);
2322
+ }));
2323
+ reports
2324
+ .command("schedule-update <sid>")
2325
+ .description("Change a schedule (only the flags you pass change); --pause / --resume toggle it")
2326
+ .option("--cadence <cadence>", "daily | weekly | monthly")
2327
+ .option("--to <emails>", "replace the recipients, comma-separated")
2328
+ .option("--at <hh:mm>", "workspace-local time, 24h")
2329
+ .option("--weekday <n>").option("--monthday <n>").option("--formats <list>").option("--timezone <zone>").option("--name <name>")
2330
+ .option("--rolling").option("--as-saved").option("--pause").option("--resume")
2331
+ .action(run(async (client, sid, opts) => {
2332
+ assertUuid(sid, "schedule id");
2333
+ const body = {};
2334
+ if (typeof opts.cadence === "string")
2335
+ body.cadence = opts.cadence;
2336
+ if (typeof opts.to === "string")
2337
+ body.recipients = opts.to.split(",").map((e) => e.trim()).filter(Boolean).map((email) => ({ email }));
2338
+ if (typeof opts.at === "string") {
2339
+ const [hh, mm] = opts.at.split(":").map((x) => Number(x));
2340
+ body.hourLocal = hh;
2341
+ body.minuteLocal = mm;
2342
+ }
2343
+ if (typeof opts.weekday === "string")
2344
+ body.weekday = Number(opts.weekday);
2345
+ if (typeof opts.monthday === "string")
2346
+ body.monthday = Number(opts.monthday);
2347
+ if (typeof opts.formats === "string")
2348
+ body.formats = opts.formats.split(",").map((f) => f.trim()).filter(Boolean);
2349
+ if (typeof opts.timezone === "string")
2350
+ body.timezone = opts.timezone;
2351
+ if (typeof opts.name === "string")
2352
+ body.name = opts.name;
2353
+ if (opts.rolling)
2354
+ body.rangeMode = "rolling";
2355
+ if (opts.asSaved)
2356
+ body.rangeMode = "as_saved";
2357
+ if (opts.pause)
2358
+ body.enabled = false;
2359
+ if (opts.resume)
2360
+ body.enabled = true;
2361
+ if (Object.keys(body).length === 0)
2362
+ throw new Error("Pass at least one change.");
2363
+ return client.patch(`/api/v1/reports/subscriptions/${sid}`, body);
2364
+ }));
2365
+ reports
2366
+ .command("schedule-delete <sid>")
2367
+ .description("Remove a schedule (past deliveries stay downloadable until they expire)")
2368
+ .action(run(async (client, sid) => { assertUuid(sid, "schedule id"); return client.del(`/api/v1/reports/subscriptions/${sid}`); }));
2369
+ reports
2370
+ .command("schedule-send <sid>")
2371
+ .description("Build and email a schedule now (one manual delivery)")
2372
+ .action(run(async (client, sid) => { assertUuid(sid, "schedule id"); return client.post(`/api/v1/reports/subscriptions/${sid}/run`, {}); }));
2373
+ reports
2374
+ .command("deliveries <sid>")
2375
+ .description("The delivery history of a schedule with download URLs")
2376
+ .action(run(async (client, sid) => { assertUuid(sid, "schedule id"); return client.get(`/api/v1/reports/subscriptions/${sid}/deliveries`); }));
2224
2377
  const smartViews = program.command("smart-views").description("Smart Views and their Smart Dialing priorities");
2225
2378
  smartViews
2226
2379
  .command("list")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conduyt",
3
- "version": "1.22.0",
3
+ "version": "1.24.0",
4
4
  "description": "Command-line interface for Conduyt CRM — manage contacts, deals, pipelines, and run insight queries from your terminal.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",