conduyt 1.14.0 → 1.16.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.
Files changed (2) hide show
  1. package/dist/index.js +45 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readFileSync } from "node:fs";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { dirname, join } from "node:path";
5
5
  import { Command } from "commander";
@@ -1633,6 +1633,50 @@ ai
1633
1633
  .description("AI-recommended next actions for a user (defaults to you; other users need admin/owner)")
1634
1634
  .option("--user <id>", "user UUID")
1635
1635
  .action(run(async (client, opts) => client.get(`/api/v1/ai/next-actions${buildQuery({ userId: opts.user })}`)));
1636
+ ai
1637
+ .command("agenda")
1638
+ .description("Today's agenda for a user: calendar, callbacks, replies waiting, tasks due, new leads, follow-ups, quiet deals, with a brief on top")
1639
+ .option("--user <id>", "user UUID (admins/owners only; defaults to you)")
1640
+ .option("--no-narrative", "skip the AI-composed brief (returns the deterministic one; spends no AI budget)")
1641
+ .action(run(async (client, opts) => client.get(`/api/v1/ai/agenda${buildQuery({ userId: opts.user, narrative: opts.narrative === false ? "0" : undefined })}`)));
1642
+ ai
1643
+ .command("act <message>")
1644
+ .description("Copilot actions: plan what the copilot would do for a plain-language request (tasks, callbacks, notes, appointments, tags, deal moves, SMS/email drafts). Prints the resolved preview + confirmation token; --apply executes the ready ones through the same routes the UI uses. Appointments are never created (customer-facing) — the plan carries a hand-off link. Save the plan with --plan-out to apply, replay or resume it later with `ai act-apply`.")
1645
+ .option("--contact <id>", "contact UUID the request refers to ('this contact')")
1646
+ .option("--deal <id>", "deal UUID the request refers to ('this deal')")
1647
+ .option("--apply", "execute the ready actions immediately (drafts are never sent)")
1648
+ .option("--select <ids>", "with --apply: comma-separated action ids to apply (default: every ready action)")
1649
+ .option("--plan-out <file>", "write the plan (actions + confirmationToken) to a JSON file for `ai act-apply`")
1650
+ .action(run(async (client, message, opts) => {
1651
+ if (message.trim() === "")
1652
+ throw new Error("message must not be empty.");
1653
+ const section = opts.contact ? { type: "contact", id: opts.contact } : opts.deal ? { type: "deal", id: opts.deal } : undefined;
1654
+ const plan = (await client.post("/api/v1/ai/actions", { message, ...(section ? { section } : {}) }));
1655
+ const data = (plan.data ?? plan);
1656
+ if (opts.planOut)
1657
+ writeFileSync(opts.planOut, JSON.stringify({ actions: data.actions ?? [], confirmationToken: data.confirmationToken ?? null }, null, 2) + "\n");
1658
+ if (!opts.apply || !data.confirmationToken || !Array.isArray(data.actions) || !data.readyCount)
1659
+ return plan;
1660
+ const selectedIds = opts.select ? opts.select.split(",").map((v) => v.trim()).filter(Boolean) : undefined;
1661
+ const applied = await client.post("/api/v1/ai/actions/execute", { actions: data.actions, confirmationToken: data.confirmationToken, ...(selectedIds ? { selectedIds } : {}) });
1662
+ return { plan: data, applied };
1663
+ }));
1664
+ ai
1665
+ .command("act-apply <planFile>")
1666
+ .description("Apply a saved plan (from `ai act --plan-out`). Sending the same plan again replays the run — nothing runs twice. Results with inFlight:true were started but never confirmed (e.g. the connection dropped mid-apply): check the record, then re-run them explicitly with --resume.")
1667
+ .option("--select <ids>", "first apply only: comma-separated action ids to apply (default: every ready action); a replay must resend the same selection")
1668
+ .option("--resume <ids>", "comma-separated ids of inFlight actions to run again — only after checking the record and after the result's resumableAt (the earlier attempt can no longer be running); later actions wait behind an in-flight one")
1669
+ .action(run(async (client, planFile, opts) => {
1670
+ const raw = JSON.parse(readFileSync(planFile, "utf8"));
1671
+ if (!Array.isArray(raw.actions) || raw.actions.length === 0)
1672
+ throw new Error(`${planFile} has no actions.`);
1673
+ if (!raw.confirmationToken)
1674
+ throw new Error(`${planFile} has no confirmationToken (the plan had nothing ready to apply).`);
1675
+ const list = (v) => (v ? v.split(",").map((x) => x.trim()).filter(Boolean) : undefined);
1676
+ const selectedIds = list(opts.select);
1677
+ const resumeIds = list(opts.resume);
1678
+ return client.post("/api/v1/ai/actions/execute", { actions: raw.actions, confirmationToken: raw.confirmationToken, ...(selectedIds ? { selectedIds } : {}), ...(resumeIds ? { resumeIds } : {}) });
1679
+ }));
1636
1680
  ai
1637
1681
  .command("daily-brief")
1638
1682
  .description("Your AI daily brief (task-focused summary)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conduyt",
3
- "version": "1.14.0",
3
+ "version": "1.16.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",