@indigoai-us/hq-cli 5.345.79 → 5.345.81

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/command-catalog.generated.d.ts +142 -0
  3. package/dist/command-catalog.generated.js +173 -0
  4. package/dist/command-help.js +2 -0
  5. package/dist/command-registration-plan.d.ts +6 -0
  6. package/dist/command-registration-plan.js +1 -0
  7. package/dist/commands/storage-core.d.ts +98 -0
  8. package/dist/commands/storage-core.js +223 -0
  9. package/dist/commands/storage-gate.d.ts +35 -0
  10. package/dist/commands/storage-gate.js +85 -0
  11. package/dist/commands/storage-offload.d.ts +342 -0
  12. package/dist/commands/storage-offload.js +943 -0
  13. package/dist/commands/storage.d.ts +199 -0
  14. package/dist/commands/storage.js +931 -0
  15. package/dist/fast-scaffold.js +5 -0
  16. package/dist/hq-cloud-sync-runner/bin/sync-runner.js +5140 -3412
  17. package/dist/hq-cloud-sync-runner/package.json +1 -1
  18. package/dist/lib/cli-flag-keys.d.ts +6 -0
  19. package/dist/lib/cli-flag-keys.js +6 -0
  20. package/dist/lib/doctor/checks/sync-health.d.ts +2 -0
  21. package/dist/lib/doctor/checks/sync-health.js +19 -0
  22. package/dist/lib/doctor/fix/apply.d.ts +14 -10
  23. package/dist/lib/doctor/fix/apply.js +30 -16
  24. package/dist/lib/doctor/fix/remediation.d.ts +5 -3
  25. package/dist/lib/doctor/fix/remediation.js +21 -7
  26. package/dist/lib/doctor/types.d.ts +1 -1
  27. package/dist/lib/doctor/types.js +1 -0
  28. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  29. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  30. package/dist/lib/storage-feature-flag.d.ts +56 -0
  31. package/dist/lib/storage-feature-flag.js +104 -0
  32. package/dist/main.js +12 -1
  33. package/dist/sentry-before-send.js +1 -0
  34. package/dist/utils/resident-package-preload.js +3 -1
  35. package/dist/utils/self-update.js +2 -2
  36. package/dist/utils/version-gate.d.ts +15 -0
  37. package/dist/utils/version-gate.js +80 -10
  38. package/package.json +2 -2
@@ -1 +1 @@
1
- {"name":"hq-cli-daemon-sync-runner","type":"module","version":"6.18.54","bundleSha256":"3a2ccf7955d7a5be1ab8e9a54e810d55ec7041e1eda534b84eba75e2199ee2f6","formatVersion":1}
1
+ {"name":"hq-cli-daemon-sync-runner","type":"module","version":"6.18.61","bundleSha256":"08a41f64915b26432d804644a2d516ef670e6d2133e8937a46c3a93f7398ab65","formatVersion":1}
@@ -1,4 +1,10 @@
1
1
  /** hq-flags keys used by CLI-wide routes. */
2
2
  export declare const CLI_COMMAND_HELP_CATALOG_FLAG = "cli.command-help-catalog";
3
3
  export declare const MULTI_COMPANY_SESSION_LOCK_FLAG = "hooks.multi-company-session-lock";
4
+ /**
5
+ * hq-flags key for HQ Storage (`hq storage` and Settings > Storage in the
6
+ * desktop app). Shared with hq-desktop-app, so it carries no `cli.` prefix,
7
+ * like `hq-anywhere-runtime`.
8
+ */
9
+ export declare const HQ_STORAGE_FLAG = "hq-storage";
4
10
  //# sourceMappingURL=cli-flag-keys.d.ts.map
@@ -1,4 +1,10 @@
1
1
  /** hq-flags keys used by CLI-wide routes. */
2
2
  export const CLI_COMMAND_HELP_CATALOG_FLAG = "cli.command-help-catalog";
3
3
  export const MULTI_COMPANY_SESSION_LOCK_FLAG = "hooks.multi-company-session-lock";
4
+ /**
5
+ * hq-flags key for HQ Storage (`hq storage` and Settings > Storage in the
6
+ * desktop app). Shared with hq-desktop-app, so it carries no `cli.` prefix,
7
+ * like `hq-anywhere-runtime`.
8
+ */
9
+ export const HQ_STORAGE_FLAG = "hq-storage";
4
10
  //# sourceMappingURL=cli-flag-keys.js.map
@@ -109,6 +109,8 @@ export interface SyncHealthDeps {
109
109
  export declare function isSafeCompanySlug(slug: string): boolean;
110
110
  /** True when this journal slug names a company rather than the personal tree. */
111
111
  export declare function isCompanyJournalSlug(slug: string): boolean;
112
+ /** True when this journal slug names the personal tree or personal vault. */
113
+ export declare function isPersonalJournalSlug(slug: string): boolean;
112
114
  /** Company slug from a `sync.journal.<slug>` check id, or null if not one. */
113
115
  export declare function journalSlugFromCheckId(checkId: string): string | null;
114
116
  /** The versions/sync check family. Registered in `createDefaultRegistry`. */
@@ -206,6 +206,10 @@ function journalSlugForCheckId(slug) {
206
206
  export function isCompanyJournalSlug(slug) {
207
207
  return !NON_COMPANY_JOURNAL_SLUGS.has(slug);
208
208
  }
209
+ /** True when this journal slug names the personal tree or personal vault. */
210
+ export function isPersonalJournalSlug(slug) {
211
+ return NON_COMPANY_JOURNAL_SLUGS.has(slug);
212
+ }
209
213
  /** Company slug from a `sync.journal.<slug>` check id, or null if not one. */
210
214
  export function journalSlugFromCheckId(checkId) {
211
215
  const match = /^sync\.journal\.(.+)$/.exec(checkId);
@@ -390,9 +394,24 @@ function journalAndManifestResults(deps) {
390
394
  }
391
395
  function journalResults(deps, journals) {
392
396
  const nowMs = deps.now().getTime();
397
+ const hasPersonalVaultJournal = journals.some((entry) => entry.slug === PERSONAL_VAULT_SCOPE_SLUG);
393
398
  return journals.map((entry) => {
394
399
  const lastSync = entry.journal?.lastSync;
395
400
  const checkId = `sync.journal.${journalSlugForCheckId(entry.slug)}`;
401
+ // The legacy `personal` shard and `__hq_personal_vault__` name the same
402
+ // tree. Once the vault journal exists, the old file is leftover
403
+ // bookkeeping: WARN would make `hq doctor --fix` look like it failed to
404
+ // repair a row it cannot refresh (a personal pull writes the vault
405
+ // journal, not this one).
406
+ if (entry.slug === PERSONAL_SCOPE_SLUG && hasPersonalVaultJournal) {
407
+ return {
408
+ status: "NA",
409
+ checkId,
410
+ reasonCode: "legacy-personal-journal",
411
+ target: entry.path,
412
+ message: "Sync journal 'personal' is unused on this machine — personal files now sync through the personal vault journal, so this leftover shard is not a live sync target.",
413
+ };
414
+ }
396
415
  // A company journal without a local tree is leftover membership state,
397
416
  // not a live sync target. WARN would make `hq doctor --fix` look like it
398
417
  // failed to repair something it was never going to touch (US-015 health
@@ -13,9 +13,10 @@
13
13
  * and blocking the pull left `sync.journal.<slug>` WARN after `--fix`.
14
14
  * 2. Allowlist only. It repairs the classified safe classes — restore an
15
15
  * execute bit, add a hook id to the gate profiles it is missing from,
16
- * re-register a script present on disk, or pull a company whose local
17
- * tree exists but whose journal is stale — and NEVER rewrites a hook body
18
- * or deletes a file. Classification is owned by {@link deriveRemediation};
16
+ * re-register a script present on disk, or pull a company or personal
17
+ * vault whose local tree exists but whose journal is stale — and NEVER
18
+ * rewrites a hook body or deletes a file. Classification is owned by
19
+ * {@link deriveRemediation};
19
20
  * a content-drift finding is manual-only and simply never appears in the
20
21
  * fixable set.
21
22
  * 3. Preview + confirmation. Every change is shown diff-style and requires
@@ -70,8 +71,9 @@ export interface ApplyFixesOptions {
70
71
  runChecks?: (hqRoot: string) => Promise<CheckResult[]>;
71
72
  /**
72
73
  * Targeted pull used by the `refresh-sync` class. Default shells out to
73
- * `hq sync pull --company <slug> --on-conflict keep`. Tests inject a stub
74
- * so `--fix` never hits the network.
74
+ * `hq sync pull --company <slug> --on-conflict keep`, or
75
+ * `hq sync pull --personal --on-conflict keep` for personal journals.
76
+ * Tests inject a stub so `--fix` never hits the network.
75
77
  */
76
78
  refreshSync?: (target: RefreshSyncTarget) => Promise<RefreshSyncResult>;
77
79
  /**
@@ -84,12 +86,14 @@ export interface ApplyFixesOptions {
84
86
  to: string;
85
87
  } | null;
86
88
  }
87
- /** One company the `refresh-sync` class will pull. */
89
+ /** One company or personal vault the `refresh-sync` class will pull. */
88
90
  export interface RefreshSyncTarget {
89
- /** Company slug from the `sync.journal.<slug>` check id. */
91
+ /** Company slug, or `personal` for the personal vault. */
90
92
  slug: string;
91
93
  /** HQ root the pull writes into. */
92
94
  hqRoot: string;
95
+ /** Pull the personal vault instead of `companies/<slug>`. */
96
+ personal?: boolean;
93
97
  }
94
98
  /** Outcome of one {@link ApplyFixesOptions.refreshSync} call. */
95
99
  export interface RefreshSyncResult {
@@ -160,9 +164,9 @@ export interface ApplyFixesResult {
160
164
  export declare function applyFixes(options: ApplyFixesOptions): Promise<ApplyFixesResult>;
161
165
  /**
162
166
  * Default `refresh-sync` repair: a bounded, pull-only, keep-conflicts
163
- * `hq sync pull --company <slug>` against the tree `--fix` is repairing.
164
- * Never a push, never interactive. A timeout or non-zero exit is reported
165
- * rather than thrown so later plans still run.
167
+ * `hq sync pull --company <slug>` (or `--personal`) against the tree
168
+ * `--fix` is repairing. Never a push, never interactive. A timeout or
169
+ * non-zero exit is reported rather than thrown so later plans still run.
166
170
  */
167
171
  export declare function defaultRefreshSync(target: RefreshSyncTarget): Promise<RefreshSyncResult>;
168
172
  /**
@@ -13,9 +13,10 @@
13
13
  * and blocking the pull left `sync.journal.<slug>` WARN after `--fix`.
14
14
  * 2. Allowlist only. It repairs the classified safe classes — restore an
15
15
  * execute bit, add a hook id to the gate profiles it is missing from,
16
- * re-register a script present on disk, or pull a company whose local
17
- * tree exists but whose journal is stale — and NEVER rewrites a hook body
18
- * or deletes a file. Classification is owned by {@link deriveRemediation};
16
+ * re-register a script present on disk, or pull a company or personal
17
+ * vault whose local tree exists but whose journal is stale — and NEVER
18
+ * rewrites a hook body or deletes a file. Classification is owned by
19
+ * {@link deriveRemediation};
19
20
  * a content-drift finding is manual-only and simply never appears in the
20
21
  * fixable set.
21
22
  * 3. Preview + confirmation. Every change is shown diff-style and requires
@@ -34,6 +35,7 @@
34
35
  import { spawnSync } from "node:child_process";
35
36
  import * as fs from "node:fs";
36
37
  import * as path from "node:path";
38
+ import { isPersonalJournalSlug } from "../checks/sync-health.js";
37
39
  import { createDefaultRegistry } from "../registry.js";
38
40
  import { flattenFamilies } from "../report.js";
39
41
  import { gateMembership, parseHookGateProfiles, } from "../hook-gate-profiles.js";
@@ -182,7 +184,13 @@ export async function applyFixes(options) {
182
184
  keysThisPass.add(key);
183
185
  plans.push(plan);
184
186
  }
185
- const refreshPlans = rotateRefreshSyncPlans(plans.filter((plan) => plan.fixClass === "refresh-sync"), lastAttemptedRefreshSyncSlug).slice(0, Math.max(0, MAX_REFRESH_SYNC_PLANS_PER_RUN - refreshSyncAppliedThisRun));
187
+ const seenRefreshTargets = new Set();
188
+ const refreshPlans = rotateRefreshSyncPlans(plans.filter((plan) => plan.fixClass === "refresh-sync"), lastAttemptedRefreshSyncSlug).filter((plan) => {
189
+ if (seenRefreshTargets.has(plan.target))
190
+ return false;
191
+ seenRefreshTargets.add(plan.target);
192
+ return true;
193
+ }).slice(0, Math.max(0, MAX_REFRESH_SYNC_PLANS_PER_RUN - refreshSyncAppliedThisRun));
186
194
  return [
187
195
  ...plans.filter((plan) => plan.fixClass !== "refresh-sync"),
188
196
  ...refreshPlans,
@@ -330,19 +338,21 @@ async function defaultRunChecks(hqRoot) {
330
338
  }
331
339
  /**
332
340
  * Default `refresh-sync` repair: a bounded, pull-only, keep-conflicts
333
- * `hq sync pull --company <slug>` against the tree `--fix` is repairing.
334
- * Never a push, never interactive. A timeout or non-zero exit is reported
335
- * rather than thrown so later plans still run.
341
+ * `hq sync pull --company <slug>` (or `--personal`) against the tree
342
+ * `--fix` is repairing. Never a push, never interactive. A timeout or
343
+ * non-zero exit is reported rather than thrown so later plans still run.
336
344
  */
337
345
  export function defaultRefreshSync(target) {
338
346
  const hqBin = process.argv[1];
347
+ const selector = target.personal || isPersonalJournalSlug(target.slug)
348
+ ? ["--personal"]
349
+ : ["--company", target.slug];
339
350
  const args = hqBin
340
351
  ? [
341
352
  hqBin,
342
353
  "sync",
343
354
  "pull",
344
- "--company",
345
- target.slug,
355
+ ...selector,
346
356
  "--hq-root",
347
357
  target.hqRoot,
348
358
  "--on-conflict",
@@ -353,8 +363,7 @@ export function defaultRefreshSync(target) {
353
363
  : [
354
364
  "sync",
355
365
  "pull",
356
- "--company",
357
- target.slug,
366
+ ...selector,
358
367
  "--hq-root",
359
368
  target.hqRoot,
360
369
  "--on-conflict",
@@ -471,23 +480,28 @@ export function defaultRewriteBotNodePath(name) {
471
480
  return null;
472
481
  return rewriteBotDaemonNodePath(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot, hqBinary: "hq" }), { platform: "darwin" });
473
482
  }
474
- /** Pull one company to refresh a stale or never-synced journal. */
483
+ /** Pull one company or the personal vault to refresh a stale journal. */
475
484
  function planRefreshSync(hqRoot, result, rem, refreshSync) {
476
485
  const slug = rem.fixTarget;
477
486
  if (!slug)
478
487
  return null;
488
+ const personal = isPersonalJournalSlug(slug);
479
489
  let outcome;
480
490
  return {
481
491
  checkId: result.checkId,
482
492
  fixClass: "refresh-sync",
483
493
  target: slug,
484
494
  relpath: "",
485
- preview: ` companies/${slug}\n` +
486
- ` ~ hq sync pull --company ${slug} --on-conflict keep\n` +
487
- ` refresh the stale sync journal (keeps local conflict copies)`,
495
+ preview: personal
496
+ ? ` personal vault\n` +
497
+ ` ~ hq sync pull --personal --on-conflict keep\n` +
498
+ ` refresh the stale personal sync journal (keeps local conflict copies)`
499
+ : ` companies/${slug}\n` +
500
+ ` ~ hq sync pull --company ${slug} --on-conflict keep\n` +
501
+ ` refresh the stale sync journal (keeps local conflict copies)`,
488
502
  summary: `pull ${slug} to refresh its sync journal`,
489
503
  apply: async () => {
490
- const result = await refreshSync({ slug, hqRoot });
504
+ const result = await refreshSync({ slug, hqRoot, personal });
491
505
  outcome = result.outcome;
492
506
  },
493
507
  refreshSyncOutcome: () => outcome,
@@ -24,9 +24,11 @@
24
24
  * never auto-registered: that is what created them.)
25
25
  * - `refresh-sync` — run a targeted pull for a company journal that is
26
26
  * stale or never-synced AND has a local
27
- * `companies/<slug>` tree. Pull-only, `--on-conflict
28
- * keep`, no hook-file rewrite. Personal journals and
29
- * leftover shards without a local tree stay manual.
27
+ * `companies/<slug>` tree, or for a live personal /
28
+ * personal-vault journal. Pull-only, `--on-conflict
29
+ * keep`, no hook-file rewrite. Leftover shards
30
+ * without a local tree stay unfixed (the check reports
31
+ * NA).
30
32
  *
31
33
  * EVERYTHING else — content drift between platform copies, a missing script, a
32
34
  * missing Codex counterpart, an unquoted `$CLAUDE_PROJECT_DIR`, a stale
@@ -24,9 +24,11 @@
24
24
  * never auto-registered: that is what created them.)
25
25
  * - `refresh-sync` — run a targeted pull for a company journal that is
26
26
  * stale or never-synced AND has a local
27
- * `companies/<slug>` tree. Pull-only, `--on-conflict
28
- * keep`, no hook-file rewrite. Personal journals and
29
- * leftover shards without a local tree stay manual.
27
+ * `companies/<slug>` tree, or for a live personal /
28
+ * personal-vault journal. Pull-only, `--on-conflict
29
+ * keep`, no hook-file rewrite. Leftover shards
30
+ * without a local tree stay unfixed (the check reports
31
+ * NA).
30
32
  *
31
33
  * EVERYTHING else — content drift between platform copies, a missing script, a
32
34
  * missing Codex counterpart, an unquoted `$CLAUDE_PROJECT_DIR`, a stale
@@ -36,7 +38,7 @@
36
38
  * content-drift finding is manual-only, because that boundary is load-bearing:
37
39
  * deciding which of two diverged copies is correct needs human judgement.
38
40
  */
39
- import { isCompanyJournalSlug, journalSlugFromCheckId, } from "../checks/sync-health.js";
41
+ import { isCompanyJournalSlug, isPersonalJournalSlug, journalSlugFromCheckId, } from "../checks/sync-health.js";
40
42
  /** Matches an exec-bit remediation command, quoted or not: `chmod +x <path>`. */
41
43
  const CHMOD_EXEC = /^chmod\s+\+x\s+(.+)$/;
42
44
  /**
@@ -117,10 +119,22 @@ export function deriveRemediation(result) {
117
119
  command: remediation ?? `hq bot start ${target}`,
118
120
  };
119
121
  }
120
- // refresh-sync — a company journal that is stale or never-synced. Only
121
- // company slugs: personal shards have no companies/<slug> tree and a
122
- // SessionStart `--fix --yes` must not pull the personal vault unprompted.
122
+ // refresh-sync — a company journal that is stale or never-synced, or a
123
+ // live personal / personal-vault journal. Leftover shards are NA at the
124
+ // check layer, so they never reach this classifier. A SessionStart
125
+ // `--fix --yes` pull is keep-conflicts and pull-only, matching the
126
+ // company repair: leaving personal journals WARN made the health hook
127
+ // report an unrepaired failure for a row doctor refused to touch.
123
128
  const journalSlug = journalSlugFromCheckId(checkId);
129
+ if (journalSlug && isPersonalJournalSlug(journalSlug)) {
130
+ return {
131
+ autoFixable: true,
132
+ fixClass: "refresh-sync",
133
+ fixTarget: "personal",
134
+ action: "Pull the personal vault to refresh its sync journal (keeps local conflict copies).",
135
+ command: "hq sync pull --personal --on-conflict keep",
136
+ };
137
+ }
124
138
  if (journalSlug && isCompanyJournalSlug(journalSlug)) {
125
139
  return {
126
140
  autoFixable: true,
@@ -19,7 +19,7 @@ export declare const DOCTOR_STATUSES: readonly ["PASS", "FAIL", "WARN", "UNTESTE
19
19
  */
20
20
  export type DoctorStatus = (typeof DOCTOR_STATUSES)[number];
21
21
  /** Stable, privacy-safe diagnostics emitted by the sync health family. */
22
- export declare const SYNC_REASON_CODES: readonly ["core-version-unavailable", "core-update-available", "no-local-tree", "never-synced", "invalid-last-sync", "stale-threshold", "manifest-unavailable", "manifest-state-unavailable", "no-manifest-scopes", "never-uploaded", "invalid-upload-time", "unresolved-company-uid", "realtime-lag-stuck", "receiver-permission-denied", "runner-restart-loop", "device-limit-backoff", "repeated-conflicts"];
22
+ export declare const SYNC_REASON_CODES: readonly ["core-version-unavailable", "core-update-available", "no-local-tree", "legacy-personal-journal", "never-synced", "invalid-last-sync", "stale-threshold", "manifest-unavailable", "manifest-state-unavailable", "no-manifest-scopes", "never-uploaded", "invalid-upload-time", "unresolved-company-uid", "realtime-lag-stuck", "receiver-permission-denied", "runner-restart-loop", "device-limit-backoff", "repeated-conflicts"];
23
23
  export type SyncReasonCode = (typeof SYNC_REASON_CODES)[number];
24
24
  /** Runtime type guard: true only for a member of the fixed vocabulary. */
25
25
  export declare function isDoctorStatus(value: unknown): value is DoctorStatus;
@@ -26,6 +26,7 @@ export const SYNC_REASON_CODES = [
26
26
  "core-version-unavailable",
27
27
  "core-update-available",
28
28
  "no-local-tree",
29
+ "legacy-personal-journal",
29
30
  "never-synced",
30
31
  "invalid-last-sync",
31
32
  "stale-threshold",