@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.
- package/CHANGELOG.md +26 -0
- package/dist/command-catalog.generated.d.ts +142 -0
- package/dist/command-catalog.generated.js +173 -0
- package/dist/command-help.js +2 -0
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/storage-core.d.ts +98 -0
- package/dist/commands/storage-core.js +223 -0
- package/dist/commands/storage-gate.d.ts +35 -0
- package/dist/commands/storage-gate.js +85 -0
- package/dist/commands/storage-offload.d.ts +342 -0
- package/dist/commands/storage-offload.js +943 -0
- package/dist/commands/storage.d.ts +199 -0
- package/dist/commands/storage.js +931 -0
- package/dist/fast-scaffold.js +5 -0
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +5140 -3412
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/cli-flag-keys.d.ts +6 -0
- package/dist/lib/cli-flag-keys.js +6 -0
- package/dist/lib/doctor/checks/sync-health.d.ts +2 -0
- package/dist/lib/doctor/checks/sync-health.js +19 -0
- package/dist/lib/doctor/fix/apply.d.ts +14 -10
- package/dist/lib/doctor/fix/apply.js +30 -16
- package/dist/lib/doctor/fix/remediation.d.ts +5 -3
- package/dist/lib/doctor/fix/remediation.js +21 -7
- package/dist/lib/doctor/types.d.ts +1 -1
- package/dist/lib/doctor/types.js +1 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/storage-feature-flag.d.ts +56 -0
- package/dist/lib/storage-feature-flag.js +104 -0
- package/dist/main.js +12 -1
- package/dist/sentry-before-send.js +1 -0
- package/dist/utils/resident-package-preload.js +3 -1
- package/dist/utils/self-update.js +2 -2
- package/dist/utils/version-gate.d.ts +15 -0
- package/dist/utils/version-gate.js +80 -10
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"hq-cli-daemon-sync-runner","type":"module","version":"6.18.
|
|
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
|
|
17
|
-
* tree exists but whose journal is stale — and NEVER
|
|
18
|
-
* or deletes a file. Classification is owned by
|
|
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
|
|
74
|
-
*
|
|
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
|
|
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
|
|
164
|
-
* Never a push, never interactive. A timeout or
|
|
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
|
|
17
|
-
* tree exists but whose journal is stale — and NEVER
|
|
18
|
-
* or deletes a file. Classification is owned by
|
|
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
|
|
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
|
|
334
|
-
* Never a push, never interactive. A timeout or
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
486
|
-
`
|
|
487
|
-
|
|
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
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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
|
|
121
|
-
//
|
|
122
|
-
//
|
|
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;
|