@indigoai-us/hq-cli 5.345.177 → 5.345.179
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/dist/command-catalog.generated.d.ts +79 -1
- package/dist/command-catalog.generated.js +96 -1
- package/dist/commands/bot-jobs.d.ts +11 -9
- package/dist/commands/bot-jobs.js +56 -21
- package/dist/commands/bot.d.ts +13 -0
- package/dist/commands/bot.js +230 -21
- package/dist/commands/cloud.d.ts +49 -0
- package/dist/commands/cloud.js +155 -15
- package/dist/commands/daemon.d.ts +2 -0
- package/dist/commands/daemon.js +15 -4
- package/dist/commands/dm-attach.js +15 -3
- package/dist/commands/integrations-core.d.ts +2 -0
- package/dist/commands/integrations-core.js +1 -0
- package/dist/commands/library-add.d.ts +9 -0
- package/dist/commands/library-add.js +19 -2
- package/dist/commands/run.js +9 -1
- package/dist/commands/sources.d.ts +89 -0
- package/dist/commands/sources.js +363 -1
- package/dist/lib/bot/config.d.ts +2 -0
- package/dist/lib/bot/fleet-default-flag.d.ts +31 -0
- package/dist/lib/bot/fleet-default-flag.js +127 -0
- package/dist/lib/bot/fleet-local.d.ts +30 -1
- package/dist/lib/bot/fleet-local.js +86 -11
- package/dist/lib/bot/index.d.ts +1 -0
- package/dist/lib/bot/index.js +1 -0
- package/dist/lib/bot/jobs/hot-signal-sync.d.ts +109 -0
- package/dist/lib/bot/jobs/hot-signal-sync.js +177 -0
- package/dist/lib/bot/local-config.js +1 -1
- package/dist/lib/bot/local-jobs.d.ts +40 -4
- package/dist/lib/bot/local-jobs.js +72 -5
- package/dist/lib/bot/run.d.ts +15 -0
- package/dist/lib/bot/run.js +61 -0
- package/dist/lib/daemon/catalog.d.ts +2 -0
- package/dist/lib/daemon/catalog.js +7 -2
- package/dist/lib/daemon/config.d.ts +2 -1
- package/dist/lib/daemon/config.js +4 -3
- package/dist/lib/daemon/handoff.d.ts +4 -0
- package/dist/lib/daemon/handoff.js +6 -2
- package/dist/lib/daemon/install.d.ts +70 -2
- package/dist/lib/daemon/install.js +185 -27
- package/dist/lib/daemon/legacy.d.ts +9 -3
- package/dist/lib/daemon/legacy.js +11 -4
- package/dist/lib/daemon/migrate.js +1 -1
- package/dist/lib/daemon/run.d.ts +3 -2
- package/dist/lib/daemon/run.js +10 -6
- package/dist/lib/doctor/checks/anywhere.d.ts +6 -0
- package/dist/lib/doctor/checks/anywhere.js +35 -6
- package/dist/lib/hot-channels/adapters/__fixtures__/dummy.d.ts +33 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/dummy.js +53 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/meeting-providers.d.ts +38 -0
- package/dist/lib/hot-channels/adapters/__fixtures__/meeting-providers.js +64 -0
- package/dist/lib/hot-channels/adapters/attio.d.ts +67 -0
- package/dist/lib/hot-channels/adapters/attio.js +374 -0
- package/dist/lib/hot-channels/adapters/gmail.d.ts +111 -0
- package/dist/lib/hot-channels/adapters/gmail.js +413 -0
- package/dist/lib/hot-channels/adapters/index.d.ts +23 -0
- package/dist/lib/hot-channels/adapters/index.js +39 -0
- package/dist/lib/hot-channels/adapters/linear.d.ts +79 -0
- package/dist/lib/hot-channels/adapters/linear.js +321 -0
- package/dist/lib/hot-channels/adapters/meeting-providers.d.ts +86 -0
- package/dist/lib/hot-channels/adapters/meeting-providers.js +253 -0
- package/dist/lib/hot-channels/adapters/meetings.d.ts +81 -0
- package/dist/lib/hot-channels/adapters/meetings.js +523 -0
- package/dist/lib/hot-channels/adapters/slack.d.ts +70 -0
- package/dist/lib/hot-channels/adapters/slack.js +277 -0
- package/dist/lib/hot-channels/alert.d.ts +78 -0
- package/dist/lib/hot-channels/alert.js +179 -0
- package/dist/lib/hot-channels/audience.d.ts +15 -0
- package/dist/lib/hot-channels/audience.js +25 -0
- package/dist/lib/hot-channels/contract.d.ts +140 -0
- package/dist/lib/hot-channels/contract.js +20 -0
- package/dist/lib/hot-channels/cursors.d.ts +41 -0
- package/dist/lib/hot-channels/cursors.js +84 -0
- package/dist/lib/hot-channels/index.d.ts +10 -0
- package/dist/lib/hot-channels/index.js +10 -0
- package/dist/lib/hot-channels/landing.d.ts +83 -0
- package/dist/lib/hot-channels/landing.js +175 -0
- package/dist/lib/hot-channels/ledger.d.ts +101 -0
- package/dist/lib/hot-channels/ledger.js +186 -0
- package/dist/lib/hot-channels/loop.d.ts +74 -0
- package/dist/lib/hot-channels/loop.js +219 -0
- package/dist/lib/hot-channels/prompts/signals-pass.md +22 -0
- package/dist/lib/hot-channels/registry.d.ts +28 -0
- package/dist/lib/hot-channels/registry.js +121 -0
- package/dist/lib/hot-channels/run.d.ts +137 -0
- package/dist/lib/hot-channels/run.js +324 -0
- package/dist/lib/hot-channels/signals-pass.d.ts +150 -0
- package/dist/lib/hot-channels/signals-pass.js +581 -0
- package/dist/lib/hot-channels/sync-lock.d.ts +51 -0
- package/dist/lib/hot-channels/sync-lock.js +224 -0
- package/dist/lib/install/hook-target.d.ts +6 -2
- package/dist/lib/install/hook-target.js +9 -4
- package/dist/lib/lanes/loop.d.ts +10 -0
- package/dist/lib/lanes/loop.js +18 -1
- package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +1 -0
- package/dist/lib/mesh/live/daemon/work-subscribe.js +26 -6
- package/dist/run/hq-plugin.d.ts +3 -0
- package/dist/run/hq-plugin.js +18 -0
- package/package.json +7 -7
package/dist/commands/sources.js
CHANGED
|
@@ -11,18 +11,34 @@
|
|
|
11
11
|
* hq sources get Fetch one source by id.
|
|
12
12
|
* hq sources channels Print the canonical SOURCE_CHANNELS enum.
|
|
13
13
|
* hq sources entities List entities the caller has access to.
|
|
14
|
+
* hq sources runs Show the local hot-channel run ledger for one day.
|
|
15
|
+
* hq sources sync Run every hot channel now for the signed-in person.
|
|
14
16
|
*
|
|
15
17
|
* Defaults:
|
|
16
18
|
* --entity falls back to .hq/config.json activeCompany (per sync.ts).
|
|
17
19
|
* --format 'table' when stdout is a TTY, 'json' when piped.
|
|
18
20
|
* --limit 50.
|
|
19
21
|
*/
|
|
22
|
+
import { randomUUID } from "node:crypto";
|
|
20
23
|
import * as fs from "node:fs";
|
|
21
24
|
import * as path from "node:path";
|
|
22
25
|
import chalk from "chalk";
|
|
23
26
|
import { SOURCE_CHANNELS, assertSourceChannel, resolveEntity, listAvailableEntities, listSources, getSource, VaultClient, } from "@indigoai-us/hq-cloud";
|
|
24
|
-
import { ensureCognitoToken, buildVaultConfig, DEFAULT_HQ_ROOT, } from "../utils/cognito-session.js";
|
|
27
|
+
import { ensureCognitoToken, ensureCognitoIdToken, buildVaultConfig, DEFAULT_HQ_ROOT, } from "../utils/cognito-session.js";
|
|
28
|
+
import { getCompanyUid, vaultApiFetch } from "../utils/vault-api.js";
|
|
29
|
+
import { isAuthError } from "../utils/auth-error.js";
|
|
30
|
+
import { IntegrationsCliError, callGateway, fetchUsableApps, gatewayResultIsError, isBuiltInGatewayProvider, raiseForResponse, toolPrefixForProvider, unwrapGatewayResult, } from "./integrations-core.js";
|
|
25
31
|
import { Sentry } from "../sentry.js";
|
|
32
|
+
import { resolveUploadAuthor } from "../utils/upload-author.js";
|
|
33
|
+
import { createSignalsAlertChannelPoster, raiseSignalsFailureAlerts } from "../lib/hot-channels/alert.js";
|
|
34
|
+
import { audienceKey } from "../lib/hot-channels/audience.js";
|
|
35
|
+
import { appendRunLedgerEntry, ledgerDay, readRunLedger, summarizeRunLedger, } from "../lib/hot-channels/ledger.js";
|
|
36
|
+
import { createClaudeSignalsPass } from "../lib/hot-channels/signals-pass.js";
|
|
37
|
+
import { assertSafeSegment } from "../lib/hot-channels/landing.js";
|
|
38
|
+
import { acquireSyncLock, SYNC_LOCK_BUSY_REASON } from "../lib/hot-channels/sync-lock.js";
|
|
39
|
+
import { createBuiltinHotChannelRegistry } from "../lib/hot-channels/adapters/index.js";
|
|
40
|
+
import { listActiveMembers } from "./members.js";
|
|
41
|
+
import { runOnDemandSync, } from "../lib/hot-channels/run.js";
|
|
26
42
|
// ---------------------------------------------------------------------------
|
|
27
43
|
// Access token resolution — honors HQ_ACCESS_TOKEN for tests + CI smoke
|
|
28
44
|
// ---------------------------------------------------------------------------
|
|
@@ -209,6 +225,330 @@ async function runEntities(options) {
|
|
|
209
225
|
.join("\n");
|
|
210
226
|
process.stdout.write([headerLine, sep, body].join("\n") + "\n");
|
|
211
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Reads one day's run ledger (`sources/_runs/@{personKey}/{day}.jsonl` in the
|
|
230
|
+
* company folder of the local HQ tree). The person key is
|
|
231
|
+
* `audienceKey([email])` of the signed-in person. No network calls.
|
|
232
|
+
*/
|
|
233
|
+
export async function runRuns(options, now = new Date()) {
|
|
234
|
+
if (options.today && options.date) {
|
|
235
|
+
throw new Error("Pass either --today or --date, not both.");
|
|
236
|
+
}
|
|
237
|
+
if (options.date !== undefined && !/^\d{4}-\d{2}-\d{2}$/.test(options.date)) {
|
|
238
|
+
throw new Error(`--date must be YYYY-MM-DD (got '${options.date}').`);
|
|
239
|
+
}
|
|
240
|
+
const day = options.date ?? ledgerDay(now);
|
|
241
|
+
const company = options.company ?? readActiveCompanySlug(options.hqRoot);
|
|
242
|
+
if (!company) {
|
|
243
|
+
throw new Error("No company specified. Pass --company <slug> or set activeCompany in .hq/config.json.");
|
|
244
|
+
}
|
|
245
|
+
const email = options.email ?? resolveUploadAuthor()?.email;
|
|
246
|
+
if (!email) {
|
|
247
|
+
throw new Error("Could not tell who is signed in. Run `hq login` or pass --email <address>.");
|
|
248
|
+
}
|
|
249
|
+
const personKey = audienceKey([email]);
|
|
250
|
+
const vaultRoot = path.join(options.hqRoot, "companies", company);
|
|
251
|
+
const { entries, malformed } = await readRunLedger(vaultRoot, personKey, day);
|
|
252
|
+
const report = {
|
|
253
|
+
company,
|
|
254
|
+
personKey,
|
|
255
|
+
day,
|
|
256
|
+
adapters: summarizeRunLedger(entries),
|
|
257
|
+
entries,
|
|
258
|
+
malformed,
|
|
259
|
+
};
|
|
260
|
+
const format = options.format ?? defaultListFormat();
|
|
261
|
+
if (format === "json") {
|
|
262
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
263
|
+
return report;
|
|
264
|
+
}
|
|
265
|
+
process.stdout.write(renderRunsTable(report) + "\n");
|
|
266
|
+
return report;
|
|
267
|
+
}
|
|
268
|
+
function renderRunsTable(report) {
|
|
269
|
+
const lines = [`Runs for ${report.company} on ${report.day} (UTC), person key @${report.personKey}`];
|
|
270
|
+
if (report.entries.length === 0) {
|
|
271
|
+
lines.push("(no runs logged)");
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
275
|
+
const header = ["ADAPTER", "RUNS", "SOURCES", "SIGNALS", "FAILED", "LAST FINISHED"];
|
|
276
|
+
const rows = report.adapters.map((a) => [
|
|
277
|
+
a.adapter,
|
|
278
|
+
String(a.runs),
|
|
279
|
+
String(a.sourcesLanded),
|
|
280
|
+
String(a.signalsGenerated),
|
|
281
|
+
String(a.failed),
|
|
282
|
+
a.lastFinishedAt,
|
|
283
|
+
]);
|
|
284
|
+
const widths = header.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
285
|
+
lines.push("", header.map((h, i) => pad(h, widths[i])).join(" "));
|
|
286
|
+
for (const row of rows)
|
|
287
|
+
lines.push(row.map((cell, i) => pad(cell, widths[i])).join(" "));
|
|
288
|
+
lines.push("", "Runs:");
|
|
289
|
+
for (const e of [...report.entries].sort((a, b) => a.startedAt.localeCompare(b.startedAt))) {
|
|
290
|
+
const outcome = e.status === "ok"
|
|
291
|
+
? "ok"
|
|
292
|
+
: e.status === "skipped"
|
|
293
|
+
? `skipped: ${e.reason ?? "no reason given"}`
|
|
294
|
+
: `failed: ${e.error ?? "unknown error"}`;
|
|
295
|
+
lines.push(` ${e.startedAt} ${e.adapter} ${e.trigger} sources=${e.sourcesLanded} signals=${e.signalsGenerated} ${outcome}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (report.malformed > 0)
|
|
299
|
+
lines.push(`(${report.malformed} unreadable line(s) skipped)`);
|
|
300
|
+
return lines.join("\n");
|
|
301
|
+
}
|
|
302
|
+
const SIGN_IN_PROMPT = "Your HQ session has expired or you're not signed in. Run `hq login`, then `hq sources sync` again.";
|
|
303
|
+
const MAX_TOOL_ERROR_TEXT = 500;
|
|
304
|
+
/** The catalog API's `hotChannels` array, or null when the server has none. */
|
|
305
|
+
async function fetchHotChannels(token, companyUid) {
|
|
306
|
+
const res = await vaultApiFetch({
|
|
307
|
+
token,
|
|
308
|
+
path: "/v1/integrations/factory/catalog",
|
|
309
|
+
query: { companyUid },
|
|
310
|
+
});
|
|
311
|
+
if (!res.ok)
|
|
312
|
+
await raiseForResponse(res, "Failed to read the integrations catalog");
|
|
313
|
+
const data = (await res.json());
|
|
314
|
+
return Array.isArray(data.hotChannels) ? data.hotChannels : null;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Network access for one sync: the catalog, the person's usable connections,
|
|
318
|
+
* and tool calls through the HQ gateway. Integration tokens stay server-side;
|
|
319
|
+
* the gateway routes each call by connection id.
|
|
320
|
+
*/
|
|
321
|
+
export function gatewaySyncDeps(token, companyUid) {
|
|
322
|
+
return {
|
|
323
|
+
fetchHotChannels: () => fetchHotChannels(token, companyUid),
|
|
324
|
+
fetchUsableApps: async () => (await fetchUsableApps(token, companyUid)).apps,
|
|
325
|
+
async callTool(app, tool, args) {
|
|
326
|
+
const idempotencyKey = `hq-sources-sync-${randomUUID()}`;
|
|
327
|
+
const params = isBuiltInGatewayProvider(app.provider)
|
|
328
|
+
? {
|
|
329
|
+
companyUid,
|
|
330
|
+
acceptAsync: true,
|
|
331
|
+
name: tool,
|
|
332
|
+
arguments: { ...args, companyUid, connectionId: app.connectionId, idempotencyKey },
|
|
333
|
+
}
|
|
334
|
+
: {
|
|
335
|
+
companyUid,
|
|
336
|
+
acceptAsync: true,
|
|
337
|
+
name: `${toolPrefixForProvider(app.provider)}.mcp.tools.call`,
|
|
338
|
+
arguments: { companyUid, connectionId: app.connectionId, toolName: tool, arguments: args, idempotencyKey },
|
|
339
|
+
};
|
|
340
|
+
const message = await callGateway(token, params, idempotencyKey, "tools/call");
|
|
341
|
+
const payload = unwrapGatewayResult(message.result);
|
|
342
|
+
if (gatewayResultIsError(message.result) || gatewayResultIsError(payload)) {
|
|
343
|
+
const text = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
344
|
+
throw new IntegrationsCliError((text ?? "tool call failed").slice(0, MAX_TOOL_ERROR_TEXT), {
|
|
345
|
+
expected: true,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return payload;
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function signInReport() {
|
|
353
|
+
return {
|
|
354
|
+
runId: null,
|
|
355
|
+
signInRequired: true,
|
|
356
|
+
outcomes: [],
|
|
357
|
+
entries: [],
|
|
358
|
+
notices: [SIGN_IN_PROMPT],
|
|
359
|
+
exitCode: 1,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
async function signedInSession(company) {
|
|
363
|
+
let token;
|
|
364
|
+
try {
|
|
365
|
+
token = process.env.HQ_ACCESS_TOKEN || (await ensureCognitoIdToken({ interactive: false }));
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
return { token, companyUid: await getCompanyUid(token, company) };
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
if (isAuthError(err) || err.status === 401)
|
|
375
|
+
return null;
|
|
376
|
+
throw err;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/** The signed-in member's `prs_` uid from the company roster, or null when the roster is unavailable. */
|
|
380
|
+
async function rosterPersonUid(token, companyUid, email) {
|
|
381
|
+
try {
|
|
382
|
+
const wanted = email.toLowerCase();
|
|
383
|
+
const member = (await listActiveMembers(token, companyUid)).find((m) => m.personEmail?.toLowerCase() === wanted);
|
|
384
|
+
return member?.personUid ?? null;
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* The signed-in person's identities a meeting audience can name: their email
|
|
392
|
+
* and their `prs_` person uid. The run's `personUid` is the Cognito sub, which
|
|
393
|
+
* meeting transcripts never carry.
|
|
394
|
+
*/
|
|
395
|
+
async function meetingIdentities(input, session, email) {
|
|
396
|
+
const personUid = await (input.resolvePersonUid ?? rosterPersonUid)(session.token, session.companyUid, email);
|
|
397
|
+
return personUid ? [email, personUid] : [email];
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* One hot-channel sync for the signed-in person in one company: each adapter
|
|
401
|
+
* once per usable connection. Writes under `companies/{company}/`: landed
|
|
402
|
+
* sources in `sources/`, index rows in `sources/_index/`, cursors in
|
|
403
|
+
* `sources/_cursors/`, one ledger line per adapter in `sources/_runs/`, and
|
|
404
|
+
* signals in `signals/@{key}/`. `hq sources sync` and the bot's scheduled
|
|
405
|
+
* hot-signal-sync job both call it. Only one run per person per company goes
|
|
406
|
+
* at a time: a second one writes a `skipped` ledger line and lands nothing.
|
|
407
|
+
*/
|
|
408
|
+
export async function runCompanyHotChannelSync(input) {
|
|
409
|
+
assertSafeSegment(input.company, "company");
|
|
410
|
+
const author = resolveUploadAuthor();
|
|
411
|
+
const session = author ? await signedInSession(input.company) : null;
|
|
412
|
+
if (!author || !session)
|
|
413
|
+
return signInReport();
|
|
414
|
+
const vaultRoot = path.join(input.hqRoot, "companies", input.company);
|
|
415
|
+
const personKey = audienceKey([author.email]);
|
|
416
|
+
const now = input.now ?? (() => new Date());
|
|
417
|
+
const lock = await acquireSyncLock(vaultRoot, personKey, { now });
|
|
418
|
+
if (!lock)
|
|
419
|
+
return skippedReport(input, vaultRoot, personKey, author.userSub, now);
|
|
420
|
+
try {
|
|
421
|
+
return await runLockedCompanySync(input, vaultRoot, personKey, author, session, lock.assertHeld);
|
|
422
|
+
}
|
|
423
|
+
finally {
|
|
424
|
+
await lock.release();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async function skippedReport(input, vaultRoot, personKey, personUid, now) {
|
|
428
|
+
const at = now().toISOString();
|
|
429
|
+
const line = {
|
|
430
|
+
runId: `run_${randomUUID()}`,
|
|
431
|
+
trigger: input.trigger ?? "on-demand",
|
|
432
|
+
adapter: "all",
|
|
433
|
+
connectionId: null,
|
|
434
|
+
sourcesLanded: 0,
|
|
435
|
+
signalsGenerated: 0,
|
|
436
|
+
startedAt: at,
|
|
437
|
+
finishedAt: at,
|
|
438
|
+
status: "skipped",
|
|
439
|
+
error: null,
|
|
440
|
+
reason: SYNC_LOCK_BUSY_REASON,
|
|
441
|
+
personUid,
|
|
442
|
+
catchUp: input.catchUp ?? false,
|
|
443
|
+
};
|
|
444
|
+
await appendRunLedgerEntry(vaultRoot, personKey, line);
|
|
445
|
+
return {
|
|
446
|
+
runId: line.runId,
|
|
447
|
+
signInRequired: false,
|
|
448
|
+
skipped: true,
|
|
449
|
+
outcomes: [],
|
|
450
|
+
entries: [line],
|
|
451
|
+
notices: [`Another hot-channel sync for ${input.company} is already running, so this one was skipped.`],
|
|
452
|
+
exitCode: 0,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
async function runLockedCompanySync(input, vaultRoot, personKey, author, session, lockHeld) {
|
|
456
|
+
const deps = gatewaySyncDeps(session.token, session.companyUid);
|
|
457
|
+
const report = await runOnDemandSync({
|
|
458
|
+
deps,
|
|
459
|
+
registry: input.registry ??
|
|
460
|
+
createBuiltinHotChannelRegistry({ vaultRoot, identities: await meetingIdentities(input, session, author.email) }),
|
|
461
|
+
vaultRoot,
|
|
462
|
+
personUid: author.userSub,
|
|
463
|
+
personKey,
|
|
464
|
+
...(input.adapter !== undefined ? { adapter: input.adapter } : {}),
|
|
465
|
+
...(input.now ? { now: input.now } : {}),
|
|
466
|
+
...(input.trigger ? { trigger: input.trigger } : {}),
|
|
467
|
+
...(input.catchUp === undefined ? {} : { catchUp: input.catchUp }),
|
|
468
|
+
...(input.signalsGenerated ? { signalsGenerated: input.signalsGenerated } : {}),
|
|
469
|
+
beforeWrite: lockHeld,
|
|
470
|
+
});
|
|
471
|
+
if (input.signalsAlert) {
|
|
472
|
+
const postCompanyChannel = input.signalsAlert.postCompanyChannel ??
|
|
473
|
+
createSignalsAlertChannelPoster({ hqRoot: input.hqRoot, company: input.company, deps });
|
|
474
|
+
await raiseSignalsFailureAlerts({
|
|
475
|
+
vaultRoot,
|
|
476
|
+
personKey,
|
|
477
|
+
entries: report.entries,
|
|
478
|
+
now: input.now ?? (() => new Date()),
|
|
479
|
+
personName: author.email,
|
|
480
|
+
sendOwnerDm: input.signalsAlert.sendOwnerDm,
|
|
481
|
+
...(postCompanyChannel ? { postCompanyChannel } : {}),
|
|
482
|
+
...(input.signalsAlert.log ? { log: input.signalsAlert.log } : {}),
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
return report;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Run every hot channel for the signed-in person now: each adapter once per
|
|
489
|
+
* usable connection. Writes cursors, landed sources and an `on-demand` ledger
|
|
490
|
+
* line under `companies/{company}/sources/`, and nothing else.
|
|
491
|
+
*/
|
|
492
|
+
export async function runSync(options, overrides = {}) {
|
|
493
|
+
const company = options.company ?? readActiveCompanySlug(options.hqRoot);
|
|
494
|
+
if (!company) {
|
|
495
|
+
throw new Error("No company specified. Pass --company <slug> or set activeCompany in .hq/config.json.");
|
|
496
|
+
}
|
|
497
|
+
const report = await runCompanyHotChannelSync({
|
|
498
|
+
hqRoot: options.hqRoot,
|
|
499
|
+
company,
|
|
500
|
+
...(options.adapter !== undefined ? { adapter: options.adapter } : {}),
|
|
501
|
+
...(overrides.registry ? { registry: overrides.registry } : {}),
|
|
502
|
+
...(overrides.now ? { now: overrides.now } : {}),
|
|
503
|
+
signalsGenerated: overrides.signalsGenerated ?? createClaudeSignalsPass({ hqRoot: options.hqRoot, company }),
|
|
504
|
+
// The CLI has no owner-DM sender: the terminal is the primary alert here.
|
|
505
|
+
signalsAlert: {
|
|
506
|
+
sendOwnerDm: async (text) => {
|
|
507
|
+
process.stderr.write(chalk.red(`${text}\n`));
|
|
508
|
+
},
|
|
509
|
+
log: (message) => process.stderr.write(chalk.yellow(`${message}\n`)),
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
if (options.json) {
|
|
513
|
+
process.stdout.write(JSON.stringify({ company, ...report }, null, 2) + "\n");
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
process.stdout.write(renderSyncTable(company, report) + "\n");
|
|
517
|
+
}
|
|
518
|
+
for (const outcome of report.outcomes) {
|
|
519
|
+
if (outcome.reconnect)
|
|
520
|
+
process.stderr.write(chalk.yellow(`${outcome.reconnect.prompt}\n`));
|
|
521
|
+
}
|
|
522
|
+
if (report.signInRequired)
|
|
523
|
+
process.stderr.write(chalk.yellow(`${SIGN_IN_PROMPT}\n`));
|
|
524
|
+
if (report.exitCode !== 0)
|
|
525
|
+
process.exitCode = report.exitCode;
|
|
526
|
+
return report;
|
|
527
|
+
}
|
|
528
|
+
function renderSyncTable(company, report) {
|
|
529
|
+
const lines = [`Hot-channel sync for ${company}`];
|
|
530
|
+
for (const notice of report.notices) {
|
|
531
|
+
if (!report.signInRequired)
|
|
532
|
+
lines.push(notice);
|
|
533
|
+
}
|
|
534
|
+
if (report.outcomes.length > 0) {
|
|
535
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
536
|
+
const header = ["ADAPTER", "CONNECTION", "LANDED", "STATUS"];
|
|
537
|
+
const rows = report.outcomes.map((o) => [
|
|
538
|
+
o.adapter,
|
|
539
|
+
o.connectionId ?? "-",
|
|
540
|
+
String(o.landed),
|
|
541
|
+
o.status === "ok" ? "ok" : o.message ? `${o.status}: ${o.message}` : o.status,
|
|
542
|
+
]);
|
|
543
|
+
const widths = header.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
544
|
+
lines.push("", header.map((h, i) => pad(h, widths[i])).join(" "));
|
|
545
|
+
for (const row of rows)
|
|
546
|
+
lines.push(row.map((cell, i) => pad(cell, widths[i])).join(" "));
|
|
547
|
+
const landed = report.outcomes.reduce((sum, o) => sum + o.landed, 0);
|
|
548
|
+
lines.push("", `${landed} source(s) landed.`);
|
|
549
|
+
}
|
|
550
|
+
return lines.join("\n");
|
|
551
|
+
}
|
|
212
552
|
// ---------------------------------------------------------------------------
|
|
213
553
|
// Registration
|
|
214
554
|
// ---------------------------------------------------------------------------
|
|
@@ -260,5 +600,27 @@ export function registerSourcesCommand(program) {
|
|
|
260
600
|
.description("List entities (companies/personal) your account has access to")
|
|
261
601
|
.option("--format <fmt>", "Output format: table | json (default: table for TTY, json piped)")
|
|
262
602
|
.action(withErrorHandling(async (options) => runEntities(options)));
|
|
603
|
+
sources
|
|
604
|
+
.command("runs")
|
|
605
|
+
.description("Show the hot-channel run log: sources landed and signals generated per adapter")
|
|
606
|
+
.option("--today", "Show today's runs (UTC); the default")
|
|
607
|
+
.option("--date <YYYY-MM-DD>", "Show runs for this UTC day")
|
|
608
|
+
.option("--company <slug>", "Company slug (defaults to .hq/config.json activeCompany)")
|
|
609
|
+
.option("--email <address>", "Whose runs to show (defaults to the signed-in person)")
|
|
610
|
+
.option("--format <fmt>", "Output format: table | json (default: table for TTY, json piped)")
|
|
611
|
+
.option("--hq-root <path>", `Local HQ tree root (default: ${DEFAULT_HQ_ROOT})`, DEFAULT_HQ_ROOT)
|
|
612
|
+
.action(withErrorHandling(async (options) => {
|
|
613
|
+
await runRuns(options);
|
|
614
|
+
}));
|
|
615
|
+
sources
|
|
616
|
+
.command("sync")
|
|
617
|
+
.description("Run every hot channel now: each adapter once per connection you can use")
|
|
618
|
+
.option("--adapter <id>", "Run one adapter only (a catalog provider or adapter id)")
|
|
619
|
+
.option("--company <slug>", "Company slug (defaults to .hq/config.json activeCompany)")
|
|
620
|
+
.option("--json", "Print the run report as JSON")
|
|
621
|
+
.option("--hq-root <path>", `Local HQ tree root (default: ${DEFAULT_HQ_ROOT})`, DEFAULT_HQ_ROOT)
|
|
622
|
+
.action(withErrorHandling(async (options) => {
|
|
623
|
+
await runSync(options);
|
|
624
|
+
}));
|
|
263
625
|
}
|
|
264
626
|
//# sourceMappingURL=sources.js.map
|
package/dist/lib/bot/config.d.ts
CHANGED
|
@@ -90,6 +90,8 @@ export interface BotConfig {
|
|
|
90
90
|
ownerUid: string;
|
|
91
91
|
runtime: BotRuntimeId;
|
|
92
92
|
engine?: BotEngineMetadata;
|
|
93
|
+
fleetAuthPending?: boolean;
|
|
94
|
+
fleetServiceInstallPending?: boolean;
|
|
93
95
|
/**
|
|
94
96
|
* "personal" (acts as its owner everywhere) or "company" (acts as itself,
|
|
95
97
|
* member of `companies`). Missing on bots created before kinds existed:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type FlagClient, type FlagClientOptions } from "@indigoai-us/hq-flags-client";
|
|
2
|
+
/** Personal bots are created on the HQ Fleet Runtime for companies with this flag on. */
|
|
3
|
+
export declare const LOCAL_BOTS_FLEET_DEFAULT_FLAG = "agents.local-bots-hq-fleet-default";
|
|
4
|
+
export declare const LOCAL_BOTS_FLEET_DEFAULT_ENV = "HQ_BOT_FLEET_DEFAULT";
|
|
5
|
+
type DefaultFlagClient = Pick<FlagClient, "ready" | "isEnabled" | "close">;
|
|
6
|
+
export interface OwnerMembership {
|
|
7
|
+
companyUid: string;
|
|
8
|
+
companySlug?: string;
|
|
9
|
+
status: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FleetDefaultFlagDependencies {
|
|
12
|
+
env?: NodeJS.ProcessEnv;
|
|
13
|
+
createClient?: (options: FlagClientOptions) => DefaultFlagClient;
|
|
14
|
+
getToken?: FlagClientOptions["getToken"];
|
|
15
|
+
fetch?: typeof fetch;
|
|
16
|
+
/** The signed-in owner's memberships; never prompts for sign-in. */
|
|
17
|
+
memberships?: () => Promise<OwnerMembership[]>;
|
|
18
|
+
}
|
|
19
|
+
/** Every active company the signed-in owner can access, independent of rollout flags or local folders. */
|
|
20
|
+
export declare function fleetOwnerCompanies(dependencies?: Pick<FleetDefaultFlagDependencies, "memberships">): Promise<string[]>;
|
|
21
|
+
/**
|
|
22
|
+
* The owner's companies that turned the fleet-default flag on: active
|
|
23
|
+
* memberships whose company folder is on this computer. Any lookup failure
|
|
24
|
+
* leaves that company out. `HQ_BOT_FLEET_DEFAULT=1` skips the flag and keeps
|
|
25
|
+
* every such membership.
|
|
26
|
+
*/
|
|
27
|
+
export declare function fleetDefaultCompanies(hqRoot: string, dependencies?: FleetDefaultFlagDependencies): Promise<string[]>;
|
|
28
|
+
/** `HQ_BOT_FLEET_DEFAULT=1|0` overrides the registry; otherwise on when any flagged company was found. */
|
|
29
|
+
export declare function fleetRuntimeIsDefault(flaggedCompanies: readonly string[], env?: NodeJS.ProcessEnv): boolean;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=fleet-default-flag.d.ts.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { loadCachedTokens } from "@indigoai-us/hq-cloud";
|
|
4
|
+
import { createFlagClient, } from "@indigoai-us/hq-flags-client";
|
|
5
|
+
import { ensureCognitoToken } from "../../utils/cognito-session.js";
|
|
6
|
+
import { vaultApiFetch } from "../../utils/vault-api.js";
|
|
7
|
+
import { resolveFlagGate } from "../flag-registry.js";
|
|
8
|
+
import { resolveFlagRegistryEndpoint } from "../flag-registry-endpoint.js";
|
|
9
|
+
/** Personal bots are created on the HQ Fleet Runtime for companies with this flag on. */
|
|
10
|
+
export const LOCAL_BOTS_FLEET_DEFAULT_FLAG = "agents.local-bots-hq-fleet-default";
|
|
11
|
+
export const LOCAL_BOTS_FLEET_DEFAULT_ENV = "HQ_BOT_FLEET_DEFAULT";
|
|
12
|
+
const FLAG_TIMEOUT_MS = 3_000;
|
|
13
|
+
const MEMBERSHIP_TIMEOUT_MS = 10_000;
|
|
14
|
+
const COMPANY_UID_RE = /^cmp_[A-Za-z0-9]{3,128}$/;
|
|
15
|
+
const COMPANY_SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
16
|
+
async function signedInMemberships() {
|
|
17
|
+
const token = await ensureCognitoToken({ tokenSource: "person", interactive: false });
|
|
18
|
+
const res = await vaultApiFetch({ token, path: "/membership/me", signal: AbortSignal.timeout(MEMBERSHIP_TIMEOUT_MS) });
|
|
19
|
+
if (!res.ok)
|
|
20
|
+
throw new Error(`membership lookup returned ${res.status}`);
|
|
21
|
+
const data = (await res.json());
|
|
22
|
+
if (!Array.isArray(data.memberships))
|
|
23
|
+
throw new Error("membership lookup returned no list");
|
|
24
|
+
return data.memberships;
|
|
25
|
+
}
|
|
26
|
+
/** Every active company the signed-in owner can access, independent of rollout flags or local folders. */
|
|
27
|
+
export async function fleetOwnerCompanies(dependencies = {}) {
|
|
28
|
+
const memberships = await (dependencies.memberships ?? signedInMemberships)();
|
|
29
|
+
const companies = new Set();
|
|
30
|
+
for (const membership of memberships) {
|
|
31
|
+
const slug = membership.companySlug?.trim() ?? "";
|
|
32
|
+
if (membership.status !== "active" || !COMPANY_UID_RE.test(membership.companyUid))
|
|
33
|
+
continue;
|
|
34
|
+
if (!COMPANY_SLUG_RE.test(slug) || slug === "personal")
|
|
35
|
+
continue;
|
|
36
|
+
companies.add(slug);
|
|
37
|
+
}
|
|
38
|
+
return [...companies].sort((a, b) => a.localeCompare(b));
|
|
39
|
+
}
|
|
40
|
+
function hasLocalFolder(hqRoot, slug) {
|
|
41
|
+
try {
|
|
42
|
+
const stat = fs.lstatSync(path.join(hqRoot, "companies", slug));
|
|
43
|
+
return stat.isDirectory() && !stat.isSymbolicLink();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The owner's companies that turned the fleet-default flag on: active
|
|
51
|
+
* memberships whose company folder is on this computer. Any lookup failure
|
|
52
|
+
* leaves that company out. `HQ_BOT_FLEET_DEFAULT=1` skips the flag and keeps
|
|
53
|
+
* every such membership.
|
|
54
|
+
*/
|
|
55
|
+
export async function fleetDefaultCompanies(hqRoot, dependencies = {}) {
|
|
56
|
+
const env = dependencies.env ?? process.env;
|
|
57
|
+
let memberships;
|
|
58
|
+
try {
|
|
59
|
+
memberships = await (dependencies.memberships ?? signedInMemberships)();
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const candidates = new Map();
|
|
65
|
+
for (const membership of memberships) {
|
|
66
|
+
const slug = membership.companySlug?.trim() ?? "";
|
|
67
|
+
if (membership.status !== "active" || !COMPANY_UID_RE.test(membership.companyUid))
|
|
68
|
+
continue;
|
|
69
|
+
if (!COMPANY_SLUG_RE.test(slug) || slug === "personal" || !hasLocalFolder(hqRoot, slug))
|
|
70
|
+
continue;
|
|
71
|
+
candidates.set(slug, membership.companyUid);
|
|
72
|
+
}
|
|
73
|
+
const entries = [...candidates.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
74
|
+
const override = env[LOCAL_BOTS_FLEET_DEFAULT_ENV]?.trim();
|
|
75
|
+
if (override === "1" || override === "true")
|
|
76
|
+
return entries.map(([slug]) => slug);
|
|
77
|
+
const createClient = dependencies.createClient ?? createFlagClient;
|
|
78
|
+
const getToken = dependencies.getToken ?? (() => loadCachedTokens()?.idToken ?? "");
|
|
79
|
+
const endpoint = resolveFlagRegistryEndpoint(undefined, env);
|
|
80
|
+
const doFetch = dependencies.fetch ?? globalThis.fetch;
|
|
81
|
+
const flagOn = async (slug, companyUid) => {
|
|
82
|
+
let client;
|
|
83
|
+
let failed = false;
|
|
84
|
+
try {
|
|
85
|
+
client = createClient({
|
|
86
|
+
endpoint,
|
|
87
|
+
companyUid,
|
|
88
|
+
companyIdentifiers: [slug],
|
|
89
|
+
env: {},
|
|
90
|
+
getToken,
|
|
91
|
+
...(doFetch ? { fetch: doFetch } : {}),
|
|
92
|
+
refreshIntervalMs: 0,
|
|
93
|
+
requestTimeoutMs: FLAG_TIMEOUT_MS,
|
|
94
|
+
onError: () => {
|
|
95
|
+
failed = true;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
await client.ready();
|
|
99
|
+
if (failed)
|
|
100
|
+
return false;
|
|
101
|
+
return resolveFlagGate(client, LOCAL_BOTS_FLEET_DEFAULT_FLAG, { fallback: false }, () => false);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
try {
|
|
108
|
+
client?.close();
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* closing a flag client never changes the answer */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const results = await Promise.all(entries.map(([slug, uid]) => flagOn(slug, uid)));
|
|
116
|
+
return entries.filter((_, index) => results[index]).map(([slug]) => slug);
|
|
117
|
+
}
|
|
118
|
+
/** `HQ_BOT_FLEET_DEFAULT=1|0` overrides the registry; otherwise on when any flagged company was found. */
|
|
119
|
+
export function fleetRuntimeIsDefault(flaggedCompanies, env = process.env) {
|
|
120
|
+
const override = env[LOCAL_BOTS_FLEET_DEFAULT_ENV]?.trim();
|
|
121
|
+
if (override === "1" || override === "true")
|
|
122
|
+
return true;
|
|
123
|
+
if (override === "0" || override === "false")
|
|
124
|
+
return false;
|
|
125
|
+
return flaggedCompanies.length > 0;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=fleet-default-flag.js.map
|
|
@@ -40,6 +40,7 @@ export interface FleetLocalProfile {
|
|
|
40
40
|
baseUrl?: string;
|
|
41
41
|
transport?: string;
|
|
42
42
|
};
|
|
43
|
+
ownerCompanies?: string[];
|
|
43
44
|
hqRoot: string;
|
|
44
45
|
profileDir: string;
|
|
45
46
|
runtime: {
|
|
@@ -69,7 +70,27 @@ export interface FleetLocalProfileInput {
|
|
|
69
70
|
installation: FleetLocalInstallation;
|
|
70
71
|
/** The bot's standing HQ instructions; written as the runtime's SOUL.md persona. */
|
|
71
72
|
systemPrompt?: string;
|
|
73
|
+
/** Which model login the bot answers with; ChatGPT when omitted. */
|
|
74
|
+
provider?: FleetLocalProfile["provider"];
|
|
75
|
+
/** The hello and first task the runtime sends and runs once, on its first start. */
|
|
76
|
+
firstStart?: {
|
|
77
|
+
intro?: string;
|
|
78
|
+
kickoff?: string;
|
|
79
|
+
};
|
|
80
|
+
/** Companies the owner's own turns may use; other senders get none of them. */
|
|
81
|
+
ownerCompanies?: string[];
|
|
72
82
|
}
|
|
83
|
+
/** The model the HQ Fleet Runtime asks for when a Claude bot names none. */
|
|
84
|
+
export declare const FLEET_CLAUDE_DEFAULT_MODEL = "claude-opus-5-5";
|
|
85
|
+
/**
|
|
86
|
+
* The runtime provider for a bot created from a model CLI choice. Claude uses
|
|
87
|
+
* the runtime's native Anthropic provider, which reads the owner's Claude Code
|
|
88
|
+
* login, so it needs no sign-in of its own; ChatGPT and Grok sign in with
|
|
89
|
+
* `hq bot auth`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function fleetProviderForRuntime(runtime: string, model?: string): FleetLocalProfile["provider"];
|
|
92
|
+
/** True when a bot with this provider still needs `hq bot auth` before it can answer. */
|
|
93
|
+
export declare function fleetProviderNeedsSignIn(provider: FleetLocalProfile["provider"]): boolean;
|
|
73
94
|
type FleetLocalExec = (executable: string, args: string[], options: Record<string, unknown>) => Buffer | string;
|
|
74
95
|
export interface FleetLocalBootstrapDeps {
|
|
75
96
|
fleetHome?: string;
|
|
@@ -91,6 +112,7 @@ export interface FleetLocalControlDeps {
|
|
|
91
112
|
run?: FleetLocalExec;
|
|
92
113
|
}
|
|
93
114
|
export interface FleetLocalAuthInput {
|
|
115
|
+
installService?: boolean;
|
|
94
116
|
agentUid: string;
|
|
95
117
|
provider: string;
|
|
96
118
|
model?: string;
|
|
@@ -111,7 +133,7 @@ export interface FleetLocalRemovalResult {
|
|
|
111
133
|
credentialsRemoved: number;
|
|
112
134
|
}
|
|
113
135
|
export declare const HQ_FLEET_LOCAL_RELEASE: FleetLocalReleasePin;
|
|
114
|
-
export declare const HQ_FLEET_LOCAL_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\
|
|
136
|
+
export declare const HQ_FLEET_LOCAL_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAbYvc1pwOmiCUPJv8yIa3E9RXfniFA84nH2+ROmLMGZU=\n-----END PUBLIC KEY-----\n";
|
|
115
137
|
export declare function fleetHome(home?: string, env?: NodeJS.ProcessEnv): string;
|
|
116
138
|
export declare function verifyFleetLocalRelease(files: FleetLocalReleaseFiles, release?: FleetLocalReleasePin, publicKey?: string): void;
|
|
117
139
|
export declare function resolveFleetReleaseToken(env?: NodeJS.ProcessEnv): string;
|
|
@@ -128,6 +150,11 @@ export declare function fleetLocalPromotionRuntime(agentUid: string, deps?: Flee
|
|
|
128
150
|
export declare function removeFleetLocalBot(agentUid: string, deps?: FleetLocalControlDeps): FleetLocalRemovalResult;
|
|
129
151
|
export declare function authenticateFleetLocalBot(input: FleetLocalAuthInput, deps?: FleetLocalControlDeps): FleetLocalAuthResult;
|
|
130
152
|
export declare function writeFleetLocalProfile(input: FleetLocalProfileInput, deps?: Pick<FleetLocalBootstrapDeps, "fleetHome" | "platform">): string;
|
|
153
|
+
/** The runtime's inbox plugin sends the intro and runs the kickoff once, then stamps this file. */
|
|
154
|
+
export declare function writeFleetLocalFirstStart(profileDir: string, firstStart: {
|
|
155
|
+
intro?: string;
|
|
156
|
+
kickoff?: string;
|
|
157
|
+
}): string;
|
|
131
158
|
export declare function writeFleetLocalSoul(agentUid: string, systemPrompt: string, deps?: Pick<FleetLocalControlDeps, "fleetHome">): string;
|
|
132
159
|
/**
|
|
133
160
|
* The pinned runtime refuses a persona file that trips its context-file
|
|
@@ -137,6 +164,8 @@ export declare function writeFleetLocalSoul(agentUid: string, systemPrompt: stri
|
|
|
137
164
|
export declare function scanFleetLocalInstructions(agentUid: string, text: string, deps?: FleetLocalControlDeps): string[];
|
|
138
165
|
/** Checks the instructions with the runtime's scanner, then makes them the bot's persona. */
|
|
139
166
|
export declare function refreshFleetLocalInstructions(agentUid: string, systemPrompt: string, deps?: FleetLocalControlDeps): string;
|
|
167
|
+
/** Moves a fresh machine credential into the bot's secure store and deletes the file. */
|
|
168
|
+
export declare function importFleetLocalMachineCredential(agentUid: string, machineCredentials: string, deps?: FleetLocalControlDeps): void;
|
|
140
169
|
export declare function bootstrapFleetLocalBot(input: FleetLocalProfileInput & {
|
|
141
170
|
machineCredentials: string;
|
|
142
171
|
}, deps?: FleetLocalBootstrapDeps): Promise<FleetLocalBootstrapResult>;
|