@indigoai-us/hq-cli 5.345.177 → 5.345.179
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 +50 -0
- package/dist/command-catalog.generated.d.ts +79 -1
- package/dist/command-catalog.generated.js +96 -1
- package/dist/commands/bot-jobs.d.ts +11 -9
- package/dist/commands/bot-jobs.js +56 -21
- package/dist/commands/bot.d.ts +13 -0
- package/dist/commands/bot.js +230 -21
- package/dist/commands/cloud.d.ts +49 -0
- package/dist/commands/cloud.js +155 -15
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +15 -4
- package/dist/commands/dm-attach.js +15 -3
- package/dist/commands/integrations-core.d.ts +2 -0
- package/dist/commands/integrations-core.js +1 -0
- package/dist/commands/library-add.d.ts +9 -0
- package/dist/commands/library-add.js +19 -2
- package/dist/commands/run.js +9 -1
- package/dist/commands/sources.d.ts +89 -0
- package/dist/commands/sources.js +363 -1
- package/dist/lib/bot/config.d.ts +2 -0
- package/dist/lib/bot/fleet-default-flag.d.ts +31 -0
- package/dist/lib/bot/fleet-default-flag.js +127 -0
- package/dist/lib/bot/fleet-local.d.ts +30 -1
- package/dist/lib/bot/fleet-local.js +86 -11
- package/dist/lib/bot/index.d.ts +1 -0
- package/dist/lib/bot/index.js +1 -0
- package/dist/lib/bot/jobs/hot-signal-sync.d.ts +109 -0
- package/dist/lib/bot/jobs/hot-signal-sync.js +177 -0
- package/dist/lib/bot/local-config.js +1 -1
- package/dist/lib/bot/local-jobs.d.ts +40 -4
- package/dist/lib/bot/local-jobs.js +72 -5
- package/dist/lib/bot/run.d.ts +15 -0
- package/dist/lib/bot/run.js +61 -0
- package/dist/lib/daemon/catalog.d.ts +2 -0
- package/dist/lib/daemon/catalog.js +7 -2
- package/dist/lib/daemon/config.d.ts +2 -1
- package/dist/lib/daemon/config.js +4 -3
- package/dist/lib/daemon/handoff.d.ts +4 -0
- package/dist/lib/daemon/handoff.js +6 -2
- package/dist/lib/daemon/install.d.ts +70 -2
- package/dist/lib/daemon/install.js +185 -27
- package/dist/lib/daemon/legacy.d.ts +9 -3
- package/dist/lib/daemon/legacy.js +11 -4
- package/dist/lib/daemon/migrate.js +1 -1
- package/dist/lib/daemon/run.d.ts +3 -2
- package/dist/lib/daemon/run.js +10 -6
- package/dist/lib/doctor/checks/anywhere.d.ts +6 -0
- package/dist/lib/doctor/checks/anywhere.js +35 -6
- package/dist/lib/hot-channels/adapters/__fixtures__/dummy.d.ts +33 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/dummy.js +53 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/meeting-providers.d.ts +38 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/meeting-providers.js +64 -0
- package/dist/lib/hot-channels/adapters/attio.d.ts +67 -0
- package/dist/lib/hot-channels/adapters/attio.js +374 -0
- package/dist/lib/hot-channels/adapters/gmail.d.ts +111 -0
- package/dist/lib/hot-channels/adapters/gmail.js +413 -0
- package/dist/lib/hot-channels/adapters/index.d.ts +23 -0
- package/dist/lib/hot-channels/adapters/index.js +39 -0
- package/dist/lib/hot-channels/adapters/linear.d.ts +79 -0
- package/dist/lib/hot-channels/adapters/linear.js +321 -0
- package/dist/lib/hot-channels/adapters/meeting-providers.d.ts +86 -0
- package/dist/lib/hot-channels/adapters/meeting-providers.js +253 -0
- package/dist/lib/hot-channels/adapters/meetings.d.ts +81 -0
- package/dist/lib/hot-channels/adapters/meetings.js +523 -0
- package/dist/lib/hot-channels/adapters/slack.d.ts +70 -0
- package/dist/lib/hot-channels/adapters/slack.js +277 -0
- package/dist/lib/hot-channels/alert.d.ts +78 -0
- package/dist/lib/hot-channels/alert.js +179 -0
- package/dist/lib/hot-channels/audience.d.ts +15 -0
- package/dist/lib/hot-channels/audience.js +25 -0
- package/dist/lib/hot-channels/contract.d.ts +140 -0
- package/dist/lib/hot-channels/contract.js +20 -0
- package/dist/lib/hot-channels/cursors.d.ts +41 -0
- package/dist/lib/hot-channels/cursors.js +84 -0
- package/dist/lib/hot-channels/index.d.ts +10 -0
- package/dist/lib/hot-channels/index.js +10 -0
- package/dist/lib/hot-channels/landing.d.ts +83 -0
- package/dist/lib/hot-channels/landing.js +175 -0
- package/dist/lib/hot-channels/ledger.d.ts +101 -0
- package/dist/lib/hot-channels/ledger.js +186 -0
- package/dist/lib/hot-channels/loop.d.ts +74 -0
- package/dist/lib/hot-channels/loop.js +219 -0
- package/dist/lib/hot-channels/prompts/signals-pass.md +22 -0
- package/dist/lib/hot-channels/registry.d.ts +28 -0
- package/dist/lib/hot-channels/registry.js +121 -0
- package/dist/lib/hot-channels/run.d.ts +137 -0
- package/dist/lib/hot-channels/run.js +324 -0
- package/dist/lib/hot-channels/signals-pass.d.ts +150 -0
- package/dist/lib/hot-channels/signals-pass.js +581 -0
- package/dist/lib/hot-channels/sync-lock.d.ts +51 -0
- package/dist/lib/hot-channels/sync-lock.js +224 -0
- package/dist/lib/install/hook-target.d.ts +6 -2
- package/dist/lib/install/hook-target.js +9 -4
- package/dist/lib/lanes/loop.d.ts +10 -0
- package/dist/lib/lanes/loop.js +18 -1
- package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +1 -0
- package/dist/lib/mesh/live/daemon/work-subscribe.js +26 -6
- package/dist/run/hq-plugin.d.ts +3 -0
- package/dist/run/hq-plugin.js +18 -0
- package/package.json +7 -7
package/dist/commands/bot.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { withLocalJobs } from "../lib/bot/local-jobs.js";
|
|
2
|
+
import { currentHotSignalSyncCompany, ensureHotSignalSyncJob, removeStaleHotSignalSyncJobs, runHotSignalSyncJob } from "../lib/bot/jobs/hot-signal-sync.js";
|
|
3
|
+
import { createClaudeSignalsPass } from "../lib/hot-channels/signals-pass.js";
|
|
4
|
+
import { machineTimeZone } from "../lib/bot/job-run.js";
|
|
5
|
+
import { runCompanyHotChannelSync } from "./sources.js";
|
|
2
6
|
import { OwnerContextCache, lookupOwnerContext } from "../lib/bot/owner-context.js";
|
|
3
7
|
import { hasActivePromotion } from "../lib/bot/promotion-receipt.js";
|
|
4
8
|
import { readInflightTurns } from "../lib/bot/inflight.js";
|
|
@@ -52,7 +56,7 @@ import { isAncestorProcess } from "../lib/bot/self-process.js";
|
|
|
52
56
|
import { runtimeDisplayName, signInCommand } from "../lib/bot/runtime-sign-in.js";
|
|
53
57
|
import { classifyRuntimeFailure, runtimeFailureReason } from "../lib/bot/runtime-failure.js";
|
|
54
58
|
import { PROBE_DEFAULT_TIMEOUT_MS, probeBotRuntime } from "../lib/bot/probe.js";
|
|
55
|
-
import { BotApi, BotApiError, BOT_RESTORE_DEFAULTS, buildBotLocalConfig, describeBotLocalConfig, orphanBotRunMessage, parseBotLocalConfig, removeOrphanBotDaemon, botDaemonStatus, botDir, botCredsPath, botLogPath, botsRoot, botTokenStateDir, botWorkerRelDir, buildBotDaemonPaths, createBotLogger, deleteBotCreds, installBotDaemon, repairBotDaemonIfStale, healBotDaemonNodeFromJob, introDmText, isBotMemoryMode, botLocalMemoryDir, botMemoryMode, resolveBotMemoryDir, validateBotIntro, validateBotDisplayName, validateBotKickoff, validateBotEffort, validateBotModel, effectiveBotEffort, BOT_EFFORT_LEVELS, DEFAULT_BOT_EFFORT, BOT_MEMORY_MODES, BOT_KINDS, isBotKind, effectiveBotKind, effectiveBotCompanies, normalizeBotCompanies, SETUP_BOT_WORKER_ID, isBotRuntimeId, localNameForRemoteBot, remoteBotRunnability, isPidAlive, listBotWorkerOptions, patchBotConfig, readBotConfig, readBotCredsIdentity, readBotStatus, runtimeCrashSinceStart, resolveBotWorker, runBot, runtimeFor, scaffoldBotMemory, scaffoldBotWorker, startBotDaemon, stopBotDaemon, uninstallBotDaemon, validateBotName, writeBotConfig, writeBotCreds, BOT_RUNTIMES, BOT_INTRO_MAX_CHARS, BOT_DISPLAY_NAME_MAX_CHARS, BOT_KICKOFF_MAX_CHARS, detectBotPlatform, withBotLock, localBotRole, remoteBotRole, remoteBotDisplayName, personFacingName, writeCloudDisplayName, setupSlugFor, ASSISTANT_ROLE, HQ_FLEET_RUNTIME_ENGINE_ID, authenticateFleetLocalBot, bootstrapFleetLocalBot, buildSystemPrompt, controlFleetLocalBot, ensureFleetPython, fleetLocalGatewayPid, refreshFleetLocalInstructions, fleetLocalPromotionRuntime, installPinnedFleetLocalDistribution, readPromptSources, removeFleetLocalBot, } from "../lib/bot/index.js";
|
|
59
|
+
import { BotApi, BotApiError, BOT_RESTORE_DEFAULTS, buildBotLocalConfig, describeBotLocalConfig, orphanBotRunMessage, parseBotLocalConfig, removeOrphanBotDaemon, botDaemonStatus, botDir, botCredsPath, botLogPath, botsRoot, botTokenStateDir, botWorkerRelDir, buildBotDaemonPaths, createBotLogger, deleteBotCreds, installBotDaemon, repairBotDaemonIfStale, healBotDaemonNodeFromJob, introDmText, isBotMemoryMode, botLocalMemoryDir, botMemoryMode, resolveBotMemoryDir, validateBotIntro, validateBotDisplayName, validateBotKickoff, validateBotEffort, validateBotModel, effectiveBotEffort, BOT_EFFORT_LEVELS, DEFAULT_BOT_EFFORT, BOT_MEMORY_MODES, BOT_KINDS, isBotKind, effectiveBotKind, effectiveBotCompanies, normalizeBotCompanies, SETUP_BOT_WORKER_ID, isBotRuntimeId, localNameForRemoteBot, remoteBotRunnability, isPidAlive, listBotWorkerOptions, patchBotConfig, readBotConfig, readBotCredsIdentity, readBotStatus, runtimeCrashSinceStart, resolveBotWorker, runBot, runtimeFor, scaffoldBotMemory, scaffoldBotWorker, startBotDaemon, stopBotDaemon, uninstallBotDaemon, validateBotName, writeBotConfig, writeBotCreds, BOT_RUNTIMES, BOT_INTRO_MAX_CHARS, BOT_DISPLAY_NAME_MAX_CHARS, BOT_KICKOFF_MAX_CHARS, detectBotPlatform, withBotLock, localBotRole, remoteBotRole, remoteBotDisplayName, personFacingName, writeCloudDisplayName, setupSlugFor, ASSISTANT_ROLE, HQ_FLEET_RUNTIME_ENGINE_ID, authenticateFleetLocalBot, bootstrapFleetLocalBot, buildSystemPrompt, controlFleetLocalBot, ensureFleetPython, fleetLocalGatewayPid, fleetProviderForRuntime, importFleetLocalMachineCredential, fleetProviderNeedsSignIn, fleetDefaultCompanies, fleetOwnerCompanies, fleetRuntimeIsDefault, refreshFleetLocalInstructions, fleetLocalPromotionRuntime, installPinnedFleetLocalDistribution, readPromptSources, removeFleetLocalBot, } from "../lib/bot/index.js";
|
|
56
60
|
function collectRepeated(value, previous) {
|
|
57
61
|
return [...previous, value];
|
|
58
62
|
}
|
|
@@ -144,11 +148,25 @@ function fleetBotSystemPrompt(name, config, overrides = {}) {
|
|
|
144
148
|
}),
|
|
145
149
|
});
|
|
146
150
|
}
|
|
151
|
+
function fleetAuthCommand(name, config) {
|
|
152
|
+
return `hq bot auth ${name} --provider ${config.runtime === "grok" ? "grok" : config.runtime === "codex" ? "chatgpt" : "claude"}`;
|
|
153
|
+
}
|
|
147
154
|
function runFleetRuntimeControl(name, config, action, json) {
|
|
155
|
+
if ((action === "start" || action === "restart") && config.fleetAuthPending === true) {
|
|
156
|
+
const authCommand = fleetAuthCommand(name, config);
|
|
157
|
+
if (json)
|
|
158
|
+
console.log(JSON.stringify({ ok: false, name, running: false, state: "stopped", needsSignIn: true, authCommand }, null, 2));
|
|
159
|
+
else
|
|
160
|
+
throw Object.assign(new Error(`Sign this bot in first: ${authCommand}`), { expected: true });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
148
163
|
if (action === "start" || action === "restart") {
|
|
149
164
|
refreshFleetLocalInstructions(config.agentUid, fleetBotSystemPrompt(name, config));
|
|
150
165
|
}
|
|
151
|
-
const
|
|
166
|
+
const installService = config.fleetServiceInstallPending === true && (action === "start" || action === "restart");
|
|
167
|
+
const result = controlFleetLocalBot(config.agentUid, installService ? "install" : action);
|
|
168
|
+
if (installService && result.ok)
|
|
169
|
+
patchBotConfig(botDir(name), { fleetServiceInstallPending: false, enabled: true });
|
|
152
170
|
if (json) {
|
|
153
171
|
console.log(JSON.stringify({ name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
154
172
|
return;
|
|
@@ -192,7 +210,7 @@ function rowFor(name, opts = {}) {
|
|
|
192
210
|
const dir = botDir(name);
|
|
193
211
|
const config = readBotConfig(dir);
|
|
194
212
|
const fleet = isFleetRuntimeBot(config);
|
|
195
|
-
const status =
|
|
213
|
+
const status = readBotStatus(dir);
|
|
196
214
|
const pid = fleet ? fleetLocalGatewayPid(config.agentUid) : (status?.pid ?? null);
|
|
197
215
|
const processAlive = pid !== null && isPidAlive(pid) && (fleet || status?.state === "running");
|
|
198
216
|
// Turns this bot has taken and not finished: what "thinking" means.
|
|
@@ -220,7 +238,7 @@ function rowFor(name, opts = {}) {
|
|
|
220
238
|
model: config.model,
|
|
221
239
|
effort: effectiveBotEffort(config),
|
|
222
240
|
effortIsDefault: !config.effort,
|
|
223
|
-
state: processAlive ? "running" : status?.state === "failed" ? "failed" : "stopped",
|
|
241
|
+
state: processAlive ? "running" : !fleet && status?.state === "failed" ? "failed" : "stopped",
|
|
224
242
|
pid: processAlive ? pid : null,
|
|
225
243
|
processAlive,
|
|
226
244
|
hosting: hasActivePromotion(dir, config.agentUid, config.ownerUid) ? "cloud" : "local",
|
|
@@ -234,8 +252,10 @@ function rowFor(name, opts = {}) {
|
|
|
234
252
|
busySince: processAlive ? (inflightTurns[0]?.startedAt ?? null) : null,
|
|
235
253
|
runtimeSignIn: status?.runtimeSignIn ?? null,
|
|
236
254
|
runtimeSignInCheck: status?.runtimeSignInCheck ?? null,
|
|
237
|
-
runtimeSignedIn: runtimeSignedIn(status, processAlive),
|
|
238
|
-
|
|
255
|
+
runtimeSignedIn: config.fleetAuthPending === true ? false : runtimeSignedIn(status, processAlive),
|
|
256
|
+
...(fleet && config.fleetAuthPending === true ? { needsSignIn: true, authCommand: fleetAuthCommand(name, config) } : {}),
|
|
257
|
+
...(fleet && config.fleetServiceInstallPending === true ? { needsSignIn: false, serviceInstallPending: true } : {}),
|
|
258
|
+
signInCommand: fleet ? fleetAuthCommand(name, config) : signInCommand(config.runtime),
|
|
239
259
|
runtimeCrash: processAlive ? runtimeCrashSinceStart(status) : null,
|
|
240
260
|
daemonInstalled,
|
|
241
261
|
daemonLoaded,
|
|
@@ -340,6 +360,8 @@ function stopProcess(dir) {
|
|
|
340
360
|
async function startBot(name, dir, config, output, extra = {}) {
|
|
341
361
|
if (hasPromotionHold(dir))
|
|
342
362
|
throw new Error("This bot is held for cloud promotion. Continue its promotion before changing local settings or lifecycle.");
|
|
363
|
+
if (isFleetRuntimeBot(config))
|
|
364
|
+
return startFleetRuntimeBot(name, dir, config, output, extra);
|
|
343
365
|
if (config.enabled === false)
|
|
344
366
|
patchBotConfig(dir, { enabled: true });
|
|
345
367
|
const paths = buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot });
|
|
@@ -401,6 +423,41 @@ async function startBot(name, dir, config, output, extra = {}) {
|
|
|
401
423
|
}
|
|
402
424
|
return { running, how };
|
|
403
425
|
}
|
|
426
|
+
/** Start (or restart) an HQ Fleet Runtime bot under its own service, with fresh instructions. */
|
|
427
|
+
async function startFleetRuntimeBot(name, dir, config, output, extra) {
|
|
428
|
+
if (config.fleetAuthPending === true) {
|
|
429
|
+
const authCommand = fleetAuthCommand(name, config);
|
|
430
|
+
if (output === "json")
|
|
431
|
+
console.log(JSON.stringify({ ok: false, name, running: false, needsSignIn: true, authCommand }, null, 2));
|
|
432
|
+
else if (output !== "silent")
|
|
433
|
+
throw Object.assign(new Error(`Sign this bot in first: ${authCommand}`), { expected: true });
|
|
434
|
+
return { running: false, how: "waiting for sign-in" };
|
|
435
|
+
}
|
|
436
|
+
refreshFleetLocalInstructions(config.agentUid, fleetBotSystemPrompt(name, config));
|
|
437
|
+
const before = readBotStatus(dir);
|
|
438
|
+
const alreadyRunning = !!before && before.state === "running" && isPidAlive(before.pid);
|
|
439
|
+
const installService = config.fleetServiceInstallPending === true;
|
|
440
|
+
const result = controlFleetLocalBot(config.agentUid, installService ? "install" : alreadyRunning ? "restart" : "start");
|
|
441
|
+
if (installService && result.ok)
|
|
442
|
+
patchBotConfig(dir, { fleetServiceInstallPending: false, enabled: true });
|
|
443
|
+
const how = alreadyRunning ? "restarted by the HQ Fleet Runtime" : "started by the HQ Fleet Runtime";
|
|
444
|
+
const running = result.ok === true && (await waitFor(() => {
|
|
445
|
+
const s = readBotStatus(dir);
|
|
446
|
+
return !!s && s.state === "running" && isPidAlive(s.pid);
|
|
447
|
+
}, 45_000));
|
|
448
|
+
const status = readBotStatus(dir);
|
|
449
|
+
if (output === "silent")
|
|
450
|
+
return { running, how };
|
|
451
|
+
if (output === "json") {
|
|
452
|
+
console.log(JSON.stringify({ ok: running, name, ...extra, running, how, state: status?.state ?? "unknown", pid: status?.pid ?? null, lastError: null }, null, 2));
|
|
453
|
+
return { running, how };
|
|
454
|
+
}
|
|
455
|
+
if (running)
|
|
456
|
+
console.log(chalk.green(`${name} is running`) + chalk.dim(` (${how})`));
|
|
457
|
+
else
|
|
458
|
+
console.log(chalk.yellow(`${name} did not report running within 45s`) + chalk.dim(` logs: ~/.hq-fleet/profiles/${config.agentUid}/logs`));
|
|
459
|
+
return { running, how };
|
|
460
|
+
}
|
|
404
461
|
/**
|
|
405
462
|
* `output`: "json" | "text" print a result; "silent" prints nothing — used
|
|
406
463
|
* when stop is a step inside rm/restart, whose own JSON must be the only
|
|
@@ -436,6 +493,14 @@ function requestSelfStopDrain(botPid) {
|
|
|
436
493
|
async function stopBot(name, dir, config, output) {
|
|
437
494
|
if (hasPromotionHold(dir))
|
|
438
495
|
throw new Error("This bot is held for cloud promotion. Continue its promotion before changing local settings or lifecycle.");
|
|
496
|
+
if (isFleetRuntimeBot(config)) {
|
|
497
|
+
const result = controlFleetLocalBot(config.agentUid, "stop");
|
|
498
|
+
if (output === "json")
|
|
499
|
+
console.log(JSON.stringify({ ok: result.ok === true, name, stopped: result.ok === true, how: "stopped by the HQ Fleet Runtime" }, null, 2));
|
|
500
|
+
else if (output === "text")
|
|
501
|
+
console.log(chalk.green(`${name} stopped`));
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
439
504
|
const paths = buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot });
|
|
440
505
|
const hqDaemon = daemonPaths();
|
|
441
506
|
const before = readBotStatus(dir);
|
|
@@ -546,6 +611,28 @@ export function resolveCreateKind(opts, worker) {
|
|
|
546
611
|
}
|
|
547
612
|
return { kind, companies };
|
|
548
613
|
}
|
|
614
|
+
async function promptFleetProvider() {
|
|
615
|
+
if (process.stdin.isTTY !== true || process.stderr.isTTY !== true) {
|
|
616
|
+
throw Object.assign(new Error("--provider is required with --hq-fleet-runtime in a non-interactive command (claude, codex, or grok)."), { expected: true });
|
|
617
|
+
}
|
|
618
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
619
|
+
try {
|
|
620
|
+
const answer = await new Promise((resolve) => {
|
|
621
|
+
rl.question("Provider: 1) Codex 2) Claude 3) Grok [1]: ", resolve);
|
|
622
|
+
});
|
|
623
|
+
const selected = answer.trim().toLowerCase();
|
|
624
|
+
if (selected === "" || selected === "1" || selected === "codex")
|
|
625
|
+
return "codex";
|
|
626
|
+
if (selected === "2" || selected === "claude")
|
|
627
|
+
return "claude";
|
|
628
|
+
if (selected === "3" || selected === "grok")
|
|
629
|
+
return "grok";
|
|
630
|
+
throw Object.assign(new Error("Provider must be claude, codex, or grok."), { expected: true });
|
|
631
|
+
}
|
|
632
|
+
finally {
|
|
633
|
+
rl.close();
|
|
634
|
+
}
|
|
635
|
+
}
|
|
549
636
|
/**
|
|
550
637
|
* `hq bot create`. Runs under the bot's lock, so a create racing an adopt,
|
|
551
638
|
* restore, rm or set of the same bot waits for it instead of tripping over
|
|
@@ -664,11 +751,21 @@ async function finishExistingSetupBot(name, dir, config, displayName, opts) {
|
|
|
664
751
|
console.log(chalk.yellow(`${name} did not report running within 15s`) + chalk.dim(` logs: hq bot logs ${name}`));
|
|
665
752
|
}
|
|
666
753
|
async function runBotCreateLocked(name, opts) {
|
|
667
|
-
const
|
|
668
|
-
if (
|
|
669
|
-
throw Object.assign(new Error("--hq-fleet-runtime
|
|
754
|
+
const requestedFleetRuntime = opts.hqFleetRuntime === true;
|
|
755
|
+
if (requestedFleetRuntime && opts.legacyRuntime) {
|
|
756
|
+
throw Object.assign(new Error("Pick one of --hq-fleet-runtime and --legacy-runtime."), { expected: true });
|
|
670
757
|
}
|
|
671
|
-
|
|
758
|
+
if (requestedFleetRuntime && (opts.effort || opts.lean)) {
|
|
759
|
+
throw Object.assign(new Error("--hq-fleet-runtime sets its own thinking level. Do not combine it with --effort or --lean."), { expected: true });
|
|
760
|
+
}
|
|
761
|
+
if (opts.provider && !isBotRuntimeId(opts.provider)) {
|
|
762
|
+
throw Object.assign(new Error(`--provider must be one of ${BOT_RUNTIMES.join(", ")}`), { expected: true });
|
|
763
|
+
}
|
|
764
|
+
if (opts.provider && opts.runtime && opts.provider !== opts.runtime) {
|
|
765
|
+
throw Object.assign(new Error("--provider and --runtime must name the same provider when both are used."), { expected: true });
|
|
766
|
+
}
|
|
767
|
+
const selectedProvider = opts.provider ?? opts.runtime ?? (requestedFleetRuntime ? await promptFleetProvider() : undefined);
|
|
768
|
+
const runtime = selectedProvider ?? "claude";
|
|
672
769
|
if (!isBotRuntimeId(runtime)) {
|
|
673
770
|
throw Object.assign(new Error(`--runtime must be one of ${BOT_RUNTIMES.join(", ")}`), { expected: true });
|
|
674
771
|
}
|
|
@@ -703,6 +800,15 @@ async function runBotCreateLocked(name, opts) {
|
|
|
703
800
|
// cost an identity).
|
|
704
801
|
const worker = opts.worker?.trim() ? resolveBotWorker(hqRoot, opts.worker) : null;
|
|
705
802
|
const { kind, companies } = resolveCreateKind(opts, worker);
|
|
803
|
+
// Companies with the fleet-default flag get their personal bots on
|
|
804
|
+
// the HQ Fleet Runtime; --legacy-runtime keeps the model-CLI runner.
|
|
805
|
+
const fleetCandidate = requestedFleetRuntime ||
|
|
806
|
+
(!opts.legacyRuntime && kind === "personal" && !opts.effort && !opts.lean);
|
|
807
|
+
// Owner turns on the bot may use only these companies: the owner's own,
|
|
808
|
+
// and only where the company turned the flag on.
|
|
809
|
+
const flaggedCompanies = fleetCandidate && kind === "personal" ? await fleetDefaultCompanies(hqRoot) : [];
|
|
810
|
+
const useFleetRuntime = requestedFleetRuntime || (fleetCandidate && fleetRuntimeIsDefault(flaggedCompanies));
|
|
811
|
+
const ownerCompanies = useFleetRuntime && kind === "personal" ? await fleetOwnerCompanies() : [];
|
|
706
812
|
if (useFleetRuntime && kind !== "personal") {
|
|
707
813
|
throw Object.assign(new Error("--hq-fleet-runtime creates a personal bot. Drop --kind company and --company."), {
|
|
708
814
|
expected: true,
|
|
@@ -726,6 +832,8 @@ async function runBotCreateLocked(name, opts) {
|
|
|
726
832
|
? await installPinnedFleetLocalDistribution()
|
|
727
833
|
: null;
|
|
728
834
|
const fleetPython = fleetInstallation ? await ensureFleetPython() : null;
|
|
835
|
+
const fleetProvider = fleetInstallation ? fleetProviderForRuntime(runtime, model) : null;
|
|
836
|
+
const fleetAuthPending = fleetProvider !== null && fleetProviderNeedsSignIn(fleetProvider);
|
|
729
837
|
const token = await ownerToken();
|
|
730
838
|
const owner = await resolveCallerPersonUid(token, undefined, { command: "hq bot create" });
|
|
731
839
|
if (!owner)
|
|
@@ -932,7 +1040,8 @@ async function runBotCreateLocked(name, opts) {
|
|
|
932
1040
|
...(kickoff ? { kickoff } : {}),
|
|
933
1041
|
...(opts.lean && runtime === "claude" ? { lean: true } : {}),
|
|
934
1042
|
createdAt: new Date().toISOString(),
|
|
935
|
-
enabled:
|
|
1043
|
+
enabled: !fleetAuthPending,
|
|
1044
|
+
...(fleetAuthPending ? { fleetAuthPending: true } : {}),
|
|
936
1045
|
};
|
|
937
1046
|
writeBotConfig(dir, config);
|
|
938
1047
|
// A company bot acts as itself, so it must be a member of each of its
|
|
@@ -971,7 +1080,13 @@ async function runBotCreateLocked(name, opts) {
|
|
|
971
1080
|
installation: fleetInstallation,
|
|
972
1081
|
machineCredentials: botCredsPath(dir),
|
|
973
1082
|
systemPrompt: fleetBotSystemPrompt(name, config, { kind, companies }),
|
|
974
|
-
|
|
1083
|
+
provider: fleetProvider,
|
|
1084
|
+
ownerCompanies,
|
|
1085
|
+
firstStart: {
|
|
1086
|
+
intro: introDmText(name, runtime, intro, { kind, companies }),
|
|
1087
|
+
...(kickoff ? { kickoff } : {}),
|
|
1088
|
+
},
|
|
1089
|
+
}, { start: opts.start !== false && !fleetAuthPending, python: fleetPython })
|
|
975
1090
|
: null;
|
|
976
1091
|
const fleetProfile = fleetBootstrap?.profile ?? null;
|
|
977
1092
|
const runtimeLabel = fleetInstallation ? HQ_FLEET_RUNTIME_ENGINE_ID : runtime;
|
|
@@ -998,6 +1113,7 @@ async function runBotCreateLocked(name, opts) {
|
|
|
998
1113
|
kickoff: kickoff ?? null,
|
|
999
1114
|
model: model ?? null,
|
|
1000
1115
|
effort: fleetInstallation ? null : effort ?? DEFAULT_BOT_EFFORT,
|
|
1116
|
+
...(fleetProvider ? { provider: fleetProvider.id, needsSignIn: fleetAuthPending, ...(fleetAuthPending ? { authCommand: fleetAuthCommand(name, config) } : {}) } : {}),
|
|
1001
1117
|
};
|
|
1002
1118
|
let daemonMessage = null;
|
|
1003
1119
|
if (!fleetInstallation && opts.daemon !== false && process.platform === "darwin") {
|
|
@@ -1015,6 +1131,9 @@ async function runBotCreateLocked(name, opts) {
|
|
|
1015
1131
|
console.log(chalk.dim(` state: ${dir}`));
|
|
1016
1132
|
if (fleetProfile)
|
|
1017
1133
|
console.log(chalk.dim(` profile: ${fleetProfile}`));
|
|
1134
|
+
if (fleetProvider && fleetProviderNeedsSignIn(fleetProvider)) {
|
|
1135
|
+
console.log(chalk.yellow(` sign it in before it can answer: hq bot auth ${name} --provider ${runtime === "grok" ? "grok" : "chatgpt"}`));
|
|
1136
|
+
}
|
|
1018
1137
|
if (daemonMessage)
|
|
1019
1138
|
console.log(chalk.dim(` ${daemonMessage}`));
|
|
1020
1139
|
}
|
|
@@ -1159,6 +1278,27 @@ async function runBotResident(nameArg) {
|
|
|
1159
1278
|
const token = botTokenSupplier(dir);
|
|
1160
1279
|
// The bot's own schedule lives in its folder and fires from this loop.
|
|
1161
1280
|
const api = withLocalJobs(new BotApi({ token }), dir);
|
|
1281
|
+
// The built-in hot-signal-sync job, registered once in the bot's own
|
|
1282
|
+
// jobs.json (06:30 daily in this computer's time zone until the owner
|
|
1283
|
+
// reschedules it with `hq bot jobs`). It runs in-process, with no model turn.
|
|
1284
|
+
const syncCompany = hotSignalSyncCompany(config);
|
|
1285
|
+
try {
|
|
1286
|
+
// A job for a company the bot no longer serves is removed before anything runs.
|
|
1287
|
+
for (const stale of removeStaleHotSignalSyncJobs(dir, syncCompany)) {
|
|
1288
|
+
console.log(`Removed the hot-channel sync job ${stale.jobId}: this bot no longer syncs that company.`);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
catch (err) {
|
|
1292
|
+
console.error(`Could not check the hot-channel sync jobs: ${err instanceof Error ? err.message : String(err)}`);
|
|
1293
|
+
}
|
|
1294
|
+
if (syncCompany) {
|
|
1295
|
+
try {
|
|
1296
|
+
ensureHotSignalSyncJob(dir, { company: syncCompany, timezone: machineTimeZone() });
|
|
1297
|
+
}
|
|
1298
|
+
catch (err) {
|
|
1299
|
+
console.error(`Could not register the hot-channel sync job for ${syncCompany}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1162
1302
|
const owner = new OwnerContextCache(() => lookupOwnerContext(config.ownerUid), Date.now, undefined, config.ownerUid);
|
|
1163
1303
|
const handle = await runBot({
|
|
1164
1304
|
dir,
|
|
@@ -1166,6 +1306,15 @@ async function runBotResident(nameArg) {
|
|
|
1166
1306
|
api,
|
|
1167
1307
|
runtime: runtimeFor(config.runtime),
|
|
1168
1308
|
ownerContext: () => owner.get(),
|
|
1309
|
+
hotSignalSync: ({ company, catchUp, now, sendAlert }) => runHotSignalSyncJob({
|
|
1310
|
+
company,
|
|
1311
|
+
catchUp,
|
|
1312
|
+
now,
|
|
1313
|
+
sendAlert,
|
|
1314
|
+
sync: (input) => runCompanyHotChannelSync({ hqRoot: config.hqRoot, ...input }),
|
|
1315
|
+
// A new pass per run: the login preflight and the 20-document cap are per run.
|
|
1316
|
+
signalsPass: createClaudeSignalsPass({ hqRoot: config.hqRoot, company }),
|
|
1317
|
+
}),
|
|
1169
1318
|
// US-005: decision picks in the owner DM, with the bot's own machine token
|
|
1170
1319
|
// (never the owner's login).
|
|
1171
1320
|
decisions: new DecisionsClient(token),
|
|
@@ -1232,25 +1381,26 @@ async function runBotList(opts) {
|
|
|
1232
1381
|
}
|
|
1233
1382
|
async function runBotStatus(nameArg, opts) {
|
|
1234
1383
|
const { name, dir, config } = requireBot(nameArg);
|
|
1235
|
-
|
|
1236
|
-
runFleetRuntimeControl(name, config, "status", opts.json === true);
|
|
1237
|
-
return;
|
|
1238
|
-
}
|
|
1384
|
+
const fleet = isFleetRuntimeBot(config);
|
|
1239
1385
|
const row = rowFor(name);
|
|
1240
1386
|
await decorateOnline([row]);
|
|
1241
1387
|
const status = readBotStatus(dir);
|
|
1242
1388
|
const creds = readBotCredsIdentity(dir);
|
|
1243
1389
|
if (opts.json) {
|
|
1244
|
-
console.log(JSON.stringify({ ...row, credsPresent: !!creds, status }, null, 2));
|
|
1390
|
+
console.log(JSON.stringify({ ...row, ...(fleet ? { engine: config.engine } : {}), credsPresent: fleet || !!creds, status }, null, 2));
|
|
1245
1391
|
return;
|
|
1246
1392
|
}
|
|
1247
1393
|
console.log(`${chalk.bold(name)} ${row.agentUid}`);
|
|
1394
|
+
if (fleet)
|
|
1395
|
+
console.log(` engine: HQ Fleet Runtime ${config.engine?.version ?? ""} ${chalk.dim(`logs ~/.hq-fleet/profiles/${config.agentUid}/logs`)}`);
|
|
1248
1396
|
console.log(` kind: ${describeKind(row.kind, row.companies)}`);
|
|
1249
1397
|
console.log(` runtime: ${row.runtime} model ${row.model ?? "default"} thinking ${row.effort}${row.effortIsDefault ? " (default)" : ""}`);
|
|
1250
1398
|
if (row.workerId)
|
|
1251
1399
|
console.log(` worker: ${row.workerId}${row.companySlug ? ` (company ${row.companySlug})` : ""} ${chalk.dim(row.workerDir)}`);
|
|
1252
1400
|
console.log(` memory: ${row.memory} ${chalk.dim(row.memoryDir)}`);
|
|
1253
1401
|
console.log(` process: ${row.processAlive ? chalk.green(`running (pid ${row.pid})`) : chalk.gray(row.state)}`);
|
|
1402
|
+
if (row.needsSignIn)
|
|
1403
|
+
console.log(` sign-in: required (${row.authCommand})`);
|
|
1254
1404
|
console.log(` HQ online: ${humanOnline(row)}${row.lastHeartbeatAt ? chalk.dim(` last heartbeat ${row.lastHeartbeatAt}`) : ""}${row.lastHeartbeatOk === false && status?.lastHeartbeatError ? chalk.dim(` (${status.lastHeartbeatError})`) : ""}`);
|
|
1255
1405
|
if (status?.lastInboxPollOk === false) {
|
|
1256
1406
|
console.log(` inbox: ${chalk.red("cannot receive")}${status.lastInboxError ? chalk.dim(` ${status.lastInboxError}`) : ""}`);
|
|
@@ -1263,7 +1413,7 @@ async function runBotStatus(nameArg, opts) {
|
|
|
1263
1413
|
if (row.daemonNodeMissing) {
|
|
1264
1414
|
console.log(` ${chalk.red(`node missing: ${row.daemonNodeMissing}`)} — launchd cannot start ${name}; fix with: hq bot start ${name}`);
|
|
1265
1415
|
}
|
|
1266
|
-
console.log(` creds: ${creds ? `present for ${creds.entityUid}` : chalk.red("missing")}`);
|
|
1416
|
+
console.log(` creds: ${fleet ? "in the system keychain" : creds ? `present for ${creds.entityUid}` : chalk.red("missing")}`);
|
|
1267
1417
|
if (status) {
|
|
1268
1418
|
console.log(` started: ${status.startedAt} restarts: ${status.restarts} replies: ${status.repliesSent}`);
|
|
1269
1419
|
if (status.cliVersion)
|
|
@@ -1729,17 +1879,30 @@ async function runBotAuth(nameArg, opts) {
|
|
|
1729
1879
|
const result = authenticateFleetLocalBot({
|
|
1730
1880
|
agentUid: b.config.agentUid,
|
|
1731
1881
|
provider: opts.provider,
|
|
1882
|
+
...(b.config.fleetAuthPending === true ? { installService: true } : {}),
|
|
1732
1883
|
...(opts.model ? { model: opts.model } : {}),
|
|
1733
1884
|
...(apiKey ? { apiKey } : {}),
|
|
1734
1885
|
...(opts.baseUrl ? { baseUrl: opts.baseUrl } : {}),
|
|
1735
1886
|
...(opts.transport ? { transport: opts.transport } : {}),
|
|
1736
1887
|
openBrowser: opts.browser !== false,
|
|
1737
1888
|
});
|
|
1889
|
+
const signedInRuntime = result.runtimeProvider === "anthropic" ? "claude" : result.runtimeProvider === "xai-oauth" ? "grok" : result.runtimeProvider === "openai-codex" ? "codex" : null;
|
|
1890
|
+
if (result.authenticated !== true)
|
|
1891
|
+
throw Object.assign(new Error("The provider has not completed sign-in."), { expected: true });
|
|
1892
|
+
patchBotConfig(b.dir, {
|
|
1893
|
+
...(signedInRuntime ? { runtime: signedInRuntime } : {}),
|
|
1894
|
+
model: result.model,
|
|
1895
|
+
...(b.config.fleetAuthPending === true ? { fleetAuthPending: false, fleetServiceInstallPending: !result.restarted, enabled: result.restarted } : {}),
|
|
1896
|
+
});
|
|
1897
|
+
const pid = fleetLocalGatewayPid(b.config.agentUid);
|
|
1898
|
+
const running = pid !== null && isPidAlive(pid);
|
|
1738
1899
|
if (opts.json) {
|
|
1739
|
-
console.log(JSON.stringify({ ok: true, name: b.name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
1900
|
+
console.log(JSON.stringify({ ok: true, name: b.name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result, needsSignIn: false, running, serviceInstallPending: b.config.fleetAuthPending === true && !result.restarted }, null, 2));
|
|
1740
1901
|
return;
|
|
1741
1902
|
}
|
|
1742
|
-
console.log(
|
|
1903
|
+
console.log(running
|
|
1904
|
+
? chalk.green(`${b.name} is signed in to ${result.provider} and running ${result.model}.`)
|
|
1905
|
+
: chalk.yellow(`${b.name} is signed in to ${result.provider}, but did not start. Run hq bot start ${b.name}.`));
|
|
1743
1906
|
}
|
|
1744
1907
|
// ── adopt / restore (bring a bot you own back to this computer) ──────────────
|
|
1745
1908
|
/**
|
|
@@ -1993,6 +2156,9 @@ async function adoptRemoteBotLocked(input) {
|
|
|
1993
2156
|
region: DEFAULT_COGNITO.region,
|
|
1994
2157
|
});
|
|
1995
2158
|
const local = parseBotLocalConfig(reissued.localConfig ?? bot.localConfig);
|
|
2159
|
+
const fleetEngine = local?.engine?.id === HQ_FLEET_RUNTIME_ENGINE_ID;
|
|
2160
|
+
if (fleetEngine && local && !local.runtime)
|
|
2161
|
+
local.runtime = "codex";
|
|
1996
2162
|
const { config, notes } = configFromLocalConfig({
|
|
1997
2163
|
name,
|
|
1998
2164
|
agentUid: bot.agentUid,
|
|
@@ -2003,14 +2169,40 @@ async function adoptRemoteBotLocked(input) {
|
|
|
2003
2169
|
...(input.overrides ? { overrides: input.overrides } : {}),
|
|
2004
2170
|
...(input.preserveFirstStart ? { preserveFirstStart: true } : {}),
|
|
2005
2171
|
});
|
|
2172
|
+
// A bot made on the HQ Fleet Runtime comes back on it, on the release this CLI pins.
|
|
2173
|
+
const fleetInstallation = fleetEngine ? await installPinnedFleetLocalDistribution() : null;
|
|
2174
|
+
const fleetPython = fleetInstallation ? await ensureFleetPython() : null;
|
|
2175
|
+
if (fleetInstallation)
|
|
2176
|
+
config.engine = fleetInstallation.engine;
|
|
2006
2177
|
writeBotConfig(dir, config);
|
|
2007
2178
|
const scaffoldOpts = { memoryDir: config.memoryDir };
|
|
2008
2179
|
const scaffold = config.workerSource === "worker"
|
|
2009
2180
|
? scaffoldBotMemory(input.hqRoot, name, undefined, scaffoldOpts)
|
|
2010
2181
|
: scaffoldBotWorker(input.hqRoot, name, bot.agentUid, config.runtime, undefined, scaffoldOpts);
|
|
2182
|
+
if (fleetInstallation && fleetPython) {
|
|
2183
|
+
await bootstrapFleetLocalBot({
|
|
2184
|
+
agentUid: bot.agentUid,
|
|
2185
|
+
ownerUid: config.ownerUid,
|
|
2186
|
+
hqRoot: input.hqRoot,
|
|
2187
|
+
botDir: dir,
|
|
2188
|
+
installation: fleetInstallation,
|
|
2189
|
+
machineCredentials: botCredsPath(dir),
|
|
2190
|
+
systemPrompt: fleetBotSystemPrompt(name, config),
|
|
2191
|
+
provider: fleetProviderForRuntime(config.runtime, config.model),
|
|
2192
|
+
ownerCompanies: await fleetOwnerCompanies(),
|
|
2193
|
+
...(input.preserveFirstStart
|
|
2194
|
+
? {
|
|
2195
|
+
firstStart: {
|
|
2196
|
+
intro: introDmText(name, config.runtime, config.intro, { kind: effectiveBotKind(config), companies: effectiveBotCompanies(config) }),
|
|
2197
|
+
...(config.kickoff ? { kickoff: config.kickoff } : {}),
|
|
2198
|
+
},
|
|
2199
|
+
}
|
|
2200
|
+
: {}),
|
|
2201
|
+
}, { python: fleetPython, start: false });
|
|
2202
|
+
}
|
|
2011
2203
|
createBotLogger(dir)("info", `adopted ${name} (${bot.agentUid}) on ${localMachineId()} kind=${config.kind}${local ? "" : " (no saved settings; defaults)"} runtime=${config.runtime}`);
|
|
2012
2204
|
let daemonMessage = null;
|
|
2013
|
-
if (input.daemon && process.platform === "darwin") {
|
|
2205
|
+
if (!fleetInstallation && input.daemon && process.platform === "darwin") {
|
|
2014
2206
|
daemonMessage = installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot: input.hqRoot })).message;
|
|
2015
2207
|
}
|
|
2016
2208
|
return {
|
|
@@ -2118,6 +2310,11 @@ async function repairLocalBot(name, api, bot, daemon) {
|
|
|
2118
2310
|
region: DEFAULT_COGNITO.region,
|
|
2119
2311
|
});
|
|
2120
2312
|
createBotLogger(dir)("info", `re-issued machine credentials for ${name} (${bot.agentUid}) on ${localMachineId()}`);
|
|
2313
|
+
if (isFleetRuntimeBot(config)) {
|
|
2314
|
+
importFleetLocalMachineCredential(bot.agentUid, botCredsPath(dir));
|
|
2315
|
+
const restarted = controlFleetLocalBot(bot.agentUid, "restart").ok === true;
|
|
2316
|
+
return restarted ? "new credentials, HQ Fleet Runtime restarted" : "new credentials; the HQ Fleet Runtime did not restart (hq bot start " + name + ")";
|
|
2317
|
+
}
|
|
2121
2318
|
if (daemon && process.platform === "darwin") {
|
|
2122
2319
|
installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }));
|
|
2123
2320
|
}
|
|
@@ -2308,7 +2505,9 @@ export function registerBotCommand(program) {
|
|
|
2308
2505
|
.option("--kind <kind>", `personal (acts as you, everywhere you are) or company (acts as itself, as a member of its companies). Default: personal, or company when created from a company worker`)
|
|
2309
2506
|
.option("--company <slug>", "Company bots: a company the bot is a member of (repeat for several); the owner invites it on creation", collectRepeated, [])
|
|
2310
2507
|
.option("--runtime <runtime>", `Model CLI to run the bot with: ${BOT_RUNTIMES.join("|")}`)
|
|
2508
|
+
.option("--provider <provider>", `HQ Fleet provider: ${BOT_RUNTIMES.join("|")} (interactive Fleet creation prompts when omitted)`)
|
|
2311
2509
|
.option("--hq-fleet-runtime", "Create this personal bot with the local HQ Fleet Runtime")
|
|
2510
|
+
.option("--legacy-runtime", "Run this bot with the model CLI even where the HQ Fleet Runtime is the default")
|
|
2312
2511
|
.option("--model <model>", "Model override passed to the runtime CLI")
|
|
2313
2512
|
.option("--effort <level>", `Thinking level: claude ${BOT_EFFORT_LEVELS.claude.join("|")}; codex ${BOT_EFFORT_LEVELS.codex.join("|")}; grok ${BOT_EFFORT_LEVELS.grok.join("|")} (default ${DEFAULT_BOT_EFFORT})`)
|
|
2314
2513
|
.option("--no-auto-approve", "Keep the runtime's permission gates (default: everything pre-approved; a headless bot cannot answer prompts)")
|
|
@@ -2476,4 +2675,14 @@ export function registerBotCommand(program) {
|
|
|
2476
2675
|
console.log(opts.json ? JSON.stringify({ ok: true, ...r }, null, 2) : r.message);
|
|
2477
2676
|
})());
|
|
2478
2677
|
}
|
|
2678
|
+
/**
|
|
2679
|
+
* The company a bot's hot-signal-sync job syncs: the bot's own company, else
|
|
2680
|
+
* the first company it serves. Null = none, and no job is registered. There is
|
|
2681
|
+
* no fallback to the HQ's active company: a personal bot syncs a company only
|
|
2682
|
+
* when it was given one explicitly (`--company`), so the job never writes into
|
|
2683
|
+
* a vault the bot does not belong to.
|
|
2684
|
+
*/
|
|
2685
|
+
export function hotSignalSyncCompany(config) {
|
|
2686
|
+
return currentHotSignalSyncCompany(config);
|
|
2687
|
+
}
|
|
2479
2688
|
//# sourceMappingURL=bot.js.map
|
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -41,6 +41,50 @@ export declare class SyncExitError extends Error {
|
|
|
41
41
|
health?: "failed" | "succeeded";
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
+
/** Shown when the session expires during a sync and cannot be renewed. */
|
|
45
|
+
export declare const SYNC_SESSION_EXPIRED_MESSAGE = "Your HQ session expired during sync and could not be refreshed. Run `hq login`, then rerun the sync.";
|
|
46
|
+
/** Shown when the refresh failed for a network or server reason. */
|
|
47
|
+
export declare const SYNC_REFRESH_UNAVAILABLE_MESSAGE = "Could not refresh your HQ session during sync because the sign-in service did not respond. Check your connection, then rerun the sync.";
|
|
48
|
+
/** Shown when the start token carries no principal to bind the run to. */
|
|
49
|
+
export declare const SYNC_NO_IDENTITY_MESSAGE = "The HQ session token does not identify an account, so the sync did not start. Run `hq login`, then rerun the sync.";
|
|
50
|
+
/** Shown when the token would change to a different account mid-run. */
|
|
51
|
+
export declare const SYNC_IDENTITY_CHANGED_MESSAGE = "The signed-in HQ account changed while this sync was running, so the sync stopped instead of continuing as a different account. Rerun the sync as the account you want.";
|
|
52
|
+
/**
|
|
53
|
+
* The session token expired during a sync run and the non-interactive
|
|
54
|
+
* refresh failed. `kind` separates a rejected session (sign in again) from a
|
|
55
|
+
* network or server failure (retry later).
|
|
56
|
+
*/
|
|
57
|
+
export declare class SyncSessionExpiredError extends Error {
|
|
58
|
+
readonly kind: "reauth" | "unavailable";
|
|
59
|
+
readonly reason?: string | undefined;
|
|
60
|
+
constructor(kind: "reauth" | "unavailable", reason?: string | undefined);
|
|
61
|
+
}
|
|
62
|
+
export interface SyncVaultConfigDeps {
|
|
63
|
+
/** Non-interactive token resolver: returns the cached token or refreshes it. */
|
|
64
|
+
ensureToken?: () => Promise<string>;
|
|
65
|
+
}
|
|
66
|
+
/** The last token failure recorded by a {@link buildSyncVaultConfig} config. */
|
|
67
|
+
export declare function syncAuthFailureFor(config: VaultServiceConfig | undefined): Error | null;
|
|
68
|
+
/**
|
|
69
|
+
* Vault config for a sync run whose token stays valid for the whole run.
|
|
70
|
+
*
|
|
71
|
+
* `initialToken` is resolved (and, on a TTY, logged in) before the run starts.
|
|
72
|
+
* The config carries a getter instead of that string, so every vault request
|
|
73
|
+
* re-reads the cached session and refreshes it when it is close to expiry.
|
|
74
|
+
* When a request still gets a 401, hq-cloud's VaultClient calls the getter
|
|
75
|
+
* once more and retries once if the token changed (no loop). A multi-company
|
|
76
|
+
* `hq sync pull --all` can outlast the one-hour Cognito access token; a
|
|
77
|
+
* captured string made every later target fail with 401 (feedback_3d3fab0b).
|
|
78
|
+
*
|
|
79
|
+
* The getter is bound to the principal of `initialToken`. If a later token
|
|
80
|
+
* belongs to a different principal (a mid-run `hq login` as another account,
|
|
81
|
+
* or the machine-identity fallback after a rejected person refresh), it throws
|
|
82
|
+
* an {@link IdentitySwapRefusal} and the run stops. It never continues as a
|
|
83
|
+
* different principal.
|
|
84
|
+
*
|
|
85
|
+
* Mid-run refreshes never open a browser.
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildSyncVaultConfig(initialToken: string, deps?: SyncVaultConfigDeps): VaultServiceConfig;
|
|
44
88
|
/**
|
|
45
89
|
* Preserve the vault's typed write-scope refusal at the CLI boundary. This is
|
|
46
90
|
* deliberately duck-typed so hq-cli remains compatible while hq-cloud and the
|
|
@@ -50,6 +94,7 @@ export declare function formatSyncFailure(err: unknown, ctx?: {
|
|
|
50
94
|
hqRoot?: string;
|
|
51
95
|
cwd?: string;
|
|
52
96
|
companySlug?: string;
|
|
97
|
+
vaultConfig?: VaultServiceConfig;
|
|
53
98
|
}): string;
|
|
54
99
|
/**
|
|
55
100
|
* The `.hqinclude` line that admits a named path: its HQ-relative spelling,
|
|
@@ -259,6 +304,8 @@ export interface SyncCallResult {
|
|
|
259
304
|
aborted: boolean;
|
|
260
305
|
}
|
|
261
306
|
export interface PullAllDeps {
|
|
307
|
+
/** Formats a per-target failure; the real path binds the run's vault config. */
|
|
308
|
+
formatFailure?: (err: unknown) => string;
|
|
262
309
|
vaultClient: PullAllVaultClient;
|
|
263
310
|
sync: (options: SyncCallOptions) => Promise<SyncCallResult>;
|
|
264
311
|
/**
|
|
@@ -352,6 +399,8 @@ export interface ShareCallResult {
|
|
|
352
399
|
planLimit?: PlanLimitRefusalSummary | null;
|
|
353
400
|
}
|
|
354
401
|
export interface PushAllDeps {
|
|
402
|
+
/** Formats a per-target failure; the real path binds the run's vault config. */
|
|
403
|
+
formatFailure?: (err: unknown) => string;
|
|
355
404
|
vaultClient: PullAllVaultClient;
|
|
356
405
|
share: (options: ShareCallOptions) => Promise<ShareCallResult>;
|
|
357
406
|
beforeShare?: (input: {
|