@indigoai-us/hq-cli 5.115.0 → 5.115.1
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 +6 -0
- package/dist/commands/bot.js +31 -6
- package/dist/lib/bot/api.d.ts +5 -0
- package/dist/lib/bot/api.js +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.115.1] — 2026-09-15
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `hq bot create --kind company` now sends the bot's companies with the create, as the cloud requires, so a company bot can actually be created; the cloud makes it a member of each company, and a company you are not an owner or admin of is refused before anything is created.
|
|
10
|
+
|
|
5
11
|
## [5.115.0] — 2026-09-15
|
|
6
12
|
|
|
7
13
|
### Added
|
package/dist/commands/bot.js
CHANGED
|
@@ -30,7 +30,7 @@ import * as path from "node:path";
|
|
|
30
30
|
import * as readline from "node:readline";
|
|
31
31
|
import { DEFAULT_COGNITO, ensureCognitoToken, resolveDefaultHqRoot, } from "../utils/cognito-session.js";
|
|
32
32
|
import { peekHqApiKey } from "../utils/resolve-vault-credential.js";
|
|
33
|
-
import { resolveCallerPersonUid } from "../utils/vault-api.js";
|
|
33
|
+
import { getCompanyUid, resolveCallerPersonUid } from "../utils/vault-api.js";
|
|
34
34
|
import { resolveHqBinary } from "../lib/mesh/live/daemon/install.js";
|
|
35
35
|
import { runtimeDisplayName } from "../lib/bot/runtime-sign-in.js";
|
|
36
36
|
import { BotApi, BotApiError, botDaemonStatus, botDir, botCredsPath, botLogPath, botsRoot, botTokenStateDir, botWorkerRelDir, buildBotDaemonPaths, createBotLogger, deleteBotCreds, installBotDaemon, introDmText, isBotMemoryMode, botLocalMemoryDir, botMemoryMode, resolveBotMemoryDir, validateBotIntro, validateBotKickoff, validateBotEffort, validateBotModel, effectiveBotEffort, BOT_EFFORT_LEVELS, DEFAULT_BOT_EFFORT, BOT_MEMORY_MODES, BOT_KINDS, isBotKind, effectiveBotKind, effectiveBotCompanies, normalizeBotCompanies, SETUP_BOT_WORKER_ID, isBotRuntimeId, isPidAlive, listBotWorkerOptions, patchBotConfig, readBotConfig, readBotCredsIdentity, readBotStatus, resolveBotWorker, runBot, runtimeFor, scaffoldBotMemory, scaffoldBotWorker, startBotDaemon, stopBotDaemon, uninstallBotDaemon, validateBotName, writeBotConfig, writeBotCreds, BOT_RUNTIMES, BOT_INTRO_MAX_CHARS, BOT_KICKOFF_MAX_CHARS, } from "../lib/bot/index.js";
|
|
@@ -368,11 +368,32 @@ export async function runBotCreate(nameArg, opts) {
|
|
|
368
368
|
if (!owner)
|
|
369
369
|
throw Object.assign(new Error("Your HQ login has no person entity yet; open the HQ desktop app once, then retry."), { expected: true });
|
|
370
370
|
const api = new BotApi({ token: async () => token });
|
|
371
|
+
// A company bot's companies are resolved first (a typo must not cost an
|
|
372
|
+
// identity) and sent with the create: the server makes the bot a member of
|
|
373
|
+
// each and refuses the whole create if the owner cannot add agents there.
|
|
374
|
+
const companyUids = [];
|
|
375
|
+
for (const slug of companies) {
|
|
376
|
+
try {
|
|
377
|
+
companyUids.push(await getCompanyUid(token, slug));
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
throw Object.assign(new Error(`Cannot create ${name}: ${err instanceof Error ? err.message : String(err)} (company "${slug}").`), { expected: true });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
371
383
|
let created;
|
|
372
384
|
try {
|
|
373
|
-
created = await api.createLocalBot({
|
|
385
|
+
created = await api.createLocalBot({
|
|
386
|
+
name,
|
|
387
|
+
kind,
|
|
388
|
+
...(kind === "company" ? { companyUid: companyUids[0], companyMemberships: companyUids.slice(1) } : {}),
|
|
389
|
+
});
|
|
374
390
|
}
|
|
375
391
|
catch (err) {
|
|
392
|
+
if (err instanceof BotApiError && err.code === "COMPANY_BOT_CREATE_NOT_ALLOWED") {
|
|
393
|
+
throw Object.assign(new Error(`The server refused to create ${name}: ${err.message} Only an owner or admin of each company can create a company bot there.`), {
|
|
394
|
+
expected: true,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
376
397
|
if (err instanceof BotApiError && err.code === "LOCAL_BOT_CAP_REACHED") {
|
|
377
398
|
// Only an older server still enforces a cap; current hq-pro-agents has none.
|
|
378
399
|
throw Object.assign(new Error("The server refused another bot (its bot limit is reached). Remove one with hq bot rm <name>, or update the server."), {
|
|
@@ -427,13 +448,17 @@ export async function runBotCreate(nameArg, opts) {
|
|
|
427
448
|
};
|
|
428
449
|
writeBotConfig(dir, config);
|
|
429
450
|
// A company bot acts as itself, so it must be a member of each of its
|
|
430
|
-
// companies
|
|
431
|
-
// it actually joined are recorded, so after a failed invite the identity
|
|
451
|
+
// companies. Only the companies it actually joined are recorded, so after a failed invite the identity
|
|
432
452
|
// and bot.json stay on disk and `hq bot companies <name> --add <slug>`
|
|
433
453
|
// retries exactly the missing ones (or `hq bot rm <name>` undoes it all).
|
|
434
454
|
if (kind === "company") {
|
|
435
|
-
|
|
436
|
-
|
|
455
|
+
// The server already made it a member of the companies it reports back;
|
|
456
|
+
// only the rest (an older server reports none) are invited here.
|
|
457
|
+
const joined = new Set(created.agent.companyMemberships ?? []);
|
|
458
|
+
const already = companies.filter((_, i) => joined.has(companyUids[i]));
|
|
459
|
+
const missing = companies.filter((_, i) => !joined.has(companyUids[i]));
|
|
460
|
+
const outcome = await addBotToCompanies({ agentUid, companies: missing, token });
|
|
461
|
+
config.companies = [...already, ...outcome.done];
|
|
437
462
|
writeBotConfig(dir, config);
|
|
438
463
|
if (outcome.failed.length > 0) {
|
|
439
464
|
createBotLogger(dir)("error", `created ${name} (${agentUid}) but could not add it to: ${describeCompanyFailures(outcome.failed)}`);
|
package/dist/lib/bot/api.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export interface AgentRecord {
|
|
|
45
45
|
ownerUid?: string | null;
|
|
46
46
|
computeMode?: string;
|
|
47
47
|
botKind?: string;
|
|
48
|
+
/** Company bots: the `cmp_` uids the server made it a member of. */
|
|
49
|
+
companyMemberships?: string[];
|
|
48
50
|
online?: boolean;
|
|
49
51
|
runtime?: {
|
|
50
52
|
status?: string;
|
|
@@ -189,6 +191,9 @@ export declare class BotApi {
|
|
|
189
191
|
name: string;
|
|
190
192
|
slug?: string;
|
|
191
193
|
kind?: "personal" | "company";
|
|
194
|
+
/** Company bots: the company it acts for, plus any further companies. The server makes it a member of each. */
|
|
195
|
+
companyUid?: string;
|
|
196
|
+
companyMemberships?: string[];
|
|
192
197
|
}): Promise<{
|
|
193
198
|
agent: AgentRecord;
|
|
194
199
|
identity: {
|
package/dist/lib/bot/api.js
CHANGED
|
@@ -193,6 +193,8 @@ export class BotApi {
|
|
|
193
193
|
...(input.slug ? { slug: input.slug } : {}),
|
|
194
194
|
computeMode: "local",
|
|
195
195
|
botKind: input.kind ?? "personal",
|
|
196
|
+
...(input.companyUid ? { companyUid: input.companyUid } : {}),
|
|
197
|
+
...(input.companyMemberships?.length ? { companyMemberships: input.companyMemberships } : {}),
|
|
196
198
|
role: "local-bot",
|
|
197
199
|
},
|
|
198
200
|
});
|