@indigoai-us/hq-cli 5.345.170 → 5.345.172
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/assets/scaffold/core/scripts/hq-delegate-send.sh +1 -1
- package/dist/command-catalog.generated.d.ts +206 -7
- package/dist/command-catalog.generated.js +252 -8
- package/dist/command-registration-plan.d.ts +7 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/access.d.ts +32 -1
- package/dist/commands/access.js +112 -3
- package/dist/commands/agent-kit.d.ts +1 -1
- package/dist/commands/agent-kit.js +3 -1
- package/dist/commands/agents.js +2 -1
- package/dist/commands/bot.d.ts +3 -0
- package/dist/commands/bot.js +179 -18
- package/dist/commands/cloud.d.ts +58 -1
- package/dist/commands/cloud.js +228 -10
- package/dist/commands/core-company-index-scope-flag.d.ts +8 -1
- package/dist/commands/core-company-index-scope-flag.js +9 -2
- package/dist/commands/core-delegate-w1b.js +5 -2
- package/dist/commands/core-dm-bind-native.js +19 -4
- package/dist/commands/core-rebuild-index-fast.js +24 -6
- package/dist/commands/core.js +18 -6
- package/dist/commands/daemon.js +16 -1
- package/dist/commands/dm.d.ts +17 -3
- package/dist/commands/dm.js +121 -26
- package/dist/commands/files.d.ts +1 -0
- package/dist/commands/files.js +22 -4
- package/dist/commands/integrations-api.d.ts +4 -0
- package/dist/commands/integrations-api.js +18 -2
- package/dist/commands/integrations-connect.d.ts +10 -3
- package/dist/commands/integrations-connect.js +70 -6
- package/dist/commands/integrations-core.d.ts +23 -0
- package/dist/commands/integrations-core.js +100 -0
- package/dist/commands/integrations-manage.js +8 -1
- package/dist/commands/integrations.js +49 -5
- package/dist/commands/lanes-loop.d.ts +20 -0
- package/dist/commands/lanes-loop.js +69 -11
- package/dist/commands/lanes.js +9 -1
- package/dist/commands/rescue.d.ts +9 -0
- package/dist/commands/rescue.js +31 -0
- package/dist/commands/run.js +115 -40
- package/dist/commands/scan.d.ts +5 -1
- package/dist/commands/scan.js +16 -4
- package/dist/commands/secrets.js +50 -9
- package/dist/commands/sync-core.d.ts +22 -0
- package/dist/commands/sync-core.js +124 -0
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +2447 -2135
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/agent-kit/inbox-state.d.ts +17 -0
- package/dist/lib/agent-kit/inbox-state.js +41 -20
- package/dist/lib/agent-kit/kit-config.d.ts +2 -0
- package/dist/lib/agent-kit/kit-config.js +6 -0
- package/dist/lib/agent-kit/mcp/tools.js +12 -5
- package/dist/lib/agent-kit/run/heartbeat.d.ts +6 -3
- package/dist/lib/agent-kit/run/heartbeat.js +6 -3
- package/dist/lib/agent-kit/run/inbox.d.ts +8 -3
- package/dist/lib/agent-kit/run/inbox.js +42 -10
- package/dist/lib/agent-kit/run/request-timeout.d.ts +26 -0
- package/dist/lib/agent-kit/run/request-timeout.js +51 -0
- package/dist/lib/bot/api.d.ts +1 -1
- package/dist/lib/bot/config.d.ts +10 -0
- package/dist/lib/bot/config.js +17 -1
- package/dist/lib/bot/fleet-local.d.ts +142 -0
- package/dist/lib/bot/fleet-local.js +689 -0
- package/dist/lib/bot/fleet-python.d.ts +47 -0
- package/dist/lib/bot/fleet-python.js +218 -0
- package/dist/lib/bot/index.d.ts +2 -0
- package/dist/lib/bot/index.js +2 -0
- package/dist/lib/bot/local-config.d.ts +3 -2
- package/dist/lib/bot/local-config.js +5 -2
- package/dist/lib/bot/promote.d.ts +10 -0
- package/dist/lib/bot/promote.js +3 -2
- package/dist/lib/bot/prompt.d.ts +6 -1
- package/dist/lib/bot/prompt.js +8 -3
- package/dist/lib/bot/runtime/index.js +8 -4
- package/dist/lib/bot/runtime/scratch-dir.d.ts +24 -0
- package/dist/lib/bot/runtime/scratch-dir.js +41 -0
- package/dist/lib/caller-principal.d.ts +4 -0
- package/dist/lib/caller-principal.js +40 -0
- package/dist/lib/capacity/collectors/grok.js +8 -2
- package/dist/lib/cli-flag-keys.d.ts +2 -0
- package/dist/lib/cli-flag-keys.js +2 -0
- package/dist/lib/daemon/catalog.d.ts +12 -4
- package/dist/lib/daemon/catalog.js +70 -24
- package/dist/lib/daemon/config.d.ts +0 -7
- package/dist/lib/daemon/config.js +0 -32
- package/dist/lib/daemon/run.d.ts +5 -1
- package/dist/lib/daemon/run.js +48 -11
- package/dist/lib/daemon/supervisor.js +3 -1
- package/dist/lib/doctor/checks/release-links.d.ts +62 -1
- package/dist/lib/doctor/checks/release-links.js +188 -2
- package/dist/lib/doctor/fix/apply.js +54 -0
- package/dist/lib/doctor/fix/remediation.d.ts +8 -1
- package/dist/lib/doctor/fix/remediation.js +22 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/index-render/index.d.ts +9 -0
- package/dist/lib/index-render/index.js +65 -5
- package/dist/lib/index-render/session-scope.d.ts +69 -0
- package/dist/lib/index-render/session-scope.js +279 -0
- package/dist/lib/lanes/admission.js +7 -20
- package/dist/lib/lanes/reconcile.js +13 -15
- package/dist/lib/lanes/stale-lock.d.ts +50 -0
- package/dist/lib/lanes/stale-lock.js +105 -0
- package/dist/lib/lanes/store.js +11 -76
- package/dist/lib/notify-recipient.d.ts +10 -4
- package/dist/lib/notify-recipient.js +16 -4
- package/dist/lib/secret-input-link.d.ts +42 -0
- package/dist/lib/secret-input-link.js +93 -0
- package/dist/lib/secret-scan/range.d.ts +57 -0
- package/dist/lib/secret-scan/range.js +266 -0
- package/dist/lib/secret-scan/repo-config.d.ts +18 -3
- package/dist/lib/secret-scan/repo-config.js +135 -2
- package/dist/lib/sync-core/engine-home.d.ts +44 -0
- package/dist/lib/sync-core/engine-home.js +193 -0
- package/dist/lib/sync-core/flag.d.ts +17 -0
- package/dist/lib/sync-core/flag.js +47 -0
- package/dist/lib/sync-core/reconcile.d.ts +31 -0
- package/dist/lib/sync-core/reconcile.js +196 -0
- package/dist/lib/sync-core/release.d.ts +32 -0
- package/dist/lib/sync-core/release.js +140 -0
- package/dist/lib/sync-core/rollout-state.d.ts +24 -0
- package/dist/lib/sync-core/rollout-state.js +94 -0
- package/dist/lib/vault-sync-switches.d.ts +5 -0
- package/dist/lib/vault-sync-switches.js +43 -0
- package/dist/run/script-bound-schema.d.ts +27 -0
- package/dist/run/script-bound-schema.js +97 -0
- package/dist/secrets-env-action.d.ts +2 -0
- package/dist/secrets-env-action.js +7 -2
- package/dist/utils/cognito-session.d.ts +3 -30
- package/dist/utils/cognito-session.js +2 -100
- package/dist/utils/machine-principal-state.d.ts +38 -0
- package/dist/utils/machine-principal-state.js +110 -0
- package/dist/utils/remote-list-not-converging.d.ts +21 -0
- package/dist/utils/remote-list-not-converging.js +40 -0
- package/dist/utils/safe-link.js +9 -0
- package/dist/utils/script-bound-exec.d.ts +158 -0
- package/dist/utils/script-bound-exec.js +568 -0
- package/dist/utils/sync-watchdog.d.ts +92 -0
- package/dist/utils/sync-watchdog.js +250 -0
- package/package.json +8 -8
- package/dist/lib/daemon/sync-core-canary.d.ts +0 -9
- package/dist/lib/daemon/sync-core-canary.js +0 -56
|
@@ -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
|
@@ -52,7 +52,7 @@ import { isAncestorProcess } from "../lib/bot/self-process.js";
|
|
|
52
52
|
import { runtimeDisplayName } from "../lib/bot/runtime-sign-in.js";
|
|
53
53
|
import { classifyRuntimeFailure, runtimeFailureReason } from "../lib/bot/runtime-failure.js";
|
|
54
54
|
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, 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, buildSystemPrompt, controlFleetLocalBot, ensureFleetPython, fleetLocalGatewayPid, refreshFleetLocalInstructions, fleetLocalPromotionRuntime, installPinnedFleetLocalDistribution, readPromptSources, removeFleetLocalBot, } from "../lib/bot/index.js";
|
|
56
56
|
function collectRepeated(value, previous) {
|
|
57
57
|
return [...previous, value];
|
|
58
58
|
}
|
|
@@ -114,6 +114,48 @@ function requireBot(name) {
|
|
|
114
114
|
}
|
|
115
115
|
return { name: valid, dir, config };
|
|
116
116
|
}
|
|
117
|
+
function isFleetRuntimeBot(config) {
|
|
118
|
+
return config.engine?.id === HQ_FLEET_RUNTIME_ENGINE_ID;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The standing HQ instructions an HQ Fleet Runtime bot runs under: the same
|
|
122
|
+
* text a legacy local bot gets, read fresh from its worker folder, with the
|
|
123
|
+
* runtime's own way of labelling senders.
|
|
124
|
+
*/
|
|
125
|
+
function fleetBotSystemPrompt(name, config, overrides = {}) {
|
|
126
|
+
return buildSystemPrompt({
|
|
127
|
+
botName: name,
|
|
128
|
+
...(config.displayName ? { displayName: config.displayName } : {}),
|
|
129
|
+
agentUid: config.agentUid,
|
|
130
|
+
ownerUid: config.ownerUid,
|
|
131
|
+
hqRoot: config.hqRoot,
|
|
132
|
+
workerDir: config.workerDir,
|
|
133
|
+
workerSource: config.workerSource,
|
|
134
|
+
workerId: config.workerId,
|
|
135
|
+
companySlug: config.companySlug,
|
|
136
|
+
kind: overrides.kind ?? effectiveBotKind(config),
|
|
137
|
+
companies: overrides.companies ?? effectiveBotCompanies(config),
|
|
138
|
+
memoryDir: config.memoryDir,
|
|
139
|
+
fleetRuntime: true,
|
|
140
|
+
sources: readPromptSources(config.hqRoot, config.workerDir, undefined, {
|
|
141
|
+
memoryDir: config.memoryDir,
|
|
142
|
+
workerSource: config.workerSource,
|
|
143
|
+
companySlug: config.companySlug,
|
|
144
|
+
}),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function runFleetRuntimeControl(name, config, action, json) {
|
|
148
|
+
if (action === "start" || action === "restart") {
|
|
149
|
+
refreshFleetLocalInstructions(config.agentUid, fleetBotSystemPrompt(name, config));
|
|
150
|
+
}
|
|
151
|
+
const result = controlFleetLocalBot(config.agentUid, action);
|
|
152
|
+
if (json) {
|
|
153
|
+
console.log(JSON.stringify({ name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const summary = typeof result.summary === "string" ? result.summary : `${action} completed`;
|
|
157
|
+
console.log(chalk.green(`${name}: ${summary}`));
|
|
158
|
+
}
|
|
117
159
|
/** Bot-identity token supplier: per-bot creds + per-bot token cache dir. */
|
|
118
160
|
export function botTokenSupplier(dir) {
|
|
119
161
|
process.env.HQ_MACHINE_CREDS_FILE = botCredsPath(dir);
|
|
@@ -137,15 +179,16 @@ async function ownerToken(interactive = process.stdin.isTTY === true) {
|
|
|
137
179
|
function rowFor(name, opts = {}) {
|
|
138
180
|
const dir = botDir(name);
|
|
139
181
|
const config = readBotConfig(dir);
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
182
|
+
const fleet = isFleetRuntimeBot(config);
|
|
183
|
+
const status = fleet ? null : readBotStatus(dir);
|
|
184
|
+
const pid = fleet ? fleetLocalGatewayPid(config.agentUid) : (status?.pid ?? null);
|
|
185
|
+
const processAlive = pid !== null && isPidAlive(pid) && (fleet || status?.state === "running");
|
|
143
186
|
// Turns this bot has taken and not finished: what "thinking" means.
|
|
144
187
|
const inflightTurns = readInflightTurns(dir);
|
|
145
188
|
let daemonInstalled = false;
|
|
146
189
|
let daemonLoaded = false;
|
|
147
190
|
let daemonNodeMissing = null;
|
|
148
|
-
if (opts.withDaemon !== false) {
|
|
191
|
+
if (opts.withDaemon !== false && !fleet) {
|
|
149
192
|
try {
|
|
150
193
|
const d = botDaemonStatus(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }), daemonDeps());
|
|
151
194
|
daemonInstalled = d.installed;
|
|
@@ -605,6 +648,10 @@ async function finishExistingSetupBot(name, dir, config, displayName, opts) {
|
|
|
605
648
|
console.log(chalk.yellow(`${name} did not report running within 15s`) + chalk.dim(` logs: hq bot logs ${name}`));
|
|
606
649
|
}
|
|
607
650
|
async function runBotCreateLocked(name, opts) {
|
|
651
|
+
const useFleetRuntime = opts.hqFleetRuntime === true;
|
|
652
|
+
if (useFleetRuntime && (opts.runtime || opts.model || opts.effort || opts.lean)) {
|
|
653
|
+
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 });
|
|
654
|
+
}
|
|
608
655
|
const runtime = opts.runtime ?? "claude";
|
|
609
656
|
if (!isBotRuntimeId(runtime)) {
|
|
610
657
|
throw Object.assign(new Error(`--runtime must be one of ${BOT_RUNTIMES.join(", ")}`), { expected: true });
|
|
@@ -640,6 +687,11 @@ async function runBotCreateLocked(name, opts) {
|
|
|
640
687
|
// cost an identity).
|
|
641
688
|
const worker = opts.worker?.trim() ? resolveBotWorker(hqRoot, opts.worker) : null;
|
|
642
689
|
const { kind, companies } = resolveCreateKind(opts, worker);
|
|
690
|
+
if (useFleetRuntime && kind !== "personal") {
|
|
691
|
+
throw Object.assign(new Error("--hq-fleet-runtime creates a personal bot. Drop --kind company and --company."), {
|
|
692
|
+
expected: true,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
643
695
|
const isSetupBot = name === RESERVED_SETUP_BOT_NAME && kind === "personal" && worker?.id === SETUP_BOT_WORKER_ID;
|
|
644
696
|
if (name === RESERVED_SETUP_BOT_NAME && kind === "personal" && !isSetupBot) {
|
|
645
697
|
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 });
|
|
@@ -654,6 +706,10 @@ async function runBotCreateLocked(name, opts) {
|
|
|
654
706
|
expected: true,
|
|
655
707
|
});
|
|
656
708
|
}
|
|
709
|
+
const fleetInstallation = useFleetRuntime
|
|
710
|
+
? await installPinnedFleetLocalDistribution()
|
|
711
|
+
: null;
|
|
712
|
+
const fleetPython = fleetInstallation ? await ensureFleetPython() : null;
|
|
657
713
|
const token = await ownerToken();
|
|
658
714
|
const owner = await resolveCallerPersonUid(token, undefined, { command: "hq bot create" });
|
|
659
715
|
if (!owner)
|
|
@@ -763,6 +819,7 @@ async function runBotCreateLocked(name, opts) {
|
|
|
763
819
|
// instead of creating a new one. The machine secret never travels.
|
|
764
820
|
const localConfig = buildBotLocalConfig({
|
|
765
821
|
runtime,
|
|
822
|
+
...(fleetInstallation ? { engine: fleetInstallation.engine } : {}),
|
|
766
823
|
kind,
|
|
767
824
|
...(kind === "company" ? { companies } : {}),
|
|
768
825
|
...(model ? { model } : {}),
|
|
@@ -829,6 +886,7 @@ async function runBotCreateLocked(name, opts) {
|
|
|
829
886
|
agentUid,
|
|
830
887
|
ownerUid: created.agent.ownerUid ?? owner,
|
|
831
888
|
runtime,
|
|
889
|
+
...(fleetInstallation ? { engine: fleetInstallation.engine } : {}),
|
|
832
890
|
kind,
|
|
833
891
|
// A company bot's list is filled in below, with the invites that went through.
|
|
834
892
|
...(kind === "company" ? { companies: [] } : {}),
|
|
@@ -885,8 +943,23 @@ async function runBotCreateLocked(name, opts) {
|
|
|
885
943
|
const scaffoldOpts = { memoryDir: config.memoryDir };
|
|
886
944
|
const scaffold = worker
|
|
887
945
|
? scaffoldBotMemory(hqRoot, name, undefined, scaffoldOpts)
|
|
888
|
-
: scaffoldBotWorker(hqRoot, name, agentUid, runtime, undefined, scaffoldOpts);
|
|
889
|
-
|
|
946
|
+
: scaffoldBotWorker(hqRoot, name, agentUid, fleetInstallation ? HQ_FLEET_RUNTIME_ENGINE_ID : runtime, undefined, scaffoldOpts);
|
|
947
|
+
if (fleetInstallation)
|
|
948
|
+
fs.rmSync(path.join(dir, "status.json"), { force: true });
|
|
949
|
+
const fleetBootstrap = fleetInstallation && fleetPython
|
|
950
|
+
? await bootstrapFleetLocalBot({
|
|
951
|
+
agentUid,
|
|
952
|
+
ownerUid: config.ownerUid,
|
|
953
|
+
hqRoot,
|
|
954
|
+
botDir: dir,
|
|
955
|
+
installation: fleetInstallation,
|
|
956
|
+
machineCredentials: botCredsPath(dir),
|
|
957
|
+
systemPrompt: fleetBotSystemPrompt(name, config, { kind, companies }),
|
|
958
|
+
}, { start: opts.start !== false, python: fleetPython })
|
|
959
|
+
: null;
|
|
960
|
+
const fleetProfile = fleetBootstrap?.profile ?? null;
|
|
961
|
+
const runtimeLabel = fleetInstallation ? HQ_FLEET_RUNTIME_ENGINE_ID : runtime;
|
|
962
|
+
createBotLogger(dir)("info", `created ${name} (${agentUid}) kind=${kind}${companies.length ? ` companies=${companies.join(",")}` : ""} runtime=${runtimeLabel}${worker ? ` worker=${worker.id} company=${worker.company ?? "-"}` : ""} memory=${memoryMode}`);
|
|
890
963
|
const created_ = {
|
|
891
964
|
outcome: "created",
|
|
892
965
|
role: localBotRole(config),
|
|
@@ -895,7 +968,9 @@ async function runBotCreateLocked(name, opts) {
|
|
|
895
968
|
agentUid,
|
|
896
969
|
kind,
|
|
897
970
|
companies,
|
|
898
|
-
runtime,
|
|
971
|
+
runtime: runtimeLabel,
|
|
972
|
+
engine: fleetInstallation?.engine ?? null,
|
|
973
|
+
profile: fleetProfile,
|
|
899
974
|
dir,
|
|
900
975
|
worker: worker ? path.join(hqRoot, worker.path) : scaffold.dir,
|
|
901
976
|
workerId: worker?.id ?? null,
|
|
@@ -906,15 +981,15 @@ async function runBotCreateLocked(name, opts) {
|
|
|
906
981
|
intro: intro ?? null,
|
|
907
982
|
kickoff: kickoff ?? null,
|
|
908
983
|
model: model ?? null,
|
|
909
|
-
effort: effort ?? DEFAULT_BOT_EFFORT,
|
|
984
|
+
effort: fleetInstallation ? null : effort ?? DEFAULT_BOT_EFFORT,
|
|
910
985
|
};
|
|
911
986
|
let daemonMessage = null;
|
|
912
|
-
if (opts.daemon !== false && process.platform === "darwin") {
|
|
987
|
+
if (!fleetInstallation && opts.daemon !== false && process.platform === "darwin") {
|
|
913
988
|
const r = installBotAgent(buildBotDaemonPaths({ name, botDir: dir, hqRoot }));
|
|
914
989
|
daemonMessage = r.message;
|
|
915
990
|
}
|
|
916
991
|
if (!opts.json) {
|
|
917
|
-
console.log(chalk.green(`Created bot ${chalk.bold(name)}`) + chalk.dim(` (${agentUid}, ${
|
|
992
|
+
console.log(chalk.green(`Created bot ${chalk.bold(name)}`) + chalk.dim(` (${agentUid}, ${runtimeLabel})`));
|
|
918
993
|
console.log(chalk.dim(` kind: ${describeKind(kind, companies)}`));
|
|
919
994
|
if (worker)
|
|
920
995
|
console.log(chalk.dim(` worker: ${worker.id}${worker.company ? ` (${worker.company})` : ""} — ${path.join(hqRoot, worker.path)}`));
|
|
@@ -922,9 +997,17 @@ async function runBotCreateLocked(name, opts) {
|
|
|
922
997
|
console.log(chalk.dim(` worker: ${scaffold.dir}`));
|
|
923
998
|
console.log(chalk.dim(` memory: ${scaffold.memoryDir} (${memoryMode})`));
|
|
924
999
|
console.log(chalk.dim(` state: ${dir}`));
|
|
1000
|
+
if (fleetProfile)
|
|
1001
|
+
console.log(chalk.dim(` profile: ${fleetProfile}`));
|
|
925
1002
|
if (daemonMessage)
|
|
926
1003
|
console.log(chalk.dim(` ${daemonMessage}`));
|
|
927
1004
|
}
|
|
1005
|
+
if (fleetInstallation) {
|
|
1006
|
+
if (opts.json) {
|
|
1007
|
+
console.log(JSON.stringify({ ok: true, name, ...created_, daemon: null, running: fleetBootstrap?.running ?? false }, null, 2));
|
|
1008
|
+
}
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
928
1011
|
if (opts.start !== false) {
|
|
929
1012
|
if (daemonMessage && /loaded\)/.test(daemonMessage)) {
|
|
930
1013
|
// RunAtLoad already started it.
|
|
@@ -1028,6 +1111,9 @@ async function runBotResident(nameArg) {
|
|
|
1028
1111
|
const name = validateBotName(nameArg);
|
|
1029
1112
|
const dir = botDir(name);
|
|
1030
1113
|
const config = readBotConfig(dir);
|
|
1114
|
+
if (config && isFleetRuntimeBot(config)) {
|
|
1115
|
+
throw Object.assign(new Error(`${name} runs on the HQ Fleet Runtime under its own background service. Use hq bot start ${name}, hq bot status ${name} or hq bot logs ${name}.`), { expected: true });
|
|
1116
|
+
}
|
|
1031
1117
|
if (!config) {
|
|
1032
1118
|
// A LaunchAgent that outlived its bot: exiting non-zero here made launchd
|
|
1033
1119
|
// relaunch this every five seconds forever. Say so once, take the stale
|
|
@@ -1127,7 +1213,11 @@ async function runBotList(opts) {
|
|
|
1127
1213
|
}
|
|
1128
1214
|
}
|
|
1129
1215
|
async function runBotStatus(nameArg, opts) {
|
|
1130
|
-
const { name, dir } = requireBot(nameArg);
|
|
1216
|
+
const { name, dir, config } = requireBot(nameArg);
|
|
1217
|
+
if (isFleetRuntimeBot(config)) {
|
|
1218
|
+
runFleetRuntimeControl(name, config, "status", opts.json === true);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1131
1221
|
const row = rowFor(name);
|
|
1132
1222
|
await decorateOnline([row]);
|
|
1133
1223
|
const status = readBotStatus(dir);
|
|
@@ -1326,6 +1416,15 @@ async function runBotRmOrphan(name, opts) {
|
|
|
1326
1416
|
else
|
|
1327
1417
|
console.log(chalk.dim(` HQ may still have a bot named "${name}". Remove that too with: hq bot rm ${name} --remote`));
|
|
1328
1418
|
}
|
|
1419
|
+
function stopFleetRuntimeBotQuietly(agentUid) {
|
|
1420
|
+
try {
|
|
1421
|
+
controlFleetLocalBot(agentUid, "stop");
|
|
1422
|
+
return true;
|
|
1423
|
+
}
|
|
1424
|
+
catch {
|
|
1425
|
+
return false;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1329
1428
|
async function runBotRm(nameArg, opts) {
|
|
1330
1429
|
const validated = validateBotName(nameArg);
|
|
1331
1430
|
// Under the bot's lock: an rm racing a create, adopt or restore of the same
|
|
@@ -1348,9 +1447,13 @@ async function runBotRmLocked(validated, opts) {
|
|
|
1348
1447
|
return;
|
|
1349
1448
|
}
|
|
1350
1449
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1450
|
+
if (isFleetRuntimeBot(config))
|
|
1451
|
+
stopFleetRuntimeBotQuietly(config.agentUid);
|
|
1452
|
+
else
|
|
1453
|
+
await stopBot(name, dir, config, "silent").catch(() => { });
|
|
1454
|
+
const daemon = isFleetRuntimeBot(config)
|
|
1455
|
+
? { message: "managed by HQ Fleet Runtime" }
|
|
1456
|
+
: uninstallBotDaemon(buildBotDaemonPaths({ name, botDir: dir, hqRoot: config.hqRoot }), daemonDeps());
|
|
1354
1457
|
const token = await ownerToken();
|
|
1355
1458
|
const api = new BotApi({ token: async () => token });
|
|
1356
1459
|
let identity;
|
|
@@ -1380,8 +1483,11 @@ async function runBotRmLocked(validated, opts) {
|
|
|
1380
1483
|
// re-created under the same name. Everything else keeps the folder, so the
|
|
1381
1484
|
// same command can pick the job back up.
|
|
1382
1485
|
const localStateRemoved = terminal || incomplete.retryable === false;
|
|
1383
|
-
if (localStateRemoved)
|
|
1486
|
+
if (localStateRemoved) {
|
|
1487
|
+
if (isFleetRuntimeBot(config))
|
|
1488
|
+
removeFleetLocalBot(config.agentUid);
|
|
1384
1489
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
1490
|
+
}
|
|
1385
1491
|
const message = incomplete
|
|
1386
1492
|
? `HQ removed what it could of "${name}", but ${incomplete.detail}.` +
|
|
1387
1493
|
(incomplete.retryable
|
|
@@ -1572,6 +1678,10 @@ export function botExists(name) {
|
|
|
1572
1678
|
/** `hq bot restart <name>`: stop, then start (launchd when installed). */
|
|
1573
1679
|
export async function runBotRestart(nameArg, opts = {}) {
|
|
1574
1680
|
const b = requireBot(nameArg);
|
|
1681
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
1682
|
+
runFleetRuntimeControl(b.name, b.config, "restart", opts.json === true || opts.output === "json");
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1575
1685
|
const running = readBotStatus(b.dir);
|
|
1576
1686
|
if (running && isPidAlive(running.pid) && selfStopProbe(running.pid)) {
|
|
1577
1687
|
// The stop half would end this turn (and this command) before the
|
|
@@ -1581,6 +1691,30 @@ export async function runBotRestart(nameArg, opts = {}) {
|
|
|
1581
1691
|
await stopBot(b.name, b.dir, b.config, "silent");
|
|
1582
1692
|
await startBot(b.name, b.dir, b.config, opts.output ?? (opts.json ? "json" : "text"));
|
|
1583
1693
|
}
|
|
1694
|
+
async function runBotAuth(nameArg, opts) {
|
|
1695
|
+
const b = requireBot(nameArg);
|
|
1696
|
+
if (!isFleetRuntimeBot(b.config)) {
|
|
1697
|
+
throw Object.assign(new Error(`hq bot auth is for bots created with --hq-fleet-runtime. ${b.name} uses ${b.config.runtime}.`), { expected: true });
|
|
1698
|
+
}
|
|
1699
|
+
const apiKey = opts.apiKey ? fs.readFileSync(0, "utf8").trim() : undefined;
|
|
1700
|
+
if (opts.apiKey && !apiKey) {
|
|
1701
|
+
throw Object.assign(new Error("No API key was received on stdin."), { expected: true });
|
|
1702
|
+
}
|
|
1703
|
+
const result = authenticateFleetLocalBot({
|
|
1704
|
+
agentUid: b.config.agentUid,
|
|
1705
|
+
provider: opts.provider,
|
|
1706
|
+
...(opts.model ? { model: opts.model } : {}),
|
|
1707
|
+
...(apiKey ? { apiKey } : {}),
|
|
1708
|
+
...(opts.baseUrl ? { baseUrl: opts.baseUrl } : {}),
|
|
1709
|
+
...(opts.transport ? { transport: opts.transport } : {}),
|
|
1710
|
+
openBrowser: opts.browser !== false,
|
|
1711
|
+
});
|
|
1712
|
+
if (opts.json) {
|
|
1713
|
+
console.log(JSON.stringify({ ok: true, name: b.name, runtime: HQ_FLEET_RUNTIME_ENGINE_ID, ...result }, null, 2));
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
console.log(chalk.green(`${b.name} is signed in to ${result.provider} and running ${result.model}.`));
|
|
1717
|
+
}
|
|
1584
1718
|
// ── adopt / restore (bring a bot you own back to this computer) ──────────────
|
|
1585
1719
|
/**
|
|
1586
1720
|
* Which computer a re-issue is for. Never a secret and never an identifier the
|
|
@@ -2090,6 +2224,7 @@ async function runBotListRemote(opts) {
|
|
|
2090
2224
|
reason: runnable.reason,
|
|
2091
2225
|
displayName: remoteBotDisplayName(bot, name),
|
|
2092
2226
|
role: remoteBotRole(bot),
|
|
2227
|
+
ownerUid: bot.ownerUid ?? null,
|
|
2093
2228
|
};
|
|
2094
2229
|
});
|
|
2095
2230
|
if (opts.json) {
|
|
@@ -2124,7 +2259,13 @@ export function registerBotCommand(program) {
|
|
|
2124
2259
|
const { dir, config } = requireBot(name);
|
|
2125
2260
|
const token = await ownerToken(false);
|
|
2126
2261
|
const api = new BotApi({ token: async () => token });
|
|
2127
|
-
const result = await promoteLocalBot({
|
|
2262
|
+
const result = await promoteLocalBot({
|
|
2263
|
+
dir,
|
|
2264
|
+
config,
|
|
2265
|
+
companyUid: opts.company,
|
|
2266
|
+
api,
|
|
2267
|
+
...(isFleetRuntimeBot(config) ? { runtime: fleetLocalPromotionRuntime(config.agentUid) } : {}),
|
|
2268
|
+
});
|
|
2128
2269
|
const details = result.pending ? await api.promotionDetails(config.agentUid, opts.company) : null;
|
|
2129
2270
|
if (opts.json)
|
|
2130
2271
|
console.log(JSON.stringify({ ...result, pairing: details?.pairing ?? null, ...(details?.failure ? { failure: details.failure } : {}) }));
|
|
@@ -2140,7 +2281,8 @@ export function registerBotCommand(program) {
|
|
|
2140
2281
|
.description("Provision a local bot identity, scaffold its worker folder, install its launchd agent, and start it")
|
|
2141
2282
|
.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`)
|
|
2142
2283
|
.option("--company <slug>", "Company bots: a company the bot is a member of (repeat for several); the owner invites it on creation", collectRepeated, [])
|
|
2143
|
-
.option("--runtime <runtime>", `Model CLI to run the bot with: ${BOT_RUNTIMES.join("|")}
|
|
2284
|
+
.option("--runtime <runtime>", `Model CLI to run the bot with: ${BOT_RUNTIMES.join("|")}`)
|
|
2285
|
+
.option("--hq-fleet-runtime", "Create this personal bot with the local HQ Fleet Runtime")
|
|
2144
2286
|
.option("--model <model>", "Model override passed to the runtime CLI")
|
|
2145
2287
|
.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})`)
|
|
2146
2288
|
.option("--no-auto-approve", "Keep the runtime's permission gates (default: everything pre-approved; a headless bot cannot answer prompts)")
|
|
@@ -2196,6 +2338,10 @@ export function registerBotCommand(program) {
|
|
|
2196
2338
|
.option("--json", "Print machine-readable JSON")
|
|
2197
2339
|
.action((name, opts) => wrap(async () => {
|
|
2198
2340
|
const b = requireBot(name);
|
|
2341
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
2342
|
+
runFleetRuntimeControl(b.name, b.config, "start", opts.json === true);
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2199
2345
|
await startBot(b.name, b.dir, b.config, opts.json ? "json" : "text");
|
|
2200
2346
|
})());
|
|
2201
2347
|
bot
|
|
@@ -2204,6 +2350,10 @@ export function registerBotCommand(program) {
|
|
|
2204
2350
|
.option("--json", "Print machine-readable JSON")
|
|
2205
2351
|
.action((name, opts) => wrap(async () => {
|
|
2206
2352
|
const b = requireBot(name);
|
|
2353
|
+
if (isFleetRuntimeBot(b.config)) {
|
|
2354
|
+
runFleetRuntimeControl(b.name, b.config, "stop", opts.json === true);
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2207
2357
|
await stopBot(b.name, b.dir, b.config, opts.json ? "json" : "text");
|
|
2208
2358
|
})());
|
|
2209
2359
|
bot
|
|
@@ -2216,6 +2366,17 @@ export function registerBotCommand(program) {
|
|
|
2216
2366
|
.description("Show the bot's process, heartbeat, launchd, and credential state")
|
|
2217
2367
|
.option("--json", "Print machine-readable JSON")
|
|
2218
2368
|
.action((name, opts) => wrap(() => runBotStatus(name, opts))());
|
|
2369
|
+
bot
|
|
2370
|
+
.command("auth <name>")
|
|
2371
|
+
.description("Sign a runtime-backed personal bot in to ChatGPT, Grok, Claude, or another supported provider")
|
|
2372
|
+
.requiredOption("--provider <provider>", "Provider: chatgpt, grok, claude, or a runtime provider id")
|
|
2373
|
+
.option("--model <model>", "Model id; required for providers without a built-in personal-bot default")
|
|
2374
|
+
.option("--api-key", "Read an API key from stdin instead of starting device authorization")
|
|
2375
|
+
.option("--base-url <url>", "Provider API base URL; required for custom runtime providers")
|
|
2376
|
+
.option("--transport <transport>", "Provider transport: chat_completions, anthropic_messages, or codex_responses")
|
|
2377
|
+
.option("--no-browser", "Do not open a browser during device authorization")
|
|
2378
|
+
.option("--json", "Print machine-readable JSON")
|
|
2379
|
+
.action((name, opts) => wrap(() => runBotAuth(name, opts))());
|
|
2219
2380
|
bot
|
|
2220
2381
|
.command("logs <name>")
|
|
2221
2382
|
.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
|
|
@@ -128,6 +176,15 @@ export declare function scopeExcludedPrefixDetail(prefixSet: readonly string[] |
|
|
|
128
176
|
* folder foo/ — and grant advice would point the reader the wrong way.
|
|
129
177
|
*/
|
|
130
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>;
|
|
131
188
|
/**
|
|
132
189
|
* Bound foreground waits for a watcher/manual sync that currently owns the
|
|
133
190
|
* per-root operation lock. The cloud engine reads this environment value on
|