@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/README.md CHANGED
@@ -465,3 +465,19 @@ Commands that need to impersonate a specific agent (`dench memory`,
465
465
  (`dench signin`) — the unified API key is org-scoped and cannot speak
466
466
  as a single agent. Those commands return a clear "agent session
467
467
  required" error in API-key mode.
468
+
469
+ ### Focused workspace context
470
+
471
+ `dench context --instructions` reads explicit IDENTITY, RULES and TOOLS notes,
472
+ plus document availability/revisions. It does not load business profiles,
473
+ personal profiles or aggregate memory. Fetch only what the task needs:
474
+
475
+ ```sh
476
+ dench context --sections organisation,user,memory --json
477
+ ```
478
+
479
+ Section names are `identity`, `organisation`, `user`, `memory`, `rules`, and
480
+ `tools`. Multiple names use one query. The existing `organisation show`,
481
+ `user show`, and `mem show` commands use the same saved documents; reading never
482
+ fills profiles or writes memory. Personal USER context is unavailable to shared
483
+ channel sessions. `dench context --json` keeps its existing workspace overview.
package/agent-config.ts CHANGED
@@ -215,22 +215,16 @@ async function handleSimpleMagicFile(
215
215
  ): Promise<void> {
216
216
  const sub = args[0];
217
217
  if (!sub || sub === "show") {
218
- const config = await loadAgentConfig(ctx);
219
- const value =
220
- opts.field === "memoryAggregate"
221
- ? config.agentConfig.memoryAggregate
222
- : opts.field === "toolsNotes"
223
- ? config.agentConfig.toolsNotes
224
- : opts.field === "identity"
225
- ? config.agentConfig.identity
226
- : opts.field === "organisation"
227
- ? config.agentConfig.organisation
228
- : null;
229
- if (opts.perMember) {
230
- out(ctx, config.userProfile?.content ?? "(empty)");
231
- return;
232
- }
233
- out(ctx, value?.content ?? "(empty)");
218
+ const context = (await runQuery(
219
+ ctx,
220
+ makeFunctionReference<"query">("functions/agentConfig:workspaceContext"),
221
+ { sections: [opts.label] },
222
+ )) as { documents: Array<{ name: string; content?: string }> };
223
+ out(
224
+ ctx,
225
+ context.documents.find((document) => document.name === opts.label)
226
+ ?.content || "(empty)",
227
+ );
234
228
  return;
235
229
  }
236
230
  if (sub === "edit" || sub === "set") {
package/app-sdk.d.ts CHANGED
@@ -497,10 +497,17 @@ export interface ApiRequests {
497
497
  organizationId?: string;
498
498
  newOrganizationName?: string;
499
499
  };
500
+ /** Read selected scoped workspace documents and a compact context index without writes. — `dench context --sections` — GET /api/v1/context/sections */
501
+ "workspace.context.sections": {
502
+ organizationId?: string;
503
+ sections?: Array<"identity" | "organisation" | "user" | "memory" | "rules" | "tools">;
504
+ };
500
505
  /** Return the current Dench workspace context for the bearer. — `dench context` — GET /api/v1/context */
501
506
  "workspace.context": Record<string, unknown>;
502
507
  /** Return the current workspace's standing instructions for external agents. — `dench context --instructions` — GET /api/v1/context/instructions */
503
- "workspace.instructions": Record<string, unknown>;
508
+ "workspace.instructions": {
509
+ organizationId?: string;
510
+ };
504
511
  /** Return workspace and agent status. — `dench status` — GET /api/v1/status */
505
512
  "workspace.status": Record<string, unknown>;
506
513
  /** List agents visible in the workspace status payload. — `dench agents` — GET /api/v1/agents */
@@ -2172,6 +2179,116 @@ export interface ApiRequests {
2172
2179
  /** Identity id, sender email, or domain (deletes every sender on the domain). Permanent: re-adding requires re-verification. */
2173
2180
  identity: string;
2174
2181
  };
2182
+ /** Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries. — `dench email draft create` — POST /api/v1/email/drafts */
2183
+ "email.drafts.create": {
2184
+ organizationId?: string;
2185
+ threadId?: string;
2186
+ mailbox?: string;
2187
+ requestId: string;
2188
+ to?: {
2189
+ email: string;
2190
+ name?: string;
2191
+ }[];
2192
+ cc?: {
2193
+ email: string;
2194
+ name?: string;
2195
+ }[];
2196
+ bcc?: {
2197
+ email: string;
2198
+ name?: string;
2199
+ }[];
2200
+ subject?: string;
2201
+ htmlBody?: string;
2202
+ textBody?: string;
2203
+ attachments?: {
2204
+ storageId: string;
2205
+ name: string;
2206
+ contentType: string;
2207
+ size: number;
2208
+ }[];
2209
+ };
2210
+ /** Read an email draft, eligible senders and provider sync status. — `dench email draft show` — GET /api/v1/email/drafts/{draftId} */
2211
+ "email.drafts.get": {
2212
+ draftId: string;
2213
+ };
2214
+ /** List native mailboxes this caller may use. — `dench email draft senders` — GET /api/v1/email/drafts/senders */
2215
+ "email.drafts.senders": {
2216
+ organizationId?: string;
2217
+ };
2218
+ /** Save draft content using expectedRevision; sender changes require a new draft after provider binding. — `dench email draft update` — PATCH /api/v1/email/drafts/{draftId} */
2219
+ "email.drafts.update": {
2220
+ draftId: string;
2221
+ expectedRevision: number;
2222
+ patch: {
2223
+ mailboxAccountId?: string;
2224
+ to?: {
2225
+ email: string;
2226
+ name?: string;
2227
+ }[];
2228
+ cc?: {
2229
+ email: string;
2230
+ name?: string;
2231
+ }[];
2232
+ bcc?: {
2233
+ email: string;
2234
+ name?: string;
2235
+ }[];
2236
+ subject?: string;
2237
+ htmlBody?: string;
2238
+ textBody?: string;
2239
+ attachments?: {
2240
+ storageId: string;
2241
+ name: string;
2242
+ contentType: string;
2243
+ size: number;
2244
+ }[];
2245
+ };
2246
+ };
2247
+ /** Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt. — `dench email draft send` — POST /api/v1/email/drafts/{draftId}/send */
2248
+ "email.drafts.send": {
2249
+ draftId: string;
2250
+ expectedRevision: number;
2251
+ requestId?: string;
2252
+ };
2253
+ /** Upload attachment bytes authorized against this draft before adding its storage reference. — `dench email draft attach` — POST /api/v1/email/drafts/{draftId}/attachments */
2254
+ "email.drafts.upload": {
2255
+ draftId: string;
2256
+ name: string;
2257
+ contentType: string;
2258
+ contentBase64: string;
2259
+ };
2260
+ /** Load the selected mailbox signature for explicit visible insertion. — `dench email draft signature` — GET /api/v1/email/drafts/{draftId}/signature */
2261
+ "email.drafts.signature": {
2262
+ draftId: string;
2263
+ };
2264
+ /** Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request. — `dench email send --mailbox` — POST /api/v1/email/native/send */
2265
+ "email.native.send": {
2266
+ organizationId?: string;
2267
+ threadId?: string;
2268
+ mailbox?: string;
2269
+ requestId: string;
2270
+ to?: {
2271
+ email: string;
2272
+ name?: string;
2273
+ }[];
2274
+ cc?: {
2275
+ email: string;
2276
+ name?: string;
2277
+ }[];
2278
+ bcc?: {
2279
+ email: string;
2280
+ name?: string;
2281
+ }[];
2282
+ subject?: string;
2283
+ htmlBody?: string;
2284
+ textBody?: string;
2285
+ attachments?: {
2286
+ storageId: string;
2287
+ name: string;
2288
+ contentType: string;
2289
+ size: number;
2290
+ }[];
2291
+ };
2175
2292
  /** Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId. — `dench email send` — POST /api/v1/email/send */
2176
2293
  "email.send": {
2177
2294
  /** Verified sender mailbox. */
@@ -3017,17 +3134,25 @@ export interface ApiRequests {
3017
3134
  /** Create a tool OAuth connection link. Slack is in-house, never a third-party connection: for toolkit slack the CLI prints the first-party install URL (/api/slack/install?slug=<workspace>, org admin) instead of calling this endpoint. — `dench tool connect` — POST /api/v1/tools/connections */
3018
3135
  "tool.connect": {
3019
3136
  /** Toolkit slug, e.g. github, gmail, stripe. */
3020
- toolkit: string;
3137
+ toolkit?: string;
3138
+ toolkit_slug?: string;
3021
3139
  /** Optional OAuth callback URL. */
3022
3140
  callback_url?: string;
3141
+ /** Native OAuth return path within the workspace. */
3142
+ returnTo?: string;
3023
3143
  };
3024
3144
  /** Search for external tool actions. — `dench tool search` — POST /api/v1/tools/search */
3025
3145
  "tool.search": {
3026
- queries: {
3146
+ queries?: {
3027
3147
  /** Natural-language use case. */
3028
3148
  use_case: string;
3029
3149
  known_fields?: string;
3030
3150
  }[];
3151
+ query?: string;
3152
+ toolkit?: string;
3153
+ toolkit_slug?: string;
3154
+ limit?: number;
3155
+ important?: boolean;
3031
3156
  session?: {
3032
3157
  id?: string;
3033
3158
  generate_id?: boolean;
@@ -3045,6 +3170,8 @@ export interface ApiRequests {
3045
3170
  /** Tool arguments object. */
3046
3171
  arguments?: Record<string, unknown>;
3047
3172
  account?: string;
3173
+ connected_account_id?: string;
3174
+ approvalId?: string;
3048
3175
  };
3049
3176
  /** Disconnect an external tool account. — `dench tool disconnect` — DELETE /api/v1/tools/connections/{connectionId} */
3050
3177
  "tool.disconnect": {
@@ -3374,6 +3501,7 @@ export interface ApiResponses {
3374
3501
  sessionExpiresAt?: number;
3375
3502
  };
3376
3503
  };
3504
+ "workspace.context.sections": Record<string, unknown>;
3377
3505
  "workspace.context": {
3378
3506
  workspace: {
3379
3507
  id: string;
@@ -5319,6 +5447,54 @@ export interface ApiResponses {
5319
5447
  disabled: boolean;
5320
5448
  }[];
5321
5449
  };
5450
+ "email.drafts.create": {
5451
+ ok: boolean;
5452
+ kind: "email";
5453
+ draftId: string;
5454
+ syncStatus: string;
5455
+ revision: number;
5456
+ [key: string]: unknown;
5457
+ };
5458
+ "email.drafts.get": {
5459
+ ok: boolean;
5460
+ kind: "email";
5461
+ draftId: string;
5462
+ syncStatus: string;
5463
+ revision: number;
5464
+ [key: string]: unknown;
5465
+ };
5466
+ "email.drafts.senders": Record<string, unknown>[];
5467
+ "email.drafts.update": {
5468
+ ok: boolean;
5469
+ kind: "email";
5470
+ draftId: string;
5471
+ syncStatus: string;
5472
+ revision: number;
5473
+ [key: string]: unknown;
5474
+ };
5475
+ "email.drafts.send": {
5476
+ ok: boolean;
5477
+ kind: "email";
5478
+ draftId: string;
5479
+ syncStatus: string;
5480
+ revision: number;
5481
+ [key: string]: unknown;
5482
+ };
5483
+ "email.drafts.upload": {
5484
+ storageId: string;
5485
+ name: string;
5486
+ contentType: string;
5487
+ size: number;
5488
+ };
5489
+ "email.drafts.signature": Record<string, unknown>;
5490
+ "email.native.send": {
5491
+ ok: boolean;
5492
+ kind: "email";
5493
+ draftId: string;
5494
+ syncStatus: string;
5495
+ revision: number;
5496
+ [key: string]: unknown;
5497
+ };
5322
5498
  "email.send": {
5323
5499
  ok: boolean;
5324
5500
  /** Dench message id for `dench email message status`. */
@@ -6567,6 +6743,14 @@ export interface ApiResponses {
6567
6743
  /** OAuth URL the user opens to finish connecting. */
6568
6744
  redirect_url?: string;
6569
6745
  connection_id?: string;
6746
+ redirectUrl?: string;
6747
+ link?: string;
6748
+ artifact?: {
6749
+ kind: "connect";
6750
+ data: {
6751
+ toolkit: string;
6752
+ };
6753
+ };
6570
6754
  [key: string]: unknown;
6571
6755
  };
6572
6756
  "tool.search": {
@@ -6592,10 +6776,13 @@ export interface ApiResponses {
6592
6776
  /** Tool slug -> schema with gateway-added execution_ref for tool.run. */
6593
6777
  tool_schemas?: Record<string, Record<string, unknown>>;
6594
6778
  /** Tool-router session; reuse session.id for follow-up calls. */
6595
- session: {
6779
+ session?: {
6596
6780
  id: string;
6597
6781
  [key: string]: unknown;
6598
6782
  };
6783
+ items?: Record<string, unknown>[];
6784
+ nativeAvailable?: boolean;
6785
+ available?: boolean;
6599
6786
  execution_ref_version?: number;
6600
6787
  [key: string]: unknown;
6601
6788
  };
@@ -7810,6 +7997,22 @@ export type DenchApiTree = {
7810
7997
  /** Submit a campaign for approval or sending. (`dench email campaign submit`) */
7811
7998
  submit(args: Req<"email.campaign.submit">): Promise<Res<"email.campaign.submit">>;
7812
7999
  };
8000
+ drafts: {
8001
+ /** Create an editable Dench email draft and synchronize its selected native mailbox asynchronously. Use a stable requestId for retries. (`dench email draft create`) */
8002
+ create(args: Req<"email.drafts.create">): Promise<Res<"email.drafts.create">>;
8003
+ /** Read an email draft, eligible senders and provider sync status. (`dench email draft show`) */
8004
+ get(args: Req<"email.drafts.get">): Promise<Res<"email.drafts.get">>;
8005
+ /** Send the current Dench draft revision through its native mailbox. Repeated requests share a durable receipt. (`dench email draft send`) */
8006
+ send(args: Req<"email.drafts.send">): Promise<Res<"email.drafts.send">>;
8007
+ /** List native mailboxes this caller may use. (`dench email draft senders`) */
8008
+ senders(args?: Req<"email.drafts.senders">): Promise<Res<"email.drafts.senders">>;
8009
+ /** Load the selected mailbox signature for explicit visible insertion. (`dench email draft signature`) */
8010
+ signature(args: Req<"email.drafts.signature">): Promise<Res<"email.drafts.signature">>;
8011
+ /** Save draft content using expectedRevision; sender changes require a new draft after provider binding. (`dench email draft update`) */
8012
+ update(args: Req<"email.drafts.update">): Promise<Res<"email.drafts.update">>;
8013
+ /** Upload attachment bytes authorized against this draft before adding its storage reference. (`dench email draft attach`) */
8014
+ upload(args: Req<"email.drafts.upload">): Promise<Res<"email.drafts.upload">>;
8015
+ };
7813
8016
  identity: {
7814
8017
  /** Begin the full Dench sender verification flow for a sending identity. (`dench email identity verify`) */
7815
8018
  beginVerification(args: Req<"email.identity.beginVerification">): Promise<Res<"email.identity.beginVerification">>;
@@ -7838,6 +8041,10 @@ export type DenchApiTree = {
7838
8041
  /** List recent raw email messages for the workspace. (`dench email message list`) */
7839
8042
  list(args?: Req<"email.message.list">): Promise<Res<"email.message.list">>;
7840
8043
  };
8044
+ native: {
8045
+ /** Send through a native Gmail or Outlook mailbox with a durable request receipt. Only use for an explicit send request. (`dench email send --mailbox`) */
8046
+ send(args: Req<"email.native.send">): Promise<Res<"email.native.send">>;
8047
+ };
7841
8048
  /** Send one raw email (no campaign): to/cc/bcc, custom from-name and reply-to, optional reply threading via replyToMessageId. (`dench email send`) */
7842
8049
  send(args: Req<"email.send">): Promise<Res<"email.send">>;
7843
8050
  sequence: {
@@ -8126,8 +8333,13 @@ export type DenchApiTree = {
8126
8333
  /** List artifacts for the authenticated workspace. (`dench artifacts`) */
8127
8334
  list(args?: Req<"workspace.artifacts.list">): Promise<Res<"workspace.artifacts.list">>;
8128
8335
  };
8129
- /** Return the current Dench workspace context for the bearer. (`dench context`) */
8130
- context(args?: Req<"workspace.context">): Promise<Res<"workspace.context">>;
8336
+ context: {
8337
+ /** Return the current Dench workspace context for the bearer. (`dench context`) */
8338
+ (args?: Req<"workspace.context">): Promise<Res<"workspace.context">>;
8339
+ $call(args?: Req<"workspace.context">): Promise<Res<"workspace.context">>;
8340
+ /** Read selected scoped workspace documents and a compact context index without writes. (`dench context --sections`) */
8341
+ sections(args?: Req<"workspace.context.sections">): Promise<Res<"workspace.context.sections">>;
8342
+ };
8131
8343
  /** Return the current workspace's standing instructions for external agents. (`dench context --instructions`) */
8132
8344
  instructions(args?: Req<"workspace.instructions">): Promise<Res<"workspace.instructions">>;
8133
8345
  /** Return workspace and agent status. (`dench status`) */
@@ -8555,6 +8767,22 @@ export interface DenchCampaigns {
8555
8767
  }
8556
8768
 
8557
8769
  export interface DenchEmail {
8770
+ /** Create a native mailbox draft with a stable request receipt. Permission: `email:write`. Wraps `email.drafts.create`. */
8771
+ createDraft(draft: Req<"email.drafts.create">): Promise<Res<"email.drafts.create">>;
8772
+ /** Read a native email draft and sync status. Permission: `email:read`. Wraps `email.drafts.get`. */
8773
+ draft(draftId: string): Promise<Res<"email.drafts.get">>;
8774
+ /** Save the next email draft revision. Permission: `email:write`. Wraps `email.drafts.update`. */
8775
+ updateDraft(input: Req<"email.drafts.update">): Promise<Res<"email.drafts.update">>;
8776
+ /** Send the frozen native email draft revision. Permission: `email:write`. Wraps `email.drafts.send`. */
8777
+ sendDraft(input: Req<"email.drafts.send">): Promise<Res<"email.drafts.send">>;
8778
+ /** List eligible native mailboxes. Permission: `email:read`. Wraps `email.drafts.senders`. */
8779
+ senders(opts?: Req<"email.drafts.senders">): Promise<Res<"email.drafts.senders">>;
8780
+ /** Upload attachment bytes for a native draft. Permission: `email:write`. Wraps `email.drafts.upload`. */
8781
+ uploadAttachment(input: Req<"email.drafts.upload">): Promise<Res<"email.drafts.upload">>;
8782
+ /** Load the selected mailbox signature for visible insertion. Permission: `email:read`. Wraps `email.drafts.signature`. */
8783
+ signature(draftId: string): Promise<Res<"email.drafts.signature">>;
8784
+ /** Explicitly send through a native Gmail or Outlook mailbox. Permission: `email:write`. Wraps `email.native.send`. */
8785
+ sendFromMailbox(message: Req<"email.native.send">): Promise<Res<"email.native.send">>;
8558
8786
  /** Send one email from a verified identity. Permission: `email:write`. Wraps `email.send`. */
8559
8787
  send(message: Req<"email.send">): Promise<Res<"email.send">>;
8560
8788
  /** Sent messages. Permission: `email:read`. Wraps `email.message.list`. */
package/crm.ts CHANGED
@@ -1063,6 +1063,15 @@ const api = {
1063
1063
  },
1064
1064
  };
1065
1065
 
1066
+ /** These read commands have local, command-specific help (no runtime needed). */
1067
+ export function isCrmReadHelpRequest(args: readonly string[]): boolean {
1068
+ const command = args.find((arg) => arg !== "--json");
1069
+ return (
1070
+ (command === "query" || command === "aggregate") &&
1071
+ (args.includes("--help") || args.includes("-h"))
1072
+ );
1073
+ }
1074
+
1066
1075
  export async function runCrmCommand(opts: {
1067
1076
  convex: ConvexHttpClient;
1068
1077
  args: string[];
@@ -1088,6 +1097,21 @@ export async function runCrmCommand(opts: {
1088
1097
  crmHelp();
1089
1098
  return;
1090
1099
  }
1100
+ if (isCrmReadHelpRequest(opts.args)) {
1101
+ if (subcommand === "query") {
1102
+ console.log(`Usage: dench crm query <object> [--where '<JSON>'] [--select Name,Email] [--sort -Score] [--limit N] [--json]
1103
+ --page [--cursor '<continueCursor>'] Return {page,isDone,continueCursor} in index order; omit --sort.
1104
+ --assigned-to me|unassigned|<userId|email> (or --mine) [--assignee-field <Field>]
1105
+ Default limit: 100. Maximum: 1000 for a one-shot array, 100 for a cursor page.
1106
+ Continue cursor pages until isDone, including empty filtered pages.
1107
+ Example: dench crm query company --where '{"Status":"New"}' --select Name --limit 25 --json`);
1108
+ } else {
1109
+ console.log(`Usage: dench crm aggregate <object> --field <Field> [--sum <NumberField>] [--json]
1110
+ Count rows per value of --field. --sum also totals a number field within each bucket.
1111
+ Example: dench crm aggregate deal --field Stage --sum Amount --json`);
1112
+ }
1113
+ return;
1114
+ }
1091
1115
  switch (subcommand) {
1092
1116
  case "objects":
1093
1117
  return await runObjectsCommand(ctx);
@@ -2391,37 +2415,92 @@ async function runEntriesCommand(ctx: CrmCliContext): Promise<void> {
2391
2415
  switch (verb) {
2392
2416
  case "list": {
2393
2417
  const objectName = shift(ctx.args, "object name");
2418
+ const withMeta = hasFlag(ctx.args, "--with-meta");
2419
+ const cursorSpecified = ctx.args.includes("--cursor");
2420
+ const cursor = getFlag(ctx.args, "--cursor");
2421
+ if (cursorSpecified && (!cursor?.trim() || cursor.startsWith("--")))
2422
+ throw new CrmCliError(
2423
+ "--cursor requires a non-empty continuation cursor.",
2424
+ );
2425
+ const assigneeScopeArgs = resolveAssigneeScopeFlags(ctx.args);
2394
2426
  const limit = resolveLimitFlag(ctx.args, {
2395
2427
  defaultValue: 100,
2396
- cap: 1000,
2428
+ cap:
2429
+ withMeta && assigneeScopeArgs.assignedTo !== undefined ? 100 : 1000,
2397
2430
  command: "crm entries list",
2431
+ ...(withMeta
2432
+ ? {
2433
+ fullDatasetHint:
2434
+ "Continue with --with-meta --cursor '<continueCursor>' when a cursor is returned.",
2435
+ }
2436
+ : {}),
2398
2437
  });
2399
- const withMeta = hasFlag(ctx.args, "--with-meta");
2400
- const assigneeScopeArgs = resolveAssigneeScopeFlags(ctx.args);
2438
+ if (cursor !== undefined && !withMeta) {
2439
+ throw new CrmCliError(
2440
+ "--cursor requires --with-meta on crm entries list.",
2441
+ );
2442
+ }
2401
2443
  assertNoUnknownFlags(ctx.args, "crm entries list");
2402
- const entries = await callQuery(ctx, api.entries.list, {
2403
- objectName,
2404
- limit: limit.effective,
2405
- ...assigneeScopeArgs,
2406
- });
2407
2444
  if (!withMeta) {
2408
2445
  // Bare-array output: the clamp warning already went to stderr
2409
2446
  // (stdout must stay a valid JSON array in --json mode).
2410
- out(ctx, entries);
2447
+ out(
2448
+ ctx,
2449
+ await callQuery(ctx, api.entries.list, {
2450
+ objectName,
2451
+ limit: limit.effective,
2452
+ ...assigneeScopeArgs,
2453
+ }),
2454
+ );
2411
2455
  return;
2412
2456
  }
2413
- const object = (await callQuery(ctx, api.objects.get, {
2414
- name: objectName,
2415
- })) as { entryCount?: number } | null;
2416
- const returnedCount = Array.isArray(entries) ? entries.length : 0;
2417
- const totalCount =
2418
- typeof object?.entryCount === "number"
2419
- ? object.entryCount
2420
- : returnedCount;
2457
+ // Catalog counts include hidden and unassigned records. Only the
2458
+ // readable page can tell us whether this caller has a continuation.
2459
+ const [result, object] = (await Promise.all([
2460
+ assigneeScopeArgs.assignedTo !== undefined
2461
+ ? callQuery(ctx, api.query.scanEntries, {
2462
+ objectName,
2463
+ dsl: { limit: limit.effective },
2464
+ paginationOpts: {
2465
+ cursor: cursor ?? null,
2466
+ numItems: limit.effective,
2467
+ },
2468
+ ...assigneeScopeArgs,
2469
+ })
2470
+ : callQuery(ctx, api.entries.listPage, {
2471
+ objectName,
2472
+ limit: limit.effective,
2473
+ ...(cursor !== undefined ? { cursor } : {}),
2474
+ }),
2475
+ callQuery(ctx, api.objects.get, { name: objectName }),
2476
+ ])) as [
2477
+ {
2478
+ page?: unknown[];
2479
+ isDone?: boolean;
2480
+ continueCursor?: string | null;
2481
+ truncated?: boolean;
2482
+ } | null,
2483
+ { entryCount?: number; visibility?: string } | null,
2484
+ ];
2485
+ const entries = Array.isArray(result?.page) ? result.page : [];
2486
+ const isDone =
2487
+ typeof result?.isDone === "boolean" ? result.isDone : null;
2488
+ const truncated = result?.truncated === true;
2489
+ const continueCursor =
2490
+ isDone === false ? result?.continueCursor || null : null;
2491
+ const hasMore = continueCursor
2492
+ ? true
2493
+ : isDone === true && !truncated
2494
+ ? false
2495
+ : null;
2421
2496
  out(ctx, {
2422
2497
  objectName,
2423
- totalCount,
2424
- returnedCount,
2498
+ totalCount:
2499
+ typeof object?.entryCount === "number" ? object.entryCount : null,
2500
+ totalCountScope: "object",
2501
+ visibility: object?.visibility ?? null,
2502
+ returnedCount: entries.length,
2503
+ returnedCountScope: "readable",
2425
2504
  limit: limit.effective,
2426
2505
  ...(limit.clamped
2427
2506
  ? {
@@ -2431,7 +2510,10 @@ async function runEntriesCommand(ctx: CrmCliContext): Promise<void> {
2431
2510
  },
2432
2511
  }
2433
2512
  : {}),
2434
- hasMore: totalCount > returnedCount,
2513
+ hasMore,
2514
+ isDone,
2515
+ truncated,
2516
+ continueCursor,
2435
2517
  entries,
2436
2518
  });
2437
2519
  return;
@@ -4785,8 +4867,12 @@ Fields (columns):
4785
4867
  Update the color (e.g. "#3b82f6") for an existing enum option.
4786
4868
 
4787
4869
  Entries (rows):
4788
- dench crm entries list <object> [--limit N] [--with-meta] [--json]
4870
+ dench crm entries list <object> [--limit N] [--with-meta [--cursor '<continueCursor>']] [--json]
4789
4871
  [--assigned-to me|unassigned|<userId|email> | --mine] [--assignee-field <Field>]
4872
+ --with-meta includes readable pagination; totalCount is the entire object's catalog count,
4873
+ not a readable or assigned total. Continue only when continueCursor is returned, preserving filters.
4874
+ Scoped reads may be truncated with no cursor (hasMore: null); repeating the same call will not advance.
4875
+ Assigned metadata pages cap at 100 rows; other list reads cap at 1000.
4790
4876
  dench crm entries get <object> <entryId> [--with-context] (--with-context appends the newest activity + notes)
4791
4877
  dench crm entries sync-history <object> <entryId> [--status]
4792
4878
  Queue a full, paged pull of the record's email history from every