@indigoai-us/hq-cli 5.345.117 → 5.345.118

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.118] — 2026-10-13
6
+ - `hq integrations call` and `hq integrations tools` now work for the
7
+ built-in Google Workspace, Linear and Slack connections. Calls use the
8
+ tool's own name (for example `google.drive.picked.list`), and `tools`
9
+ lists only the selected connection's tools. `--args` may not set
10
+ `companyUid`, `connectionId` or `idempotencyKey`; hq fills those in from
11
+ the selected connection.
12
+
5
13
  ## [5.345.117] — 2026-10-13
6
14
  - `hq lanes monitor-check` answers a session that owns no active lane from the lane-record directory alone, without loading the command graph. The Claude Stop hook runs it after every turn in every session; per-call CPU drops from about 545 ms to about 60 ms. Sessions with an active lane, corrupt records, or conflict sidecars still use the full command.
7
15
 
@@ -257,6 +257,12 @@ export interface UsableAppsResult {
257
257
  viewerAccessKnown: boolean;
258
258
  apps: UsableApp[];
259
259
  }
260
+ /**
261
+ * Built-in providers expose their tools under their own names
262
+ * (`google.drive.picked.list`), not through the factory passthrough
263
+ * `<prefix>.mcp.tools.call`, which the gateway never registers for them.
264
+ */
265
+ export declare function isBuiltInGatewayProvider(provider: string): boolean;
260
266
  /**
261
267
  * The apps the caller may use, from `GET /v1/integrations/admin?view=summary`.
262
268
  * A row counts only when all of these hold, mirroring the gateway's checks:
@@ -296,7 +302,7 @@ export declare function resolveConnection(token: string, companyUid: string, app
296
302
  }, recoveryOpts?: {
297
303
  allowSingleRevoked?: boolean;
298
304
  }): Promise<AdminConnection>;
299
- export declare function callGateway(token: string, params: Record<string, unknown>, idempotencyKey?: string): Promise<GatewayMessage>;
305
+ export declare function callGateway(token: string, params: Record<string, unknown>, idempotencyKey?: string, method?: "tools/call" | "tools/list"): Promise<GatewayMessage>;
300
306
  /**
301
307
  * Gateway results arrive MCP-style: `{ content: [{ type: "text", text }] }`
302
308
  * where `text` is the provider's JSON. Unwrap to the inner payload; fall back
@@ -368,6 +368,14 @@ const GATEWAY_SERVED_STATUSES = new Set(["connected", "needs-attention"]);
368
368
  * gateway as `ProviderUnsupported`.
369
369
  */
370
370
  const STATIC_GATEWAY_PROVIDERS = new Set(["google-workspace", "linear", "slack"]);
371
+ /**
372
+ * Built-in providers expose their tools under their own names
373
+ * (`google.drive.picked.list`), not through the factory passthrough
374
+ * `<prefix>.mcp.tools.call`, which the gateway never registers for them.
375
+ */
376
+ export function isBuiltInGatewayProvider(provider) {
377
+ return STATIC_GATEWAY_PROVIDERS.has(provider);
378
+ }
371
379
  const MAX_APP_NAME_LENGTH = 60;
372
380
  /**
373
381
  * Display names are set by whoever installed the app and end up in agent
@@ -561,7 +569,9 @@ export async function resolveConnection(token, companyUid, app, opts, recoveryOp
561
569
  }
562
570
  return selectConnection(connections, opts);
563
571
  }
564
- function gatewaySubcommandFor(params) {
572
+ function gatewaySubcommandFor(params, method) {
573
+ if (method === "tools/list")
574
+ return "tools_list";
565
575
  const name = params.name;
566
576
  if (typeof name !== "string")
567
577
  return "other";
@@ -569,10 +579,13 @@ function gatewaySubcommandFor(params) {
569
579
  return "tools_list";
570
580
  if (name.endsWith(".mcp.tools.call"))
571
581
  return "tools_call";
582
+ // Built-in providers are called by the tool's own name, with no passthrough.
583
+ if (!name.includes(".mcp."))
584
+ return "tools_call";
572
585
  return "other";
573
586
  }
574
- export async function callGateway(token, params, idempotencyKey) {
575
- const gatewaySubcommand = gatewaySubcommandFor(params);
587
+ export async function callGateway(token, params, idempotencyKey, method = "tools/call") {
588
+ const gatewaySubcommand = gatewaySubcommandFor(params, method);
576
589
  const deadline = Date.now() + ASYNC_GATEWAY_DEADLINE_MS;
577
590
  const res = await vaultApiFetch({
578
591
  token,
@@ -581,7 +594,7 @@ export async function callGateway(token, params, idempotencyKey) {
581
594
  body: {
582
595
  jsonrpc: "2.0",
583
596
  id: `hq-cli-${randomUUID()}`,
584
- method: "tools/call",
597
+ method,
585
598
  params,
586
599
  },
587
600
  });
@@ -54,12 +54,39 @@ import chalk from "chalk";
54
54
  import { ensureCognitoIdToken } from "../utils/cognito-session.js";
55
55
  import { getCompanyUid, vaultApiFetch } from "../utils/vault-api.js";
56
56
  import { redactSensitiveUrl, redactSensitiveUrls, redactUrlsInText } from "../utils/redact-url.js";
57
- import { IntegrationsCliError, bareProvider, callGateway, fetchConnections, fetchUsableApps, isClientError, printHealthNotice, printJson, printIntegrationCallResultJson, raiseIfUnauthorized, raiseIfUpstreamUnavailable, gatewayResultIsError, selectConnection, revokedConnectionDetails, toolPrefixForProvider, unwrapGatewayResult, queuedOutcome, } from "./integrations-core.js";
57
+ import { IntegrationsCliError, bareProvider, callGateway, fetchConnections, fetchUsableApps, isBuiltInGatewayProvider, isClientError, printHealthNotice, printJson, printIntegrationCallResultJson, raiseIfUnauthorized, raiseIfUpstreamUnavailable, gatewayResultIsError, selectConnection, revokedConnectionDetails, toolPrefixForProvider, unwrapGatewayResult, queuedOutcome, } from "./integrations-core.js";
58
58
  import { registerConnectCommands } from "./integrations-connect.js";
59
59
  import { registerImportCommands } from "./integrations-import.js";
60
60
  import { registerManageCommands } from "./integrations-manage.js";
61
61
  import { registerSlackCommands } from "./integrations-slack.js";
62
62
  import { fetchPendingApprovals } from "./integrations-api.js";
63
+ /** Routing ids hq sets on a built-in tool call; never accepted from --args. */
64
+ const BUILT_IN_ROUTING_ARGS = ["companyUid", "connectionId", "idempotencyKey"];
65
+ /**
66
+ * hq sets the routing ids on every built-in call and refuses them in --args,
67
+ * so discovery must not list them as inputs the caller provides.
68
+ */
69
+ function withoutRoutingArgs(tool) {
70
+ const schema = tool.inputSchema;
71
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
72
+ return tool;
73
+ const { properties, required, ...rest } = schema;
74
+ const routing = new Set(BUILT_IN_ROUTING_ARGS);
75
+ const next = { ...rest };
76
+ if (properties && typeof properties === "object" && !Array.isArray(properties)) {
77
+ next.properties = Object.fromEntries(Object.entries(properties).filter(([key]) => !routing.has(key)));
78
+ }
79
+ else if (properties !== undefined) {
80
+ next.properties = properties;
81
+ }
82
+ if (Array.isArray(required)) {
83
+ next.required = required.filter((key) => !(typeof key === "string" && routing.has(key)));
84
+ }
85
+ else if (required !== undefined) {
86
+ next.required = required;
87
+ }
88
+ return { ...tool, inputSchema: next };
89
+ }
63
90
  export { IntegrationsCliError, callGateway, fetchConnections, fetchUsableApps, queuedOutcome, selectConnection, toolPrefixForProvider, unwrapGatewayResult, } from "./integrations-core.js";
64
91
  /**
65
92
  * Gateway metadata is additive and may be absent when talking to an older
@@ -285,16 +312,33 @@ export function registerIntegrationsCommand(program) {
285
312
  .action(async (opts) => {
286
313
  const token = await ensureCognitoIdToken();
287
314
  const companyUid = await getCompanyUid(token, opts.company);
288
- const connection = selectConnection(await fetchConnections(token, companyUid), opts);
315
+ const connections = await fetchConnections(token, companyUid);
316
+ const connection = selectConnection(connections, opts);
289
317
  if (reportRevokedConnection(connection, opts))
290
318
  return;
291
- const prefix = toolPrefixForProvider(connection.provider);
292
- const message = await callGateway(token, {
293
- companyUid,
294
- name: `${prefix}.mcp.tools.list`,
295
- arguments: { companyUid, connectionId: connection.id },
296
- });
297
- const payload = unwrapGatewayResult(message.result);
319
+ let payload;
320
+ const builtIn = isBuiltInGatewayProvider(connection.provider);
321
+ if (builtIn) {
322
+ // Built-in providers answer the gateway's own tools/list, which spans
323
+ // every connection in the company; keep only this connection's tools.
324
+ const message = await callGateway(token, { companyUid }, undefined, "tools/list");
325
+ const listed = unwrapGatewayResult(message.result);
326
+ payload = {
327
+ ...listed,
328
+ tools: (listed?.tools ?? [])
329
+ .filter((tool) => tool.annotations?.connectionId === connection.id)
330
+ .map(withoutRoutingArgs),
331
+ };
332
+ }
333
+ else {
334
+ const prefix = toolPrefixForProvider(connection.provider);
335
+ const message = await callGateway(token, {
336
+ companyUid,
337
+ name: `${prefix}.mcp.tools.list`,
338
+ arguments: { companyUid, connectionId: connection.id },
339
+ });
340
+ payload = unwrapGatewayResult(message.result);
341
+ }
298
342
  const tools = payload?.tools ?? [];
299
343
  if (tools.length === 0) {
300
344
  if (opts.json) {
@@ -331,7 +375,14 @@ export function registerIntegrationsCommand(program) {
331
375
  const badge = formatToolBadge(tool);
332
376
  console.log(`${chalk.bold(tool.name)}${badge ? ` ${badge}` : ""}${label}${required ? ` ${chalk.dim(required)}` : ""}`);
333
377
  }
334
- console.log(chalk.dim(`\n${tools.length} tools. Describe inputs: hq integrations tools --provider ${bareProvider(connection.provider)} --describe <tool>\nCall one with: hq integrations call <tool> --provider ${bareProvider(connection.provider)} --args '<json>'`));
378
+ // `--provider` resolves to the first matching connection, so when
379
+ // several connections share this provider the hint must name this one.
380
+ const sharedProvider = builtIn &&
381
+ connections.some((c) => c.id !== connection.id && c.status !== "revoked" && c.provider === connection.provider);
382
+ const selector = sharedProvider
383
+ ? `--connection ${connection.id}`
384
+ : `--provider ${bareProvider(connection.provider)}`;
385
+ console.log(chalk.dim(`\n${tools.length} tools. Describe inputs: hq integrations tools ${selector} --describe <tool>\nCall one with: hq integrations call <tool> ${selector} --args '<json>'`));
335
386
  });
336
387
  integrations
337
388
  .command("call <tool>")
@@ -359,20 +410,38 @@ export function registerIntegrationsCommand(program) {
359
410
  const connection = selectConnection(await fetchConnections(token, companyUid), opts);
360
411
  if (reportRevokedConnection(connection, { ...opts, fail: true }))
361
412
  return;
362
- const prefix = toolPrefixForProvider(connection.provider);
363
413
  const idempotencyKey = opts.idempotencyKey ?? `hq-cli-${randomUUID()}`;
364
- const message = await callGateway(token, {
365
- companyUid,
366
- acceptAsync: true,
367
- name: `${prefix}.mcp.tools.call`,
368
- arguments: {
414
+ let gatewayParams;
415
+ if (isBuiltInGatewayProvider(connection.provider)) {
416
+ // Built-in tools take their args flat beside the routing ids, so an
417
+ // arg with a routing name would redirect the call; refuse it.
418
+ const reserved = BUILT_IN_ROUTING_ARGS.filter((key) => key in parsedArgs);
419
+ if (reserved.length) {
420
+ throw new IntegrationsCliError(`--args cannot include ${reserved.join(", ")}: it is set by hq from the selected connection.`, { expected: true });
421
+ }
422
+ gatewayParams = {
423
+ companyUid,
424
+ acceptAsync: true,
425
+ name: tool,
426
+ arguments: { ...parsedArgs, companyUid, connectionId: connection.id, idempotencyKey },
427
+ };
428
+ }
429
+ else {
430
+ const prefix = toolPrefixForProvider(connection.provider);
431
+ gatewayParams = {
369
432
  companyUid,
370
- connectionId: connection.id,
371
- toolName: tool,
372
- arguments: parsedArgs,
373
- idempotencyKey,
374
- },
375
- }, idempotencyKey);
433
+ acceptAsync: true,
434
+ name: `${prefix}.mcp.tools.call`,
435
+ arguments: {
436
+ companyUid,
437
+ connectionId: connection.id,
438
+ toolName: tool,
439
+ arguments: parsedArgs,
440
+ idempotencyKey,
441
+ },
442
+ };
443
+ }
444
+ const message = await callGateway(token, gatewayParams, idempotencyKey);
376
445
  const payload = unwrapGatewayResult(message.result);
377
446
  const queued = queuedOutcome(payload);
378
447
  if (queued) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.117",
3
+ "version": "5.345.118",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {