@indigoai-us/hq-cli 5.345.201 → 5.345.203
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 +16 -0
- package/dist/command-catalog.generated.d.ts +24 -0
- package/dist/command-catalog.generated.js +26 -0
- package/dist/commands/capacity.js +10 -2
- package/dist/commands/daemon.d.ts +2 -1
- package/dist/commands/daemon.js +225 -4
- package/dist/commands/integrations-core.d.ts +3 -0
- package/dist/commands/integrations-core.js +11 -0
- package/dist/commands/integrations-manage.js +2 -2
- package/dist/commands/integrations.js +5 -5
- package/dist/commands/sync-core.js +2 -1
- package/dist/lib/bot/executive-settings.d.ts +1 -1
- package/dist/lib/bot/executive-settings.js +16 -6
- package/dist/lib/bot/jobs/meeting-detect.js +2 -2
- package/dist/lib/bot/jobs/meeting-rider.js +2 -2
- package/dist/lib/bot/jobs/signal-to-lane.d.ts +3 -2
- package/dist/lib/bot/jobs/signal-to-lane.js +31 -8
- package/dist/lib/bot/run.js +3 -3
- package/dist/lib/capacity/codex-availability.d.ts +6 -0
- package/dist/lib/capacity/codex-availability.js +33 -0
- package/dist/lib/capacity/ledger.d.ts +0 -11
- package/dist/lib/capacity/ledger.js +30 -3
- package/dist/lib/capacity/route.js +11 -5
- package/dist/lib/daemon/catalog.d.ts +3 -0
- package/dist/lib/daemon/catalog.js +15 -2
- package/dist/lib/daemon/handoff.d.ts +2 -0
- package/dist/lib/daemon/handoff.js +9 -2
- package/dist/lib/daemon/install.d.ts +99 -0
- package/dist/lib/daemon/install.js +316 -7
- package/dist/lib/daemon/migrate.d.ts +3 -1
- package/dist/lib/daemon/migrate.js +14 -2
- package/dist/lib/daemon/plist-refresh.d.ts +34 -0
- package/dist/lib/daemon/plist-refresh.js +62 -0
- package/dist/lib/daemon/run.js +25 -0
- package/dist/lib/daemon/selfcheck.d.ts +71 -0
- package/dist/lib/daemon/selfcheck.js +150 -0
- package/dist/lib/daemon/supervisor.d.ts +31 -0
- package/dist/lib/daemon/supervisor.js +130 -6
- package/dist/lib/daemon/unit-holds.js +2 -1
- package/dist/lib/service-manager/launchd.d.ts +25 -0
- package/dist/lib/service-manager/launchd.js +51 -3
- package/dist/lib/service-manager/migration.d.ts +14 -0
- package/dist/lib/service-manager/migration.js +34 -0
- package/dist/lib/service-manager/systemd.d.ts +13 -0
- package/dist/lib/service-manager/systemd.js +19 -0
- package/dist/lib/service-manager/types.d.ts +8 -0
- package/dist/lib/sync-core/reconcile.d.ts +4 -1
- package/dist/lib/sync-core/reconcile.js +12 -2
- package/dist/lib/sync-core/release.d.ts +23 -0
- package/dist/lib/sync-core/release.js +39 -0
- package/dist/main.js +3 -3
- package/dist/utils/cli-network-lifecycle.d.ts +9 -0
- package/dist/utils/cli-network-lifecycle.js +25 -1
- package/package.json +9 -8
|
@@ -21,6 +21,14 @@ export interface ServiceSpec {
|
|
|
21
21
|
restartSec: number;
|
|
22
22
|
/** systemd unit file name; defaults to `hq-agent-<name>.service`. */
|
|
23
23
|
unitName?: string;
|
|
24
|
+
/**
|
|
25
|
+
* macOS: run the job directly under node, without the HQ.app launcher and
|
|
26
|
+
* without AssociatedBundleIdentifiers, so launchd loads it at login whether
|
|
27
|
+
* or not the app is installed, enabled or allowed. The daemon sets this:
|
|
28
|
+
* on 2026-11-03 launchd skipped both app-associated agents at login and the
|
|
29
|
+
* daemon stayed down for 16 hours.
|
|
30
|
+
*/
|
|
31
|
+
independentOfApp?: boolean;
|
|
24
32
|
}
|
|
25
33
|
export interface ServiceHostPaths {
|
|
26
34
|
home: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SyncCoreVault } from "./engine-home.js";
|
|
2
|
-
import { type SyncCoreBinaryInstall } from "./release.js";
|
|
2
|
+
import { type SyncCoreBinaryInstall, type SyncCorePin } from "./release.js";
|
|
3
3
|
import { type SyncCoreRolloutState } from "./rollout-state.js";
|
|
4
4
|
export interface SyncCoreMembership {
|
|
5
5
|
companyUid: string;
|
|
@@ -14,7 +14,10 @@ export interface SyncCoreReconcileDeps {
|
|
|
14
14
|
resolvePersonUid: () => Promise<string | null>;
|
|
15
15
|
readRolloutFlag: (companyUid: string) => Promise<boolean>;
|
|
16
16
|
ensureBinary: (release: string) => Promise<SyncCoreBinaryInstall>;
|
|
17
|
+
/** A fixed release (tests). Otherwise readPin decides, then SYNC_CORE_RELEASE. */
|
|
17
18
|
release?: string;
|
|
19
|
+
/** Reads the server-side engine pin; never throws (see readSyncCorePin). */
|
|
20
|
+
readPin?: () => Promise<SyncCorePin>;
|
|
18
21
|
now?: () => Date;
|
|
19
22
|
log?: (line: string) => void;
|
|
20
23
|
}
|
|
@@ -3,7 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import { readCompaniesManifestMap } from "../work-context/repo-remote.js";
|
|
4
4
|
import { readVaultSyncSwitches, writeVaultSyncSwitches } from "../vault-sync-switches.js";
|
|
5
5
|
import { clearEngineStatus, engineFirstCycle, isSyncCoreVaultUid, removeEngineOwnership, syncCoreEngineHome, writeEngineHome, } from "./engine-home.js";
|
|
6
|
-
import { SYNC_CORE_FULL_RELEASE, SYNC_CORE_RELEASE, fullModeAllowed, installedSyncCoreRelease, syncCoreBinaryPath, } from "./release.js";
|
|
6
|
+
import { SYNC_CORE_FULL_RELEASE, SYNC_CORE_RELEASE, compareSyncCoreReleases, fullModeAllowed, installedSyncCoreRelease, syncCoreBinaryPath, } from "./release.js";
|
|
7
7
|
import { readSyncCoreSkips } from "./skip.js";
|
|
8
8
|
import { SYNC_RUST_ENGINE_ROLLOUT_FLAG } from "./flag.js";
|
|
9
9
|
import { readSyncCoreRolloutState, syncCoreRolloutStatePath, writeSyncCoreRolloutState, } from "./rollout-state.js";
|
|
@@ -65,8 +65,8 @@ function ownedVaultsWithoutState(home, hqRoot) {
|
|
|
65
65
|
export async function reconcileSyncCore(deps) {
|
|
66
66
|
const now = deps.now ?? (() => new Date());
|
|
67
67
|
const log = deps.log ?? (() => { });
|
|
68
|
-
const release = deps.release ?? SYNC_CORE_RELEASE;
|
|
69
68
|
const warnings = [];
|
|
69
|
+
let release = deps.release ?? SYNC_CORE_RELEASE;
|
|
70
70
|
const previous = readSyncCoreRolloutState(deps.home);
|
|
71
71
|
const previousVaults = previous?.vaults ?? ownedVaultsWithoutState(deps.home, deps.hqRoot);
|
|
72
72
|
const previousByUid = new Map(previousVaults.map((vault) => [vault.uid, vault]));
|
|
@@ -117,6 +117,16 @@ export async function reconcileSyncCore(deps) {
|
|
|
117
117
|
let binaryPath = syncCoreBinaryPath(deps.home);
|
|
118
118
|
let installedRelease = installedSyncCoreRelease(deps.home);
|
|
119
119
|
if (desired.length > 0) {
|
|
120
|
+
if (deps.release === undefined && deps.readPin) {
|
|
121
|
+
const pin = await deps.readPin();
|
|
122
|
+
release = pin.release;
|
|
123
|
+
if (pin.warning)
|
|
124
|
+
warnings.push(pin.warning);
|
|
125
|
+
if (pin.source === "server" && installedRelease && compareSyncCoreReleases(pin.release, installedRelease) < 0) {
|
|
126
|
+
// The no-downgrade guard in ensureSyncCoreBinary keeps the newer engine.
|
|
127
|
+
log(`the server pins hq-syncd ${pin.release}, older than the installed ${installedRelease}; keeping ${installedRelease}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
120
130
|
try {
|
|
121
131
|
const install = await deps.ensureBinary(release);
|
|
122
132
|
binaryPath = install.binaryPath;
|
|
@@ -4,6 +4,29 @@ export declare function compareSyncCoreReleases(a: string, b: string): number;
|
|
|
4
4
|
export declare function fullModeAllowed(release: string): boolean;
|
|
5
5
|
export declare const SYNC_CORE_DOWNLOAD_BASE = "https://indigoai-public.s3.amazonaws.com/hq-sync-core";
|
|
6
6
|
export declare const SYNC_CORE_DOWNLOAD_BASE_ENV = "HQ_SYNC_CORE_DOWNLOAD_BASE";
|
|
7
|
+
/** The server-side engine pin, published next to the release folders on the download base. */
|
|
8
|
+
export declare const SYNC_CORE_PIN_FILE = "pin.json";
|
|
9
|
+
export interface SyncCorePin {
|
|
10
|
+
/** The engine release machines should run. */
|
|
11
|
+
release: string;
|
|
12
|
+
/** "server": read from pin.json; "built-in": SYNC_CORE_RELEASE, because no server pin could be used. */
|
|
13
|
+
source: "server" | "built-in";
|
|
14
|
+
/** Why the server pin was not used, when it exists but could not be read. A missing pin.json sets none. */
|
|
15
|
+
warning?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The engine release to install, read from `<download base>/pin.json`
|
|
19
|
+
* (`{"release":"v0.1.24"}`), so an engine release reaches machines without an
|
|
20
|
+
* hq-cli release. Falls back to SYNC_CORE_RELEASE when the file is missing,
|
|
21
|
+
* unreadable or malformed. Never throws. Windows stays unsupported: the pin
|
|
22
|
+
* only picks a version, and syncCoreAssetName has no Windows build.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readSyncCorePin(opts?: {
|
|
25
|
+
env?: NodeJS.ProcessEnv;
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
fetch?: typeof fetch;
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
}): Promise<SyncCorePin>;
|
|
7
30
|
export declare function syncCoreBinaryPath(home?: string): string;
|
|
8
31
|
export declare function syncCoreReleaseMarkerPath(home?: string): string;
|
|
9
32
|
export declare function syncCoreAssetName(release: string, platform: NodeJS.Platform, arch: string): string | null;
|
|
@@ -21,6 +21,45 @@ export function fullModeAllowed(release) {
|
|
|
21
21
|
export const SYNC_CORE_DOWNLOAD_BASE = "https://indigoai-public.s3.amazonaws.com/hq-sync-core";
|
|
22
22
|
export const SYNC_CORE_DOWNLOAD_BASE_ENV = "HQ_SYNC_CORE_DOWNLOAD_BASE";
|
|
23
23
|
const DOWNLOAD_TIMEOUT_MS = 600_000;
|
|
24
|
+
/** The server-side engine pin, published next to the release folders on the download base. */
|
|
25
|
+
export const SYNC_CORE_PIN_FILE = "pin.json";
|
|
26
|
+
const PIN_TIMEOUT_MS = 10_000;
|
|
27
|
+
const RELEASE_PATTERN = /^v\d+\.\d+\.\d+$/;
|
|
28
|
+
/**
|
|
29
|
+
* The engine release to install, read from `<download base>/pin.json`
|
|
30
|
+
* (`{"release":"v0.1.24"}`), so an engine release reaches machines without an
|
|
31
|
+
* hq-cli release. Falls back to SYNC_CORE_RELEASE when the file is missing,
|
|
32
|
+
* unreadable or malformed. Never throws. Windows stays unsupported: the pin
|
|
33
|
+
* only picks a version, and syncCoreAssetName has no Windows build.
|
|
34
|
+
*/
|
|
35
|
+
export async function readSyncCorePin(opts = {}) {
|
|
36
|
+
const builtIn = (warning) => ({ release: SYNC_CORE_RELEASE, source: "built-in", ...(warning ? { warning } : {}) });
|
|
37
|
+
const url = `${opts.baseUrl?.replace(/\/+$/, "") ?? syncCoreDownloadBase(opts.env)}/${SYNC_CORE_PIN_FILE}`;
|
|
38
|
+
let response;
|
|
39
|
+
try {
|
|
40
|
+
response = await (opts.fetch ?? fetch)(url, { signal: AbortSignal.timeout(opts.timeoutMs ?? PIN_TIMEOUT_MS) });
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return builtIn(`could not read the engine pin ${url}: ${error instanceof Error ? error.message : String(error)}; using built-in ${SYNC_CORE_RELEASE}`);
|
|
44
|
+
}
|
|
45
|
+
// S3 answers 403 for a missing key on a bucket without public listing.
|
|
46
|
+
if (response.status === 404 || response.status === 403)
|
|
47
|
+
return builtIn();
|
|
48
|
+
if (!response.ok)
|
|
49
|
+
return builtIn(`could not read the engine pin ${url}: HTTP ${response.status}; using built-in ${SYNC_CORE_RELEASE}`);
|
|
50
|
+
let parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = JSON.parse(await response.text());
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return builtIn(`the engine pin ${url} is not JSON; using built-in ${SYNC_CORE_RELEASE}`);
|
|
56
|
+
}
|
|
57
|
+
const release = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed.release : undefined;
|
|
58
|
+
if (typeof release !== "string" || !RELEASE_PATTERN.test(release)) {
|
|
59
|
+
return builtIn(`the engine pin ${url} has no valid "release" (want vX.Y.Z); using built-in ${SYNC_CORE_RELEASE}`);
|
|
60
|
+
}
|
|
61
|
+
return { release, source: "server" };
|
|
62
|
+
}
|
|
24
63
|
export function syncCoreBinaryPath(home = os.homedir()) {
|
|
25
64
|
return path.join(home, ".hq", "bin", "hq-syncd");
|
|
26
65
|
}
|
package/dist/main.js
CHANGED
|
@@ -61,7 +61,7 @@ import { packageRoot } from "./utils/hq-roots.js";
|
|
|
61
61
|
import { classifyModuleNotFound, installTreeTornCaptureContext, installTreeTornStderrLine, isInstallTreeTornError, } from "./utils/install-tree-torn.js";
|
|
62
62
|
import { isVaultAccessDeniedError, vaultAccessDeniedMessage, } from "./utils/vault-access-denied-error.js";
|
|
63
63
|
import { fallbackOperatorMessage, unexpectedCliErrorMessage } from "./utils/unexpected-cli-error.js";
|
|
64
|
-
import { runGlobalNetworkLifecycle } from "./utils/cli-network-lifecycle.js";
|
|
64
|
+
import { isHqDaemonRunCommand, runGlobalNetworkLifecycle, runSentryInitialization, } from "./utils/cli-network-lifecycle.js";
|
|
65
65
|
import * as os from "node:os";
|
|
66
66
|
import { adoptAgentIdentityEnv } from "./lib/agent-kit/adopt-identity.js";
|
|
67
67
|
import { agentKitPaths } from "./lib/agent-kit/paths.js";
|
|
@@ -131,7 +131,7 @@ let activeForegroundNetworkBudget;
|
|
|
131
131
|
*/
|
|
132
132
|
const RUNNING_ENTRY_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "index.js");
|
|
133
133
|
installStreamErrorBoundary();
|
|
134
|
-
|
|
134
|
+
runSentryInitialization(process.argv, () => initSentry());
|
|
135
135
|
const program = new Command();
|
|
136
136
|
program
|
|
137
137
|
.name("hq")
|
|
@@ -169,7 +169,7 @@ program.hook("preAction", async () => {
|
|
|
169
169
|
export async function runCli() {
|
|
170
170
|
const xpcServiceName = process.env.XPC_SERVICE_NAME ?? "";
|
|
171
171
|
const launchedByHqAgent = xpcServiceName.startsWith("ai.indigo.") || xpcServiceName.startsWith("ai.getindigo.");
|
|
172
|
-
const isDaemonEntryPoint = process.argv
|
|
172
|
+
const isDaemonEntryPoint = isHqDaemonRunCommand(process.argv);
|
|
173
173
|
const isBotHotPath = process.argv[2] === "bot" && process.argv[3] === "run";
|
|
174
174
|
if (process.platform === "darwin" && typeof process.getuid === "function" &&
|
|
175
175
|
!launchedByHqAgent && !isDaemonEntryPoint && !isBotHotPath) {
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
export declare function isHqDaemonRunCommand(argv: readonly string[]): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Resident daemons keep their own bounded local logs. Do not initialize the
|
|
4
|
+
* process-wide Sentry transport in these commands: they can live across many
|
|
5
|
+
* network changes, while the SDK is designed around one short CLI invocation.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isLongLivedDaemonCommand(argv: readonly string[]): boolean;
|
|
8
|
+
/** Suppress only Sentry startup; every other global lifecycle operation still runs. */
|
|
9
|
+
export declare function runSentryInitialization<T>(argv: readonly string[], operation: () => T): T | undefined;
|
|
1
10
|
export declare function isMonitorFastPathCommand(argv: readonly string[]): boolean;
|
|
2
11
|
/** The commit-msg hook runs `hq fingerprint self --offline`; it must stay fast and offline. */
|
|
3
12
|
export declare function isOfflineFingerprintCommand(argv: readonly string[]): boolean;
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
const MONITOR_HIDDEN_NETWORK_BYPASS = new Set(["drain", "wait", "enabled", "_run"]);
|
|
2
|
+
function commandArgv(argv) {
|
|
3
|
+
return argv.slice(2).filter((arg) => arg !== "--verbose");
|
|
4
|
+
}
|
|
5
|
+
export function isHqDaemonRunCommand(argv) {
|
|
6
|
+
const command = commandArgv(argv);
|
|
7
|
+
return command[0] === "daemon" && command[1] === "run";
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resident daemons keep their own bounded local logs. Do not initialize the
|
|
11
|
+
* process-wide Sentry transport in these commands: they can live across many
|
|
12
|
+
* network changes, while the SDK is designed around one short CLI invocation.
|
|
13
|
+
*/
|
|
14
|
+
export function isLongLivedDaemonCommand(argv) {
|
|
15
|
+
const command = commandArgv(argv);
|
|
16
|
+
return (isHqDaemonRunCommand(argv) ||
|
|
17
|
+
(command[0] === "mesh" && command[1] === "daemon" && command[2] === "run"));
|
|
18
|
+
}
|
|
19
|
+
/** Suppress only Sentry startup; every other global lifecycle operation still runs. */
|
|
20
|
+
export function runSentryInitialization(argv, operation) {
|
|
21
|
+
if (isLongLivedDaemonCommand(argv))
|
|
22
|
+
return undefined;
|
|
23
|
+
return operation();
|
|
24
|
+
}
|
|
2
25
|
export function isMonitorFastPathCommand(argv) {
|
|
3
26
|
return argv[2] === "monitor" && MONITOR_HIDDEN_NETWORK_BYPASS.has(argv[3] ?? "");
|
|
4
27
|
}
|
|
@@ -8,8 +31,9 @@ export function isOfflineFingerprintCommand(argv) {
|
|
|
8
31
|
}
|
|
9
32
|
/** Skip process-wide network lifecycle work for hooks and detached monitor supervisors. */
|
|
10
33
|
export function runGlobalNetworkLifecycle(argv, operation) {
|
|
11
|
-
if (isMonitorFastPathCommand(argv) || isOfflineFingerprintCommand(argv))
|
|
34
|
+
if (isMonitorFastPathCommand(argv) || isOfflineFingerprintCommand(argv)) {
|
|
12
35
|
return undefined;
|
|
36
|
+
}
|
|
13
37
|
return operation();
|
|
14
38
|
}
|
|
15
39
|
//# sourceMappingURL=cli-network-lifecycle.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.203",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"prepare": "husky || true",
|
|
49
49
|
"check:no-hermes": "bash scripts/check-no-hermes.sh",
|
|
50
50
|
"prepack": "node scripts/hook-engine-manifest.mjs",
|
|
51
|
-
"postpublish": "node scripts/hook-engine-manifest.mjs restore"
|
|
51
|
+
"postpublish": "node scripts/hook-engine-manifest.mjs restore",
|
|
52
|
+
"build:ci": "node scripts/prepare-fixture-privacy-baseline.mjs && pnpm run build"
|
|
52
53
|
},
|
|
53
54
|
"dependencies": {
|
|
54
55
|
"@aws-sdk/client-iot-data-plane": "^3.1096.0",
|
|
@@ -116,11 +117,11 @@
|
|
|
116
117
|
"*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}": "eslint --cache --no-error-on-unmatched-pattern"
|
|
117
118
|
},
|
|
118
119
|
"optionalDependencies": {
|
|
119
|
-
"@indigoai-us/hq-hook-win32-x64": "5.345.
|
|
120
|
-
"@indigoai-us/hq-hook-win32-arm64": "5.345.
|
|
121
|
-
"@indigoai-us/hq-hook-darwin-x64": "5.345.
|
|
122
|
-
"@indigoai-us/hq-hook-darwin-arm64": "5.345.
|
|
123
|
-
"@indigoai-us/hq-hook-linux-x64": "5.345.
|
|
124
|
-
"@indigoai-us/hq-hook-linux-arm64": "5.345.
|
|
120
|
+
"@indigoai-us/hq-hook-win32-x64": "5.345.203",
|
|
121
|
+
"@indigoai-us/hq-hook-win32-arm64": "5.345.203",
|
|
122
|
+
"@indigoai-us/hq-hook-darwin-x64": "5.345.203",
|
|
123
|
+
"@indigoai-us/hq-hook-darwin-arm64": "5.345.203",
|
|
124
|
+
"@indigoai-us/hq-hook-linux-x64": "5.345.203",
|
|
125
|
+
"@indigoai-us/hq-hook-linux-arm64": "5.345.203"
|
|
125
126
|
}
|
|
126
127
|
}
|