@indigoai-us/hq-cli 5.345.169 → 5.345.171
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 +69 -0
- package/assets/scaffold/core/scripts/hq-delegate-send.sh +1 -1
- package/dist/command-catalog.generated.d.ts +181 -9
- package/dist/command-catalog.generated.js +224 -10
- package/dist/commands/access.d.ts +32 -1
- package/dist/commands/access.js +119 -5
- package/dist/commands/agent-kit.d.ts +1 -1
- package/dist/commands/agent-kit.js +3 -1
- package/dist/commands/agents.js +2 -1
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.js +141 -14
- package/dist/commands/cloud.d.ts +78 -1
- package/dist/commands/cloud.js +274 -9
- package/dist/commands/core-company-index-scope-flag.d.ts +8 -1
- package/dist/commands/core-company-index-scope-flag.js +9 -2
- package/dist/commands/core-delegate-w1b.js +5 -2
- package/dist/commands/core-dm-bind-native.js +19 -4
- package/dist/commands/core-rebuild-index-fast.js +24 -6
- package/dist/commands/core.js +18 -6
- package/dist/commands/dm.d.ts +17 -3
- package/dist/commands/dm.js +121 -26
- package/dist/commands/feedback-triage.d.ts +43 -1
- package/dist/commands/feedback-triage.js +123 -23
- package/dist/commands/feedback.d.ts +40 -1
- package/dist/commands/feedback.js +184 -4
- package/dist/commands/files.d.ts +42 -0
- package/dist/commands/files.js +223 -30
- package/dist/commands/integrations-api.d.ts +4 -0
- package/dist/commands/integrations-api.js +18 -2
- package/dist/commands/integrations-connect.d.ts +10 -3
- package/dist/commands/integrations-connect.js +70 -6
- package/dist/commands/integrations-core.d.ts +23 -0
- package/dist/commands/integrations-core.js +100 -0
- package/dist/commands/integrations-manage.js +8 -1
- package/dist/commands/integrations.js +49 -5
- package/dist/commands/lanes-loop.d.ts +20 -0
- package/dist/commands/lanes-loop.js +69 -11
- package/dist/commands/lanes.js +9 -1
- package/dist/commands/mesh.js +6 -0
- package/dist/commands/rescue.d.ts +9 -0
- package/dist/commands/rescue.js +31 -0
- package/dist/commands/run.js +115 -40
- package/dist/commands/scan.d.ts +5 -1
- package/dist/commands/scan.js +16 -4
- package/dist/commands/secrets.js +50 -9
- package/dist/commands/sync-manifest.d.ts +16 -0
- package/dist/commands/sync-manifest.js +17 -1
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +2367 -2109
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-state.d.ts +17 -0
- package/dist/lib/agent-kit/inbox-state.js +41 -20
- package/dist/lib/agent-kit/kit-config.d.ts +2 -0
- package/dist/lib/agent-kit/kit-config.js +6 -0
- package/dist/lib/agent-kit/mcp/tools.js +12 -5
- package/dist/lib/agent-kit/run/heartbeat.d.ts +6 -3
- package/dist/lib/agent-kit/run/heartbeat.js +6 -3
- package/dist/lib/agent-kit/run/inbox.d.ts +8 -3
- package/dist/lib/agent-kit/run/inbox.js +42 -10
- package/dist/lib/agent-kit/run/request-timeout.d.ts +26 -0
- package/dist/lib/agent-kit/run/request-timeout.js +51 -0
- package/dist/lib/bot/api.d.ts +1 -1
- package/dist/lib/bot/config.d.ts +10 -0
- package/dist/lib/bot/config.js +17 -1
- package/dist/lib/bot/decisions.d.ts +62 -0
- package/dist/lib/bot/decisions.js +228 -0
- package/dist/lib/bot/fleet-local.d.ts +127 -0
- package/dist/lib/bot/fleet-local.js +638 -0
- package/dist/lib/bot/index.d.ts +2 -0
- package/dist/lib/bot/index.js +2 -0
- package/dist/lib/bot/local-config.d.ts +3 -2
- package/dist/lib/bot/local-config.js +5 -2
- package/dist/lib/bot/promote.d.ts +10 -0
- package/dist/lib/bot/promote.js +3 -2
- package/dist/lib/bot/run.d.ts +7 -0
- package/dist/lib/bot/run.js +104 -1
- package/dist/lib/bot/runtime/index.js +8 -4
- package/dist/lib/bot/runtime/scratch-dir.d.ts +24 -0
- package/dist/lib/bot/runtime/scratch-dir.js +41 -0
- package/dist/lib/caller-principal.d.ts +4 -0
- package/dist/lib/caller-principal.js +40 -0
- package/dist/lib/capacity/collectors/grok.js +8 -2
- package/dist/lib/cli-flag-keys.d.ts +2 -0
- package/dist/lib/cli-flag-keys.js +2 -0
- package/dist/lib/daemon/catalog.d.ts +4 -0
- package/dist/lib/daemon/catalog.js +63 -29
- package/dist/lib/daemon/config.d.ts +7 -0
- package/dist/lib/daemon/config.js +32 -0
- package/dist/lib/daemon/run.d.ts +3 -2
- package/dist/lib/daemon/run.js +23 -3
- package/dist/lib/daemon/supervisor.d.ts +1 -0
- package/dist/lib/daemon/supervisor.js +4 -0
- package/dist/lib/daemon/sync-core-canary.d.ts +12 -0
- package/dist/lib/daemon/sync-core-canary.js +61 -0
- package/dist/lib/doctor/checks/release-links.d.ts +62 -1
- package/dist/lib/doctor/checks/release-links.js +188 -2
- package/dist/lib/doctor/checks/sync-health.d.ts +32 -0
- package/dist/lib/doctor/checks/sync-health.js +54 -1
- package/dist/lib/doctor/fix/apply.d.ts +26 -4
- package/dist/lib/doctor/fix/apply.js +149 -11
- package/dist/lib/doctor/fix/remediation.d.ts +8 -1
- package/dist/lib/doctor/fix/remediation.js +22 -0
- package/dist/lib/doctor/types.d.ts +1 -1
- package/dist/lib/doctor/types.js +1 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/index-render/index.d.ts +9 -0
- package/dist/lib/index-render/index.js +65 -5
- package/dist/lib/index-render/session-scope.d.ts +69 -0
- package/dist/lib/index-render/session-scope.js +279 -0
- package/dist/lib/lanes/admission.js +7 -20
- package/dist/lib/lanes/reconcile.js +13 -15
- package/dist/lib/lanes/stale-lock.d.ts +50 -0
- package/dist/lib/lanes/stale-lock.js +105 -0
- package/dist/lib/lanes/store.js +11 -76
- package/dist/lib/mesh/live/daemon/work-subscribe.js +31 -0
- package/dist/lib/notify-recipient.d.ts +10 -4
- package/dist/lib/notify-recipient.js +16 -4
- package/dist/lib/secret-input-link.d.ts +42 -0
- package/dist/lib/secret-input-link.js +93 -0
- package/dist/lib/secret-scan/range.d.ts +57 -0
- package/dist/lib/secret-scan/range.js +266 -0
- package/dist/lib/secret-scan/repo-config.d.ts +18 -3
- package/dist/lib/secret-scan/repo-config.js +135 -2
- package/dist/lib/work-context/organize.d.ts +7 -0
- package/dist/lib/work-context/organize.js +21 -1
- package/dist/run/script-bound-schema.d.ts +27 -0
- package/dist/run/script-bound-schema.js +97 -0
- package/dist/secrets-env-action.d.ts +2 -0
- package/dist/secrets-env-action.js +7 -2
- package/dist/sentry-before-send.js +1 -0
- package/dist/utils/cognito-session.d.ts +3 -30
- package/dist/utils/cognito-session.js +2 -100
- package/dist/utils/machine-principal-state.d.ts +38 -0
- package/dist/utils/machine-principal-state.js +110 -0
- package/dist/utils/safe-link.js +9 -0
- package/dist/utils/script-bound-exec.d.ts +158 -0
- package/dist/utils/script-bound-exec.js +568 -0
- package/dist/utils/sync-watchdog.d.ts +92 -0
- package/dist/utils/sync-watchdog.js +250 -0
- package/package.json +8 -8
|
@@ -153,7 +153,7 @@ export function buildKitRuntime(service) {
|
|
|
153
153
|
process.env.HQ_REQUIRE_MACHINE_IDENTITY = "1";
|
|
154
154
|
process.env.HQ_VAULT_API_URL = creds.apiBaseUrl;
|
|
155
155
|
const log = createKitLogger(paths, service, { echo: process.stdout.isTTY === true });
|
|
156
|
-
const getToken = () => ensureCognitoToken({ tokenSource: "machine", interactive: false });
|
|
156
|
+
const getToken = (signal) => ensureCognitoToken({ tokenSource: "machine", interactive: false, ...(signal ? { signal } : {}) });
|
|
157
157
|
return { paths, creds, config, getToken, log, credsSource };
|
|
158
158
|
}
|
|
159
159
|
export async function runKitService(service, rt) {
|
|
@@ -177,6 +177,7 @@ export async function runKitService(service, rt) {
|
|
|
177
177
|
},
|
|
178
178
|
apiBaseUrl: rt.creds.apiBaseUrl,
|
|
179
179
|
intervalMs: rt.config.heartbeatIntervalMs,
|
|
180
|
+
requestTimeoutMs: rt.config.requestTimeoutMs,
|
|
180
181
|
getToken: rt.getToken,
|
|
181
182
|
log: rt.log,
|
|
182
183
|
components: enabledKitComponents(rt.config),
|
|
@@ -192,6 +193,7 @@ export async function runKitService(service, rt) {
|
|
|
192
193
|
agentUid: rt.creds.entityUid,
|
|
193
194
|
apiBaseUrl: rt.creds.apiBaseUrl,
|
|
194
195
|
pollMs: rt.config.inboxPollMs,
|
|
196
|
+
requestTimeoutMs: rt.config.requestTimeoutMs,
|
|
195
197
|
ack: rt.config.inboxAck,
|
|
196
198
|
getToken: rt.getToken,
|
|
197
199
|
log: rt.log,
|
package/dist/commands/agents.js
CHANGED
|
@@ -43,6 +43,7 @@ import { launchSessionManagerPlugin, SessionManagerPluginLaunchError, TerminalSe
|
|
|
43
43
|
import { peekIdToken } from "../utils/id-token.js";
|
|
44
44
|
import { canOfferTeamUpgrade, formatUpgradeRefusal, isPlanGateError, offerUpgradeLink, } from "../utils/plan-gate-error.js";
|
|
45
45
|
import { AGENT_UID_PATTERN, defaultAudienceFor, isAgentUid } from "../lib/notify-recipient.js";
|
|
46
|
+
import { callerIsMachinePrincipal } from "../lib/caller-principal.js";
|
|
46
47
|
import { AGENT_MODEL_PROVIDERS, modelSelectionErrorMessage, readAgentModelCatalog, validateAgentModelSelection, } from "../lib/agents/model-catalog.js";
|
|
47
48
|
import { fetchCompanyPricingPlan, isUsageOnly, usageOnlyBoxSentence, usageOnlyCardRequiredLines, } from "../lib/billing/usage-only.js";
|
|
48
49
|
import { BUNDLED_USAGE_CARD, fetchUsageCard, } from "../lib/billing/usage-card.js";
|
|
@@ -1139,7 +1140,7 @@ export async function sendAgentDm(token, agentUid, message) {
|
|
|
1139
1140
|
token,
|
|
1140
1141
|
path: "/v1/notify/dm",
|
|
1141
1142
|
method: "POST",
|
|
1142
|
-
body: { toPersonUid: agentUid, body: message, audience: defaultAudienceFor("agent") },
|
|
1143
|
+
body: { toPersonUid: agentUid, body: message, audience: defaultAudienceFor("agent", callerIsMachinePrincipal()) },
|
|
1143
1144
|
});
|
|
1144
1145
|
}
|
|
1145
1146
|
/** Read the two-way DM conversation with an agent (most recent `limit`). */
|
package/dist/commands/bot.d.ts
CHANGED
|
@@ -109,6 +109,7 @@ export declare function resolveCreateKind(opts: {
|
|
|
109
109
|
};
|
|
110
110
|
export interface BotCreateOptions {
|
|
111
111
|
runtime?: string;
|
|
112
|
+
hqFleetRuntime?: boolean;
|
|
112
113
|
model?: string;
|
|
113
114
|
effort?: string;
|
|
114
115
|
autoApprove?: boolean;
|
|
@@ -343,6 +344,8 @@ export interface RemoteBotRow {
|
|
|
343
344
|
displayName: string | null;
|
|
344
345
|
/** "assistant" for HQ's setup assistant, else null. */
|
|
345
346
|
role: BotRole;
|
|
347
|
+
/** The owner's person uid exactly as GET /v1/agents/mine sends it; null when the server omits it. */
|
|
348
|
+
ownerUid: string | null;
|
|
346
349
|
}
|
|
347
350
|
export declare function registerBotCommand(program: Command): void;
|
|
348
351
|
//# sourceMappingURL=bot.d.ts.map
|
package/dist/commands/bot.js
CHANGED
|
@@ -26,6 +26,7 @@ import { hasPromotionHold, promotionHoldSummary } from "../lib/bot/promotion-hol
|
|
|
26
26
|
* list (online flag), and rm. Secrets are never printed.
|
|
27
27
|
*/
|
|
28
28
|
import { promoteLocalBot } from "../lib/bot/promote.js";
|
|
29
|
+
import { DecisionsClient } from "../lib/decisions/client.js";
|
|
29
30
|
import { releaseCurrentPackageUseLease, releasePackageUseLeaseAfterResidentPreload } from "../utils/package-use-lease.js";
|
|
30
31
|
import { preloadResidentPackageModules, reportResidentPackagePreloadFailure, runResidentCommandWithPackageLease, } from "../utils/resident-package-preload.js";
|
|
31
32
|
import { followLogFile } from "../lib/log-follow.js";
|
|
@@ -51,7 +52,7 @@ import { isAncestorProcess } from "../lib/bot/self-process.js";
|
|
|
51
52
|
import { runtimeDisplayName } from "../lib/bot/runtime-sign-in.js";
|
|
52
53
|
import { classifyRuntimeFailure, runtimeFailureReason } from "../lib/bot/runtime-failure.js";
|
|
53
54
|
import { PROBE_DEFAULT_TIMEOUT_MS, probeBotRuntime } from "../lib/bot/probe.js";
|
|
54
|
-
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, 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, } from "../lib/bot/index.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, 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, controlFleetLocalBot, fleetLocalPromotionRuntime, installPinnedFleetLocalDistribution, removeFleetLocalBot, } from "../lib/bot/index.js";
|
|
55
56
|
function collectRepeated(value, previous) {
|
|
56
57
|
return [...previous, value];
|
|
57
58
|
}
|
|
@@ -113,6 +114,18 @@ function requireBot(name) {
|
|
|
113
114
|
}
|
|
114
115
|
return { name: valid, dir, config };
|
|
115
116
|
}
|
|
117
|
+
function isFleetRuntimeBot(config) {
|
|
118
|
+
return config.engine?.id === HQ_FLEET_RUNTIME_ENGINE_ID;
|
|
119
|
+
}
|
|
120
|
+
function runFleetRuntimeControl(name, config, action, json) {
|
|
121
|
+
const result = controlFleetLocalBot(config.agentUid, action);
|
|
122
|
+
if (json) {
|
|
123
|
+
console.log(JSON.stringify({ name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const summary = typeof result.summary === "string" ? result.summary : `${action} completed`;
|
|
127
|
+
console.log(chalk.green(`${name}: ${summary}`));
|
|
128
|
+
}
|
|
116
129
|
/** Bot-identity token supplier: per-bot creds + per-bot token cache dir. */
|
|
117
130
|
export function botTokenSupplier(dir) {
|
|
118
131
|
process.env.HQ_MACHINE_CREDS_FILE = botCredsPath(dir);
|
|
@@ -604,6 +617,10 @@ async function finishExistingSetupBot(name, dir, config, displayName, opts) {
|
|
|
604
617
|
console.log(chalk.yellow(`${name} did not report running within 15s`) + chalk.dim(` logs: hq bot logs ${name}`));
|
|
605
618
|
}
|
|
606
619
|
async function runBotCreateLocked(name, opts) {
|
|
620
|
+
const useFleetRuntime = opts.hqFleetRuntime === true;
|
|
621
|
+
if (useFleetRuntime && (opts.runtime || opts.model || opts.effort || opts.lean)) {
|
|
622
|
+
throw Object.assign(new Error("--hq-fleet-runtime selects the local HQ runtime. Do not combine it with --runtime, --model, --effort, or --lean."), { expected: true });
|
|
623
|
+
}
|
|
607
624
|
const runtime = opts.runtime ?? "claude";
|
|
608
625
|
if (!isBotRuntimeId(runtime)) {
|
|
609
626
|
throw Object.assign(new Error(`--runtime must be one of ${BOT_RUNTIMES.join(", ")}`), { expected: true });
|
|
@@ -639,6 +656,11 @@ async function runBotCreateLocked(name, opts) {
|
|
|
639
656
|
// cost an identity).
|
|
640
657
|
const worker = opts.worker?.trim() ? resolveBotWorker(hqRoot, opts.worker) : null;
|
|
641
658
|
const { kind, companies } = resolveCreateKind(opts, worker);
|
|
659
|
+
if (useFleetRuntime && kind !== "personal") {
|
|
660
|
+
throw Object.assign(new Error("--hq-fleet-runtime creates a personal bot. Drop --kind company and --company."), {
|
|
661
|
+
expected: true,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
642
664
|
const isSetupBot = name === RESERVED_SETUP_BOT_NAME && kind === "personal" && worker?.id === SETUP_BOT_WORKER_ID;
|
|
643
665
|
if (name === RESERVED_SETUP_BOT_NAME && kind === "personal" && !isSetupBot) {
|
|
644
666
|
throw Object.assign(new Error(`The name ${RESERVED_SETUP_BOT_NAME} is reserved for HQ's assistant; create it with --worker ${RESERVED_SETUP_BOT_NAME}.`), { expected: true });
|
|
@@ -653,6 +675,9 @@ async function runBotCreateLocked(name, opts) {
|
|
|
653
675
|
expected: true,
|
|
654
676
|
});
|
|
655
677
|
}
|
|
678
|
+
const fleetInstallation = useFleetRuntime
|
|
679
|
+
? await installPinnedFleetLocalDistribution()
|
|
680
|
+
: null;
|
|
656
681
|
const token = await ownerToken();
|
|
657
682
|
const owner = await resolveCallerPersonUid(token, undefined, { command: "hq bot create" });
|
|
658
683
|
if (!owner)
|
|
@@ -762,6 +787,7 @@ async function runBotCreateLocked(name, opts) {
|
|
|
762
787
|
// instead of creating a new one. The machine secret never travels.
|
|
763
788
|
const localConfig = buildBotLocalConfig({
|
|
764
789
|
runtime,
|
|
790
|
+
...(fleetInstallation ? { engine: fleetInstallation.engine } : {}),
|
|
765
791
|
kind,
|
|
766
792
|
...(kind === "company" ? { companies } : {}),
|
|
767
793
|
...(model ? { model } : {}),
|
|
@@ -828,6 +854,7 @@ async function runBotCreateLocked(name, opts) {
|
|
|
828
854
|
agentUid,
|
|
829
855
|
ownerUid: created.agent.ownerUid ?? owner,
|
|
830
856
|
runtime,
|
|
857
|
+
...(fleetInstallation ? { engine: fleetInstallation.engine } : {}),
|
|
831
858
|
kind,
|
|
832
859
|
// A company bot's list is filled in below, with the invites that went through.
|
|
833
860
|
...(kind === "company" ? { companies: [] } : {}),
|
|
@@ -884,8 +911,20 @@ async function runBotCreateLocked(name, opts) {
|
|
|
884
911
|
const scaffoldOpts = { memoryDir: config.memoryDir };
|
|
885
912
|
const scaffold = worker
|
|
886
913
|
? scaffoldBotMemory(hqRoot, name, undefined, scaffoldOpts)
|
|
887
|
-
: scaffoldBotWorker(hqRoot, name, agentUid, runtime, undefined, scaffoldOpts);
|
|
888
|
-
|
|
914
|
+
: scaffoldBotWorker(hqRoot, name, agentUid, fleetInstallation ? HQ_FLEET_RUNTIME_ENGINE_ID : runtime, undefined, scaffoldOpts);
|
|
915
|
+
const fleetBootstrap = fleetInstallation
|
|
916
|
+
? bootstrapFleetLocalBot({
|
|
917
|
+
agentUid,
|
|
918
|
+
ownerUid: config.ownerUid,
|
|
919
|
+
hqRoot,
|
|
920
|
+
botDir: dir,
|
|
921
|
+
installation: fleetInstallation,
|
|
922
|
+
machineCredentials: botCredsPath(dir),
|
|
923
|
+
}, { start: opts.start !== false })
|
|
924
|
+
: null;
|
|
925
|
+
const fleetProfile = fleetBootstrap?.profile ?? null;
|
|
926
|
+
const runtimeLabel = fleetInstallation ? HQ_FLEET_RUNTIME_ENGINE_ID : runtime;
|
|
927
|
+
createBotLogger(dir)("info", `created ${name} (${agentUid}) kind=${kind}${companies.length ? ` companies=${companies.join(",")}` : ""} runtime=${runtimeLabel}${worker ? ` worker=${worker.id} company=${worker.company ?? "-"}` : ""} memory=${memoryMode}`);
|
|
889
928
|
const created_ = {
|
|
890
929
|
outcome: "created",
|
|
891
930
|
role: localBotRole(config),
|
|
@@ -894,7 +933,9 @@ async function runBotCreateLocked(name, opts) {
|
|
|
894
933
|
agentUid,
|
|
895
934
|
kind,
|
|
896
935
|
companies,
|
|
897
|
-
runtime,
|
|
936
|
+
runtime: runtimeLabel,
|
|
937
|
+
engine: fleetInstallation?.engine ?? null,
|
|
938
|
+
profile: fleetProfile,
|
|
898
939
|
dir,
|
|
899
940
|
worker: worker ? path.join(hqRoot, worker.path) : scaffold.dir,
|
|
900
941
|
workerId: worker?.id ?? null,
|
|
@@ -905,15 +946,15 @@ async function runBotCreateLocked(name, opts) {
|
|
|
905
946
|
intro: intro ?? null,
|
|
906
947
|
kickoff: kickoff ?? null,
|
|
907
948
|
model: model ?? null,
|
|
908
|
-
effort: effort ?? DEFAULT_BOT_EFFORT,
|
|
949
|
+
effort: fleetInstallation ? null : effort ?? DEFAULT_BOT_EFFORT,
|
|
909
950
|
};
|
|
910
951
|
let daemonMessage = null;
|
|
911
|
-
if (opts.daemon !== false && process.platform === "darwin") {
|
|
952
|
+
if (!fleetInstallation && opts.daemon !== false && process.platform === "darwin") {
|
|
912
953
|
const r = installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot }));
|
|
913
954
|
daemonMessage = r.message;
|
|
914
955
|
}
|
|
915
956
|
if (!opts.json) {
|
|
916
|
-
console.log(chalk.green(`Created bot ${chalk.bold(name)}`) + chalk.dim(` (${agentUid}, ${
|
|
957
|
+
console.log(chalk.green(`Created bot ${chalk.bold(name)}`) + chalk.dim(` (${agentUid}, ${runtimeLabel})`));
|
|
917
958
|
console.log(chalk.dim(` kind: ${describeKind(kind, companies)}`));
|
|
918
959
|
if (worker)
|
|
919
960
|
console.log(chalk.dim(` worker: ${worker.id}${worker.company ? ` (${worker.company})` : ""} — ${path.join(hqRoot, worker.path)}`));
|
|
@@ -921,9 +962,17 @@ async function runBotCreateLocked(name, opts) {
|
|
|
921
962
|
console.log(chalk.dim(` worker: ${scaffold.dir}`));
|
|
922
963
|
console.log(chalk.dim(` memory: ${scaffold.memoryDir} (${memoryMode})`));
|
|
923
964
|
console.log(chalk.dim(` state: ${dir}`));
|
|
965
|
+
if (fleetProfile)
|
|
966
|
+
console.log(chalk.dim(` profile: ${fleetProfile}`));
|
|
924
967
|
if (daemonMessage)
|
|
925
968
|
console.log(chalk.dim(` ${daemonMessage}`));
|
|
926
969
|
}
|
|
970
|
+
if (fleetInstallation) {
|
|
971
|
+
if (opts.json) {
|
|
972
|
+
console.log(JSON.stringify({ ok: true, name, ...created_, daemon: null, running: fleetBootstrap?.running ?? false }, null, 2));
|
|
973
|
+
}
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
927
976
|
if (opts.start !== false) {
|
|
928
977
|
if (daemonMessage && /loaded\)/.test(daemonMessage)) {
|
|
929
978
|
// RunAtLoad already started it.
|
|
@@ -1063,6 +1112,9 @@ async function runBotResident(nameArg) {
|
|
|
1063
1112
|
api,
|
|
1064
1113
|
runtime: runtimeFor(config.runtime),
|
|
1065
1114
|
ownerContext: () => owner.get(),
|
|
1115
|
+
// US-005: decision picks in the owner DM, with the bot's own machine token
|
|
1116
|
+
// (never the owner's login).
|
|
1117
|
+
decisions: new DecisionsClient(token),
|
|
1066
1118
|
// Chat attachments are fetched with the bot's own machine identity against
|
|
1067
1119
|
// the same API its inbox and posts use (BotApi has no baseUrl override either).
|
|
1068
1120
|
downloadAttachment: createVaultObjectDownloader({ getToken: token }),
|
|
@@ -1123,7 +1175,11 @@ async function runBotList(opts) {
|
|
|
1123
1175
|
}
|
|
1124
1176
|
}
|
|
1125
1177
|
async function runBotStatus(nameArg, opts) {
|
|
1126
|
-
const { name, dir } = requireBot(nameArg);
|
|
1178
|
+
const { name, dir, config } = requireBot(nameArg);
|
|
1179
|
+
if (isFleetRuntimeBot(config)) {
|
|
1180
|
+
runFleetRuntimeControl(name, config, "status", opts.json === true);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1127
1183
|
const row = rowFor(name);
|
|
1128
1184
|
await decorateOnline([row]);
|
|
1129
1185
|
const status = readBotStatus(dir);
|
|
@@ -1322,6 +1378,15 @@ async function runBotRmOrphan(name, opts) {
|
|
|
1322
1378
|
else
|
|
1323
1379
|
console.log(chalk.dim(` HQ may still have a bot named "${name}". Remove that too with: hq bot rm ${name} --remote`));
|
|
1324
1380
|
}
|
|
1381
|
+
function stopFleetRuntimeBotQuietly(agentUid) {
|
|
1382
|
+
try {
|
|
1383
|
+
controlFleetLocalBot(agentUid, "stop");
|
|
1384
|
+
return true;
|
|
1385
|
+
}
|
|
1386
|
+
catch {
|
|
1387
|
+
return false;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1325
1390
|
async function runBotRm(nameArg, opts) {
|
|
1326
1391
|
const validated = validateBotName(nameArg);
|
|
1327
1392
|
// Under the bot's lock: an rm racing a create, adopt or restore of the same
|
|
@@ -1344,9 +1409,13 @@ async function runBotRmLocked(validated, opts) {
|
|
|
1344
1409
|
return;
|
|
1345
1410
|
}
|
|
1346
1411
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1412
|
+
if (isFleetRuntimeBot(config))
|
|
1413
|
+
stopFleetRuntimeBotQuietly(config.agentUid);
|
|
1414
|
+
else
|
|
1415
|
+
await stopBot(name, dir, config, "silent").catch(() => { });
|
|
1416
|
+
const daemon = isFleetRuntimeBot(config)
|
|
1417
|
+
? { message: "managed by HQ Fleet Runtime" }
|
|
1418
|
+
: uninstallBotDaemon(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }), daemonDeps());
|
|
1350
1419
|
const token = await ownerToken();
|
|
1351
1420
|
const api = new BotApi({ token: async () => token });
|
|
1352
1421
|
let identity;
|
|
@@ -1376,8 +1445,11 @@ async function runBotRmLocked(validated, opts) {
|
|
|
1376
1445
|
// re-created under the same name. Everything else keeps the folder, so the
|
|
1377
1446
|
// same command can pick the job back up.
|
|
1378
1447
|
const localStateRemoved = terminal || incomplete.retryable === false;
|
|
1379
|
-
if (localStateRemoved)
|
|
1448
|
+
if (localStateRemoved) {
|
|
1449
|
+
if (isFleetRuntimeBot(config))
|
|
1450
|
+
removeFleetLocalBot(config.agentUid);
|
|
1380
1451
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
1452
|
+
}
|
|
1381
1453
|
const message = incomplete
|
|
1382
1454
|
? `HQ removed what it could of "${name}", but ${incomplete.detail}.` +
|
|
1383
1455
|
(incomplete.retryable
|
|
@@ -1568,6 +1640,10 @@ export function botExists(name) {
|
|
|
1568
1640
|
/** `hq bot restart <name>`: stop, then start (launchd when installed). */
|
|
1569
1641
|
export async function runBotRestart(nameArg, opts = {}) {
|
|
1570
1642
|
const b = requireBot(nameArg);
|
|
1643
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
1644
|
+
runFleetRuntimeControl(b.name, b.config, "restart", opts.json === true || opts.output === "json");
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1571
1647
|
const running = readBotStatus(b.dir);
|
|
1572
1648
|
if (running && isPidAlive(running.pid) && selfStopProbe(running.pid)) {
|
|
1573
1649
|
// The stop half would end this turn (and this command) before the
|
|
@@ -1577,6 +1653,30 @@ export async function runBotRestart(nameArg, opts = {}) {
|
|
|
1577
1653
|
await stopBot(b.name, b.dir, b.config, "silent");
|
|
1578
1654
|
await startBot(b.name, b.dir, b.config, opts.output ?? (opts.json ? "json" : "text"));
|
|
1579
1655
|
}
|
|
1656
|
+
async function runBotAuth(nameArg, opts) {
|
|
1657
|
+
const b = requireBot(nameArg);
|
|
1658
|
+
if (!isFleetRuntimeBot(b.config)) {
|
|
1659
|
+
throw Object.assign(new Error(`hq bot auth is for bots created with --hq-fleet-runtime. ${b.name} uses ${b.config.runtime}.`), { expected: true });
|
|
1660
|
+
}
|
|
1661
|
+
const apiKey = opts.apiKey ? fs.readFileSync(0, "utf8").trim() : undefined;
|
|
1662
|
+
if (opts.apiKey && !apiKey) {
|
|
1663
|
+
throw Object.assign(new Error("No API key was received on stdin."), { expected: true });
|
|
1664
|
+
}
|
|
1665
|
+
const result = authenticateFleetLocalBot({
|
|
1666
|
+
agentUid: b.config.agentUid,
|
|
1667
|
+
provider: opts.provider,
|
|
1668
|
+
...(opts.model ? { model: opts.model } : {}),
|
|
1669
|
+
...(apiKey ? { apiKey } : {}),
|
|
1670
|
+
...(opts.baseUrl ? { baseUrl: opts.baseUrl } : {}),
|
|
1671
|
+
...(opts.transport ? { transport: opts.transport } : {}),
|
|
1672
|
+
openBrowser: opts.browser !== false,
|
|
1673
|
+
});
|
|
1674
|
+
if (opts.json) {
|
|
1675
|
+
console.log(JSON.stringify({ ok: true, name: b.name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
console.log(chalk.green(`${b.name} is signed in to ${result.provider} and running ${result.model}.`));
|
|
1679
|
+
}
|
|
1580
1680
|
// ── adopt / restore (bring a bot you own back to this computer) ──────────────
|
|
1581
1681
|
/**
|
|
1582
1682
|
* Which computer a re-issue is for. Never a secret and never an identifier the
|
|
@@ -2086,6 +2186,7 @@ async function runBotListRemote(opts) {
|
|
|
2086
2186
|
reason: runnable.reason,
|
|
2087
2187
|
displayName: remoteBotDisplayName(bot, name),
|
|
2088
2188
|
role: remoteBotRole(bot),
|
|
2189
|
+
ownerUid: bot.ownerUid ?? null,
|
|
2089
2190
|
};
|
|
2090
2191
|
});
|
|
2091
2192
|
if (opts.json) {
|
|
@@ -2120,7 +2221,13 @@ export function registerBotCommand(program) {
|
|
|
2120
2221
|
const { dir, config } = requireBot(name);
|
|
2121
2222
|
const token = await ownerToken(false);
|
|
2122
2223
|
const api = new BotApi({ token: async () => token });
|
|
2123
|
-
const result = await promoteLocalBot({
|
|
2224
|
+
const result = await promoteLocalBot({
|
|
2225
|
+
dir,
|
|
2226
|
+
config,
|
|
2227
|
+
companyUid: opts.company,
|
|
2228
|
+
api,
|
|
2229
|
+
...(isFleetRuntimeBot(config) ? { runtime: fleetLocalPromotionRuntime(config.agentUid) } : {}),
|
|
2230
|
+
});
|
|
2124
2231
|
const details = result.pending ? await api.promotionDetails(config.agentUid, opts.company) : null;
|
|
2125
2232
|
if (opts.json)
|
|
2126
2233
|
console.log(JSON.stringify({ ...result, pairing: details?.pairing ?? null, ...(details?.failure ? { failure: details.failure } : {}) }));
|
|
@@ -2136,7 +2243,8 @@ export function registerBotCommand(program) {
|
|
|
2136
2243
|
.description("Provision a local bot identity, scaffold its worker folder, install its launchd agent, and start it")
|
|
2137
2244
|
.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`)
|
|
2138
2245
|
.option("--company <slug>", "Company bots: a company the bot is a member of (repeat for several); the owner invites it on creation", collectRepeated, [])
|
|
2139
|
-
.option("--runtime <runtime>", `Model CLI to run the bot with: ${BOT_RUNTIMES.join("|")}
|
|
2246
|
+
.option("--runtime <runtime>", `Model CLI to run the bot with: ${BOT_RUNTIMES.join("|")}`)
|
|
2247
|
+
.option("--hq-fleet-runtime", "Create this personal bot with the local HQ Fleet Runtime")
|
|
2140
2248
|
.option("--model <model>", "Model override passed to the runtime CLI")
|
|
2141
2249
|
.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})`)
|
|
2142
2250
|
.option("--no-auto-approve", "Keep the runtime's permission gates (default: everything pre-approved; a headless bot cannot answer prompts)")
|
|
@@ -2192,6 +2300,10 @@ export function registerBotCommand(program) {
|
|
|
2192
2300
|
.option("--json", "Print machine-readable JSON")
|
|
2193
2301
|
.action((name, opts) => wrap(async () => {
|
|
2194
2302
|
const b = requireBot(name);
|
|
2303
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
2304
|
+
runFleetRuntimeControl(b.name, b.config, "start", opts.json === true);
|
|
2305
|
+
return;
|
|
2306
|
+
}
|
|
2195
2307
|
await startBot(b.name, b.dir, b.config, opts.json ? "json" : "text");
|
|
2196
2308
|
})());
|
|
2197
2309
|
bot
|
|
@@ -2200,6 +2312,10 @@ export function registerBotCommand(program) {
|
|
|
2200
2312
|
.option("--json", "Print machine-readable JSON")
|
|
2201
2313
|
.action((name, opts) => wrap(async () => {
|
|
2202
2314
|
const b = requireBot(name);
|
|
2315
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
2316
|
+
runFleetRuntimeControl(b.name, b.config, "stop", opts.json === true);
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2203
2319
|
await stopBot(b.name, b.dir, b.config, opts.json ? "json" : "text");
|
|
2204
2320
|
})());
|
|
2205
2321
|
bot
|
|
@@ -2212,6 +2328,17 @@ export function registerBotCommand(program) {
|
|
|
2212
2328
|
.description("Show the bot's process, heartbeat, launchd, and credential state")
|
|
2213
2329
|
.option("--json", "Print machine-readable JSON")
|
|
2214
2330
|
.action((name, opts) => wrap(() => runBotStatus(name, opts))());
|
|
2331
|
+
bot
|
|
2332
|
+
.command("auth <name>")
|
|
2333
|
+
.description("Sign a runtime-backed personal bot in to ChatGPT, Grok, Claude, or another supported provider")
|
|
2334
|
+
.requiredOption("--provider <provider>", "Provider: chatgpt, grok, claude, or a runtime provider id")
|
|
2335
|
+
.option("--model <model>", "Model id; required for providers without a built-in personal-bot default")
|
|
2336
|
+
.option("--api-key", "Read an API key from stdin instead of starting device authorization")
|
|
2337
|
+
.option("--base-url <url>", "Provider API base URL; required for custom runtime providers")
|
|
2338
|
+
.option("--transport <transport>", "Provider transport: chat_completions, anthropic_messages, or codex_responses")
|
|
2339
|
+
.option("--no-browser", "Do not open a browser during device authorization")
|
|
2340
|
+
.option("--json", "Print machine-readable JSON")
|
|
2341
|
+
.action((name, opts) => wrap(() => runBotAuth(name, opts))());
|
|
2215
2342
|
bot
|
|
2216
2343
|
.command("logs <name>")
|
|
2217
2344
|
.description("Show the bot's log")
|
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { Command } from "commander";
|
|
16
16
|
import { type ConflictStrategy, type EntityContext, type MembershipSyncConfig, type SyncMode, type PullScope, type ExplicitGrant, type ShareOptions, type VaultServiceConfig } from "@indigoai-us/hq-cloud";
|
|
17
|
+
import { withSyncWatchdog, type SyncWatchdogLimits } from "../utils/sync-watchdog.js";
|
|
17
18
|
import { type BannerLevel } from "../lib/narrow-hint-banner.js";
|
|
18
19
|
import { type PlanLimitRefusalSummary } from "../lib/billing/plan-limit-refusals.js";
|
|
19
20
|
/**
|
|
@@ -45,7 +46,54 @@ export declare class SyncExitError extends Error {
|
|
|
45
46
|
* deliberately duck-typed so hq-cli remains compatible while hq-cloud and the
|
|
46
47
|
* CLI are released independently.
|
|
47
48
|
*/
|
|
48
|
-
export declare function formatSyncFailure(err: unknown
|
|
49
|
+
export declare function formatSyncFailure(err: unknown, ctx?: {
|
|
50
|
+
hqRoot?: string;
|
|
51
|
+
cwd?: string;
|
|
52
|
+
companySlug?: string;
|
|
53
|
+
}): string;
|
|
54
|
+
/**
|
|
55
|
+
* The `.hqinclude` line that admits a named path: its HQ-relative spelling,
|
|
56
|
+
* with a trailing slash for a folder. Resolved the way the push resolver
|
|
57
|
+
* reads a named path (absolute, HQ root, the company folder, then the current
|
|
58
|
+
* directory); a path that resolves nowhere inside the HQ tree is suggested as
|
|
59
|
+
* typed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function hqincludeEntryFor(namedPath: string, ctx?: {
|
|
62
|
+
hqRoot?: string;
|
|
63
|
+
cwd?: string;
|
|
64
|
+
companySlug?: string;
|
|
65
|
+
}): string;
|
|
66
|
+
/**
|
|
67
|
+
* Re-render hq-cloud's UnreachablePushPathsError with the real blocker per
|
|
68
|
+
* path (feedback_6afa6ce4). The upstream message always ends with advice
|
|
69
|
+
* about symlinks, so a path left out of `.hqinclude` read as a symlink
|
|
70
|
+
* problem. This names the `.hqinclude` line to add, and keeps the symlink
|
|
71
|
+
* advice only for reasons that are about links or paths outside the company
|
|
72
|
+
* folder. Returns null for any other error.
|
|
73
|
+
*/
|
|
74
|
+
export declare function formatUnreachablePushPaths(err: unknown, ctx?: {
|
|
75
|
+
hqRoot?: string;
|
|
76
|
+
cwd?: string;
|
|
77
|
+
companySlug?: string;
|
|
78
|
+
}): string | null;
|
|
79
|
+
/**
|
|
80
|
+
* Lines naming the blocker when a push with user-named paths uploaded nothing
|
|
81
|
+
* and every not-uploaded file fell outside write scope (feedback_5baccb9e).
|
|
82
|
+
* The summary before this gave a count and the granted prefixes; this names
|
|
83
|
+
* each requested path as the thing no write grant covers and points at
|
|
84
|
+
* `hq access`, which reports the ACL row that blocks it.
|
|
85
|
+
*/
|
|
86
|
+
export declare function explicitPushBlockedLines(input: {
|
|
87
|
+
userNamedPaths: boolean;
|
|
88
|
+
namedPaths: readonly string[];
|
|
89
|
+
filesUploaded: number;
|
|
90
|
+
filesExcludedByScope: number;
|
|
91
|
+
otherNotUploaded: number;
|
|
92
|
+
prefixSet: readonly string[] | undefined;
|
|
93
|
+
hqRoot: string;
|
|
94
|
+
cwd?: string;
|
|
95
|
+
companySlug?: string;
|
|
96
|
+
}): string[];
|
|
49
97
|
/**
|
|
50
98
|
* US-003: run one sync fanout under a client-health attempt/outcome report.
|
|
51
99
|
* The report is best-effort, bounded, and swallowed — it can only append a
|
|
@@ -67,6 +115,26 @@ export declare function withSyncHealthReport<T>(run: () => Promise<T>): Promise<
|
|
|
67
115
|
*/
|
|
68
116
|
export declare function scopeExcludedExitCode(count: number): 0 | 1;
|
|
69
117
|
export declare function scopeExcludedWarning(count: number): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Counts the files share() held back because this sync scope is fenced after an account
|
|
120
|
+
* switch on this computer (feedback_a69e12ba). share() reports the hold only as
|
|
121
|
+
* an `identity-switch-push-held` event and leaves the files out of every
|
|
122
|
+
* result counter, so without this the push printed "Pushed 0 file(s) (0 B,
|
|
123
|
+
* 0 skipped)" as a success while the vault kept the old copy.
|
|
124
|
+
*
|
|
125
|
+
* Each event carries the size of one fenced hold, so the tracker keeps the
|
|
126
|
+
* largest count it sees instead of a sum: a repeated emit for the same hold
|
|
127
|
+
* cannot inflate the total. A missing, non-numeric or negative count reads as 0.
|
|
128
|
+
*/
|
|
129
|
+
export declare function createIdentityHeldTracker(): {
|
|
130
|
+
observe: (event: {
|
|
131
|
+
type: string;
|
|
132
|
+
count?: unknown;
|
|
133
|
+
}) => void;
|
|
134
|
+
count: () => number;
|
|
135
|
+
};
|
|
136
|
+
/** Recovery lines for files held by the account-switch push fence. */
|
|
137
|
+
export declare function identityHeldLines(count: number): string[];
|
|
70
138
|
/** Actionable recovery for files refused because the vault baseline is stale. */
|
|
71
139
|
export declare function staleUploadRefusalLines(count: number, paths?: readonly string[]): string[];
|
|
72
140
|
/**
|
|
@@ -108,6 +176,15 @@ export declare function scopeExcludedPrefixDetail(prefixSet: readonly string[] |
|
|
|
108
176
|
* folder foo/ — and grant advice would point the reader the wrong way.
|
|
109
177
|
*/
|
|
110
178
|
export declare function scopeExcludedLines(count: number, prefixSet: readonly string[] | undefined): string[];
|
|
179
|
+
/**
|
|
180
|
+
* feedback_b7c00a62: run a `sync now` runner under the watchdog (see
|
|
181
|
+
* `utils/sync-watchdog.ts` for the limits). A timeout prints a clear message
|
|
182
|
+
* and unwinds as a failed {@link SyncExitError}, so {@link withSyncHealthReport}
|
|
183
|
+
* records the failure and exits 124. The failure report gets at most
|
|
184
|
+
* {@link SYNC_WATCHDOG_REPORT_GRACE_MS}; after that the process exits 124
|
|
185
|
+
* regardless, and the worker backstop stays armed behind both.
|
|
186
|
+
*/
|
|
187
|
+
export declare function runUnderSyncWatchdog<T>(limits: SyncWatchdogLimits, label: string, run: () => Promise<T>, watchdog?: typeof withSyncWatchdog, exit?: (code: number) => void): Promise<T>;
|
|
111
188
|
/**
|
|
112
189
|
* Bound foreground waits for a watcher/manual sync that currently owns the
|
|
113
190
|
* per-root operation lock. The cloud engine reads this environment value on
|