@indigoai-us/hq-cli 5.345.99 → 5.345.101

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,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.101] — 2026-10-12
6
+ - Doctor JSON no longer counts an ordinary HQ Core upgrade warning in its
7
+ summary after omitting it from results. Session-start health that only saw
8
+ that leftover warning after `hq doctor --fix` stops treating it as an
9
+ unrepaired failure. `hq doctor` still prints the upgrade.
10
+
11
+ ## [5.345.100] — 2026-10-12
12
+ - `hq storage status` no longer runs the big-file scan, so it returns the
13
+ local backup and cloud history figures without waiting minutes on a big HQ.
14
+ Its JSON adds `big_files_included: false` and leaves out `offload`.
15
+ - New `hq storage big-files [--json]` runs only the big-file scan and returns
16
+ `{ offload, generated_at }`. Read-only; a failed scan reports
17
+ `offload.available: false` instead of failing.
18
+ - `hq storage status --big-files` keeps the old single call: the scan runs and
19
+ `offload` is included as before (`big_files_included: true`).
20
+
5
21
  ## [5.345.99] — 2026-10-12
6
22
  - Session-start health no longer files an ordinary HQ Core upgrade warning as
7
23
  a failed doctor repair, including older hooks that only read `hq doctor --json`.
@@ -2935,6 +2935,26 @@ export declare const COMMAND_CATALOG: readonly [{
2935
2935
  readonly flags: "--no-cache";
2936
2936
  readonly description: "List cloud file history live instead of using figures from the last 15 minutes";
2937
2937
  readonly hidden: false;
2938
+ }, {
2939
+ readonly flags: "--big-files";
2940
+ readonly description: "Also scan for big files (slow on a big HQ); same as `hq storage big-files`";
2941
+ readonly hidden: false;
2942
+ }];
2943
+ readonly subcommands: readonly [];
2944
+ }, {
2945
+ readonly name: "big-files";
2946
+ readonly description: "Show big files that could move to HQ cloud (the slow scan `status` skips; read-only)";
2947
+ readonly aliases: readonly [];
2948
+ readonly hidden: false;
2949
+ readonly helpOption: true;
2950
+ readonly helpCommand: false;
2951
+ readonly usage: "[options]";
2952
+ readonly helpText: readonly [];
2953
+ readonly arguments: readonly [];
2954
+ readonly options: readonly [{
2955
+ readonly flags: "--json";
2956
+ readonly description: "Print JSON";
2957
+ readonly hidden: false;
2938
2958
  }];
2939
2959
  readonly subcommands: readonly [];
2940
2960
  }, {
@@ -3538,6 +3538,30 @@ export const COMMAND_CATALOG = [
3538
3538
  "flags": "--no-cache",
3539
3539
  "description": "List cloud file history live instead of using figures from the last 15 minutes",
3540
3540
  "hidden": false
3541
+ },
3542
+ {
3543
+ "flags": "--big-files",
3544
+ "description": "Also scan for big files (slow on a big HQ); same as `hq storage big-files`",
3545
+ "hidden": false
3546
+ }
3547
+ ],
3548
+ "subcommands": []
3549
+ },
3550
+ {
3551
+ "name": "big-files",
3552
+ "description": "Show big files that could move to HQ cloud (the slow scan `status` skips; read-only)",
3553
+ "aliases": [],
3554
+ "hidden": false,
3555
+ "helpOption": true,
3556
+ "helpCommand": false,
3557
+ "usage": "[options]",
3558
+ "helpText": [],
3559
+ "arguments": [],
3560
+ "options": [
3561
+ {
3562
+ "flags": "--json",
3563
+ "description": "Print JSON",
3564
+ "hidden": false
3541
3565
  }
3542
3566
  ],
3543
3567
  "subcommands": []
@@ -16,8 +16,22 @@
16
16
  * before vending, and `status` marks each company with `can_delete`.
17
17
  *
18
18
  * `offload` and `fetch` (big files to the personal vault) live in
19
- * `storage-offload.ts`; this file registers them and adds the offload section
20
- * to `status`.
19
+ * `storage-offload.ts`; this file registers them and the big-files read.
20
+ *
21
+ * The big-file scan (`hq-storage.sh large`, minutes on a big HQ) is not part
22
+ * of a default `status`. JSON shapes:
23
+ *
24
+ * `hq storage status --json`
25
+ * { local, cloud, cloud_error?, big_files_included: false, generated_at }
26
+ * `hq storage status --big-files --json` (one call, as older CLIs did)
27
+ * { local, cloud, cloud_error?, offload, big_files_included: true, generated_at }
28
+ * `hq storage big-files --json`
29
+ * { offload, generated_at }
30
+ *
31
+ * `offload` is the OffloadStatus from `storage-offload.ts`; its fields are
32
+ * unchanged. A failed scan reports `offload.available: false` with a
33
+ * `reason` instead of failing the command. Older CLIs have no
34
+ * `big_files_included` and always included `offload` in status.
21
35
  */
22
36
  import { Command } from "commander";
23
37
  import { type ReclaimReport } from "./storage-core.js";
@@ -59,7 +73,19 @@ export interface StorageStatus {
59
73
  cloud: CloudCompanyStatus[];
60
74
  /** Set when cloud history could not be read at all, e.g. not signed in. */
61
75
  cloud_error?: string;
76
+ /** Big files. Present only when the scan ran (`--big-files`). */
62
77
  offload?: OffloadStatus;
78
+ /**
79
+ * Whether this status ran the big-file scan. False on a default status:
80
+ * get big files with `hq storage big-files`. Absent on older CLIs,
81
+ * which always ran it.
82
+ */
83
+ big_files_included: boolean;
84
+ generated_at: string;
85
+ }
86
+ /** `hq storage big-files --json`: the big-file scan on its own. */
87
+ export interface StorageBigFiles {
88
+ offload: OffloadStatus;
63
89
  generated_at: string;
64
90
  }
65
91
  export interface CloudPruneResult {
@@ -192,7 +218,15 @@ export declare function pruneCloud(company: CompanyRef, cutoff: Date, dryRun: bo
192
218
  export declare function runStorageStatus(opts: {
193
219
  company?: string;
194
220
  noCache?: boolean;
221
+ bigFiles?: boolean;
195
222
  }, deps: StorageDeps): Promise<StorageStatus>;
223
+ /**
224
+ * The big-file scan on its own (`hq storage big-files`): what a default
225
+ * `status` leaves out. Read-only like status: never drops backups, runs gc,
226
+ * prunes or touches the cloud. A failed scan is reported in the result
227
+ * (`offload.available: false`), not thrown.
228
+ */
229
+ export declare function runStorageBigFiles(deps: StorageDeps): Promise<StorageBigFiles>;
196
230
  export declare function parseCutoff(value: string, flag: string): Date;
197
231
  export declare function runStoragePrune(opts: {
198
232
  localBefore?: string;
@@ -16,8 +16,22 @@
16
16
  * before vending, and `status` marks each company with `can_delete`.
17
17
  *
18
18
  * `offload` and `fetch` (big files to the personal vault) live in
19
- * `storage-offload.ts`; this file registers them and adds the offload section
20
- * to `status`.
19
+ * `storage-offload.ts`; this file registers them and the big-files read.
20
+ *
21
+ * The big-file scan (`hq-storage.sh large`, minutes on a big HQ) is not part
22
+ * of a default `status`. JSON shapes:
23
+ *
24
+ * `hq storage status --json`
25
+ * { local, cloud, cloud_error?, big_files_included: false, generated_at }
26
+ * `hq storage status --big-files --json` (one call, as older CLIs did)
27
+ * { local, cloud, cloud_error?, offload, big_files_included: true, generated_at }
28
+ * `hq storage big-files --json`
29
+ * { offload, generated_at }
30
+ *
31
+ * `offload` is the OffloadStatus from `storage-offload.ts`; its fields are
32
+ * unchanged. A failed scan reports `offload.available: false` with a
33
+ * `reason` instead of failing the command. Older CLIs have no
34
+ * `big_files_included` and always included `offload` in status.
21
35
  */
22
36
  import chalk from "chalk";
23
37
  import * as fs from "node:fs";
@@ -527,10 +541,13 @@ export async function pruneCloud(company, cutoff, dryRun, deps) {
527
541
  // ── Orchestrators ───────────────────────────────────────────────────────────
528
542
  export async function runStorageStatus(opts, deps) {
529
543
  // Read-only: no backup drop, no gc. Pending backup bytes come from report.
530
- // The local report, the offload scan and the cloud listing are independent,
531
- // so they run at the same time: status takes as long as the slowest one.
544
+ // The big-file scan is the slow part on a big HQ, so it runs only when
545
+ // asked for (`--big-files`); `hq storage big-files` runs it on its own.
546
+ // The local report, that scan and the cloud listing are independent, so
547
+ // they run at the same time: status takes as long as the slowest one.
548
+ const bigFiles = opts.bigFiles === true;
532
549
  const localP = getLocalReport(deps);
533
- const offloadP = deps.getOffload ? deps.getOffload().catch(offloadUnavailable) : Promise.resolve(undefined);
550
+ const offloadP = bigFiles && deps.getOffload ? deps.getOffload().catch(offloadUnavailable) : Promise.resolve(undefined);
534
551
  const cloudP = (async () => {
535
552
  let memberships;
536
553
  try {
@@ -564,9 +581,22 @@ export async function runStorageStatus(opts, deps) {
564
581
  cloud,
565
582
  ...(cloud_error !== undefined ? { cloud_error } : {}),
566
583
  ...(offload ? { offload } : {}),
584
+ big_files_included: bigFiles,
567
585
  generated_at: deps.now().toISOString(),
568
586
  };
569
587
  }
588
+ /**
589
+ * The big-file scan on its own (`hq storage big-files`): what a default
590
+ * `status` leaves out. Read-only like status: never drops backups, runs gc,
591
+ * prunes or touches the cloud. A failed scan is reported in the result
592
+ * (`offload.available: false`), not thrown.
593
+ */
594
+ export async function runStorageBigFiles(deps) {
595
+ const offload = deps.getOffload
596
+ ? await deps.getOffload().catch(offloadUnavailable)
597
+ : offloadUnavailable(new Error("big-file scan not available"));
598
+ return { offload, generated_at: deps.now().toISOString() };
599
+ }
570
600
  const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
571
601
  export function parseCutoff(value, flag) {
572
602
  const d = new Date(`${value}T00:00:00Z`);
@@ -710,6 +740,9 @@ export function formatStorageStatus(status) {
710
740
  }
711
741
  if (status.offload)
712
742
  lines.push("", ...formatOffloadStatus(status.offload));
743
+ else if (status.big_files_included === false) {
744
+ lines.push("", chalk.bold("Big files"), " Not checked. Run `hq storage big-files` to scan for them.");
745
+ }
713
746
  return lines.join("\n");
714
747
  }
715
748
  function offloadUnavailable(err) {
@@ -1077,9 +1110,10 @@ export function registerStorageCommand(program) {
1077
1110
  .option("--json", "Print JSON")
1078
1111
  .option("--company <slug>", "Only this company (must be one of yours)")
1079
1112
  .option("--no-cache", "List cloud file history live instead of using figures from the last 15 minutes")
1113
+ .option("--big-files", "Also scan for big files (slow on a big HQ); same as `hq storage big-files`")
1080
1114
  .action(async (opts) => {
1081
1115
  try {
1082
- const status = await runStorageStatus({ company: opts.company, noCache: opts.cache === false }, await buildDeps());
1116
+ const status = await runStorageStatus({ company: opts.company, noCache: opts.cache === false, bigFiles: opts.bigFiles === true }, await buildDeps());
1083
1117
  console.log(opts.json ? JSON.stringify(status, null, 2) : formatStorageStatus(status));
1084
1118
  }
1085
1119
  catch (err) {
@@ -1087,6 +1121,20 @@ export function registerStorageCommand(program) {
1087
1121
  process.exitCode = 1;
1088
1122
  }
1089
1123
  });
1124
+ storage
1125
+ .command("big-files")
1126
+ .description("Show big files that could move to HQ cloud (the slow scan `status` skips; read-only)")
1127
+ .option("--json", "Print JSON")
1128
+ .action(async (opts) => {
1129
+ try {
1130
+ const result = await runStorageBigFiles(await buildDeps());
1131
+ console.log(opts.json ? JSON.stringify(result, null, 2) : formatOffloadStatus(result.offload).join("\n"));
1132
+ }
1133
+ catch (err) {
1134
+ console.error(chalk.red(err.message));
1135
+ process.exitCode = 1;
1136
+ }
1137
+ });
1090
1138
  storage
1091
1139
  .command("prune")
1092
1140
  .description("Delete local autosave history and old cloud file versions before a date")
@@ -107,12 +107,12 @@ export interface BuildDoctorJsonInput {
107
107
  /**
108
108
  * JSON consumed by the SessionStart health hook (`--client-health-report`).
109
109
  * Ordinary hq-core upgrade WARNs are omitted from every JSON document
110
- * (`--json` and `--client-health-report`): `--fix` cannot apply a release,
111
- * and both current hooks and older ones that only call `hq doctor --json`
112
- * treated the leftover WARN as an unrepaired failure. Human `hq doctor`
113
- * still prints the upgrade. Company journals this `--fix` pass did not try
114
- * to refresh are omitted only from `--client-health-report`: the repair cap
115
- * leaves them for a later session.
110
+ * (`--json` and `--client-health-report`), including `summary` tallies:
111
+ * `--fix` cannot apply a release, and both current hooks and older ones
112
+ * that only call `hq doctor --json` treated the leftover WARN as an
113
+ * unrepaired failure. Human `hq doctor` still prints the upgrade. Company
114
+ * journals this `--fix` pass did not try to refresh are omitted only from
115
+ * `--client-health-report`: the repair cap leaves them for a later session.
116
116
  */
117
117
  clientHealthReport?: boolean;
118
118
  /** Clock for the leftover-journal freshness window. Default: `Date.now`. */
@@ -121,8 +121,9 @@ export interface BuildDoctorJsonInput {
121
121
  /**
122
122
  * True when a sync finding is an ordinary, non-repairable hq-core upgrade.
123
123
  * FAIL stays visible: that is a broken local core, not "a newer release exists".
124
- * JSON omits the WARN so SessionStart health (including core 15.x hooks that
125
- * only call `hq doctor --json`) does not file it as a failed repair.
124
+ * JSON omits the WARN (from `results` and `summary`) so SessionStart health
125
+ * (including core 15.x hooks that only call `hq doctor --json`) does not file
126
+ * it as a failed repair.
126
127
  */
127
128
  export declare function isOrdinaryCoreUpdateWarn(result: {
128
129
  checkId: string;
@@ -17,7 +17,7 @@
17
17
  * `target` and `remediation` are emitted only when present, matching the
18
18
  * per-item result shape where both are optional.
19
19
  */
20
- import { computeExitCode, summarize, UNKNOWN_PLATFORM, } from "./report.js";
20
+ import { computeExitCode, emptyStatusCounts, UNKNOWN_PLATFORM, } from "./report.js";
21
21
  import { deriveRemediation } from "./fix/remediation.js";
22
22
  import { freshAttemptedCompanyJournalCheckIds, isUnreachedCompanyJournalForClientHealth, } from "./fix/refresh-sync-progress.js";
23
23
  /**
@@ -33,12 +33,20 @@ export const DOCTOR_JSON_SCHEMA_VERSION = 2;
33
33
  /**
34
34
  * True when a sync finding is an ordinary, non-repairable hq-core upgrade.
35
35
  * FAIL stays visible: that is a broken local core, not "a newer release exists".
36
- * JSON omits the WARN so SessionStart health (including core 15.x hooks that
37
- * only call `hq doctor --json`) does not file it as a failed repair.
36
+ * JSON omits the WARN (from `results` and `summary`) so SessionStart health
37
+ * (including core 15.x hooks that only call `hq doctor --json`) does not file
38
+ * it as a failed repair.
38
39
  */
39
40
  export function isOrdinaryCoreUpdateWarn(result) {
40
41
  return result.checkId === "sync.update.core" && result.status === "WARN";
41
42
  }
43
+ /** Tally the results that actually ship in the JSON document. */
44
+ function summarizeJsonResults(results) {
45
+ const counts = emptyStatusCounts();
46
+ for (const result of results)
47
+ counts[result.status] += 1;
48
+ return counts;
49
+ }
42
50
  /** Assemble the machine-readable document from a completed run. */
43
51
  export function buildDoctorJson(input) {
44
52
  const attemptedRefreshSyncCheckIds = input.clientHealthReport === true
@@ -61,7 +69,7 @@ export function buildDoctorJson(input) {
61
69
  schemaVersion: DOCTOR_JSON_SCHEMA_VERSION,
62
70
  platform: input.platform ?? UNKNOWN_PLATFORM,
63
71
  hqRoot: input.hqRoot,
64
- summary: summarize(input.families),
72
+ summary: summarizeJsonResults(results),
65
73
  exitCode: computeExitCode(input.families),
66
74
  ...(input.scope && input.scope.length > 0 ? { scope: [...input.scope] } : {}),
67
75
  results,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.99",
3
+ "version": "5.345.101",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {