@dench.com/cli 3.6.4-staging.377 → 3.6.6-staging.386

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/dench.ts CHANGED
@@ -32,7 +32,6 @@ import { cliVersion } from "./lib/cli-version";
32
32
  import { denchConfigDirectory } from "./lib/config-path.mjs";
33
33
  import { resolveOrganizationBySelector } from "./lib/organizationSelector";
34
34
  import { backendErrorText } from "./lib/public-error";
35
- import { normalizeUnipileToolkitSlug } from "./lib/unipile-toolkits";
36
35
  import { formatApprovalOpenMessage, openUrl } from "./openUrl";
37
36
  import {
38
37
  explicitSessionKeyInput,
@@ -176,6 +175,9 @@ const api = {
176
175
  ),
177
176
  },
178
177
  agentConfig: {
178
+ workspaceContext: makeFunctionReference<"query">(
179
+ "functions/agentConfig:workspaceContext",
180
+ ),
179
181
  workspaceInstructions: makeFunctionReference<"query">(
180
182
  "functions/agentConfig:workspaceInstructions",
181
183
  ),
@@ -465,6 +467,7 @@ Usage:
465
467
  dench logout [session-key-or-workspace-slug] [--session <key-or-scope>] [--host <host>] [--all] [--json]
466
468
  dench backend [show|set|clear] [<production|staging|local|<url>>] [--json]
467
469
  dench context [--instructions] [--json]
470
+ dench context --sections organisation,user,memory [--json]
468
471
  dench instructions [--json]
469
472
  dench status [--mine|--self] [--json]
470
473
  dench memory search "query" [--limit 8] [--json]
@@ -742,6 +745,7 @@ function contextHelp() {
742
745
 
743
746
  Usage:
744
747
  dench context [--instructions] [--json]
748
+ dench context --sections organisation,user,memory [--json]
745
749
  dench instructions [--json]
746
750
 
747
751
  Shows the current workspace, current agent, assigned tasks, pending approvals
@@ -3222,19 +3226,22 @@ function formatContext(context: JsonRecord) {
3222
3226
 
3223
3227
  async function buildWorkspaceInstructionsContext(
3224
3228
  runtime: Awaited<ReturnType<typeof getRuntime>>,
3229
+ sections?: string[],
3225
3230
  ) {
3226
3231
  if (runtime.mode === "dev") {
3227
3232
  return (await runtime.client.query(
3228
3233
  api.functions.agentConfig.devWorkspaceInstructions,
3229
- runtime.workspaceArgs,
3234
+ { ...runtime.workspaceArgs, ...(sections ? { sections } : {}) },
3230
3235
  )) as JsonRecord;
3231
3236
  }
3232
3237
  if (runtime.mode !== "session" && runtime.mode !== "apiKey") {
3233
3238
  throw loginRequiredError("dench context --instructions");
3234
3239
  }
3235
3240
  return (await runtime.client.query(
3236
- api.functions.agentConfig.workspaceInstructions,
3237
- { sessionToken: runtime.sessionToken },
3241
+ sections
3242
+ ? api.functions.agentConfig.workspaceContext
3243
+ : api.functions.agentConfig.workspaceInstructions,
3244
+ { sessionToken: runtime.sessionToken, ...(sections ? { sections } : {}) },
3238
3245
  )) as JsonRecord;
3239
3246
  }
3240
3247
 
@@ -4452,18 +4459,22 @@ async function main() {
4452
4459
  if (command === "crm") {
4453
4460
  const subArgs = stripRuntimeFlags(args.slice(args.indexOf("crm") + 1));
4454
4461
  const sub = subArgs[0];
4462
+ const { runCrmCommand, isCrmReadHelpRequest } = await import("./crm");
4455
4463
  // Short-circuit help so users don't need a session to read the
4456
4464
  // surface. The crm dispatcher's own help resolves --json + the
4457
4465
  // subcommand list inline.
4458
- if (!sub || sub === "help" || sub === "--help") {
4459
- const { runCrmCommand } = await import("./crm");
4466
+ if (
4467
+ !sub ||
4468
+ sub === "help" ||
4469
+ sub === "--help" ||
4470
+ isCrmReadHelpRequest(subArgs)
4471
+ ) {
4460
4472
  // runCrmCommand only needs `convex` for actual queries; help
4461
4473
  // doesn't touch it. Pass a minimal stub.
4462
4474
  // biome-ignore lint/suspicious/noExplicitAny: harmless help-only stub
4463
4475
  await runCrmCommand({ convex: {} as any, args: subArgs });
4464
4476
  return;
4465
4477
  }
4466
- const { runCrmCommand } = await import("./crm");
4467
4478
  const runtime = await getRuntime();
4468
4479
  // CRM is org-scoped — accept either an agent session token
4469
4480
  // (`dch_agent_*` from `dench signin`) or a unified Dench API key
@@ -4801,7 +4812,14 @@ async function main() {
4801
4812
  | Awaited<ReturnType<typeof resolveGatewayCommandAuth>>
4802
4813
  | undefined;
4803
4814
  try {
4804
- gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench email");
4815
+ if (
4816
+ subArgs[0] !== "draft" &&
4817
+ !subArgs.some(
4818
+ (arg) => arg === "--mailbox" || arg.startsWith("--mailbox="),
4819
+ )
4820
+ ) {
4821
+ gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench email");
4822
+ }
4805
4823
  } catch {
4806
4824
  gatewayAuth = undefined;
4807
4825
  }
@@ -4882,35 +4900,16 @@ async function main() {
4882
4900
  if (argsIndex !== -1) parseJson(filteredSubArgs[argsIndex + 1]);
4883
4901
  }
4884
4902
  const runtime = await getRuntime();
4885
- const isSlackConnect =
4886
- sub === "connect" &&
4887
- ["slack", "slackbot"].includes(
4888
- (filteredSubArgs[1] ?? "").trim().toLowerCase(),
4889
- );
4890
- const isUnipileCommand =
4891
- (sub === "connect" || sub === "status") &&
4892
- normalizeUnipileToolkitSlug(filteredSubArgs[1] ?? "") !== null;
4893
- let gatewayAuth: GatewayCommandAuth | null = null;
4894
- let gatewayAuthError: string | undefined;
4895
- if (!isSlackConnect && !isUnipileCommand) {
4896
- try {
4897
- gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench tool");
4898
- } catch (error) {
4899
- if (sub !== "status") throw error;
4900
- gatewayAuthError = gatewayAuthFailureReason(error);
4901
- }
4902
- }
4903
4903
  await runToolCommand({
4904
4904
  args: filteredSubArgs,
4905
4905
  jsonOutput: json,
4906
- gatewayAuthError,
4907
- ...(gatewayAuth
4908
- ? {
4909
- bearerToken: gatewayAuth.bearerToken,
4910
- gatewayBaseUrl: gatewayAuth.gatewayBaseUrl,
4911
- gatewayHeaders: gatewayAuth.gatewayHeaders,
4912
- }
4913
- : {}),
4906
+ resolveGatewayAuth: async () => {
4907
+ try {
4908
+ return await resolveGatewayCommandAuth(runtime, "dench tool");
4909
+ } catch (error) {
4910
+ return { gatewayAuthError: gatewayAuthFailureReason(error) };
4911
+ }
4912
+ },
4914
4913
  ...unipileQueryAuth(runtime),
4915
4914
  ...(runtime.mode !== "dev"
4916
4915
  ? {
@@ -5261,6 +5260,44 @@ async function main() {
5261
5260
  return;
5262
5261
  }
5263
5262
 
5263
+ if (command === "context" && args.includes("--sections")) {
5264
+ const raw = args[args.indexOf("--sections") + 1];
5265
+ const sections = raw
5266
+ ?.split(",")
5267
+ .map((section) => section.trim().toLowerCase())
5268
+ .filter(Boolean);
5269
+ const allowed = [
5270
+ "identity",
5271
+ "organisation",
5272
+ "user",
5273
+ "memory",
5274
+ "rules",
5275
+ "tools",
5276
+ ];
5277
+ if (
5278
+ !sections?.length ||
5279
+ sections.some((section) => !allowed.includes(section))
5280
+ )
5281
+ throw new Error(
5282
+ `Usage: dench context --sections ${allowed.join(",")} [--json]`,
5283
+ );
5284
+ const context = await buildWorkspaceInstructionsContext(runtime, [
5285
+ ...new Set(sections),
5286
+ ]);
5287
+ const documents = Array.isArray(context.documents)
5288
+ ? (context.documents as Array<{ name: string; content?: string }>)
5289
+ : [];
5290
+ print(
5291
+ json
5292
+ ? context
5293
+ : documents
5294
+ .filter((doc) => doc.content !== undefined)
5295
+ .map((doc) => `## ${doc.name}\n${doc.content || "(empty)"}`)
5296
+ .join("\n\n"),
5297
+ );
5298
+ return;
5299
+ }
5300
+
5264
5301
  if (command === "context" && args.includes("--instructions")) {
5265
5302
  const instructions = await buildWorkspaceInstructionsContext(runtime);
5266
5303
  print(
package/email.ts CHANGED
@@ -1,7 +1,15 @@
1
- import { readFile } from "node:fs/promises";
1
+ import { createHash, createHmac, randomUUID } from "node:crypto";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { basename, extname, join } from "node:path";
2
4
  import type { ConvexHttpClient } from "convex/browser";
3
5
  import { makeFunctionReference } from "convex/server";
4
- import { getFlag, hasFlag, parseJson } from "./lib/cli-args";
6
+ import {
7
+ assertNoUnknownFlags,
8
+ getFlag,
9
+ hasFlag,
10
+ parseJson,
11
+ } from "./lib/cli-args";
12
+ import { denchConfigDirectory } from "./lib/config-path.mjs";
5
13
 
6
14
  type EmailCliContext = {
7
15
  convex: ConvexHttpClient;
@@ -358,6 +366,13 @@ export function emailHelp() {
358
366
  console.log(`dench email — outbound email from a connected inbox (or Dench Emailing Service)
359
367
 
360
368
  Usage:
369
+ dench email draft create --to <email> --subject <subject> --text <body> [--mailbox <id/email>] [--request-id <id>] [--json]
370
+ dench email draft show <id> [--json]
371
+ dench email draft update|send <id> --revision <n> [--json]
372
+ dench email draft attach <id> --revision <n> --file <path> [--content-type <mime>] [--json] # up to 5 MB/file
373
+ dench email draft signature <id> [--json] # read signature HTML; insert visibly into the body
374
+ # Identical native create/send invocations reuse a saved request ID. Use --request-id <new-id> for another identical email.
375
+ dench email send --mailbox <id/email> --to <email> --subject <subject> --text <body> [--request-id <id>] [--json]
361
376
  dench email identity verify --from founder@example.com [--private] [--json]
362
377
  dench email identity verify --domain example.com [--from founder@example.com] [--private] [--json]
363
378
  dench email identity list [--domain example.com] [--json]
@@ -432,11 +447,20 @@ Email + LinkedIn multichannel sequences (see \`dench campaign\` — the fuller s
432
447
  }
433
448
 
434
449
  export async function runEmailCommand(ctx: EmailCliContext): Promise<void> {
450
+ ctx.args = ctx.args.flatMap((arg) => {
451
+ const split = arg.startsWith("--") ? arg.indexOf("=") : -1;
452
+ return split > 2 ? [arg.slice(0, split), arg.slice(split + 1)] : [arg];
453
+ });
454
+ ctx.jsonOutput = hasFlag(ctx.args, "--json") || ctx.jsonOutput;
435
455
  const group = ctx.args.shift();
436
456
  if (!group || group === "help" || group === "--help" || group === "-h") {
437
457
  emailHelp();
438
458
  return;
439
459
  }
460
+ if (group === "draft") {
461
+ await runDraft(ctx);
462
+ return;
463
+ }
440
464
  if (group === "identity") {
441
465
  await runIdentity(ctx);
442
466
  return;
@@ -500,6 +524,17 @@ function parseAddressList(
500
524
  }
501
525
 
502
526
  async function runSend(ctx: EmailCliContext) {
527
+ if (ctx.args.includes("--mailbox")) {
528
+ const content = {
529
+ ...(await draftContent(ctx)),
530
+ mailbox: requiredFlag(ctx.args, "--mailbox"),
531
+ threadId: getFlag(ctx.args, "--thread") ?? process.env.DENCH_THREAD_ID,
532
+ mode: "send",
533
+ };
534
+ const payload = await createNativeEmail(ctx, content);
535
+ out(ctx, payload, JSON.stringify(payload, null, 2));
536
+ return;
537
+ }
503
538
  const from = requiredFlag(ctx.args, "--from");
504
539
  const to = parseAddressList(requiredFlag(ctx.args, "--to"));
505
540
  if (to.length === 0) {
@@ -540,6 +575,176 @@ async function runSend(ctx: EmailCliContext) {
540
575
  );
541
576
  }
542
577
 
578
+ /** Persist before HTTP. Identical invocations recover the same request even
579
+ * after the CLI process dies; an explicit new --request-id starts another email. */
580
+ async function createNativeEmail(ctx: EmailCliContext, content: JsonRecord) {
581
+ let requestId = getFlag(ctx.args, "--request-id");
582
+ assertEmailArgs(ctx);
583
+ if (!requestId) {
584
+ // The credential keys the receipt fingerprint; it is never serialized into
585
+ // receipt data. Different sessions must not reuse one another's request IDs.
586
+ const fingerprint = ctx.sessionToken
587
+ ? createHmac("sha256", ctx.sessionToken)
588
+ : createHash("sha256");
589
+ const key = fingerprint
590
+ .update(JSON.stringify([ctx.convex.url, content]))
591
+ .digest("hex");
592
+ const directory = join(denchConfigDirectory(), "email-requests");
593
+ await mkdir(directory, { recursive: true, mode: 0o700 });
594
+ const path = join(directory, `${key}.json`);
595
+ const proposed = randomUUID();
596
+ try {
597
+ await writeFile(path, JSON.stringify({ requestId: proposed }), {
598
+ flag: "wx",
599
+ mode: 0o600,
600
+ });
601
+ } catch (error) {
602
+ if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
603
+ }
604
+ const saved = JSON.parse(await readFile(path, "utf8")) as {
605
+ requestId: string;
606
+ };
607
+ if (typeof saved.requestId !== "string" || !saved.requestId)
608
+ throw new EmailCliError("Invalid local email request receipt");
609
+ requestId = saved.requestId;
610
+ }
611
+ return await callMutation(ctx, "functions/emailDrafts:create", {
612
+ ...content,
613
+ requestId,
614
+ });
615
+ }
616
+
617
+ function assertEmailArgs(ctx: EmailCliContext) {
618
+ assertNoUnknownFlags(ctx.args, "dench email");
619
+ if (ctx.args.length)
620
+ throw new EmailCliError(`Unexpected argument: ${ctx.args[0]}`);
621
+ }
622
+
623
+ function draftIdArg(ctx: EmailCliContext) {
624
+ const positional =
625
+ ctx.args[0] && !ctx.args[0].startsWith("--") ? ctx.args.shift() : undefined;
626
+ return positional ?? requiredFlag(ctx.args, "--draft");
627
+ }
628
+
629
+ function revisionArg(ctx: EmailCliContext) {
630
+ const revision = Number(requiredFlag(ctx.args, "--revision"));
631
+ if (!Number.isSafeInteger(revision) || revision < 1)
632
+ throw new EmailCliError(
633
+ "--revision must be a positive integer from draft show",
634
+ );
635
+ return revision;
636
+ }
637
+
638
+ async function draftContent(ctx: EmailCliContext) {
639
+ const to = getFlag(ctx.args, "--to");
640
+ const cc = getFlag(ctx.args, "--cc");
641
+ const bcc = getFlag(ctx.args, "--bcc");
642
+ const subject = getFlag(ctx.args, "--subject");
643
+ const htmlBody = await readTextFlag(ctx.args, "--html", "--html-file");
644
+ const textBody = await readTextFlag(ctx.args, "--text", "--text-file");
645
+ return {
646
+ ...(to !== undefined ? { to: parseAddressList(to) } : {}),
647
+ ...(cc !== undefined ? { cc: parseAddressList(cc) } : {}),
648
+ ...(bcc !== undefined ? { bcc: parseAddressList(bcc) } : {}),
649
+ ...(subject !== undefined ? { subject } : {}),
650
+ ...(htmlBody !== undefined ? { htmlBody } : {}),
651
+ ...(textBody !== undefined ? { textBody } : {}),
652
+ };
653
+ }
654
+
655
+ async function runDraft(ctx: EmailCliContext) {
656
+ const sub = ctx.args.shift();
657
+ let result: unknown;
658
+ if (sub === "create") {
659
+ result = await createNativeEmail(ctx, {
660
+ ...(await draftContent(ctx)),
661
+ mailbox: getFlag(ctx.args, "--mailbox"),
662
+ threadId: getFlag(ctx.args, "--thread") ?? process.env.DENCH_THREAD_ID,
663
+ });
664
+ } else if (sub === "show" || sub === "signature") {
665
+ const draftId = draftIdArg(ctx);
666
+ assertEmailArgs(ctx);
667
+ result =
668
+ sub === "show"
669
+ ? await callQuery(ctx, "functions/emailDrafts:get", { draftId })
670
+ : await callAction(ctx, "functions/emailDraftsNode:loadSignature", {
671
+ draftId,
672
+ });
673
+ } else if (sub === "update" || sub === "send") {
674
+ const draftId = draftIdArg(ctx);
675
+ const expectedRevision = revisionArg(ctx);
676
+ const args =
677
+ sub === "update"
678
+ ? {
679
+ draftId,
680
+ expectedRevision,
681
+ patch: {
682
+ ...(await draftContent(ctx)),
683
+ mailboxAccountId: getFlag(ctx.args, "--mailbox"),
684
+ },
685
+ }
686
+ : {
687
+ draftId,
688
+ expectedRevision,
689
+ requestId: getFlag(ctx.args, "--request-id"),
690
+ };
691
+ assertEmailArgs(ctx);
692
+ result = await callMutation(ctx, `functions/emailDrafts:${sub}`, args);
693
+ } else if (sub === "attach") {
694
+ const draftId = draftIdArg(ctx);
695
+ const expectedRevision = revisionArg(ctx);
696
+ const file = requiredFlag(ctx.args, "--file");
697
+ const contentType =
698
+ getFlag(ctx.args, "--content-type") ??
699
+ (
700
+ {
701
+ ".txt": "text/plain",
702
+ ".csv": "text/csv",
703
+ ".pdf": "application/pdf",
704
+ ".png": "image/png",
705
+ ".jpg": "image/jpeg",
706
+ ".jpeg": "image/jpeg",
707
+ ".json": "application/json",
708
+ ".html": "text/html",
709
+ } as Record<string, string>
710
+ )[extname(file).toLowerCase()] ??
711
+ "application/octet-stream";
712
+ assertEmailArgs(ctx);
713
+ const bytes = await readFile(file);
714
+ if (bytes.length > 5 * 1024 * 1024)
715
+ throw new EmailCliError("Attachments can be up to 5 MB each");
716
+ const draft = (await callQuery(ctx, "functions/emailDrafts:get", {
717
+ draftId,
718
+ })) as { revision: number; attachments: unknown[]; canEdit: boolean };
719
+ if (draft.revision !== expectedRevision)
720
+ throw new EmailCliError("Draft changed. Refresh before attaching a file");
721
+ if (!draft.canEdit) throw new EmailCliError("This draft is read-only");
722
+ const attachment = await callAction(
723
+ ctx,
724
+ "functions/emailDraftsNode:uploadAttachment",
725
+ {
726
+ draftId,
727
+ name: basename(file),
728
+ contentType,
729
+ contentBase64: bytes.toString("base64"),
730
+ },
731
+ );
732
+ result = await callMutation(ctx, "functions/emailDrafts:update", {
733
+ draftId,
734
+ expectedRevision,
735
+ patch: { attachments: [...draft.attachments, attachment] },
736
+ });
737
+ } else if (sub === "senders") {
738
+ assertEmailArgs(ctx);
739
+ result = await callQuery(ctx, "functions/emailDrafts:listSenders", {});
740
+ } else {
741
+ throw new EmailCliError(
742
+ "Usage: dench email draft create|show|update|send|senders|attach|signature. update/send/attach require --revision from draft show. attach: --file <path> [--content-type <mime>]. create: --to --subject --text/--html [--mailbox <id/email>] [--request-id <stable-id>] [--thread <chat-id>].",
743
+ );
744
+ }
745
+ out(ctx, result, JSON.stringify(result, null, 2));
746
+ }
747
+
543
748
  async function runMessage(ctx: EmailCliContext) {
544
749
  const sub = ctx.args.shift();
545
750
  if (sub === "status") {
@@ -31,6 +31,42 @@ import {
31
31
  MIN_WITHDRAW_AFTER_HOURS,
32
32
  } from "./campaign-steps";
33
33
 
34
+ const nativeEmailRecipient = z.object({
35
+ email: z.string(),
36
+ name: z.string().optional(),
37
+ });
38
+ const nativeEmailAttachment = z.object({
39
+ storageId: z.string(),
40
+ name: z.string(),
41
+ contentType: z.string(),
42
+ size: z.number(),
43
+ });
44
+ const nativeEmailContent = {
45
+ to: z.array(nativeEmailRecipient).optional(),
46
+ cc: z.array(nativeEmailRecipient).optional(),
47
+ bcc: z.array(nativeEmailRecipient).optional(),
48
+ subject: z.string().optional(),
49
+ htmlBody: z.string().optional(),
50
+ textBody: z.string().optional(),
51
+ attachments: z.array(nativeEmailAttachment).optional(),
52
+ };
53
+ const nativeEmailCreate = z.object({
54
+ organizationId: z.string().optional(),
55
+ threadId: z.string().optional(),
56
+ mailbox: z.string().optional(),
57
+ requestId: z.string(),
58
+ ...nativeEmailContent,
59
+ });
60
+ const nativeEmailReceipt = z
61
+ .object({
62
+ ok: z.boolean(),
63
+ kind: z.literal("email"),
64
+ draftId: z.string(),
65
+ syncStatus: z.string(),
66
+ revision: z.number(),
67
+ })
68
+ .passthrough();
69
+
34
70
  // ---------------------------------------------------------------------------
35
71
  // Shared enums + fragments (mirror convex validators)
36
72
  // ---------------------------------------------------------------------------
@@ -1786,7 +1822,11 @@ const toolSearchResponse = z
1786
1822
  session: z
1787
1823
  .object({ id: z.string() })
1788
1824
  .passthrough()
1825
+ .optional()
1789
1826
  .describe("Tool-router session; reuse session.id for follow-up calls."),
1827
+ items: z.array(z.record(z.string(), z.unknown())).optional(),
1828
+ nativeAvailable: z.boolean().optional(),
1829
+ available: z.boolean().optional(),
1790
1830
  execution_ref_version: z.number().optional(),
1791
1831
  })
1792
1832
  .passthrough()
@@ -2022,13 +2062,27 @@ const imageEdit = imageGenerate.extend({
2022
2062
  mask_base64: z.string().optional().describe("Optional base64 mask image."),
2023
2063
  });
2024
2064
 
2025
- const composioConnect = z.object({
2026
- toolkit: z
2027
- .string()
2028
- .min(1)
2029
- .describe("Toolkit slug, e.g. github, gmail, stripe."),
2030
- callback_url: z.string().optional().describe("Optional OAuth callback URL."),
2031
- });
2065
+ const composioConnect = z
2066
+ .object({
2067
+ toolkit: z
2068
+ .string()
2069
+ .min(1)
2070
+ .optional()
2071
+ .describe("Toolkit slug, e.g. github, gmail, stripe."),
2072
+ toolkit_slug: z.string().min(1).optional(),
2073
+ callback_url: z
2074
+ .string()
2075
+ .optional()
2076
+ .describe("Optional OAuth callback URL."),
2077
+ returnTo: z
2078
+ .string()
2079
+ .optional()
2080
+ .describe("Native OAuth return path within the workspace."),
2081
+ })
2082
+ .refine((value) => Boolean(value.toolkit || value.toolkit_slug), {
2083
+ message: "A toolkit is required.",
2084
+ path: ["toolkit"],
2085
+ });
2032
2086
 
2033
2087
  const composioToolSearch = z.object({
2034
2088
  queries: z
@@ -2039,7 +2093,13 @@ const composioToolSearch = z.object({
2039
2093
  }),
2040
2094
  )
2041
2095
  .min(1)
2042
- .max(7),
2096
+ .max(7)
2097
+ .optional(),
2098
+ query: z.string().min(1).optional(),
2099
+ toolkit: z.string().min(1).optional(),
2100
+ toolkit_slug: z.string().min(1).optional(),
2101
+ limit: z.number().int().min(1).max(100).optional(),
2102
+ important: z.boolean().optional(),
2043
2103
  session: z
2044
2104
  .object({ id: z.string().optional(), generate_id: z.boolean().optional() })
2045
2105
  .optional(),
@@ -2064,6 +2124,8 @@ const composioToolRun = z.object({
2064
2124
  .optional()
2065
2125
  .describe("Tool arguments object."),
2066
2126
  account: z.string().optional(),
2127
+ connected_account_id: z.string().optional(),
2128
+ approvalId: z.string().optional(),
2067
2129
  });
2068
2130
 
2069
2131
  /**
@@ -3315,8 +3377,47 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
3315
3377
  }),
3316
3378
 
3317
3379
  // Workspace
3380
+ "workspace.context.sections": z.object({
3381
+ organizationId: z.string().optional(),
3382
+ sections: z
3383
+ .array(
3384
+ z.enum([
3385
+ "identity",
3386
+ "organisation",
3387
+ "user",
3388
+ "memory",
3389
+ "rules",
3390
+ "tools",
3391
+ ]),
3392
+ )
3393
+ .optional(),
3394
+ }),
3395
+ "email.drafts.create": nativeEmailCreate,
3396
+ "email.native.send": nativeEmailCreate,
3397
+ "email.drafts.get": z.object({ draftId: z.string() }),
3398
+ "email.drafts.senders": z.object({ organizationId: z.string().optional() }),
3399
+ "email.drafts.update": z.object({
3400
+ draftId: z.string(),
3401
+ expectedRevision: z.number().int().nonnegative(),
3402
+ patch: z.object({
3403
+ mailboxAccountId: z.string().optional(),
3404
+ ...nativeEmailContent,
3405
+ }),
3406
+ }),
3407
+ "email.drafts.send": z.object({
3408
+ draftId: z.string(),
3409
+ expectedRevision: z.number().int().nonnegative(),
3410
+ requestId: z.string().optional(),
3411
+ }),
3412
+ "email.drafts.upload": z.object({
3413
+ draftId: z.string(),
3414
+ name: z.string(),
3415
+ contentType: z.string(),
3416
+ contentBase64: z.string(),
3417
+ }),
3418
+ "email.drafts.signature": z.object({ draftId: z.string() }),
3318
3419
  "workspace.context": noInput,
3319
- "workspace.instructions": noInput,
3420
+ "workspace.instructions": z.object({ organizationId: z.string().optional() }),
3320
3421
  "workspace.status": noInput,
3321
3422
  "workspace.agents": noInput,
3322
3423
  "workspace.approvals.list": noInput,
@@ -5055,6 +5156,15 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
5055
5156
  }),
5056
5157
 
5057
5158
  // Workspace orientation
5159
+ "workspace.context.sections": z.object({}).passthrough(),
5160
+ "email.drafts.create": nativeEmailReceipt,
5161
+ "email.drafts.get": nativeEmailReceipt,
5162
+ "email.drafts.update": nativeEmailReceipt,
5163
+ "email.drafts.send": nativeEmailReceipt,
5164
+ "email.native.send": nativeEmailReceipt,
5165
+ "email.drafts.senders": z.array(z.object({}).passthrough()),
5166
+ "email.drafts.upload": nativeEmailAttachment,
5167
+ "email.drafts.signature": z.object({}).passthrough(),
5058
5168
  "workspace.context": workspaceStatusPayload,
5059
5169
  "workspace.instructions": workspaceInstructionsResponse,
5060
5170
  "workspace.status": workspaceStatusPayload,
@@ -5865,6 +5975,14 @@ export const responseSchemas: Record<string, ZodTypeAny> = {
5865
5975
  .optional()
5866
5976
  .describe("OAuth URL the user opens to finish connecting."),
5867
5977
  connection_id: z.string().optional(),
5978
+ redirectUrl: z.string().optional(),
5979
+ link: z.string().optional(),
5980
+ artifact: z
5981
+ .object({
5982
+ kind: z.literal("connect"),
5983
+ data: z.object({ toolkit: z.string() }),
5984
+ })
5985
+ .optional(),
5868
5986
  })
5869
5987
  .passthrough()
5870
5988
  .describe("Connect-link response."),
@@ -106,6 +106,7 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
106
106
  {"id":"auth.otp.start","group":"auth","summary":"Start the email OTP sign-in flow.","cli":"dench signin --email","method":"POST","path":"/auth/otp/start","permission":"auth:write","pathParams":[]},
107
107
  {"id":"auth.otp.verify","group":"auth","summary":"Verify an email OTP sign-in code.","cli":"dench signin --email","method":"POST","path":"/auth/otp/verify","permission":"auth:write","pathParams":[]},
108
108
  {"id":"auth.otp.finalize","group":"auth","summary":"Finalize an email OTP sign-in session.","cli":"dench signin --email","method":"POST","path":"/auth/otp/finalize","permission":"auth:write","pathParams":[]},
109
+ {"id":"workspace.context.sections","group":"workspace","summary":"Read selected scoped workspace documents and a compact context index without writes.","cli":"dench context --sections","method":"GET","path":"/context/sections","permission":"workspace:read","pathParams":[]},
109
110
  {"id":"workspace.context","group":"workspace","summary":"Return the current Dench workspace context for the bearer.","cli":"dench context","method":"GET","path":"/context","permission":"workspace:read","pathParams":[]},
110
111
  {"id":"workspace.instructions","group":"workspace","summary":"Return the current workspace's standing instructions for external agents.","cli":"dench context --instructions","method":"GET","path":"/context/instructions","permission":"workspace:read","pathParams":[]},
111
112
  {"id":"workspace.status","group":"workspace","summary":"Return workspace and agent status.","cli":"dench status","method":"GET","path":"/status","permission":"workspace:read","pathParams":[]},
@@ -314,6 +315,14 @@ export const APP_SDK_OPERATIONS: readonly AppSdkOperationInfo[] = [
314
315
  {"id":"email.identity.disable","group":"email","summary":"Soft-disable a sender (or every sender on a domain) for the workspace; sends are blocked until restored.","cli":"dench email identity disable","method":"POST","path":"/email/sending-identities/{identity}/disable","permission":"email:write","pathParams":["identity"]},
315
316
  {"id":"email.identity.restore","group":"email","summary":"Restore a previously disabled sender for the workspace.","cli":"dench email identity restore","method":"POST","path":"/email/sending-identities/{identity}/restore","permission":"email:write","pathParams":["identity"]},
316
317
  {"id":"email.identity.delete","group":"email","summary":"Permanently delete a sender (or every sender on a domain) from the workspace; re-adding it requires verification from scratch.","cli":"dench email identity delete","method":"DELETE","path":"/email/sending-identities/{identity}","permission":"email:write","pathParams":["identity"]},
318
+ {"id":"email.drafts.create","group":"email","summary":"Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries.","cli":"dench email draft create","method":"POST","path":"/email/drafts","permission":"email:write","pathParams":[]},
319
+ {"id":"email.drafts.get","group":"email","summary":"Read an email draft, eligible senders and provider sync status.","cli":"dench email draft show","method":"GET","path":"/email/drafts/{draftId}","permission":"email:read","pathParams":["draftId"]},
320
+ {"id":"email.drafts.senders","group":"email","summary":"List native mailboxes this caller may use.","cli":"dench email draft senders","method":"GET","path":"/email/drafts/senders","permission":"email:read","pathParams":[]},
321
+ {"id":"email.drafts.update","group":"email","summary":"Save draft content using expectedRevision; sender changes require a new draft after provider binding.","cli":"dench email draft update","method":"PATCH","path":"/email/drafts/{draftId}","permission":"email:write","pathParams":["draftId"]},
322
+ {"id":"email.drafts.send","group":"email","summary":"Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt.","cli":"dench email draft send","method":"POST","path":"/email/drafts/{draftId}/send","permission":"email:write","pathParams":["draftId"]},
323
+ {"id":"email.drafts.upload","group":"email","summary":"Upload attachment bytes authorized against this draft before adding its storage reference.","cli":"dench email draft attach","method":"POST","path":"/email/drafts/{draftId}/attachments","permission":"email:write","pathParams":["draftId"]},
324
+ {"id":"email.drafts.signature","group":"email","summary":"Load the selected mailbox signature for explicit visible insertion.","cli":"dench email draft signature","method":"GET","path":"/email/drafts/{draftId}/signature","permission":"email:read","pathParams":["draftId"]},
325
+ {"id":"email.native.send","group":"email","summary":"Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request.","cli":"dench email send --mailbox","method":"POST","path":"/email/native/send","permission":"email:write","pathParams":[]},
317
326
  {"id":"email.send","group":"email","summary":"Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId.","cli":"dench email send","method":"POST","path":"/email/send","permission":"email:write","pathParams":[]},
318
327
  {"id":"email.message.get","group":"email","summary":"Read a raw email message's status and open/click counters.","cli":"dench email message status","method":"GET","path":"/email/messages/{messageId}","permission":"email:read","pathParams":["messageId"]},
319
328
  {"id":"email.message.list","group":"email","summary":"List recent raw email messages for the workspace.","cli":"dench email message list","method":"GET","path":"/email/messages","permission":"email:read","pathParams":[]},
@@ -608,6 +617,14 @@ export const APP_SDK_METHODS: Readonly<Record<string, AppSdkMethodInfo>> = {
608
617
  "campaigns.campaignsForRecord": {"kind":"op","permission":"campaigns:read","op":"campaigns.people.forRecord","doc":"The campaigns a CRM record is in, with its status in each."},
609
618
  "campaigns.personTimeline": {"kind":"op","permission":"campaigns:read","op":"campaigns.people.timeline","doc":"Everything a campaign did for one person, step by step."},
610
619
  "campaigns.removePerson": {"kind":"op","permission":"campaigns:write","op":"campaigns.people.remove","doc":"Remove a never-contacted person from a draft campaign."},
620
+ "email.createDraft": {"kind":"op","permission":"email:write","op":"email.drafts.create","doc":"Create a native mailbox draft with a stable request receipt."},
621
+ "email.draft": {"kind":"op","permission":"email:read","op":"email.drafts.get","doc":"Read a native email draft and sync status."},
622
+ "email.updateDraft": {"kind":"op","permission":"email:write","op":"email.drafts.update","doc":"Save the next email draft revision."},
623
+ "email.sendDraft": {"kind":"op","permission":"email:write","op":"email.drafts.send","doc":"Send the frozen native email draft revision."},
624
+ "email.senders": {"kind":"op","permission":"email:read","op":"email.drafts.senders","doc":"List eligible native mailboxes."},
625
+ "email.uploadAttachment": {"kind":"op","permission":"email:write","op":"email.drafts.upload","doc":"Upload attachment bytes for a native draft."},
626
+ "email.signature": {"kind":"op","permission":"email:read","op":"email.drafts.signature","doc":"Load the selected mailbox signature for visible insertion."},
627
+ "email.sendFromMailbox": {"kind":"op","permission":"email:write","op":"email.native.send","doc":"Explicitly send through a native Gmail or Outlook mailbox."},
611
628
  "email.send": {"kind":"op","permission":"email:write","op":"email.send","doc":"Send one email from a verified identity."},
612
629
  "email.messages": {"kind":"op","permission":"email:read","op":"email.message.list","doc":"Sent messages."},
613
630
  "email.message": {"kind":"op","permission":"email:read","op":"email.message.get","doc":"One sent message with delivery events."},