@indigoai-us/hq-cli 5.345.170 → 5.345.172
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 +84 -0
- package/assets/scaffold/core/scripts/hq-delegate-send.sh +1 -1
- package/dist/command-catalog.generated.d.ts +206 -7
- package/dist/command-catalog.generated.js +252 -8
- package/dist/command-registration-plan.d.ts +7 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/access.d.ts +32 -1
- package/dist/commands/access.js +112 -3
- package/dist/commands/agent-kit.d.ts +1 -1
- package/dist/commands/agent-kit.js +3 -1
- package/dist/commands/agents.js +2 -1
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.js +179 -18
- package/dist/commands/cloud.d.ts +58 -1
- package/dist/commands/cloud.js +228 -10
- package/dist/commands/core-company-index-scope-flag.d.ts +8 -1
- package/dist/commands/core-company-index-scope-flag.js +9 -2
- package/dist/commands/core-delegate-w1b.js +5 -2
- package/dist/commands/core-dm-bind-native.js +19 -4
- package/dist/commands/core-rebuild-index-fast.js +24 -6
- package/dist/commands/core.js +18 -6
- package/dist/commands/daemon.js +16 -1
- package/dist/commands/dm.d.ts +17 -3
- package/dist/commands/dm.js +121 -26
- package/dist/commands/files.d.ts +1 -0
- package/dist/commands/files.js +22 -4
- package/dist/commands/integrations-api.d.ts +4 -0
- package/dist/commands/integrations-api.js +18 -2
- package/dist/commands/integrations-connect.d.ts +10 -3
- package/dist/commands/integrations-connect.js +70 -6
- package/dist/commands/integrations-core.d.ts +23 -0
- package/dist/commands/integrations-core.js +100 -0
- package/dist/commands/integrations-manage.js +8 -1
- package/dist/commands/integrations.js +49 -5
- package/dist/commands/lanes-loop.d.ts +20 -0
- package/dist/commands/lanes-loop.js +69 -11
- package/dist/commands/lanes.js +9 -1
- package/dist/commands/rescue.d.ts +9 -0
- package/dist/commands/rescue.js +31 -0
- package/dist/commands/run.js +115 -40
- package/dist/commands/scan.d.ts +5 -1
- package/dist/commands/scan.js +16 -4
- package/dist/commands/secrets.js +50 -9
- package/dist/commands/sync-core.d.ts +22 -0
- package/dist/commands/sync-core.js +124 -0
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +2447 -2135
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-state.d.ts +17 -0
- package/dist/lib/agent-kit/inbox-state.js +41 -20
- package/dist/lib/agent-kit/kit-config.d.ts +2 -0
- package/dist/lib/agent-kit/kit-config.js +6 -0
- package/dist/lib/agent-kit/mcp/tools.js +12 -5
- package/dist/lib/agent-kit/run/heartbeat.d.ts +6 -3
- package/dist/lib/agent-kit/run/heartbeat.js +6 -3
- package/dist/lib/agent-kit/run/inbox.d.ts +8 -3
- package/dist/lib/agent-kit/run/inbox.js +42 -10
- package/dist/lib/agent-kit/run/request-timeout.d.ts +26 -0
- package/dist/lib/agent-kit/run/request-timeout.js +51 -0
- package/dist/lib/bot/api.d.ts +1 -1
- package/dist/lib/bot/config.d.ts +10 -0
- package/dist/lib/bot/config.js +17 -1
- package/dist/lib/bot/fleet-local.d.ts +142 -0
- package/dist/lib/bot/fleet-local.js +689 -0
- package/dist/lib/bot/fleet-python.d.ts +47 -0
- package/dist/lib/bot/fleet-python.js +218 -0
- package/dist/lib/bot/index.d.ts +2 -0
- package/dist/lib/bot/index.js +2 -0
- package/dist/lib/bot/local-config.d.ts +3 -2
- package/dist/lib/bot/local-config.js +5 -2
- package/dist/lib/bot/promote.d.ts +10 -0
- package/dist/lib/bot/promote.js +3 -2
- package/dist/lib/bot/prompt.d.ts +6 -1
- package/dist/lib/bot/prompt.js +8 -3
- package/dist/lib/bot/runtime/index.js +8 -4
- package/dist/lib/bot/runtime/scratch-dir.d.ts +24 -0
- package/dist/lib/bot/runtime/scratch-dir.js +41 -0
- package/dist/lib/caller-principal.d.ts +4 -0
- package/dist/lib/caller-principal.js +40 -0
- package/dist/lib/capacity/collectors/grok.js +8 -2
- package/dist/lib/cli-flag-keys.d.ts +2 -0
- package/dist/lib/cli-flag-keys.js +2 -0
- package/dist/lib/daemon/catalog.d.ts +12 -4
- package/dist/lib/daemon/catalog.js +70 -24
- package/dist/lib/daemon/config.d.ts +0 -7
- package/dist/lib/daemon/config.js +0 -32
- package/dist/lib/daemon/run.d.ts +5 -1
- package/dist/lib/daemon/run.js +48 -11
- package/dist/lib/daemon/supervisor.js +3 -1
- package/dist/lib/doctor/checks/release-links.d.ts +62 -1
- package/dist/lib/doctor/checks/release-links.js +188 -2
- package/dist/lib/doctor/fix/apply.js +54 -0
- package/dist/lib/doctor/fix/remediation.d.ts +8 -1
- package/dist/lib/doctor/fix/remediation.js +22 -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/index-render/index.d.ts +9 -0
- package/dist/lib/index-render/index.js +65 -5
- package/dist/lib/index-render/session-scope.d.ts +69 -0
- package/dist/lib/index-render/session-scope.js +279 -0
- package/dist/lib/lanes/admission.js +7 -20
- package/dist/lib/lanes/reconcile.js +13 -15
- package/dist/lib/lanes/stale-lock.d.ts +50 -0
- package/dist/lib/lanes/stale-lock.js +105 -0
- package/dist/lib/lanes/store.js +11 -76
- package/dist/lib/notify-recipient.d.ts +10 -4
- package/dist/lib/notify-recipient.js +16 -4
- package/dist/lib/secret-input-link.d.ts +42 -0
- package/dist/lib/secret-input-link.js +93 -0
- package/dist/lib/secret-scan/range.d.ts +57 -0
- package/dist/lib/secret-scan/range.js +266 -0
- package/dist/lib/secret-scan/repo-config.d.ts +18 -3
- package/dist/lib/secret-scan/repo-config.js +135 -2
- package/dist/lib/sync-core/engine-home.d.ts +44 -0
- package/dist/lib/sync-core/engine-home.js +193 -0
- package/dist/lib/sync-core/flag.d.ts +17 -0
- package/dist/lib/sync-core/flag.js +47 -0
- package/dist/lib/sync-core/reconcile.d.ts +31 -0
- package/dist/lib/sync-core/reconcile.js +196 -0
- package/dist/lib/sync-core/release.d.ts +32 -0
- package/dist/lib/sync-core/release.js +140 -0
- package/dist/lib/sync-core/rollout-state.d.ts +24 -0
- package/dist/lib/sync-core/rollout-state.js +94 -0
- package/dist/lib/vault-sync-switches.d.ts +5 -0
- package/dist/lib/vault-sync-switches.js +43 -0
- package/dist/run/script-bound-schema.d.ts +27 -0
- package/dist/run/script-bound-schema.js +97 -0
- package/dist/secrets-env-action.d.ts +2 -0
- package/dist/secrets-env-action.js +7 -2
- package/dist/utils/cognito-session.d.ts +3 -30
- package/dist/utils/cognito-session.js +2 -100
- package/dist/utils/machine-principal-state.d.ts +38 -0
- package/dist/utils/machine-principal-state.js +110 -0
- package/dist/utils/remote-list-not-converging.d.ts +21 -0
- package/dist/utils/remote-list-not-converging.js +40 -0
- package/dist/utils/safe-link.js +9 -0
- package/dist/utils/script-bound-exec.d.ts +158 -0
- package/dist/utils/script-bound-exec.js +568 -0
- package/dist/utils/sync-watchdog.d.ts +92 -0
- package/dist/utils/sync-watchdog.js +250 -0
- package/package.json +8 -8
- package/dist/lib/daemon/sync-core-canary.d.ts +0 -9
- package/dist/lib/daemon/sync-core-canary.js +0 -56
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in watchdog for `hq sync now` (feedback_b7c00a62).
|
|
3
|
+
*
|
|
4
|
+
* A scheduled `hq sync now --all --on-conflict keep` held a CPU core for
|
|
5
|
+
* hours and never exited. The cause, a LIST that re-requested the same page
|
|
6
|
+
* forever, is fixed in hq-cloud and hq-pro. This watchdog is a safety net
|
|
7
|
+
* for scheduled or unattended jobs, and it is OFF by default: a healthy sync
|
|
8
|
+
* is never stopped unless the caller asks for a limit.
|
|
9
|
+
*
|
|
10
|
+
* - Idle limit (`--max-idle` / HQ_SYNC_MAX_IDLE, default off): stop the run
|
|
11
|
+
* after this long with no observed progress. Progress is a change in this
|
|
12
|
+
* process's hq-cloud sync-progress snapshot: a leg starting, its plan, or a
|
|
13
|
+
* file transferred, skipped, or in conflict. The snapshot has no counter
|
|
14
|
+
* for LIST pages or planned rows, so the remote LIST and planning phase of
|
|
15
|
+
* a leg counts as no progress; set the idle limit longer than the slowest
|
|
16
|
+
* expected planning phase. One file transfer also counts only when it
|
|
17
|
+
* completes.
|
|
18
|
+
* - Total cap (`--max-runtime` / HQ_SYNC_MAX_RUNTIME, default off).
|
|
19
|
+
*
|
|
20
|
+
* Time is measured on the monotonic clock (`process.hrtime`), which does not
|
|
21
|
+
* advance while a Mac or Linux laptop sleeps, so sleep is not idle time.
|
|
22
|
+
*
|
|
23
|
+
* Two layers enforce the limits:
|
|
24
|
+
*
|
|
25
|
+
* 1. An in-process check. When a limit passes, the run rejects with
|
|
26
|
+
* {@link SyncWatchdogTimeoutError}; the command prints the message,
|
|
27
|
+
* records a failed sync (bounded to {@link SYNC_WATCHDOG_REPORT_GRACE_MS}),
|
|
28
|
+
* and exits {@link SYNC_WATCHDOG_EXIT_CODE} (124).
|
|
29
|
+
* 2. A worker-thread backstop. A timer on the main thread cannot fire while
|
|
30
|
+
* the main thread spins in a loop that never yields. The worker reads the
|
|
31
|
+
* same progress clock through shared memory and, once a limit is exceeded
|
|
32
|
+
* by {@link SYNC_WATCHDOG_BACKSTOP_GRACE_MS}, writes the message to stderr
|
|
33
|
+
* and SIGKILLs the process. The backstop stays armed after an in-process
|
|
34
|
+
* timeout until the process exits, so hung post-timeout work is still
|
|
35
|
+
* ended. A backstop kill exits 137 on POSIX (128 + SIGKILL), not 124; on
|
|
36
|
+
* Windows the process ends with exit code 1.
|
|
37
|
+
*/
|
|
38
|
+
import { Worker } from "node:worker_threads";
|
|
39
|
+
/** Default no-progress limit: off. Opt in with --max-idle / HQ_SYNC_MAX_IDLE. */
|
|
40
|
+
export const DEFAULT_SYNC_MAX_IDLE_SECONDS = 0;
|
|
41
|
+
/** Default total cap: off. */
|
|
42
|
+
export const DEFAULT_SYNC_MAX_RUNTIME_SECONDS = 0;
|
|
43
|
+
/** How long the worker backstop waits past a limit before it kills. */
|
|
44
|
+
export const SYNC_WATCHDOG_BACKSTOP_GRACE_MS = 60_000;
|
|
45
|
+
/** Upper bound on the failed-sync report after a timeout, before exit 124. */
|
|
46
|
+
export const SYNC_WATCHDOG_REPORT_GRACE_MS = 10_000;
|
|
47
|
+
/** Exit code for a run the in-process watchdog ended (same as coreutils `timeout`). */
|
|
48
|
+
export const SYNC_WATCHDOG_EXIT_CODE = 124;
|
|
49
|
+
export class SyncWatchdogTimeoutError extends Error {
|
|
50
|
+
code = "SYNC_WATCHDOG_TIMEOUT";
|
|
51
|
+
reason;
|
|
52
|
+
seconds;
|
|
53
|
+
constructor(reason, seconds, label) {
|
|
54
|
+
super(syncWatchdogMessage(reason, seconds, label));
|
|
55
|
+
this.name = "SyncWatchdogTimeoutError";
|
|
56
|
+
this.reason = reason;
|
|
57
|
+
this.seconds = seconds;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function syncWatchdogMessage(reason, seconds, label) {
|
|
61
|
+
const what = reason === "idle"
|
|
62
|
+
? `${label} made no progress for ${seconds}s`
|
|
63
|
+
: `${label} did not finish within ${seconds}s`;
|
|
64
|
+
return (`${what} and was stopped by the sync watchdog. Run it again; if it stops ` +
|
|
65
|
+
"here every time, report it with `hq feedback bug`. Change the limits with " +
|
|
66
|
+
"--max-idle / HQ_SYNC_MAX_IDLE and --max-runtime / HQ_SYNC_MAX_RUNTIME " +
|
|
67
|
+
"(0 turns a limit off).");
|
|
68
|
+
}
|
|
69
|
+
function parseSeconds(value, flag) {
|
|
70
|
+
const seconds = Number(value);
|
|
71
|
+
if (!Number.isInteger(seconds) || seconds < 0) {
|
|
72
|
+
throw new Error(`${flag} must be a non-negative integer number of seconds`);
|
|
73
|
+
}
|
|
74
|
+
return seconds;
|
|
75
|
+
}
|
|
76
|
+
/** Resolve both limits. A flag wins, then the environment, then the default. */
|
|
77
|
+
export function resolveSyncWatchdogLimits(raw, env = process.env) {
|
|
78
|
+
return {
|
|
79
|
+
idleSeconds: parseSeconds(raw.maxIdle ?? env.HQ_SYNC_MAX_IDLE ?? String(DEFAULT_SYNC_MAX_IDLE_SECONDS), "--max-idle"),
|
|
80
|
+
maxRuntimeSeconds: parseSeconds(raw.maxRuntime ?? env.HQ_SYNC_MAX_RUNTIME ?? String(DEFAULT_SYNC_MAX_RUNTIME_SECONDS), "--max-runtime"),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// ── Progress clock ──────────────────────────────────────────────────────────
|
|
84
|
+
// One per process. Float64 slot holds the last progress time (ms since epoch)
|
|
85
|
+
// in shared memory, so the worker backstop sees updates made on the main
|
|
86
|
+
// thread without any message passing.
|
|
87
|
+
let progressClock = null;
|
|
88
|
+
/** Monotonic milliseconds, shared by every thread in the process. */
|
|
89
|
+
function hrtimeMs() {
|
|
90
|
+
return Number(process.hrtime.bigint() / 1000000n);
|
|
91
|
+
}
|
|
92
|
+
let monotonicNow = hrtimeMs;
|
|
93
|
+
/** Test seam: replace the monotonic clock. `null` restores process.hrtime. */
|
|
94
|
+
export function setSyncWatchdogClockForTesting(clock) {
|
|
95
|
+
monotonicNow = clock ?? hrtimeMs;
|
|
96
|
+
}
|
|
97
|
+
let lastProgressAt = monotonicNow();
|
|
98
|
+
/** Record sync progress. Cheap; safe to call on every row or event. */
|
|
99
|
+
export function noteSyncProgress() {
|
|
100
|
+
const now = monotonicNow();
|
|
101
|
+
lastProgressAt = now;
|
|
102
|
+
if (progressClock)
|
|
103
|
+
progressClock[0] = now;
|
|
104
|
+
}
|
|
105
|
+
/** Last recorded progress time, for tests and the in-process check. */
|
|
106
|
+
export function lastSyncProgressAt() {
|
|
107
|
+
return lastProgressAt;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Build a probe that calls {@link noteSyncProgress} whenever THIS process's
|
|
111
|
+
* sync-progress snapshot changes. hq-cloud rewrites that snapshot when a leg
|
|
112
|
+
* starts, when it plans, and for every file transferred or skipped, for both
|
|
113
|
+
* push and pull, so a moving sync keeps resetting the idle limit without any
|
|
114
|
+
* change to the engine's progress recorders. Snapshots written by another
|
|
115
|
+
* process (the menubar runner) are ignored. A single file transfer is not
|
|
116
|
+
* seen until it completes; the engine's own per-body idle timeouts cover a
|
|
117
|
+
* transfer that stalls.
|
|
118
|
+
*/
|
|
119
|
+
export function createSnapshotProgressProbe(read, pid = process.pid) {
|
|
120
|
+
let last = null;
|
|
121
|
+
return () => {
|
|
122
|
+
let snap;
|
|
123
|
+
try {
|
|
124
|
+
snap = read();
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!snap || snap.pid !== pid)
|
|
130
|
+
return;
|
|
131
|
+
const key = [snap.startedAt, snap.phase, snap.company, snap.filesTotal, snap.filesDone, snap.conflicts].join("|");
|
|
132
|
+
if (last !== null && key !== last)
|
|
133
|
+
noteSyncProgress();
|
|
134
|
+
last = key;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Runs in a worker. Wakes every `checkMs` (or on cancel), reads the shared
|
|
138
|
+
// progress clock, and kills the whole process once a limit plus grace passes.
|
|
139
|
+
const BACKSTOP_SOURCE = `
|
|
140
|
+
const { workerData } = require("node:worker_threads");
|
|
141
|
+
const fs = require("node:fs");
|
|
142
|
+
const flag = new Int32Array(workerData.flag);
|
|
143
|
+
const clock = new Float64Array(workerData.clock);
|
|
144
|
+
const { startedAt, idleMs, maxRuntimeMs, graceMs, idleMessage, runtimeMessage } = workerData;
|
|
145
|
+
const checkMs = Math.max(10, Math.min(5000, Math.floor(graceMs / 4)));
|
|
146
|
+
for (;;) {
|
|
147
|
+
Atomics.wait(flag, 0, 0, checkMs);
|
|
148
|
+
if (Atomics.load(flag, 0) !== 0) break;
|
|
149
|
+
const now = Number(process.hrtime.bigint() / 1000000n);
|
|
150
|
+
let message = null;
|
|
151
|
+
if (idleMs > 0 && now - clock[0] > idleMs + graceMs) message = idleMessage;
|
|
152
|
+
else if (maxRuntimeMs > 0 && now - startedAt > maxRuntimeMs + graceMs) message = runtimeMessage;
|
|
153
|
+
if (message !== null) {
|
|
154
|
+
try { fs.writeSync(2, "\\n\\u2717 " + message + " (forced exit)\\n"); } catch {}
|
|
155
|
+
process.kill(process.pid, "SIGKILL");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
export const startWorkerBackstop = (options) => {
|
|
160
|
+
const flagBuffer = new SharedArrayBuffer(4);
|
|
161
|
+
const flag = new Int32Array(flagBuffer);
|
|
162
|
+
const worker = new Worker(BACKSTOP_SOURCE, {
|
|
163
|
+
eval: true,
|
|
164
|
+
workerData: {
|
|
165
|
+
flag: flagBuffer,
|
|
166
|
+
clock: options.clock.buffer,
|
|
167
|
+
startedAt: options.startedAt,
|
|
168
|
+
idleMs: options.idleMs,
|
|
169
|
+
maxRuntimeMs: options.maxRuntimeMs,
|
|
170
|
+
graceMs: options.graceMs,
|
|
171
|
+
idleMessage: options.idleMessage,
|
|
172
|
+
runtimeMessage: options.runtimeMessage,
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
worker.unref();
|
|
176
|
+
worker.on("error", () => {
|
|
177
|
+
// Best-effort; the in-process check still applies.
|
|
178
|
+
});
|
|
179
|
+
return {
|
|
180
|
+
cancel() {
|
|
181
|
+
Atomics.store(flag, 0, 1);
|
|
182
|
+
Atomics.notify(flag, 0);
|
|
183
|
+
void worker.terminate().catch(() => undefined);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
let backstopStarterForTest = null;
|
|
188
|
+
/** Test seam: replace the worker backstop. `null` restores the real one. */
|
|
189
|
+
export function setSyncBackstopStarterForTesting(start) {
|
|
190
|
+
backstopStarterForTest = start;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Run `run` under the watchdog. Resolves or rejects with `run`'s outcome when
|
|
194
|
+
* it finishes within the limits. Otherwise rejects with
|
|
195
|
+
* {@link SyncWatchdogTimeoutError} and leaves the backstop armed: the caller
|
|
196
|
+
* is expected to exit the process. With both limits 0 it just runs `run`.
|
|
197
|
+
*/
|
|
198
|
+
export async function withSyncWatchdog(run, options) {
|
|
199
|
+
const { idleMs, maxRuntimeMs, label } = options;
|
|
200
|
+
if (idleMs <= 0 && maxRuntimeMs <= 0)
|
|
201
|
+
return run();
|
|
202
|
+
const startedAt = monotonicNow();
|
|
203
|
+
if (!progressClock)
|
|
204
|
+
progressClock = new Float64Array(new SharedArrayBuffer(8));
|
|
205
|
+
noteSyncProgress();
|
|
206
|
+
const idleSeconds = Math.round(idleMs / 1000);
|
|
207
|
+
const runtimeSeconds = Math.round(maxRuntimeMs / 1000);
|
|
208
|
+
const backstop = (options.startBackstop ?? backstopStarterForTest ?? startWorkerBackstop)({
|
|
209
|
+
clock: progressClock,
|
|
210
|
+
startedAt,
|
|
211
|
+
idleMs,
|
|
212
|
+
maxRuntimeMs,
|
|
213
|
+
graceMs: options.backstopGraceMs ?? SYNC_WATCHDOG_BACKSTOP_GRACE_MS,
|
|
214
|
+
idleMessage: syncWatchdogMessage("idle", idleSeconds, label),
|
|
215
|
+
runtimeMessage: syncWatchdogMessage("runtime", runtimeSeconds, label),
|
|
216
|
+
});
|
|
217
|
+
const limits = [idleMs, maxRuntimeMs].filter((ms) => ms > 0);
|
|
218
|
+
const checkMs = options.checkIntervalMs ?? Math.max(10, Math.min(30_000, Math.floor(Math.min(...limits) / 4)));
|
|
219
|
+
let interval;
|
|
220
|
+
const deadline = new Promise((_, reject) => {
|
|
221
|
+
interval = setInterval(() => {
|
|
222
|
+
options.probeProgress?.();
|
|
223
|
+
const now = monotonicNow();
|
|
224
|
+
if (maxRuntimeMs > 0 && now - startedAt >= maxRuntimeMs) {
|
|
225
|
+
reject(new SyncWatchdogTimeoutError("runtime", runtimeSeconds, label));
|
|
226
|
+
}
|
|
227
|
+
else if (idleMs > 0 && now - lastProgressAt >= idleMs) {
|
|
228
|
+
reject(new SyncWatchdogTimeoutError("idle", idleSeconds, label));
|
|
229
|
+
}
|
|
230
|
+
}, checkMs);
|
|
231
|
+
});
|
|
232
|
+
let timedOut = false;
|
|
233
|
+
try {
|
|
234
|
+
return await Promise.race([run(), deadline]);
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
if (err instanceof SyncWatchdogTimeoutError)
|
|
238
|
+
timedOut = true;
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
if (interval !== undefined)
|
|
243
|
+
clearInterval(interval);
|
|
244
|
+
// After a timeout the backstop stays armed until the process exits, so
|
|
245
|
+
// a report or cleanup step that hangs cannot keep the process alive.
|
|
246
|
+
if (!timedOut)
|
|
247
|
+
backstop.cancel();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=sync-watchdog.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigoai-us/hq-cli",
|
|
3
|
-
"version": "5.345.
|
|
3
|
+
"version": "5.345.172",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@aws-sdk/client-iot-data-plane": "^3.1096.0",
|
|
53
53
|
"@aws-sdk/client-s3": "^3.1049.0",
|
|
54
54
|
"@aws-sdk/dsql-signer": "^3.1146.0",
|
|
55
|
-
"@indigoai-us/hq-cloud": "6.18.
|
|
55
|
+
"@indigoai-us/hq-cloud": "6.18.103",
|
|
56
56
|
"@indigoai-us/hq-flags-client": "^0.1.2",
|
|
57
57
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
58
58
|
"@sentry/node": "^10.49.0",
|
|
@@ -114,11 +114,11 @@
|
|
|
114
114
|
"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}": "eslint --cache --no-error-on-unmatched-pattern"
|
|
115
115
|
},
|
|
116
116
|
"optionalDependencies": {
|
|
117
|
-
"@indigoai-us/hq-hook-win32-x64": "5.345.
|
|
118
|
-
"@indigoai-us/hq-hook-win32-arm64": "5.345.
|
|
119
|
-
"@indigoai-us/hq-hook-darwin-x64": "5.345.
|
|
120
|
-
"@indigoai-us/hq-hook-darwin-arm64": "5.345.
|
|
121
|
-
"@indigoai-us/hq-hook-linux-x64": "5.345.
|
|
122
|
-
"@indigoai-us/hq-hook-linux-arm64": "5.345.
|
|
117
|
+
"@indigoai-us/hq-hook-win32-x64": "5.345.172",
|
|
118
|
+
"@indigoai-us/hq-hook-win32-arm64": "5.345.172",
|
|
119
|
+
"@indigoai-us/hq-hook-darwin-x64": "5.345.172",
|
|
120
|
+
"@indigoai-us/hq-hook-darwin-arm64": "5.345.172",
|
|
121
|
+
"@indigoai-us/hq-hook-linux-x64": "5.345.172",
|
|
122
|
+
"@indigoai-us/hq-hook-linux-arm64": "5.345.172"
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { SyncCoreCanaryConfig } from "./config.js";
|
|
2
|
-
export interface SyncCoreCanaryPlan {
|
|
3
|
-
binaryPath?: string;
|
|
4
|
-
vaultUid?: string;
|
|
5
|
-
canaryPath?: string;
|
|
6
|
-
blockedReason?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function inspectSyncCoreCanary(home: string, hqRoot: string | undefined, config: SyncCoreCanaryConfig, platform: NodeJS.Platform): SyncCoreCanaryPlan;
|
|
9
|
-
//# sourceMappingURL=sync-core-canary.d.ts.map
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { parse as parseToml } from "smol-toml";
|
|
4
|
-
function blocked(config, blockedReason) {
|
|
5
|
-
return { ...config, blockedReason };
|
|
6
|
-
}
|
|
7
|
-
function record(value) {
|
|
8
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
9
|
-
? value
|
|
10
|
-
: undefined;
|
|
11
|
-
}
|
|
12
|
-
export function inspectSyncCoreCanary(home, hqRoot, config, platform) {
|
|
13
|
-
if (platform !== "darwin" && platform !== "linux") {
|
|
14
|
-
return blocked(config, "the sync-core canary requires macOS or Linux");
|
|
15
|
-
}
|
|
16
|
-
try {
|
|
17
|
-
if (!fs.statSync(config.binaryPath).isFile())
|
|
18
|
-
return blocked(config, "the sync-core binary is missing");
|
|
19
|
-
fs.accessSync(config.binaryPath, fs.constants.X_OK);
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return blocked(config, "the sync-core binary is missing or not executable");
|
|
23
|
-
}
|
|
24
|
-
const configPath = path.join(home, ".hq", "sync-core", "config.toml");
|
|
25
|
-
let sync;
|
|
26
|
-
try {
|
|
27
|
-
sync = record(record(parseToml(fs.readFileSync(configPath, "utf8")))?.sync);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return blocked(config, `the sync-core config at ${configPath} is missing or invalid`);
|
|
31
|
-
}
|
|
32
|
-
if (sync?.engine !== "rust-test" || sync.mode !== "full") {
|
|
33
|
-
return blocked(config, "the sync-core config must select engine rust-test in full mode");
|
|
34
|
-
}
|
|
35
|
-
const vaults = sync.vaults;
|
|
36
|
-
if (!Array.isArray(vaults) || vaults.length !== 1 || vaults[0] !== config.vaultUid) {
|
|
37
|
-
return blocked(config, `the sync-core config must name exactly ${config.vaultUid}`);
|
|
38
|
-
}
|
|
39
|
-
if (!hqRoot || typeof sync.hq_root !== "string" || path.resolve(sync.hq_root) !== path.resolve(hqRoot)) {
|
|
40
|
-
return blocked(config, "the sync-core config must use the daemon's HQ folder");
|
|
41
|
-
}
|
|
42
|
-
const canaryPath = typeof sync.canary_path === "string" ? sync.canary_path.trim() : "";
|
|
43
|
-
if (!canaryPath)
|
|
44
|
-
return blocked(config, "the sync-core config must name one canary path");
|
|
45
|
-
const ownedPath = path.join(home, ".hq", "sync-core", "owned", `${config.vaultUid}.json`);
|
|
46
|
-
try {
|
|
47
|
-
const owned = record(JSON.parse(fs.readFileSync(ownedPath, "utf8")));
|
|
48
|
-
if (owned?.vault !== config.vaultUid)
|
|
49
|
-
throw new Error("mismatch");
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return blocked(config, `the sync-core ownership record for ${config.vaultUid} is missing or invalid`);
|
|
53
|
-
}
|
|
54
|
-
return { ...config, canaryPath };
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=sync-core-canary.js.map
|