@dench.com/cli 3.5.8-staging.350 → 3.6.0-staging.356

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dench.com/cli",
3
- "version": "3.5.8-staging.350",
3
+ "version": "3.6.0-staging.356",
4
4
  "description": "Dench agent workspace CLI.",
5
5
  "type": "module",
6
6
  "bin": {
package/search.ts CHANGED
@@ -108,8 +108,8 @@ function assertFlagsSupportedForCategory(
108
108
  );
109
109
  if (offenders.length === 0) return;
110
110
  throw new SearchCliError(
111
- `${offenders.join(", ")} has no effect on ${category} search — Exa ` +
112
- "either rejects it or silently ignores it, so the results would not " +
111
+ `${offenders.join(", ")} has no effect on ${category} search — the ` +
112
+ "search either rejects it or silently ignores it, so the results would not " +
113
113
  "match what you asked for. (Unsupported for " +
114
114
  `${category}: ${[...unsupported].join(", ")}.) ` +
115
115
  "Put those constraints in the query text instead, e.g. " +
@@ -194,12 +194,6 @@ function asString(value: unknown): string | undefined {
194
194
  return typeof value === "string" ? value : undefined;
195
195
  }
196
196
 
197
- function asNumber(value: unknown): number | undefined {
198
- return typeof value === "number" && Number.isFinite(value)
199
- ? value
200
- : undefined;
201
- }
202
-
203
197
  function asObject(value: unknown): Record<string, unknown> | undefined {
204
198
  return value && typeof value === "object" && !Array.isArray(value)
205
199
  ? (value as Record<string, unknown>)
@@ -229,11 +223,6 @@ function formatSearchResults(payload: unknown, limit?: number): string {
229
223
  if (!root) return "(no results)";
230
224
  const results = asArray(root.results);
231
225
  const lines: string[] = [];
232
- const auto = asString(root.autopromptString);
233
- if (auto) {
234
- lines.push(`Auto-prompt: ${auto}`);
235
- lines.push("");
236
- }
237
226
  if (results.length === 0) {
238
227
  lines.push("(no results)");
239
228
  return lines.join("\n");
@@ -263,10 +252,6 @@ function formatSearchResults(payload: unknown, limit?: number): string {
263
252
  if (snippet) lines.push(` ${trimSnippet(snippet, 240)}`);
264
253
  lines.push("");
265
254
  }
266
- const cost = asNumber(asObject(root.costDollars)?.total);
267
- if (cost !== undefined) {
268
- lines.push(`Cost (USD): $${cost.toFixed(4)}`);
269
- }
270
255
  return lines.join("\n").trimEnd();
271
256
  }
272
257
 
@@ -278,11 +263,6 @@ function formatSearchResults(payload: unknown, limit?: number): string {
278
263
  function formatPeopleResults(payload: unknown, limit?: number): string {
279
264
  const hits = parseExaPeopleResults(payload);
280
265
  const lines: string[] = [];
281
- const auto = asString(asObject(payload)?.autopromptString);
282
- if (auto) {
283
- lines.push(`Auto-prompt: ${auto}`);
284
- lines.push("");
285
- }
286
266
  if (hits.length === 0) {
287
267
  lines.push("(no people found)");
288
268
  return lines.join("\n");
@@ -301,8 +281,6 @@ function formatPeopleResults(payload: unknown, limit?: number): string {
301
281
  if (hit.url) lines.push(` ${hit.url}`);
302
282
  lines.push("");
303
283
  }
304
- const cost = asNumber(asObject(asObject(payload)?.costDollars)?.total);
305
- if (cost !== undefined) lines.push(`Cost (USD): $${cost.toFixed(4)}`);
306
284
  return lines.join("\n").trimEnd();
307
285
  }
308
286
 
@@ -314,11 +292,6 @@ function formatPeopleResults(payload: unknown, limit?: number): string {
314
292
  function formatCompanyResults(payload: unknown, limit?: number): string {
315
293
  const hits = parseExaCompanyResults(payload);
316
294
  const lines: string[] = [];
317
- const auto = asString(asObject(payload)?.autopromptString);
318
- if (auto) {
319
- lines.push(`Auto-prompt: ${auto}`);
320
- lines.push("");
321
- }
322
295
  if (hits.length === 0) {
323
296
  lines.push("(no companies found)");
324
297
  return lines.join("\n");
@@ -355,8 +328,6 @@ function formatCompanyResults(payload: unknown, limit?: number): string {
355
328
  }
356
329
  lines.push("");
357
330
  }
358
- const cost = asNumber(asObject(asObject(payload)?.costDollars)?.total);
359
- if (cost !== undefined) lines.push(`Cost (USD): $${cost.toFixed(4)}`);
360
331
  return lines.join("\n").trimEnd();
361
332
  }
362
333
 
@@ -550,7 +521,7 @@ async function runAnswerSubcommand(ctx: SearchCliContext): Promise<void> {
550
521
  function searchHelp(): void {
551
522
  console.log(`Usage: dench search <subcommand>
552
523
 
553
- Live web access through the Dench Cloud Gateway (Exa Search). Auths
524
+ Live web access through the Dench Cloud Gateway. Auths
554
525
  with DENCH_API_KEY or the active \`dench signin\` agent session. Agent
555
526
  sessions require a paid workspace.
556
527
 
@@ -582,10 +553,10 @@ Find people or companies (--category people|company):
582
553
  published-date filters work with neither. Passing one that does not
583
554
  apply is refused rather than silently ignored.
584
555
 
585
- Deep-read one or more URLs (Exa /search/contents):
556
+ Deep-read one or more URLs:
586
557
  dench search contents <url> [<url>...] [--max-chars 4000] [--summary "..."] [--json]
587
558
 
588
- One-shot synthesised answer with citations (Exa /search/answer):
559
+ One-shot synthesised answer with citations:
589
560
  dench search answer "<query>" [--json]
590
561
 
591
562
  Environment variables:
package/tools.ts CHANGED
@@ -53,11 +53,17 @@ import {
53
53
  parseJson,
54
54
  shift as shiftRaw,
55
55
  } from "./lib/cli-args";
56
+ import {
57
+ type ConnectionSource,
58
+ connectionSource,
59
+ } from "./lib/connection-source";
56
60
  import {
57
61
  normalizeUnipileToolkitSlug,
58
62
  unipileConnectKindFromToolkitSlug,
59
63
  } from "./lib/unipile-toolkits";
60
64
 
65
+ export { type ConnectionSource, connectionSource };
66
+
61
67
  // ---------------------------------------------------------------------------
62
68
  // Public dispatcher
63
69
  // ---------------------------------------------------------------------------
@@ -240,15 +246,15 @@ export async function fetchConnectedAppsSummary(
240
246
  available: boolean;
241
247
  count: number;
242
248
  connections: CompactConnection[];
243
- unipileAvailable: boolean;
244
- unipileError?: string;
249
+ nativeAvailable: boolean;
250
+ nativeError?: string;
245
251
  error?: string;
246
252
  reason?: string;
247
253
  }> {
248
254
  const unipile = await fetchUnipileConnections(ctx);
249
255
  const unipileFields = {
250
- unipileAvailable: unipile.available,
251
- ...(unipile.error ? { unipileError: unipile.error } : {}),
256
+ nativeAvailable: unipile.available,
257
+ ...(unipile.error ? { nativeError: unipile.error } : {}),
252
258
  };
253
259
  if (ctx.gatewayAuthError) {
254
260
  return {
@@ -310,8 +316,8 @@ async function runStatusSubcommand(ctx: ToolCliContext): Promise<void> {
310
316
  available: unipile.available,
311
317
  count: unipile.connections.length,
312
318
  connections: unipile.connections,
313
- unipileAvailable: unipile.available,
314
- ...(unipile.error ? { unipileError: unipile.error } : {}),
319
+ nativeAvailable: unipile.available,
320
+ ...(unipile.error ? { nativeError: unipile.error } : {}),
315
321
  };
316
322
  } else {
317
323
  connectionsSummary = await fetchConnectedAppsSummary(ctx);
@@ -339,14 +345,14 @@ async function runStatusSubcommand(ctx: ToolCliContext): Promise<void> {
339
345
  : allConnections;
340
346
 
341
347
  const summary = {
342
- ok: unipileToolkit ? connectionsSummary.unipileAvailable : true,
348
+ ok: unipileToolkit ? connectionsSummary.nativeAvailable : true,
343
349
  available: connectionsSummary.available,
344
350
  toolkit: filterToolkit ?? null,
345
351
  count: filteredConnections.length,
346
352
  connections: filteredConnections,
347
- unipileAvailable: connectionsSummary.unipileAvailable,
348
- ...(connectionsSummary.unipileError
349
- ? { unipileError: connectionsSummary.unipileError }
353
+ nativeAvailable: connectionsSummary.nativeAvailable,
354
+ ...(connectionsSummary.nativeError
355
+ ? { nativeError: connectionsSummary.nativeError }
350
356
  : {}),
351
357
  ...(connectionsSummary.error ? { error: connectionsSummary.error } : {}),
352
358
  ...(connectionsSummary.reason ? { reason: connectionsSummary.reason } : {}),
@@ -409,8 +415,8 @@ async function runSearchSubcommand(ctx: ToolCliContext): Promise<void> {
409
415
  ),
410
416
  ...unipile.tools,
411
417
  ],
412
- unipileAvailable: unipile.available,
413
- ...(unipile.error ? { unipileError: unipile.error } : {}),
418
+ nativeAvailable: unipile.available,
419
+ ...(unipile.error ? { nativeError: unipile.error } : {}),
414
420
  };
415
421
 
416
422
  if (ctx.jsonOutput) {
@@ -519,7 +525,12 @@ async function fetchUnipileTools(
519
525
  available: true,
520
526
  tools: rows
521
527
  .map((row) => asRecord(row))
522
- .filter((row): row is JsonRecord => row !== undefined),
528
+ .filter((row): row is JsonRecord => row !== undefined)
529
+ .map((row) =>
530
+ typeof row.source === "string"
531
+ ? { ...row, source: connectionSource(row.source, "dench") }
532
+ : row,
533
+ ),
523
534
  };
524
535
  } catch (error) {
525
536
  return { available: false, tools: [], error: errorMessage(error) };
@@ -530,7 +541,7 @@ async function runRunSubcommand(ctx: ToolCliContext): Promise<void> {
530
541
  const toolSlug = ctx.args[0];
531
542
  if (!toolSlug || toolSlug.startsWith("--")) {
532
543
  throw new ToolCliError(
533
- 'Usage: dench tool run <composio_tool_slug> [--args \'{"key":"value"}\'] [--account <connectedAccountId>] [--json]',
544
+ 'Usage: dench tool run <tool_slug> [--args \'{"key":"value"}\'] [--account <connectedAccountId>] [--json]',
534
545
  );
535
546
  }
536
547
  ctx.args.shift();
@@ -659,7 +670,7 @@ async function runSlackConnectSubcommand(
659
670
  redirectUrl,
660
671
  message,
661
672
  note:
662
- "Slack is Dench's in-house integration (not Composio). One install powers " +
673
+ "Slack is Dench's in-house integration. One install powers " +
663
674
  "both the Slack messaging channel and the agent SLACK_* tools " +
664
675
  "(SLACK_SEND_MESSAGE, SLACK_FETCH_HISTORY, …).",
665
676
  };
@@ -669,7 +680,7 @@ async function runSlackConnectSubcommand(
669
680
  }
670
681
  console.log(message);
671
682
  console.log(
672
- "Slack is Dench's in-house integration (not Composio). Once an admin installs it,",
683
+ "Slack is Dench's in-house integration. Once an admin installs it,",
673
684
  );
674
685
  console.log(
675
686
  "run tools with `dench tool run SLACK_SEND_MESSAGE --args '{…}'` — see `dench tool search --toolkit slack`.",
@@ -699,7 +710,7 @@ async function runConnectSubcommand(ctx: ToolCliContext): Promise<void> {
699
710
  }
700
711
  if (ctx.args.includes("--callback-url")) {
701
712
  throw new ToolCliError(
702
- "Unipile connections use Dench's managed callback. --callback-url is only supported for Composio integrations.",
713
+ "Dench-connected accounts use Dench's managed callback. --callback-url is only supported for connected apps.",
703
714
  );
704
715
  }
705
716
  const result = asRecord(
@@ -717,7 +728,7 @@ async function runConnectSubcommand(ctx: ToolCliContext): Promise<void> {
717
728
  );
718
729
  const redirectUrl = stringField(result, "link");
719
730
  if (!redirectUrl) {
720
- throw new ToolCliError("Unipile did not return a connection link.");
731
+ throw new ToolCliError("Dench did not return a connection link.");
721
732
  }
722
733
  const message = `Connect ${toolkit} here: ${redirectUrl}`;
723
734
  if (ctx.jsonOutput) {
@@ -725,7 +736,7 @@ async function runConnectSubcommand(ctx: ToolCliContext): Promise<void> {
725
736
  JSON.stringify(
726
737
  {
727
738
  ok: true,
728
- source: "unipile",
739
+ source: "dench",
729
740
  toolkit: normalizeUnipileToolkitSlug(toolkit),
730
741
  redirectUrl,
731
742
  expiresAt: result?.expiresAt,
@@ -845,9 +856,7 @@ class GatewayHttpError extends ToolCliError {
845
856
  constructor(args: { status: number; body: string; path: string }) {
846
857
  const truncated =
847
858
  args.body.length > 500 ? `${args.body.slice(0, 500)}…` : args.body;
848
- super(
849
- `Gateway ${args.path} returned ${args.status}: ${truncated || "(empty)"}`,
850
- );
859
+ super(`Dench gateway error (${args.status}): ${truncated || "(empty)"}`);
851
860
  this.name = "GatewayHttpError";
852
861
  this.status = args.status;
853
862
  this.body = args.body;
@@ -1093,12 +1102,12 @@ function extractToolkits(payload: unknown): JsonRecord[] {
1093
1102
  }
1094
1103
 
1095
1104
  /**
1096
- * The merged row shape. `source` is the discriminator: `composio` rows carry a
1105
+ * The merged row shape. `source` is the discriminator: `app` rows carry a
1097
1106
  * routable `connectedAccountId` (usable as `dench tool run --account`), while
1098
- * `unipile` rows never do — their account id is an internal credential.
1107
+ * `dench` rows never do — their account id is an internal credential.
1099
1108
  */
1100
1109
  export type CompactConnection = {
1101
- source: "composio" | "unipile";
1110
+ source: ConnectionSource;
1102
1111
  toolkit: string;
1103
1112
  status: string;
1104
1113
  connectedAccountId: string | null;
@@ -1115,7 +1124,7 @@ export type CompactConnection = {
1115
1124
 
1116
1125
  function compactConnection(connection: JsonRecord): CompactConnection {
1117
1126
  return {
1118
- source: "composio",
1127
+ source: connectionSource(connection.source, "app"),
1119
1128
  toolkit:
1120
1129
  stringField(connection, "toolkit_slug", "toolkit") ??
1121
1130
  stringField(asRecord(connection.toolkit), "slug", "name") ??
@@ -1135,7 +1144,7 @@ function compactConnection(connection: JsonRecord): CompactConnection {
1135
1144
 
1136
1145
  function compactUnipileConnection(connection: JsonRecord): CompactConnection {
1137
1146
  return {
1138
- source: "unipile",
1147
+ source: connectionSource(connection.source, "dench"),
1139
1148
  toolkit: stringField(connection, "toolkit") ?? "unknown",
1140
1149
  status: stringField(connection, "status") ?? "unknown",
1141
1150
  connectedAccountId: null,
@@ -1153,11 +1162,11 @@ function formatConnectionLine(connection: CompactConnection): string {
1153
1162
  : "";
1154
1163
  // "via Dench" both names the broker and explains why the row has no
1155
1164
  // connected-account id to pass to `dench tool run`.
1156
- const via = connection.source === "unipile" ? " via Dench" : "";
1165
+ const via = connection.source === "dench" ? " via Dench" : "";
1157
1166
  // Whose mailbox/LinkedIn it is only matters when it is not this agent's —
1158
1167
  // `dench email --mailbox` picks between them.
1159
1168
  const owner =
1160
- connection.source === "unipile" &&
1169
+ connection.source === "dench" &&
1161
1170
  connection.isOwner === false &&
1162
1171
  connection.ownerName
1163
1172
  ? ` · ${connection.ownerName}`
@@ -1172,8 +1181,8 @@ function formatStatusSummary(summary: {
1172
1181
  toolkit: string | null;
1173
1182
  count: number;
1174
1183
  connections: CompactConnection[];
1175
- unipileAvailable?: boolean;
1176
- unipileError?: string;
1184
+ nativeAvailable?: boolean;
1185
+ nativeError?: string;
1177
1186
  reason?: string;
1178
1187
  error?: string;
1179
1188
  }): string {
@@ -1190,16 +1199,16 @@ function formatStatusSummary(summary: {
1190
1199
  }
1191
1200
  // Say so rather than silently listing Composio only — otherwise a connected
1192
1201
  // calendar reads as absent, which is the failure this merge exists to fix.
1193
- if (summary.unipileAvailable === false) {
1202
+ if (summary.nativeAvailable === false) {
1194
1203
  lines.push(
1195
1204
  ` (could not check Gmail/Outlook/Calendar/LinkedIn: ${
1196
- summary.unipileError ?? "unknown error"
1205
+ summary.nativeError ?? "unknown error"
1197
1206
  })`,
1198
1207
  );
1199
1208
  }
1200
1209
  if (summary.reason || summary.error) {
1201
1210
  lines.push(
1202
- ` (could not check Composio integrations: ${summary.reason ?? summary.error})`,
1211
+ ` (could not check connected apps: ${summary.reason ?? summary.error})`,
1203
1212
  );
1204
1213
  }
1205
1214
  return lines.join("\n");
@@ -1234,8 +1243,8 @@ function formatSearchResult(searchResult: unknown, compact = false): string {
1234
1243
  return [
1235
1244
  "No matching tools found.",
1236
1245
  "",
1237
- "`dench tool search` is a KEYWORD search over Composio's tool",
1238
- "names and descriptions, not a semantic / natural-language search.",
1246
+ "`dench tool search` is a KEYWORD search over tool names and",
1247
+ "descriptions, not a semantic / natural-language search.",
1239
1248
  "Retry with one or two concrete tokens that likely appear in the",
1240
1249
  'tool slug or its docs ("fetch emails", "send message", "create',
1241
1250
  'issue", "list channels"). Drop filter words like "today" /',
@@ -1361,18 +1370,18 @@ Usage:
1361
1370
 
1362
1371
  Notes:
1363
1372
  All commands authenticate with DENCH_API_KEY or the active \`dench signin\`
1364
- agent session. Composio commands use paid-workspace gateway credentials.
1373
+ agent session. Connected-app commands use paid-workspace gateway credentials.
1365
1374
  Native Gmail/Outlook/Calendar/LinkedIn connect/status need no gateway key;
1366
1375
  connect requires a workspace member or a member-owned Dench API key.
1367
- Results carry a "source". "composio" rows are brokered by Composio; "unipile"
1368
- rows (gmail, outlook, calendar, linkedin) and "dench" rows (slack) are
1369
- connected by Dench itself. ALL of them run through \`dench tool run\` with the
1376
+ Results carry a "source". "app" rows are third-party connected apps; "dench"
1377
+ rows (gmail, outlook, calendar, linkedin, slack) are connected by Dench
1378
+ itself. ALL of them run through \`dench tool run\` with the
1370
1379
  same slug + --args contract. \`dench tool connect slack\` prints the in-house
1371
1380
  Slack install URL (org admin, one click). For gmail/outlook/calendar/linkedin,
1372
- connect prints a Unipile hosted-auth link using the web app's configuration.
1381
+ connect prints a Dench sign-in link using the web app's configuration.
1373
1382
  Sign in as a workspace member and open the link to authorize the account.
1374
1383
  Calendar status accepts calendar, google-calendar, or outlook-calendar.
1375
- Other toolkits connect through Composio; --callback-url applies only to them.
1384
+ Other toolkits connect as connected apps; --callback-url applies only to them.
1376
1385
  Slack is ALWAYS in-house: SLACK_* slugs (SLACK_SEND_MESSAGE with Block Kit
1377
1386
  blocks/buttons, SLACK_FETCH_HISTORY, SLACK_LIST_CHANNELS, …) run through the
1378
1387
  org's own Slack app install and can post to / read any channel.
package/web.ts CHANGED
@@ -144,7 +144,7 @@ through the Dench gateway. Prefer these over writing your own scraper.
144
144
  dench web brand-search <query> [--json]
145
145
 
146
146
  Crawl defaults to 15 pages and is hard-capped at 50. Search stays on
147
- \`dench search\` (Exa). \`dench context\` is workspace orientation, not this.
147
+ \`dench search\`. \`dench context\` is workspace orientation, not this.
148
148
  `);
149
149
  }
150
150