@indigoai-us/hq-cli 5.319.0 → 5.321.0
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 +13 -0
- package/assets/scaffold/core/scripts/repo-run-registry.sh +3 -1
- package/assets/scaffold/core/scripts/session-journal.sh +40 -2
- package/dist/bin/hq-auth-refresh.d.ts +3 -1
- package/dist/bin/hq-auth-refresh.js +41 -6
- package/dist/command-catalog.generated.d.ts +24 -0
- package/dist/command-catalog.generated.js +30 -0
- package/dist/commands/core-hook-batch-command.d.ts +3 -0
- package/dist/commands/core-hook-batch-command.js +27 -0
- package/dist/commands/core-hook-batch-flag.d.ts +4 -0
- package/dist/commands/core-hook-batch-flag.js +7 -0
- package/dist/commands/core-hook-batch-native.d.ts +10 -0
- package/dist/commands/core-hook-batch-native.js +85 -0
- package/dist/commands/core-repo-run-registry-native.js +6 -1
- package/dist/commands/core-session-journal-native.d.ts +8 -1
- package/dist/commands/core-session-journal-native.js +77 -18
- package/dist/commands/core.js +2 -0
- package/dist/commands/lanes.js +28 -5
- package/dist/fast-core.js +13 -0
- package/dist/fast-scaffold.d.ts +2 -0
- package/dist/fast-scaffold.js +10 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +135 -63
- package/dist/lib/daemon/run.d.ts +2 -0
- package/dist/lib/daemon/run.js +10 -1
- package/dist/lib/lanes/flag-keys.d.ts +3 -0
- package/dist/lib/lanes/flag-keys.js +3 -0
- package/dist/lib/work-context/bind-best.d.ts +1 -1
- package/dist/lib/work-context/bind-best.js +3 -3
- package/dist/utils/package-use-lease.d.ts +25 -0
- package/dist/utils/package-use-lease.js +213 -0
- package/package.json +1 -1
package/dist/commands/lanes.js
CHANGED
|
@@ -35,7 +35,7 @@ import { withCliFeatureUsed } from "../utils/cli-telemetry.js";
|
|
|
35
35
|
import { resolveLanesHqRoot } from "../lib/lanes/hq-root.js";
|
|
36
36
|
import { isSsmRunCommandProcess } from "../lib/lanes/ssm-command-context.js";
|
|
37
37
|
import { readLanesFlagLocalOverride, readLanesRegistryFlag, readLanesRegistryFlagFailOff } from "../lib/lanes/registry-flag.js";
|
|
38
|
-
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_MESSAGE_ROUTE_OWNER_HOST_FLAG, LANE_ORPHANED_BARE_ID_DROPBOX_REPAIR_FLAG } from "../lib/lanes/flag-keys.js";
|
|
38
|
+
import { LANE_HIRE_GRANT_FINISHED_LANES_FLAG, LANE_LIST_SKIP_REMOTE_REFRESH_FLAG, LANE_MESSAGE_ROUTE_OWNER_HOST_FLAG, LANE_ORPHANED_BARE_ID_DROPBOX_REPAIR_FLAG, } from "../lib/lanes/flag-keys.js";
|
|
39
39
|
import { CODEX_ROLLOUT_RETENTION_FLAG, configuredCodexRolloutHomes, lowDiskGuardEnabledForLane, retainCodexRollouts } from "../lib/lanes/disk-guard.js";
|
|
40
40
|
import { isControllerAliasOutpostId } from "../lib/lanes/admission-host.js";
|
|
41
41
|
import { runLeadAutopilotPass } from "../lib/lanes/autopilot.js";
|
|
@@ -1337,6 +1337,7 @@ async function refreshRemoteLaneMirrors(ctx, hqRoot, records, parentLaneIds, opt
|
|
|
1337
1337
|
updated: new Map(),
|
|
1338
1338
|
unverifiedRemote: new Map(),
|
|
1339
1339
|
missingOnOwner: new Map(),
|
|
1340
|
+
skippedRemoteRefresh: new Set(),
|
|
1340
1341
|
};
|
|
1341
1342
|
const now = ctx.now();
|
|
1342
1343
|
const nowMs = now.getTime();
|
|
@@ -1378,6 +1379,7 @@ async function refreshRemoteLaneMirrors(ctx, hqRoot, records, parentLaneIds, opt
|
|
|
1378
1379
|
if (candidates.length === 0)
|
|
1379
1380
|
return result;
|
|
1380
1381
|
const enabledByCompany = new Map();
|
|
1382
|
+
const skipRefreshByCompany = new Map();
|
|
1381
1383
|
const enabledCandidates = [];
|
|
1382
1384
|
for (const lane of candidates) {
|
|
1383
1385
|
const company = resolveLaneCompany(hqRoot, lane).company;
|
|
@@ -1392,8 +1394,20 @@ async function refreshRemoteLaneMirrors(ctx, hqRoot, records, parentLaneIds, opt
|
|
|
1392
1394
|
});
|
|
1393
1395
|
enabledByCompany.set(companyKey, enabled);
|
|
1394
1396
|
}
|
|
1395
|
-
if (enabled)
|
|
1396
|
-
|
|
1397
|
+
if (!enabled)
|
|
1398
|
+
continue;
|
|
1399
|
+
if (options.skipRemoteRefreshForCompany) {
|
|
1400
|
+
let skipRefresh = skipRefreshByCompany.get(companyKey);
|
|
1401
|
+
if (skipRefresh === undefined) {
|
|
1402
|
+
skipRefresh = await options.skipRemoteRefreshForCompany(company);
|
|
1403
|
+
skipRefreshByCompany.set(companyKey, skipRefresh);
|
|
1404
|
+
}
|
|
1405
|
+
if (skipRefresh) {
|
|
1406
|
+
result.skippedRemoteRefresh.add(lane.lane_id);
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
enabledCandidates.push(lane);
|
|
1397
1411
|
}
|
|
1398
1412
|
if (enabledCandidates.length === 0)
|
|
1399
1413
|
return result;
|
|
@@ -4950,7 +4964,12 @@ async function runList(ctx, opts) {
|
|
|
4950
4964
|
}
|
|
4951
4965
|
const remoteRead = ctx.env[REMOTE_LANE_READ_ENV] === "1";
|
|
4952
4966
|
const remoteRefresh = remoteRead
|
|
4953
|
-
? {
|
|
4967
|
+
? {
|
|
4968
|
+
updated: new Map(),
|
|
4969
|
+
unverifiedRemote: new Map(),
|
|
4970
|
+
missingOnOwner: new Map(),
|
|
4971
|
+
skippedRemoteRefresh: new Set(),
|
|
4972
|
+
}
|
|
4954
4973
|
: await refreshRemoteLaneMirrors(ctx, hqRoot, laneSource, new Set(laneSource
|
|
4955
4974
|
.filter((lane) => matchesLaneFilters(lane, false))
|
|
4956
4975
|
.map((lane) => lane.lane_id)), {
|
|
@@ -4958,6 +4977,7 @@ async function runList(ctx, opts) {
|
|
|
4958
4977
|
laneIds: new Set(laneSource
|
|
4959
4978
|
.filter((lane) => matchesLaneFilters(lane, false))
|
|
4960
4979
|
.map((lane) => lane.lane_id)),
|
|
4980
|
+
skipRemoteRefreshForCompany: (company) => readLanesRegistryFlagFailOff(LANE_LIST_SKIP_REMOTE_REFRESH_FLAG, { company, env: ctx.env }),
|
|
4961
4981
|
});
|
|
4962
4982
|
for (const [laneId, updated] of remoteRefresh.updated) {
|
|
4963
4983
|
const index = laneSource.findIndex((lane) => lane.lane_id === laneId);
|
|
@@ -4995,6 +5015,7 @@ async function runList(ctx, opts) {
|
|
|
4995
5015
|
const ownerEligibleLaneIds = new Set();
|
|
4996
5016
|
for (const lane of selectedLanes) {
|
|
4997
5017
|
if (remoteRead ||
|
|
5018
|
+
remoteRefresh.skippedRemoteRefresh.has(lane.lane_id) ||
|
|
4998
5019
|
lane.host.kind !== "outpost" ||
|
|
4999
5020
|
isTerminalLaneState(lane.state) ||
|
|
5000
5021
|
laneRunsHere(lane, host)) {
|
|
@@ -5034,6 +5055,7 @@ async function runList(ctx, opts) {
|
|
|
5034
5055
|
const livenessBySession = new Map();
|
|
5035
5056
|
let livenessDeps;
|
|
5036
5057
|
const lanes = selectedLanes.map((lane) => {
|
|
5058
|
+
const overdue = Boolean(lane.overdue) || isOverdue(hqRoot, lane.lane_id, now);
|
|
5037
5059
|
const remoteQueued = lane.state === "queued" &&
|
|
5038
5060
|
lane.host.kind === "outpost" &&
|
|
5039
5061
|
!laneRunsHere(lane, host);
|
|
@@ -5052,7 +5074,7 @@ async function runList(ctx, opts) {
|
|
|
5052
5074
|
queued_details: lane.queued_reason === "low_disk" ? lane.queued_details : undefined,
|
|
5053
5075
|
}
|
|
5054
5076
|
: {}),
|
|
5055
|
-
overdue
|
|
5077
|
+
overdue,
|
|
5056
5078
|
stalled: Boolean(lane.stalled),
|
|
5057
5079
|
// Listing is observational. Reconcile owns durable liveness transitions.
|
|
5058
5080
|
senior_lost: lane.state === "running" && lane.senior.kind === "session" && lane.senior.id
|
|
@@ -7873,6 +7895,7 @@ async function runReconcile(ctx, opts, recoverQueuedMessages) {
|
|
|
7873
7895
|
updated: new Map(),
|
|
7874
7896
|
unverifiedRemote: new Map(),
|
|
7875
7897
|
missingOnOwner: new Map(),
|
|
7898
|
+
skippedRemoteRefresh: new Set(),
|
|
7876
7899
|
}
|
|
7877
7900
|
: await refreshRemoteLaneMirrors(ctx, hqRoot, loadAllLanes(hqRoot));
|
|
7878
7901
|
const remoteLost = [];
|
package/dist/fast-core.js
CHANGED
|
@@ -35,6 +35,11 @@ export async function runFastCore(argv) {
|
|
|
35
35
|
const envOverride = localBooleanFlagOverride(entry.familyFlagKey, process.env);
|
|
36
36
|
familyEnabled = envOverride ?? await (await import("./native-fast-route.js")).fastFlagEnabled(entry.familyFlagKey, process.env, { numericEnvironmentOverride: false });
|
|
37
37
|
}
|
|
38
|
+
if (entry.kind === "native" && entry.fallbackToCommandGraph && !familyEnabled) {
|
|
39
|
+
const { runCli } = await import("./main.js");
|
|
40
|
+
await runCli();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
38
43
|
const useShell = entry.kind === "native" && Boolean(entry.familyFlagKey) && !familyEnabled;
|
|
39
44
|
const worktreeScopeFixEnabled = entry.name === "repo-run-registry"
|
|
40
45
|
? await (await import("./native-fast-route.js")).fastFlagEnabled(CORE_RRR_WORKTREE_SCOPE_FIX_FLAG, process.env, { numericEnvironmentOverride: false })
|
|
@@ -74,6 +79,14 @@ export async function runFastCore(argv) {
|
|
|
74
79
|
const readsStdin = entry.readsStdinFor?.(parsed.args) ?? entry.readsStdin ?? false;
|
|
75
80
|
const stdin = readsStdin ? await readStdinIfPiped(process.stdin) : "";
|
|
76
81
|
const code = await handler(parsed.args, stdin, process.cwd(), hqRoot, entry.name.split(" ").at(-1) ?? entry.name, parsed.hqRootArg, worktreeScopeFixEnabled);
|
|
82
|
+
if (code === undefined) {
|
|
83
|
+
if (!entry.fallbackToCommandGraph) {
|
|
84
|
+
throw new Error(`Native fast handler ${entry.exportName} requested an unavailable command-graph fallback`);
|
|
85
|
+
}
|
|
86
|
+
const { runCli } = await import("./main.js");
|
|
87
|
+
await runCli();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
77
90
|
// Let Node drain handler output before terminating. The timeout guard's
|
|
78
91
|
// stderr message must survive the native route's process boundary.
|
|
79
92
|
process.exitCode = code;
|
package/dist/fast-scaffold.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export type FastScaffoldScript = {
|
|
|
32
32
|
familyFlagKey?: string;
|
|
33
33
|
/** Shell rollback companion used while the family gate is off. */
|
|
34
34
|
asset?: string;
|
|
35
|
+
/** Return to the Commander graph when this new route has no shell companion. */
|
|
36
|
+
fallbackToCommandGraph?: boolean;
|
|
35
37
|
/** Root context used by the native handler. */
|
|
36
38
|
root?: "live" | "cwd" | "passthrough";
|
|
37
39
|
/** Cwd used for a shell rollback companion. Defaults to the caller cwd. */
|
package/dist/fast-scaffold.js
CHANGED
|
@@ -217,6 +217,16 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
217
217
|
shellHqRoot: "live",
|
|
218
218
|
...(name === "session-project" ? { readsStdin: true, readsStdinFor: (args) => args[0] === "ingest-plan" } : {}),
|
|
219
219
|
})),
|
|
220
|
+
{
|
|
221
|
+
name: "hook-batch journal-due",
|
|
222
|
+
kind: "native",
|
|
223
|
+
modulePath: "./commands/core-hook-batch-native.js",
|
|
224
|
+
exportName: "runCoreHookBatchFast",
|
|
225
|
+
flagKey: "hq-core-native-fast-route",
|
|
226
|
+
familyFlagKey: "core-hook-batch",
|
|
227
|
+
root: "live",
|
|
228
|
+
fallbackToCommandGraph: true,
|
|
229
|
+
},
|
|
220
230
|
...[
|
|
221
231
|
{ name: "eval-trigger", modulePath: "./commands/core-eval-trigger-native.js", exportName: "runEvalTriggerFast", asset: "core/scripts/eval-trigger.sh", root: "cwd", shellCwd: "caller", shellHqRoot: "none", readsStdinFor: (args) => args[0] === "--check" },
|
|
222
232
|
{ name: "migrate-policy-triggers", modulePath: "./commands/core-migrate-policy-triggers-native.js", exportName: "runMigratePolicyTriggersFast", asset: "core/scripts/migrate-policy-triggers.sh", root: "live", shellCwd: "caller", shellHqRoot: "live" },
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,17 @@ import "./node-preflight.js";
|
|
|
3
3
|
import "./node-network-compat-fast.js";
|
|
4
4
|
import { isVersionRequest } from "./version-request.js";
|
|
5
5
|
import { isFastCoreRequest } from "./fast-scaffold.js";
|
|
6
|
+
type PackageUseLeaseLoader = () => Promise<void>;
|
|
7
|
+
declare function isNpmPackageEntry(entryUrl: string): boolean;
|
|
8
|
+
declare function dispatchWithPackageUseLease(entryUrl: string, dispatch: () => void, loadLease?: PackageUseLeaseLoader): void | Promise<void>;
|
|
9
|
+
declare function runCliEntry(entryUrl: string, dispatch: () => void, loadLease?: PackageUseLeaseLoader): void | Promise<void>;
|
|
6
10
|
export declare const __test__: {
|
|
7
11
|
isVersionRequest: typeof isVersionRequest;
|
|
8
12
|
isFastCoreRequest: typeof isFastCoreRequest;
|
|
13
|
+
dispatchWithPackageUseLease: typeof dispatchWithPackageUseLease;
|
|
14
|
+
runCliEntry: typeof runCliEntry;
|
|
15
|
+
isNpmPackageEntry: typeof isNpmPackageEntry;
|
|
16
|
+
acquirePackageUseLease: (prefix: string, version: string, stateDirectory?: string) => Promise<import("./utils/package-use-lease.js").PackageUseLease>;
|
|
9
17
|
};
|
|
18
|
+
export {};
|
|
10
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -17,77 +17,149 @@ import { installProcessRejectionBoundary } from "./unhandled-rejection-boundary.
|
|
|
17
17
|
// command never run (HQ-CLI-W). Sets process.exitCode only, never process.exit,
|
|
18
18
|
// so runCli's finally still finalizes release health and flushes Sentry.
|
|
19
19
|
installProcessRejectionBoundary();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
function dispatchCliEntry() {
|
|
21
|
+
if (isVersionRequest(process.argv)) {
|
|
22
|
+
// Bare `--version` is the CLI semver only (the contract field updaters
|
|
23
|
+
// compare). `hq version` and `--json` print the labelled HQ/CLI report.
|
|
24
|
+
// Lazy so this path still skips the command graph.
|
|
25
|
+
if (wantsLabelledVersionReport(process.argv)) {
|
|
26
|
+
void import("./lib/flag-registry.js").then(({ kickFlagRegistryReadiness }) => {
|
|
27
|
+
kickFlagRegistryReadiness();
|
|
28
|
+
return import("./utils/version-report.js").then(({ runVersionCommand }) => runVersionCommand(process.argv));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Keep the benchmarked updater fast route limited to the installed semver.
|
|
33
|
+
// Registry checks and flag resolution belong to the regular command path.
|
|
34
|
+
void import("./cli-version.js").then(({ CLI_VERSION }) => {
|
|
35
|
+
process.stdout.write(`${CLI_VERSION}\n`);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (parseFastCore(process.argv)?.entry.kind === "native" &&
|
|
40
|
+
(process.env.HQ_FLAG_HQ_CORE_NATIVE_FAST_ROUTE === "true" ||
|
|
41
|
+
process.env.HQ_FLAG_HQ_CORE_NATIVE_FAST_ROUTE === "1")) {
|
|
42
|
+
// An explicit enabled override has already decided the global gate. Skip the
|
|
43
|
+
// snapshot reader import on hot native plumbing paths; runFastCore still
|
|
44
|
+
// checks the command-family flag before choosing native or shell rollback.
|
|
45
|
+
void import("./fast-core.js").then(({ runFastCore }) => runFastCore(process.argv));
|
|
46
|
+
}
|
|
47
|
+
else if (parseFastCore(process.argv)?.entry.kind === "native") {
|
|
48
|
+
// Native routes are default-off. Resolve the company-scoped persisted flag
|
|
49
|
+
// without loading the command graph; a miss or stale snapshot takes the
|
|
50
|
+
// existing full-graph route.
|
|
51
|
+
void import("./native-fast-route.js").then(async ({ nativeFastRouteEnabled }) => {
|
|
52
|
+
if (await nativeFastRouteEnabled(process.argv)) {
|
|
53
|
+
const { runFastCore } = await import("./fast-core.js");
|
|
54
|
+
await runFastCore(process.argv);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const { runCli } = await import("./main.js");
|
|
58
|
+
await runCli();
|
|
59
|
+
}
|
|
28
60
|
});
|
|
29
61
|
}
|
|
30
|
-
else {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
else if (parseSecretsEnvFastRequest(process.argv)) {
|
|
63
|
+
const request = parseSecretsEnvFastRequest(process.argv);
|
|
64
|
+
void import("./secrets-env-fast-route.js").then(async (route) => {
|
|
65
|
+
await route.dispatchSecretsEnvFastRequest(request, {
|
|
66
|
+
isEnabled: () => route.secretsEnvFastRouteEnabled(request),
|
|
67
|
+
runFast: async () => {
|
|
68
|
+
const { runSecretsEnvFastPath } = await import("./secrets-env-fast-path.js");
|
|
69
|
+
return runSecretsEnvFastPath(request);
|
|
70
|
+
},
|
|
71
|
+
runCurrent: async () => {
|
|
72
|
+
const { runCli } = await import("./main.js");
|
|
73
|
+
await runCli();
|
|
74
|
+
},
|
|
75
|
+
});
|
|
35
76
|
});
|
|
36
77
|
}
|
|
78
|
+
else if (isFastCoreRequest(process.argv)) {
|
|
79
|
+
// Hot relocated plumbing (`hq core hq-session`, `hq core checkpoint-stop-gate`)
|
|
80
|
+
// dispatches straight to the bundled-script runner, so it never pays for the
|
|
81
|
+
// ~60-module command graph main.ts imports. See src/fast-scaffold.ts.
|
|
82
|
+
void import("./fast-core.js").then(({ runFastCore }) => runFastCore(process.argv));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Keep the command lifecycle detached from module evaluation, as it was
|
|
86
|
+
// before the fast --version split. Some best-effort teardown work uses
|
|
87
|
+
// unref'd handles; top-level-awaiting runCli() makes Node turn an otherwise
|
|
88
|
+
// successful command into exit 13 when that teardown promise remains pending.
|
|
89
|
+
// A floated rejection here no longer exits 0 silently: the boundary installed
|
|
90
|
+
// above turns it into a non-zero exit (HQ-CLI-W).
|
|
91
|
+
void import("./main.js").then(({ runCli }) => runCli());
|
|
92
|
+
}
|
|
37
93
|
}
|
|
38
|
-
|
|
39
|
-
(
|
|
40
|
-
process.env.HQ_FLAG_HQ_CORE_NATIVE_FAST_ROUTE === "1")) {
|
|
41
|
-
// An explicit enabled override has already decided the global gate. Skip the
|
|
42
|
-
// snapshot reader import on hot native plumbing paths; runFastCore still
|
|
43
|
-
// checks the command-family flag before choosing native or shell rollback.
|
|
44
|
-
void import("./fast-core.js").then(({ runFastCore }) => runFastCore(process.argv));
|
|
94
|
+
function isNpmPackageEntry(entryUrl) {
|
|
95
|
+
return /\/node_modules\/@indigoai-us\/hq-cli\/dist\/index\.js$/i.test(entryUrl);
|
|
45
96
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
void import("./native-fast-route.js").then(async ({ nativeFastRouteEnabled }) => {
|
|
51
|
-
if (await nativeFastRouteEnabled(process.argv)) {
|
|
52
|
-
const { runFastCore } = await import("./fast-core.js");
|
|
53
|
-
await runFastCore(process.argv);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
const { runCli } = await import("./main.js");
|
|
57
|
-
await runCli();
|
|
58
|
-
}
|
|
59
|
-
});
|
|
97
|
+
function isPackageUseUpdatePendingError(error) {
|
|
98
|
+
return Boolean(error &&
|
|
99
|
+
typeof error === "object" &&
|
|
100
|
+
error.name === "PackageUseUpdatePendingError");
|
|
60
101
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
102
|
+
function packageUseErrorClass(error) {
|
|
103
|
+
if (!error || typeof error !== "object")
|
|
104
|
+
return "unknown";
|
|
105
|
+
const value = error;
|
|
106
|
+
if (typeof value.code === "string")
|
|
107
|
+
return value.code;
|
|
108
|
+
if (value.cause && typeof value.cause === "object") {
|
|
109
|
+
const cause = value.cause;
|
|
110
|
+
if (typeof cause.code === "string")
|
|
111
|
+
return cause.code;
|
|
112
|
+
if (typeof cause.name === "string")
|
|
113
|
+
return cause.name;
|
|
114
|
+
}
|
|
115
|
+
return typeof value.name === "string" ? value.name : "unknown";
|
|
76
116
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
117
|
+
function dispatchWithPackageUseLease(entryUrl, dispatch, loadLease = async () => {
|
|
118
|
+
const { acquireCurrentPackageUseLease } = await import("./utils/package-use-lease.js");
|
|
119
|
+
acquireCurrentPackageUseLease();
|
|
120
|
+
}) {
|
|
121
|
+
if (!isNpmPackageEntry(entryUrl)) {
|
|
122
|
+
dispatch();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
return loadLease().then(dispatch, (error) => {
|
|
126
|
+
if (isPackageUseUpdatePendingError(error))
|
|
127
|
+
throw error;
|
|
128
|
+
process.stderr.write(`hq-cli package-use lease unavailable (${packageUseErrorClass(error)}); continuing without lease\n`);
|
|
129
|
+
dispatch();
|
|
130
|
+
});
|
|
82
131
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
132
|
+
function runCliEntry(entryUrl, dispatch, loadLease) {
|
|
133
|
+
const handlePendingUpdate = (error) => {
|
|
134
|
+
if (!isPackageUseUpdatePendingError(error))
|
|
135
|
+
throw error;
|
|
136
|
+
const message = error instanceof Error
|
|
137
|
+
? error.message
|
|
138
|
+
: "The HQ CLI package is being updated";
|
|
139
|
+
process.stderr.write(`hq-cli: ${message}\n`);
|
|
140
|
+
process.exitCode = 1;
|
|
141
|
+
};
|
|
142
|
+
try {
|
|
143
|
+
const result = dispatchWithPackageUseLease(entryUrl, dispatch, loadLease);
|
|
144
|
+
return result?.catch(handlePendingUpdate);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
handlePendingUpdate(error);
|
|
148
|
+
}
|
|
91
149
|
}
|
|
92
|
-
|
|
150
|
+
// Local builds and benchmark fixtures are not installed in an npm prefix.
|
|
151
|
+
// Keep their fast route free of package-use filesystem work; npm installs still
|
|
152
|
+
// publish a lease before dispatch.
|
|
153
|
+
void runCliEntry(import.meta.url, dispatchCliEntry);
|
|
154
|
+
export const __test__ = {
|
|
155
|
+
isVersionRequest,
|
|
156
|
+
isFastCoreRequest,
|
|
157
|
+
dispatchWithPackageUseLease,
|
|
158
|
+
runCliEntry,
|
|
159
|
+
isNpmPackageEntry,
|
|
160
|
+
acquirePackageUseLease: async (prefix, version, stateDirectory) => {
|
|
161
|
+
const lease = await import("./utils/package-use-lease.js");
|
|
162
|
+
return lease.acquirePackageUseLease(prefix, version, stateDirectory);
|
|
163
|
+
},
|
|
164
|
+
};
|
|
93
165
|
//# sourceMappingURL=index.js.map
|
package/dist/lib/daemon/run.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ import { type HostApp } from "./supervisor.js";
|
|
|
12
12
|
export declare const LOG_ROTATE_BYTES: number;
|
|
13
13
|
/** Exit code for "restart me": non-zero so every service manager relaunches (Windows tasks only restart on failure). */
|
|
14
14
|
export declare const RESTART_EXIT_CODE = 75;
|
|
15
|
+
/** Route an updater request through the daemon's existing graceful handoff. */
|
|
16
|
+
export declare function handoffForPackageUpdateRequest(requested: boolean, restartDaemon: () => void): void;
|
|
15
17
|
export interface RunDaemonOptions {
|
|
16
18
|
foreground?: boolean;
|
|
17
19
|
/** Started by the OS unit, which relaunches the daemon whenever it exits. */
|
package/dist/lib/daemon/run.js
CHANGED
|
@@ -12,6 +12,7 @@ import * as os from "node:os";
|
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { loadCachedTokens } from "@indigoai-us/hq-cloud";
|
|
14
14
|
import { CLI_VERSION } from "../../cli-version.js";
|
|
15
|
+
import { currentPackageUseUpdateRequested } from "../../utils/package-use-lease.js";
|
|
15
16
|
import { isLocalDependencyInstall, resolveRunningInstall } from "../../utils/version-gate.js";
|
|
16
17
|
import { agentKitPaths } from "../agent-kit/paths.js";
|
|
17
18
|
import { readBotConfig } from "../bot/config.js";
|
|
@@ -39,6 +40,11 @@ import { userToolDirs } from "./tools.js";
|
|
|
39
40
|
export const LOG_ROTATE_BYTES = 5 * 1024 * 1024;
|
|
40
41
|
/** Exit code for "restart me": non-zero so every service manager relaunches (Windows tasks only restart on failure). */
|
|
41
42
|
export const RESTART_EXIT_CODE = 75;
|
|
43
|
+
/** Route an updater request through the daemon's existing graceful handoff. */
|
|
44
|
+
export function handoffForPackageUpdateRequest(requested, restartDaemon) {
|
|
45
|
+
if (requested)
|
|
46
|
+
restartDaemon();
|
|
47
|
+
}
|
|
42
48
|
const LEGACY_PROBE_TTL_MS = 60_000;
|
|
43
49
|
/** A flag read that has not answered by then counts as off. */
|
|
44
50
|
const HANDOFF_FLAG_TIMEOUT_MS = 10_000;
|
|
@@ -603,7 +609,10 @@ export async function runDaemon(opts) {
|
|
|
603
609
|
log("info", `rotated ${n} log file(s)`);
|
|
604
610
|
return true;
|
|
605
611
|
},
|
|
606
|
-
takeRequests: () =>
|
|
612
|
+
takeRequests: () => {
|
|
613
|
+
handoffForPackageUpdateRequest(currentPackageUseUpdateRequested(), restartDaemon);
|
|
614
|
+
return takeControlRequests(paths.requestsDir);
|
|
615
|
+
},
|
|
607
616
|
restartDaemon: () => restartDaemon(),
|
|
608
617
|
writeState: (state) => writeJsonAtomic(paths.statePath, state),
|
|
609
618
|
log,
|
|
@@ -4,6 +4,9 @@ export declare const LANE_OUTPOST_LOAD_BALANCING_FLAG = "lanes.outpost-load-bala
|
|
|
4
4
|
export declare const LANE_ENVELOPE_REPAIR_CONTINUE_FLAG = "lanes.envelope-repair-continue";
|
|
5
5
|
/** Count only children with live work against their senior's hire grant. */
|
|
6
6
|
export declare const LANE_HIRE_GRANT_FINISHED_LANES_FLAG = "lanes.hire-grant-count-live-only";
|
|
7
|
+
/** Skips owner refreshes during ordinary lane list polling when explicitly enabled. */
|
|
8
|
+
export declare const LANE_LIST_SKIP_REMOTE_REFRESH_FLAG = "lanes.list-skip-remote-refresh";
|
|
9
|
+
export declare const LANE_LIST_SKIP_REMOTE_REFRESH_DEFAULT_ENABLED = false;
|
|
7
10
|
/** Enables missed-deadline lead nudges and second-miss operator escalation. */
|
|
8
11
|
export declare const LANE_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = "lanes.autopilot-missed-deadline-escalation";
|
|
9
12
|
export declare const LANE_AUTOPILOT_NUDGE_DEDUPE_FLAG = "lanes.autopilot-nudge-dedupe";
|
|
@@ -4,6 +4,9 @@ export const LANE_OUTPOST_LOAD_BALANCING_FLAG = "lanes.outpost-load-balancing";
|
|
|
4
4
|
export const LANE_ENVELOPE_REPAIR_CONTINUE_FLAG = "lanes.envelope-repair-continue";
|
|
5
5
|
/** Count only children with live work against their senior's hire grant. */
|
|
6
6
|
export const LANE_HIRE_GRANT_FINISHED_LANES_FLAG = "lanes.hire-grant-count-live-only";
|
|
7
|
+
/** Skips owner refreshes during ordinary lane list polling when explicitly enabled. */
|
|
8
|
+
export const LANE_LIST_SKIP_REMOTE_REFRESH_FLAG = "lanes.list-skip-remote-refresh";
|
|
9
|
+
export const LANE_LIST_SKIP_REMOTE_REFRESH_DEFAULT_ENABLED = false;
|
|
7
10
|
/** Enables missed-deadline lead nudges and second-miss operator escalation. */
|
|
8
11
|
export const LANE_AUTOPILOT_MISSED_DEADLINE_ESCALATION_FLAG = "lanes.autopilot-missed-deadline-escalation";
|
|
9
12
|
export const LANE_AUTOPILOT_NUDGE_DEDUPE_FLAG = "lanes.autopilot-nudge-dedupe";
|
|
@@ -41,7 +41,7 @@ export declare function discoverProjects(input: {
|
|
|
41
41
|
env?: NodeJS.ProcessEnv;
|
|
42
42
|
home?: string;
|
|
43
43
|
}): CatalogProject[];
|
|
44
|
-
/** discoverProjects memoized by directory mtime. A
|
|
44
|
+
/** discoverProjects memoized by source directory and mtime. A hit does not rescan. */
|
|
45
45
|
export declare function discoverProjectsCached(input: Parameters<typeof discoverProjects>[0], nowMs?: number): CatalogProject[];
|
|
46
46
|
export declare function refineProjectBinding(input: {
|
|
47
47
|
hint?: string;
|
|
@@ -215,14 +215,14 @@ function catalogStamp(input) {
|
|
|
215
215
|
if (!dir)
|
|
216
216
|
return "0";
|
|
217
217
|
try {
|
|
218
|
-
return
|
|
218
|
+
return `${dir}:${fs.statSync(dir).mtimeMs}`;
|
|
219
219
|
}
|
|
220
220
|
catch {
|
|
221
|
-
return
|
|
221
|
+
return `${dir}:0`;
|
|
222
222
|
}
|
|
223
223
|
}).join("|");
|
|
224
224
|
}
|
|
225
|
-
/** discoverProjects memoized by directory mtime. A
|
|
225
|
+
/** discoverProjects memoized by source directory and mtime. A hit does not rescan. */
|
|
226
226
|
export function discoverProjectsCached(input, nowMs = Date.now()) {
|
|
227
227
|
const key = `${input.hqRoot ?? ""}|${input.companySlug ?? ""}|${input.companyUid ?? ""}|${input.home ?? ""}|${catalogStamp(input)}`;
|
|
228
228
|
if (catalogCache && catalogCache.key === key && nowMs - catalogCache.at < CATALOG_CACHE_TTL_MS) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare class PackageUseUpdatePendingError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export interface PackageUseLease {
|
|
5
|
+
readonly leasePath: string;
|
|
6
|
+
release(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface PackageUseLeaseRecord {
|
|
9
|
+
pid: number;
|
|
10
|
+
start_time_ms: number;
|
|
11
|
+
hq_version: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function npmPrefix(root: string, platform?: NodeJS.Platform): string | null;
|
|
14
|
+
export declare function packageUseLeaseDirectory(prefix: string, stateDirectory?: string): string;
|
|
15
|
+
export declare function packageUseUpdateRequestPath(prefix: string, stateDirectory?: string): string;
|
|
16
|
+
declare function waitForUpdateRequest(requestPath: string, timeoutMs: number): void;
|
|
17
|
+
export declare function acquirePackageUseLease(prefix: string, hqVersion: string, stateDirectory?: string): PackageUseLease;
|
|
18
|
+
export declare function acquireCurrentPackageUseLease(): PackageUseLease | null;
|
|
19
|
+
/** True while the desktop updater owns the per-prefix update request. */
|
|
20
|
+
export declare function currentPackageUseUpdateRequested(): boolean;
|
|
21
|
+
export declare const __test__: {
|
|
22
|
+
waitForUpdateRequest: typeof waitForUpdateRequest;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=package-use-lease.d.ts.map
|