@indigoai-us/hq-cli 5.115.6 → 5.117.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +169 -11
- package/dist/command-catalog.generated.d.ts +220 -2
- package/dist/command-catalog.generated.js +281 -2
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/agent-enroll.d.ts +105 -0
- package/dist/commands/agent-enroll.js +273 -0
- package/dist/commands/agent-kit.d.ts +53 -0
- package/dist/commands/agent-kit.js +260 -0
- package/dist/commands/agent-mcp.d.ts +22 -0
- package/dist/commands/agent-mcp.js +104 -0
- package/dist/commands/agent-probe.d.ts +71 -0
- package/dist/commands/agent-probe.js +294 -0
- package/dist/commands/agent.d.ts +12 -0
- package/dist/commands/agent.js +23 -0
- package/dist/commands/agents.d.ts +27 -0
- package/dist/commands/agents.js +280 -6
- package/dist/commands/bot.d.ts +140 -1
- package/dist/commands/bot.js +757 -22
- package/dist/commands/secrets.js +17 -5
- package/dist/lib/agent-kit/creds.d.ts +60 -0
- package/dist/lib/agent-kit/creds.js +123 -0
- package/dist/lib/agent-kit/kit-config.d.ts +29 -0
- package/dist/lib/agent-kit/kit-config.js +54 -0
- package/dist/lib/agent-kit/log.d.ts +17 -0
- package/dist/lib/agent-kit/log.js +46 -0
- package/dist/lib/agent-kit/mcp/jsonrpc.d.ts +84 -0
- package/dist/lib/agent-kit/mcp/jsonrpc.js +164 -0
- package/dist/lib/agent-kit/mcp/tools.d.ts +45 -0
- package/dist/lib/agent-kit/mcp/tools.js +280 -0
- package/dist/lib/agent-kit/paths.d.ts +42 -0
- package/dist/lib/agent-kit/paths.js +56 -0
- package/dist/lib/agent-kit/run/heartbeat.d.ts +52 -0
- package/dist/lib/agent-kit/run/heartbeat.js +97 -0
- package/dist/lib/agent-kit/run/inbox.d.ts +59 -0
- package/dist/lib/agent-kit/run/inbox.js +152 -0
- package/dist/lib/agent-kit/run/mesh-listener.d.ts +58 -0
- package/dist/lib/agent-kit/run/mesh-listener.js +193 -0
- package/dist/lib/agent-kit/run/sync.d.ts +33 -0
- package/dist/lib/agent-kit/run/sync.js +58 -0
- package/dist/lib/agent-kit/services.d.ts +21 -0
- package/dist/lib/agent-kit/services.js +46 -0
- package/dist/lib/agent-kit/skills.d.ts +18 -0
- package/dist/lib/agent-kit/skills.js +149 -0
- package/dist/lib/bot/api.d.ts +51 -0
- package/dist/lib/bot/api.js +32 -0
- package/dist/lib/bot/daemon.d.ts +17 -0
- package/dist/lib/bot/daemon.js +44 -3
- package/dist/lib/bot/index.d.ts +4 -0
- package/dist/lib/bot/index.js +4 -0
- package/dist/lib/bot/inflight.d.ts +14 -0
- package/dist/lib/bot/local-config.d.ts +70 -0
- package/dist/lib/bot/local-config.js +147 -0
- package/dist/lib/bot/local-name.d.ts +54 -0
- package/dist/lib/bot/local-name.js +114 -0
- package/dist/lib/bot/run.d.ts +9 -0
- package/dist/lib/bot/run.js +117 -24
- package/dist/lib/bot/runnable.d.ts +51 -0
- package/dist/lib/bot/runnable.js +65 -0
- package/dist/lib/bot/self-heal.d.ts +52 -0
- package/dist/lib/bot/self-heal.js +79 -0
- package/dist/lib/bot/split.d.ts +32 -0
- package/dist/lib/bot/split.js +241 -0
- package/dist/lib/service-manager/index.d.ts +43 -0
- package/dist/lib/service-manager/index.js +114 -0
- package/dist/lib/service-manager/launchd.d.ts +23 -0
- package/dist/lib/service-manager/launchd.js +81 -0
- package/dist/lib/service-manager/systemd.d.ts +19 -0
- package/dist/lib/service-manager/systemd.js +72 -0
- package/dist/lib/service-manager/types.d.ts +32 -0
- package/dist/lib/service-manager/types.js +26 -0
- package/dist/utils/self-update.js +2 -30
- package/dist/utils/update-command-supervisor.cjs +194 -0
- package/dist/utils/version-gate.d.ts +18 -0
- package/dist/utils/version-gate.js +126 -7
- package/package.json +2 -2
package/dist/commands/agents.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* hq agents start|stop <uid> — EC2 start/stop
|
|
16
16
|
* hq agents retry <uid> — resume setup from first non-done step
|
|
17
17
|
* hq agents rm <uid> --yes — deprovision (destructive; flag-guarded)
|
|
18
|
+
* hq agents rotate <uid> — new enrollment code for an external agent
|
|
19
|
+
* hq agents revoke <uid> --yes — revoke an external agent (--remove deletes it)
|
|
18
20
|
* hq agents jobs list <uid> — off-box job roster (schedule + rate)
|
|
19
21
|
* hq agents jobs pause <uid> <jobId> — flip schedule State=DISABLED
|
|
20
22
|
* hq agents jobs cancel <uid> <jobId> — delete schedule + drop the job
|
|
@@ -387,6 +389,143 @@ export async function getAgentStatus(token, agentUid) {
|
|
|
387
389
|
path: `/v1/agents/${encodeURIComponent(agentUid)}/status`,
|
|
388
390
|
});
|
|
389
391
|
}
|
|
392
|
+
function recordValue(value) {
|
|
393
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
394
|
+
? value
|
|
395
|
+
: null;
|
|
396
|
+
}
|
|
397
|
+
function nonEmptyString(value) {
|
|
398
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
399
|
+
}
|
|
400
|
+
function safeActionUrl(value) {
|
|
401
|
+
const raw = nonEmptyString(value);
|
|
402
|
+
if (!raw)
|
|
403
|
+
return null;
|
|
404
|
+
try {
|
|
405
|
+
const url = new URL(raw);
|
|
406
|
+
return url.protocol === "https:" && !url.username && !url.password ? raw : null;
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function signInProviderName(url) {
|
|
413
|
+
const parsed = new URL(url);
|
|
414
|
+
if (parsed.hostname === "auth.openai.com" &&
|
|
415
|
+
parsed.pathname.startsWith("/codex/")) {
|
|
416
|
+
return "Codex";
|
|
417
|
+
}
|
|
418
|
+
if (parsed.hostname === "accounts.x.ai")
|
|
419
|
+
return "Grok";
|
|
420
|
+
if (parsed.hostname.endsWith("anthropic.com"))
|
|
421
|
+
return "Claude";
|
|
422
|
+
return "your provider";
|
|
423
|
+
}
|
|
424
|
+
function currentDeviceSignInAction(status) {
|
|
425
|
+
const pairing = recordValue(status.pairing);
|
|
426
|
+
const url = safeActionUrl(pairing?.url);
|
|
427
|
+
if (!url)
|
|
428
|
+
return null;
|
|
429
|
+
const rawCode = nonEmptyString(pairing?.code);
|
|
430
|
+
const code = rawCode && /^[A-Z0-9]{4,8}-[A-Z0-9]{4,8}$/i.test(rawCode)
|
|
431
|
+
? rawCode
|
|
432
|
+
: undefined;
|
|
433
|
+
const provider = signInProviderName(url);
|
|
434
|
+
return {
|
|
435
|
+
type: provider === "Codex" ? "codex-device-sign-in" : "provider-sign-in",
|
|
436
|
+
title: `Sign in to ${provider}`,
|
|
437
|
+
summary: `sign in to ${provider}`,
|
|
438
|
+
instruction: code
|
|
439
|
+
? "Open this page and enter the code."
|
|
440
|
+
: "Open this page and follow the sign-in instructions.",
|
|
441
|
+
url,
|
|
442
|
+
urlLabel: "Open",
|
|
443
|
+
code,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function pendingSlackAction(status) {
|
|
447
|
+
const agent = recordValue(status.agent);
|
|
448
|
+
const diagnostics = recordValue(agent?.channelDiagnostics);
|
|
449
|
+
const slack = recordValue(diagnostics?.slack);
|
|
450
|
+
const url = safeActionUrl(slack?.pendingInstallUrl);
|
|
451
|
+
if (!url)
|
|
452
|
+
return null;
|
|
453
|
+
if (slack?.inboundCapability === "socket-mode-degraded") {
|
|
454
|
+
return {
|
|
455
|
+
type: "slack-app-token",
|
|
456
|
+
title: "Finish setting up the Slack app",
|
|
457
|
+
summary: "finish setting up the Slack app",
|
|
458
|
+
instruction: "Open this page, create the app-level token, then provide it in the agent's Slack setup.",
|
|
459
|
+
url,
|
|
460
|
+
urlLabel: "Open",
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (slack?.inboundCapability !== "pending-install")
|
|
464
|
+
return null;
|
|
465
|
+
return {
|
|
466
|
+
type: "slack-install",
|
|
467
|
+
title: "Install the Slack app",
|
|
468
|
+
summary: "install the Slack app so it can talk to your workspace",
|
|
469
|
+
instruction: "Open this link and install the app in your workspace.",
|
|
470
|
+
url,
|
|
471
|
+
urlLabel: "Install",
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* The server owns action detection. This client converts its safe, current
|
|
476
|
+
* status fields into a list so another operator action can be added without
|
|
477
|
+
* changing the renderers or command control flow.
|
|
478
|
+
*/
|
|
479
|
+
function pendingOperatorActions(status) {
|
|
480
|
+
return [
|
|
481
|
+
currentDeviceSignInAction(status),
|
|
482
|
+
pendingSlackAction(status),
|
|
483
|
+
].filter((action) => action !== null);
|
|
484
|
+
}
|
|
485
|
+
function pendingActionsJson(actions) {
|
|
486
|
+
return actions.map(({ type, title, instruction, url, code }) => ({
|
|
487
|
+
type,
|
|
488
|
+
title,
|
|
489
|
+
instruction,
|
|
490
|
+
...(url ? { url } : {}),
|
|
491
|
+
...(code ? { code } : {}),
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
function statusAgentSlug(status) {
|
|
495
|
+
return nonEmptyString(recordValue(status.agent)?.slug);
|
|
496
|
+
}
|
|
497
|
+
/** The provision endpoint returns this nested identity; old response shapes omit it. */
|
|
498
|
+
function provisionedAgentIdentity(result) {
|
|
499
|
+
const agent = recordValue(result.agent);
|
|
500
|
+
const uid = nonEmptyString(agent?.uid) ?? nonEmptyString(agent?.agentUid);
|
|
501
|
+
const slug = nonEmptyString(agent?.slug);
|
|
502
|
+
return uid && slug ? { uid, slug } : null;
|
|
503
|
+
}
|
|
504
|
+
function printPendingOperatorActions(slug, actions) {
|
|
505
|
+
if (actions.length === 0)
|
|
506
|
+
return;
|
|
507
|
+
const first = actions[0];
|
|
508
|
+
console.log(chalk.yellow(actions.length === 1
|
|
509
|
+
? `Your agent's box is up. One step left: ${first.summary}.`
|
|
510
|
+
: "Your agent's box is up. A few steps remain before it can talk to your workspace."));
|
|
511
|
+
for (const action of actions) {
|
|
512
|
+
console.log("");
|
|
513
|
+
console.log(chalk.bold(`${action.title}:`));
|
|
514
|
+
console.log(action.instruction);
|
|
515
|
+
if (action.url)
|
|
516
|
+
console.log(chalk.cyan(`${action.urlLabel ?? "Open"}: ${action.url}`));
|
|
517
|
+
if (action.code)
|
|
518
|
+
console.log(chalk.bold(`Code: ${action.code}`));
|
|
519
|
+
}
|
|
520
|
+
const currentCodeHint = actions.some((action) => action.code)
|
|
521
|
+
? "current sign-in code and instructions"
|
|
522
|
+
: "these instructions";
|
|
523
|
+
const statusCommand = slug
|
|
524
|
+
? `Run \`hq agents status ${slug}\` any time to get ${currentCodeHint} again.`
|
|
525
|
+
: `Run \`hq agents status\` again any time to get ${currentCodeHint}.`;
|
|
526
|
+
console.log("");
|
|
527
|
+
console.log(chalk.dim(`Until that's done, the agent will show as still setting up. ${statusCommand}`));
|
|
528
|
+
}
|
|
390
529
|
export async function patchAgentProfile(token, agentUid, patch) {
|
|
391
530
|
return agentsRequest({
|
|
392
531
|
token,
|
|
@@ -656,6 +795,59 @@ function shortTime(iso) {
|
|
|
656
795
|
function sleep(ms) {
|
|
657
796
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
658
797
|
}
|
|
798
|
+
/**
|
|
799
|
+
* POST /v1/agents/{uid}/rotate — invalidate the current secret and host key
|
|
800
|
+
* and issue a fresh one-time enrollment code (returned exactly once).
|
|
801
|
+
*/
|
|
802
|
+
export async function rotateAgent(token, agentUid) {
|
|
803
|
+
const data = await agentsRequest({
|
|
804
|
+
token,
|
|
805
|
+
path: `/v1/agents/${encodeURIComponent(agentUid)}/rotate`,
|
|
806
|
+
method: "POST",
|
|
807
|
+
});
|
|
808
|
+
const e = data.enrollment ?? {};
|
|
809
|
+
if (typeof e.code !== "string" || !e.code) {
|
|
810
|
+
throw new AgentsHttpError(502, "rotate succeeded but the response carried no enrollment code");
|
|
811
|
+
}
|
|
812
|
+
return {
|
|
813
|
+
agentUid: data.agentUid ?? agentUid,
|
|
814
|
+
enrollment: {
|
|
815
|
+
code: e.code,
|
|
816
|
+
expiresAt: typeof e.expiresAt === "string" ? e.expiresAt : "",
|
|
817
|
+
enrollmentId: typeof e.enrollmentId === "string" ? e.enrollmentId : "",
|
|
818
|
+
},
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
/** Display form of a 24-char code: six groups of four. */
|
|
822
|
+
export function groupEnrollmentCode(code) {
|
|
823
|
+
const flat = code.replace(/[\s-]+/g, "").toUpperCase();
|
|
824
|
+
return flat.match(/.{1,4}/g)?.join("-") ?? flat;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* POST /v1/agents/{uid}/revoke — disable the Cognito user, drop membership,
|
|
828
|
+
* mark the enrollment revoked; `remove` also deletes the entity.
|
|
829
|
+
*/
|
|
830
|
+
export async function revokeAgent(token, agentUid, remove) {
|
|
831
|
+
const data = await agentsRequest({
|
|
832
|
+
token,
|
|
833
|
+
path: `/v1/agents/${encodeURIComponent(agentUid)}/revoke`,
|
|
834
|
+
method: "POST",
|
|
835
|
+
body: { remove },
|
|
836
|
+
});
|
|
837
|
+
return { removed: data.removed === true || remove };
|
|
838
|
+
}
|
|
839
|
+
/** Lines printed after a rotate: the code is shown once and never stored. */
|
|
840
|
+
export function formatRotateOutput(result) {
|
|
841
|
+
const lines = [
|
|
842
|
+
`Rotated ${result.agentUid}. The old secret and host key no longer mint.`,
|
|
843
|
+
"",
|
|
844
|
+
` enrollment code: ${groupEnrollmentCode(result.enrollment.code)}`,
|
|
845
|
+
];
|
|
846
|
+
if (result.enrollment.expiresAt)
|
|
847
|
+
lines.push(` expires: ${result.enrollment.expiresAt} (15 minutes)`);
|
|
848
|
+
lines.push("", "Shown once. On the agent's host run:", ` hq agent enroll ${groupEnrollmentCode(result.enrollment.code)} --replace`, " hq agent probe");
|
|
849
|
+
return lines;
|
|
850
|
+
}
|
|
659
851
|
// ---------------------------------------------------------------------------
|
|
660
852
|
// Command registration
|
|
661
853
|
// ---------------------------------------------------------------------------
|
|
@@ -711,6 +903,11 @@ export function registerAgentsCommand(program) {
|
|
|
711
903
|
// Interactive terminals are for humans: hq-pro serves no keyed
|
|
712
904
|
// `/v1/keys/agents/{uid}/terminal` route, so machine keys fail closed.
|
|
713
905
|
terminal: { capability: "agents:use", routeAvailable: false },
|
|
906
|
+
// External-agent lifecycle is an admin action on the JWT-only
|
|
907
|
+
// /v1/agents/{uid}/rotate|revoke routes (api-contract v1); no keyed
|
|
908
|
+
// parallel exists, so machine keys fail closed here too.
|
|
909
|
+
rotate: { capability: "agents:use", routeAvailable: false },
|
|
910
|
+
revoke: { capability: "agents:use", routeAvailable: false },
|
|
714
911
|
},
|
|
715
912
|
});
|
|
716
913
|
// `--company` may live on the group or the subcommand; the subcommand value
|
|
@@ -955,13 +1152,34 @@ export function registerAgentsCommand(program) {
|
|
|
955
1152
|
quoteCatalogVersion: createOptions.catalogVersion,
|
|
956
1153
|
surface: CLI_AGENT_CREATE_SURFACE,
|
|
957
1154
|
});
|
|
958
|
-
const
|
|
1155
|
+
const identity = provisionedAgentIdentity(result);
|
|
1156
|
+
const status = identity
|
|
1157
|
+
? await getAgentStatus(token, identity.uid)
|
|
1158
|
+
: null;
|
|
1159
|
+
const actions = status ? pendingOperatorActions(status) : [];
|
|
1160
|
+
const slackInstall = actions.find((action) => action.type === "slack-install");
|
|
959
1161
|
if (opts.json) {
|
|
960
|
-
console.log(JSON.stringify(
|
|
1162
|
+
console.log(JSON.stringify({
|
|
1163
|
+
...result,
|
|
1164
|
+
...(actions.length > 0
|
|
1165
|
+
? { pendingActions: pendingActionsJson(actions) }
|
|
1166
|
+
: {}),
|
|
1167
|
+
...(slackInstall?.url
|
|
1168
|
+
? {
|
|
1169
|
+
slackInstallPending: true,
|
|
1170
|
+
slackInstallUrl: slackInstall.url,
|
|
1171
|
+
}
|
|
1172
|
+
: {}),
|
|
1173
|
+
}));
|
|
961
1174
|
}
|
|
962
1175
|
else {
|
|
963
1176
|
console.log(chalk.green(`Provisioning started for agent "${name}".`));
|
|
964
|
-
|
|
1177
|
+
if (actions.length > 0) {
|
|
1178
|
+
printPendingOperatorActions(identity?.slug ?? null, actions);
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
console.log(chalk.dim(`Track setup: hq agents status ${identity?.slug ?? slug} --company <slug>`));
|
|
1182
|
+
}
|
|
965
1183
|
}
|
|
966
1184
|
}
|
|
967
1185
|
catch (err) {
|
|
@@ -1050,16 +1268,28 @@ export function registerAgentsCommand(program) {
|
|
|
1050
1268
|
}
|
|
1051
1269
|
});
|
|
1052
1270
|
agents
|
|
1053
|
-
.command("status <
|
|
1271
|
+
.command("status <agent>")
|
|
1054
1272
|
.description("Show an agent's setup state and runtime detail")
|
|
1055
1273
|
.option("--company <slug>", "Company slug (resolves to companyUid)")
|
|
1056
1274
|
.option("--json", "Emit raw JSON")
|
|
1057
|
-
.action(async function (
|
|
1275
|
+
.action(async function (agent, opts) {
|
|
1058
1276
|
try {
|
|
1059
1277
|
const token = (await resolveVaultCredential()).token;
|
|
1278
|
+
const agentUid = await resolveAgentUid(token, agent, companyOf(this));
|
|
1060
1279
|
const status = await getAgentStatus(token, agentUid);
|
|
1280
|
+
const actions = pendingOperatorActions(status);
|
|
1061
1281
|
if (opts.json) {
|
|
1062
|
-
process.stdout.write(JSON.stringify(
|
|
1282
|
+
process.stdout.write(JSON.stringify({
|
|
1283
|
+
...status,
|
|
1284
|
+
...(actions.length > 0
|
|
1285
|
+
? { pendingActions: pendingActionsJson(actions) }
|
|
1286
|
+
: {}),
|
|
1287
|
+
}, null, 2) + "\n");
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
if (actions.length > 0) {
|
|
1291
|
+
printPendingOperatorActions(statusAgentSlug(status) ??
|
|
1292
|
+
(AGENT_UID_PATTERN.test(agent.trim()) ? null : agent.trim()), actions);
|
|
1063
1293
|
return;
|
|
1064
1294
|
}
|
|
1065
1295
|
// Pretty but faithful: dump the top-level fields as key: value.
|
|
@@ -1268,6 +1498,50 @@ export function registerAgentsCommand(program) {
|
|
|
1268
1498
|
fail(err);
|
|
1269
1499
|
}
|
|
1270
1500
|
});
|
|
1501
|
+
agents
|
|
1502
|
+
.command("rotate <agentUid>")
|
|
1503
|
+
.description("Issue a fresh enrollment code for an external agent (old secret + host key stop minting)")
|
|
1504
|
+
.option("--company <slug>", "Company slug (resolves to companyUid)")
|
|
1505
|
+
.option("--json", "Emit raw JSON (code included — pipe carefully)")
|
|
1506
|
+
.action(async function (agentUid, opts) {
|
|
1507
|
+
try {
|
|
1508
|
+
const token = (await resolveVaultCredential()).token;
|
|
1509
|
+
const result = await rotateAgent(token, agentUid);
|
|
1510
|
+
if (opts.json) {
|
|
1511
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
for (const line of formatRotateOutput(result))
|
|
1515
|
+
console.log(line);
|
|
1516
|
+
}
|
|
1517
|
+
catch (err) {
|
|
1518
|
+
fail(err);
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1521
|
+
agents
|
|
1522
|
+
.command("revoke <agentUid>")
|
|
1523
|
+
.description("Revoke an external agent: disable its login and drop it from the team")
|
|
1524
|
+
.option("--company <slug>", "Company slug (resolves to companyUid)")
|
|
1525
|
+
.option("--remove", "Also delete the agent entity (it disappears from the roster)")
|
|
1526
|
+
.option("--yes", "Confirm the revoke (required)")
|
|
1527
|
+
.action(async function (agentUid, opts) {
|
|
1528
|
+
if (!opts.yes) {
|
|
1529
|
+
console.error(chalk.yellow(`This will revoke agent ${agentUid}: its credentials stop working immediately and it ` +
|
|
1530
|
+
`leaves the team${opts.remove ? ", and the agent record is deleted" : ""}. ` +
|
|
1531
|
+
`Re-run with --yes to confirm: hq agents revoke ${agentUid}${opts.remove ? " --remove" : ""} --yes`));
|
|
1532
|
+
process.exit(1);
|
|
1533
|
+
}
|
|
1534
|
+
try {
|
|
1535
|
+
const token = (await resolveVaultCredential()).token;
|
|
1536
|
+
const result = await revokeAgent(token, agentUid, opts.remove === true);
|
|
1537
|
+
console.log(chalk.green(result.removed
|
|
1538
|
+
? `Revoked and removed agent ${agentUid}.`
|
|
1539
|
+
: `Revoked agent ${agentUid}. Its next mint will be refused (401).`));
|
|
1540
|
+
}
|
|
1541
|
+
catch (err) {
|
|
1542
|
+
fail(err);
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1271
1545
|
// Off-box job control (US-003). Nested group so `hq agents jobs --help`
|
|
1272
1546
|
// lists list|pause|cancel. Same vaultApiFetch + person JWT as the rest of
|
|
1273
1547
|
// this file; keyed HQ_API_KEY rewrites /v1/agents → /v1/keys/agents.
|
package/dist/commands/bot.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { type RuntimeSignInIssue } from "../lib/bot/runtime-sign-in.js";
|
|
3
|
-
import { type BotKind, type BotMemoryMode, type BotRuntimeId, type LaunchctlExec } from "../lib/bot/index.js";
|
|
3
|
+
import { type BotLocalConfig, type MyLocalBot, type BotKind, type BotMemoryMode, type BotNotRunnableReason, type BotConfig, type BotRuntimeId, type LaunchctlExec } from "../lib/bot/index.js";
|
|
4
4
|
/** Real launchctl; every failure is a non-ok result, never a throw. */
|
|
5
5
|
export declare const defaultLaunchctl: LaunchctlExec;
|
|
6
6
|
/** The desktop app creates HQ's setup bot under this name, always from the `setup` worker. */
|
|
@@ -101,5 +101,144 @@ export declare function runBotSet(nameArg: string, opts: {
|
|
|
101
101
|
effort?: string;
|
|
102
102
|
json?: boolean;
|
|
103
103
|
}): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* The one bot the caller means. Matches the local folder name, the cloud slug,
|
|
106
|
+
* the display name, or the agt_ uid; an ambiguous name is refused rather than
|
|
107
|
+
* guessed at.
|
|
108
|
+
*/
|
|
109
|
+
export declare function matchRemoteBots(bots: readonly MyLocalBot[], wanted: string): MyLocalBot[];
|
|
110
|
+
export declare function resolveRemoteBot(bots: readonly MyLocalBot[], wanted: string): MyLocalBot;
|
|
111
|
+
/**
|
|
112
|
+
* Why HQ could not say which bots the account owns. The desktop app switches
|
|
113
|
+
* on these values, so they are contract, not prose:
|
|
114
|
+
*
|
|
115
|
+
* server-unsupported the HQ Cloud in front of us has no listing route
|
|
116
|
+
* auth the sign-in was refused
|
|
117
|
+
* network HQ could not be reached at all
|
|
118
|
+
* server-error HQ answered 5xx
|
|
119
|
+
* error anything else
|
|
120
|
+
*/
|
|
121
|
+
export type RemoteBotsUnavailableReason = "server-unsupported" | "auth" | "network" | "server-error" | "error";
|
|
122
|
+
export interface RemoteBotsUnavailable {
|
|
123
|
+
reason: RemoteBotsUnavailableReason;
|
|
124
|
+
message: string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Turn any failure of `GET /v1/agents/mine` into one plain sentence plus a
|
|
128
|
+
* stable reason. Production HQ Cloud does not serve that route yet, and an
|
|
129
|
+
* uncaught 404 reached the person verbatim as "HQ API /v1/agents/mine → 404:
|
|
130
|
+
* Not found" — and, under --json, as no document at all.
|
|
131
|
+
*/
|
|
132
|
+
export declare function remoteBotsUnavailable(err: unknown): RemoteBotsUnavailable;
|
|
133
|
+
/**
|
|
134
|
+
* A cloud teardown that only got part of the way, said in the same vocabulary
|
|
135
|
+
* the desktop switches on, plus the one decision that follows from it.
|
|
136
|
+
*
|
|
137
|
+
* `DELETE /v1/agents/{uid}` answers 200 with `terminal:false` and a per-step
|
|
138
|
+
* `failures` map when it could do only part of the job. Those strings are raw
|
|
139
|
+
* infrastructure: one real answer carried the AWS account id, an assumed-role
|
|
140
|
+
* ARN and a DynamoDB table ARN. They are classified here and never repeated —
|
|
141
|
+
* `detail` is a plain clause, `steps` is the server's own step names and
|
|
142
|
+
* nothing of what they said.
|
|
143
|
+
*
|
|
144
|
+
* `retryable` is the local-state decision. Running `hq bot rm` again can only
|
|
145
|
+
* finish the job when the step that failed might behave differently next time.
|
|
146
|
+
* A refusal, or a step whose target was already gone, answers the same way
|
|
147
|
+
* forever, so the local copy goes and the message says the leftover is HQ's.
|
|
148
|
+
*
|
|
149
|
+
* `reason` reuses {@link RemoteBotsUnavailableReason}: `auth` for a refused
|
|
150
|
+
* step (a permission problem, on either side of the call), `error` for a step
|
|
151
|
+
* whose target was already gone, `server-error` for anything HQ may yet
|
|
152
|
+
* finish.
|
|
153
|
+
*/
|
|
154
|
+
export interface BotRemovalIncomplete {
|
|
155
|
+
reason: RemoteBotsUnavailableReason;
|
|
156
|
+
/** One plain clause naming what stopped. Never a transport string. */
|
|
157
|
+
detail: string;
|
|
158
|
+
/** Whether running the same command again can still finish the removal. */
|
|
159
|
+
retryable: boolean;
|
|
160
|
+
/** The server's step names only — no ids, ARNs or messages. */
|
|
161
|
+
steps: string[];
|
|
162
|
+
}
|
|
163
|
+
export declare function botRemovalIncomplete(failures?: Record<string, string>): BotRemovalIncomplete;
|
|
164
|
+
/**
|
|
165
|
+
* Rebuild a bot.json from the settings the cloud kept for it. A bot created
|
|
166
|
+
* before HQ saved settings comes back on defaults, and anything this HQ can no
|
|
167
|
+
* longer provide (a worker that is not here, a thinking level the chosen
|
|
168
|
+
* runtime does not accept) is reported rather than silently kept.
|
|
169
|
+
*/
|
|
170
|
+
export declare function configFromLocalConfig(input: {
|
|
171
|
+
name: string;
|
|
172
|
+
agentUid: string;
|
|
173
|
+
ownerUid: string;
|
|
174
|
+
hqRoot: string;
|
|
175
|
+
dir: string;
|
|
176
|
+
local: BotLocalConfig | null;
|
|
177
|
+
overrides?: {
|
|
178
|
+
runtime?: BotRuntimeId;
|
|
179
|
+
model?: string;
|
|
180
|
+
};
|
|
181
|
+
now?: () => Date;
|
|
182
|
+
}): {
|
|
183
|
+
config: BotConfig;
|
|
184
|
+
notes: string[];
|
|
185
|
+
};
|
|
186
|
+
export interface BotAdoptResult {
|
|
187
|
+
name: string;
|
|
188
|
+
agentUid: string;
|
|
189
|
+
runtime: BotRuntimeId;
|
|
190
|
+
kind: BotKind;
|
|
191
|
+
companies: string[];
|
|
192
|
+
dir: string;
|
|
193
|
+
worker: string;
|
|
194
|
+
memory: BotMemoryMode;
|
|
195
|
+
memoryDir: string;
|
|
196
|
+
/** True when the cloud had no saved settings and defaults were used. */
|
|
197
|
+
defaulted: boolean;
|
|
198
|
+
notes: string[];
|
|
199
|
+
daemon: string | null;
|
|
200
|
+
}
|
|
201
|
+
export declare function runBotAdopt(nameArg: string, opts: {
|
|
202
|
+
runtime?: string;
|
|
203
|
+
model?: string;
|
|
204
|
+
daemon?: boolean;
|
|
205
|
+
start?: boolean;
|
|
206
|
+
json?: boolean;
|
|
207
|
+
}): Promise<void>;
|
|
208
|
+
export interface BotRestoreRow {
|
|
209
|
+
name: string;
|
|
210
|
+
agentUid: string;
|
|
211
|
+
/** restored = brought back here; repaired = new credentials for one already here. */
|
|
212
|
+
action: "restored" | "repaired" | "skipped" | "failed" | "would-restore" | "would-repair" | "would-skip";
|
|
213
|
+
detail: string;
|
|
214
|
+
/** Present only on a bot skipped because this computer cannot run it. */
|
|
215
|
+
reason?: BotNotRunnableReason;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* `hq bot restore` — every local bot this account owns that is not set up on
|
|
219
|
+
* this computer comes back. This is what the desktop app and a post-install
|
|
220
|
+
* hook call after a reinstall or on a new Mac.
|
|
221
|
+
*/
|
|
222
|
+
export declare function runBotRestore(opts: {
|
|
223
|
+
all?: boolean;
|
|
224
|
+
dryRun?: boolean;
|
|
225
|
+
daemon?: boolean;
|
|
226
|
+
start?: boolean;
|
|
227
|
+
json?: boolean;
|
|
228
|
+
}): Promise<void>;
|
|
229
|
+
export interface RemoteBotRow {
|
|
230
|
+
name: string;
|
|
231
|
+
agentUid: string;
|
|
232
|
+
kind: string;
|
|
233
|
+
online: boolean;
|
|
234
|
+
lastHeartbeatAt: string | null;
|
|
235
|
+
/** True when this bot is set up on this computer. */
|
|
236
|
+
here: boolean;
|
|
237
|
+
settings: string;
|
|
238
|
+
/** False when this computer cannot run it, whatever the listing says. */
|
|
239
|
+
runnable: boolean;
|
|
240
|
+
/** Why not, when `runnable` is false: the same vocabulary adopt and restore use. */
|
|
241
|
+
reason: BotNotRunnableReason | null;
|
|
242
|
+
}
|
|
104
243
|
export declare function registerBotCommand(program: Command): void;
|
|
105
244
|
//# sourceMappingURL=bot.d.ts.map
|