@indigoai-us/hq-cli 5.227.0 → 5.227.1

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,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.227.1] — 2026-09-27
6
+
7
+ ### Fixed
8
+
9
+ - `hq files browse` and `hq files search` no longer crash on vaults with many objects.
10
+
5
11
  ## [5.227.0] — 2026-09-27
6
12
 
7
13
  ### Added
@@ -30,6 +30,7 @@ import chalk from "chalk";
30
30
  import { randomUUID } from "node:crypto";
31
31
  import * as readline from "node:readline";
32
32
  import { resolveVaultCredential } from "../utils/resolve-vault-credential.js";
33
+ import { maxLength } from "../utils/table-width.js";
33
34
  import { DEFAULT_VAULT_API_URL } from "../utils/cognito-session.js";
34
35
  import { gateApiKeyCapabilities } from "../utils/api-key-command-gate.js";
35
36
  import { vaultApiFetch, getCompanyUid } from "../utils/vault-api.js";
@@ -849,7 +850,7 @@ export function formatJobsTable(jobs) {
849
850
  j.lastRunOutcome ?? "-",
850
851
  j.status ?? "",
851
852
  ]);
852
- const widths = cols.map((c, i) => Math.max(c.length, ...rows.map((r) => r[i].length)));
853
+ const widths = cols.map((c, i) => maxLength(rows, (row) => row[i].length, c.length));
853
854
  const render = (cells) => cells.map((cell, i) => cell.padEnd(widths[i])).join(" ");
854
855
  return [chalk.bold(render(cols)), ...rows.map(render)].join("\n");
855
856
  }
@@ -44,6 +44,7 @@ import { VaultClient, } from "@indigoai-us/hq-cloud";
44
44
  import { isPrivateFolderPattern } from "./_patterns.js";
45
45
  import { DEFAULT_HQ_ROOT, DEFAULT_COGNITO, buildVaultConfig, } from "../utils/cognito-session.js";
46
46
  import { resolveVaultCredential } from "../utils/resolve-vault-credential.js";
47
+ import { maxLength } from "../utils/table-width.js";
47
48
  import { getCompanyUid, looksLikeCompanyUid, looksLikePersonVaultUid, vaultApiFetch, } from "../utils/vault-api.js";
48
49
  import { resolveCanonicalPersonUid } from "./cloud.js";
49
50
  // ── Pure helpers ────────────────────────────────────────────────────────────
@@ -181,13 +182,14 @@ export function formatBrowseTable(rows) {
181
182
  r.lastModified ? r.lastModified.toISOString() : "—",
182
183
  displayAclSource(r.aclSource),
183
184
  ]);
184
- const widths = cols.map((c, i) => Math.max(c.length, ...data.map((row) => row[i].length)));
185
+ const widths = cols.map((c, i) => maxLength(data, (row) => row[i].length, c.length));
185
186
  const renderRow = (row) => row.map((cell, i) => cell.padEnd(widths[i])).join(" ");
186
187
  const lines = [
187
188
  chalk.bold(renderRow(cols)),
188
189
  chalk.dim(renderRow(widths.map((w) => "─".repeat(w)))),
189
- ...data.map(renderRow),
190
190
  ];
191
+ for (const row of data)
192
+ lines.push(renderRow(row));
191
193
  return lines.join("\n");
192
194
  }
193
195
  /** Guard: the personal path needs an S3 factory. */
@@ -494,13 +496,14 @@ export function formatSharedWithMeTable(rows) {
494
496
  r.permission,
495
497
  r.source,
496
498
  ]);
497
- const widths = cols.map((c, i) => Math.max(c.length, ...data.map((row) => row[i].length)));
499
+ const widths = cols.map((c, i) => maxLength(data, (row) => row[i].length, c.length));
498
500
  const renderRow = (row) => row.map((cell, i) => cell.padEnd(widths[i])).join(" ");
499
501
  const lines = [
500
502
  chalk.bold(renderRow(cols)),
501
503
  chalk.dim(renderRow(widths.map((w) => "─".repeat(w)))),
502
- ...data.map(renderRow),
503
504
  ];
505
+ for (const row of data)
506
+ lines.push(renderRow(row));
504
507
  if (rows.some((row) => isPrivateFolderPattern(row.path))) {
505
508
  lines.push("Private folders expose the folder only; children are creator-only.");
506
509
  }
@@ -11,6 +11,7 @@ import { formatAccessDenied, offerAccessLadder, } from "../utils/access-denied-h
11
11
  import { fetchChannels, matchChannelsByName } from "./dm.js";
12
12
  import { resolveCompanySlug, resolvePersonWithRosterFallback, } from "./people.js";
13
13
  import { findHqRoot } from "../utils/manifest.js";
14
+ import { maxLength } from "../utils/table-width.js";
14
15
  const PERSON_UID_PATTERN = /^(prs|agt)_[A-Za-z0-9_-]+$/;
15
16
  function collectMentions(value, previous) {
16
17
  return [...previous, value];
@@ -1227,13 +1228,15 @@ export function formatFilesVersionsTable(rows) {
1227
1228
  row.lastModified,
1228
1229
  row.isDeleteMarker ? "—" : formatBytes(row.size),
1229
1230
  ]);
1230
- const widths = cols.map((col, index) => Math.max(col.length, ...data.map((row) => row[index].length)));
1231
+ const widths = cols.map((col, index) => maxLength(data, (row) => row[index].length, col.length));
1231
1232
  const renderRow = (row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ");
1232
- return [
1233
+ const lines = [
1233
1234
  chalk.bold(renderRow(cols)),
1234
1235
  chalk.dim(renderRow(widths.map((width) => "─".repeat(width)))),
1235
- ...data.map(renderRow),
1236
- ].join("\n");
1236
+ ];
1237
+ for (const row of data)
1238
+ lines.push(renderRow(row));
1239
+ return lines.join("\n");
1237
1240
  }
1238
1241
  /** Render durable delete tombstones without implying the objects still exist. */
1239
1242
  export function formatFilesTrashTable(rows) {
@@ -1247,13 +1250,15 @@ export function formatFilesTrashTable(rows) {
1247
1250
  row.deletedBy,
1248
1251
  row.deletedPrefix,
1249
1252
  ]);
1250
- const widths = cols.map((col, index) => Math.max(col.length, ...data.map((row) => row[index].length)));
1253
+ const widths = cols.map((col, index) => maxLength(data, (row) => row[index].length, col.length));
1251
1254
  const renderRow = (row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ");
1252
- return [
1255
+ const lines = [
1253
1256
  chalk.bold(renderRow(cols)),
1254
1257
  chalk.dim(renderRow(widths.map((width) => "─".repeat(width)))),
1255
- ...data.map(renderRow),
1256
- ].join("\n");
1258
+ ];
1259
+ for (const row of data)
1260
+ lines.push(renderRow(row));
1261
+ return lines.join("\n");
1257
1262
  }
1258
1263
  function throwRecoveryHttpError(status, body, statusText) {
1259
1264
  throw new FilesRecoveryHttpError(status, body.message ?? body.error ?? statusText, body.code);
@@ -2,6 +2,7 @@ import chalk from "chalk";
2
2
  import { ensureCognitoToken } from "../utils/cognito-session.js";
3
3
  import { vaultApiFetch, getCompanyUid } from "./secrets.js";
4
4
  import { GROUP_ID_PATTERN } from "./_patterns.js";
5
+ import { maxLength } from "../utils/table-width.js";
5
6
  const EMAIL_PATTERN = /^[^\s]+@[^\s]+$/;
6
7
  const PERSON_UID_PATTERN = /^prs_[A-Za-z0-9_-]+$/;
7
8
  const AGENT_UID_PATTERN = /^agt_[A-Za-z0-9_-]+$/;
@@ -261,9 +262,9 @@ export function registerGroupsCommand(program) {
261
262
  console.log(chalk.gray("No groups in this company yet."));
262
263
  return;
263
264
  }
264
- const idW = Math.max(8, ...data.groups.map((g) => g.groupId.length));
265
- const nameW = Math.max(4, ...data.groups.map((g) => g.name.length));
266
- const descW = Math.max(11, ...data.groups.map((g) => (g.description ?? "").length));
265
+ const idW = maxLength(data.groups, (group) => group.groupId.length, 8);
266
+ const nameW = maxLength(data.groups, (group) => group.name.length, 4);
267
+ const descW = maxLength(data.groups, (group) => (group.description ?? "").length, 11);
267
268
  console.log(chalk.bold([
268
269
  "GROUP_ID".padEnd(idW),
269
270
  "NAME".padEnd(nameW),
@@ -326,8 +327,8 @@ export function registerGroupsCommand(program) {
326
327
  console.log(chalk.gray("No members yet — use 'hq groups add' to add."));
327
328
  return;
328
329
  }
329
- const uidW = Math.max(10, ...data.members.map((m) => m.personUid.length));
330
- const byW = Math.max(8, ...data.members.map((m) => m.addedBy.length));
330
+ const uidW = maxLength(data.members, (member) => member.personUid.length, 10);
331
+ const byW = maxLength(data.members, (member) => member.addedBy.length, 8);
331
332
  console.log(chalk.bold([
332
333
  "PERSON_UID".padEnd(uidW),
333
334
  "ADDED_BY".padEnd(byW),
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Return the largest measured cell length without passing an unbounded number
3
+ * of values as function arguments. Large vault tables can contain hundreds of
4
+ * thousands of rows, beyond the argument limit of Math.max(...values).
5
+ */
6
+ export declare function maxLength<T>(values: Iterable<T>, measure: (value: T) => number, floor: number): number;
7
+ //# sourceMappingURL=table-width.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Return the largest measured cell length without passing an unbounded number
3
+ * of values as function arguments. Large vault tables can contain hundreds of
4
+ * thousands of rows, beyond the argument limit of Math.max(...values).
5
+ */
6
+ export function maxLength(values, measure, floor) {
7
+ let maximum = floor;
8
+ for (const value of values) {
9
+ const length = measure(value);
10
+ if (length > maximum)
11
+ maximum = length;
12
+ }
13
+ return maximum;
14
+ }
15
+ //# sourceMappingURL=table-width.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.227.0",
3
+ "version": "5.227.1",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {