@indigoai-us/hq-cli 5.345.180 → 5.345.182
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 +7 -0
- package/dist/commands/bot.js +37 -9
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +204 -201
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/lib/bot/fleet-local.d.ts +7 -3
- package/dist/lib/bot/fleet-local.js +171 -53
- 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/sync-core/flag.d.ts +1 -1
- package/dist/lib/sync-core/flag.js +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"hq-cli-daemon-sync-runner","type":"module","version":"6.18.
|
|
1
|
+
{"name":"hq-cli-daemon-sync-runner","type":"module","version":"6.18.106","bundleSha256":"ae4c7a7b3040977faff6e9ea7f302bc9e46cf77675347788642e362c3337e3fe","formatVersion":1}
|
|
@@ -99,6 +99,9 @@ export interface FleetLocalBootstrapDeps {
|
|
|
99
99
|
start?: boolean;
|
|
100
100
|
python?: FleetPython;
|
|
101
101
|
}
|
|
102
|
+
type FleetLocalProfileDeps = Pick<FleetLocalBootstrapDeps, "fleetHome" | "platform"> & {
|
|
103
|
+
runtimeRoot?: string;
|
|
104
|
+
};
|
|
102
105
|
export interface FleetLocalBootstrapResult {
|
|
103
106
|
profile: string;
|
|
104
107
|
runtime: string;
|
|
@@ -133,7 +136,7 @@ export interface FleetLocalRemovalResult {
|
|
|
133
136
|
credentialsRemoved: number;
|
|
134
137
|
}
|
|
135
138
|
export declare const HQ_FLEET_LOCAL_RELEASE: FleetLocalReleasePin;
|
|
136
|
-
export declare const HQ_FLEET_LOCAL_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\
|
|
139
|
+
export declare const HQ_FLEET_LOCAL_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwi1nsHS34c3m1k/hvuqnk+9nEuv5qCHh7iFB9BN6iMY=\n-----END PUBLIC KEY-----\n";
|
|
137
140
|
export declare function fleetHome(home?: string, env?: NodeJS.ProcessEnv): string;
|
|
138
141
|
export declare function verifyFleetLocalRelease(files: FleetLocalReleaseFiles, release?: FleetLocalReleasePin, publicKey?: string): void;
|
|
139
142
|
export declare function resolveFleetReleaseToken(env?: NodeJS.ProcessEnv): string;
|
|
@@ -144,12 +147,13 @@ export declare const FLEET_LOCAL_RUNTIME_DOWNLOAD_TIMEOUT_MS: number;
|
|
|
144
147
|
export declare function installPinnedFleetLocalDistribution(deps?: FleetLocalInstallDeps): Promise<FleetLocalInstallation>;
|
|
145
148
|
/** The process id the bot's gateway recorded, when its file reads; the caller checks whether it is alive. */
|
|
146
149
|
export declare function fleetLocalGatewayPid(agentUid: string, deps?: Pick<FleetLocalControlDeps, "fleetHome">): number | null;
|
|
150
|
+
export declare function fleetLocalProfileNeedsAdoption(agentUid: string, deps?: Pick<FleetLocalControlDeps, "fleetHome" | "platform">): boolean;
|
|
147
151
|
export declare function controlFleetLocalBot(agentUid: string, action: FleetLocalServiceAction, deps?: FleetLocalControlDeps): Record<string, unknown>;
|
|
148
152
|
export declare function exportFleetLocalMachineCredential(agentUid: string, deps?: FleetLocalControlDeps): BotMachineCreds;
|
|
149
153
|
export declare function fleetLocalPromotionRuntime(agentUid: string, deps?: FleetLocalControlDeps): LocalBotPromotionRuntime;
|
|
150
154
|
export declare function removeFleetLocalBot(agentUid: string, deps?: FleetLocalControlDeps): FleetLocalRemovalResult;
|
|
151
155
|
export declare function authenticateFleetLocalBot(input: FleetLocalAuthInput, deps?: FleetLocalControlDeps): FleetLocalAuthResult;
|
|
152
|
-
export declare function writeFleetLocalProfile(input: FleetLocalProfileInput, deps?:
|
|
156
|
+
export declare function writeFleetLocalProfile(input: FleetLocalProfileInput, deps?: FleetLocalProfileDeps): string;
|
|
153
157
|
/** The runtime's inbox plugin sends the intro and runs the kickoff once, then stamps this file. */
|
|
154
158
|
export declare function writeFleetLocalFirstStart(profileDir: string, firstStart: {
|
|
155
159
|
intro?: string;
|
|
@@ -167,7 +171,7 @@ export declare function refreshFleetLocalInstructions(agentUid: string, systemPr
|
|
|
167
171
|
/** Moves a fresh machine credential into the bot's secure store and deletes the file. */
|
|
168
172
|
export declare function importFleetLocalMachineCredential(agentUid: string, machineCredentials: string, deps?: FleetLocalControlDeps): void;
|
|
169
173
|
export declare function bootstrapFleetLocalBot(input: FleetLocalProfileInput & {
|
|
170
|
-
machineCredentials
|
|
174
|
+
machineCredentials?: string;
|
|
171
175
|
}, deps?: FleetLocalBootstrapDeps): Promise<FleetLocalBootstrapResult>;
|
|
172
176
|
export {};
|
|
173
177
|
//# sourceMappingURL=fleet-local.d.ts.map
|
|
@@ -36,18 +36,18 @@ export function fleetProviderNeedsSignIn(provider) {
|
|
|
36
36
|
}
|
|
37
37
|
export const HQ_FLEET_LOCAL_RELEASE = {
|
|
38
38
|
repository: "indigoai-us/hq-fleet-local",
|
|
39
|
-
tag: "v0.4.
|
|
40
|
-
version: "0.4.
|
|
41
|
-
artifact: "hq-fleet-local-0.4.
|
|
42
|
-
artifactSha256: "
|
|
39
|
+
tag: "v0.4.15",
|
|
40
|
+
version: "0.4.15",
|
|
41
|
+
artifact: "hq-fleet-local-0.4.15.zip",
|
|
42
|
+
artifactSha256: "0f7994047e3348d63bc3838f68e3474192e626082eea678e280f7a9308ce5a1e",
|
|
43
43
|
runtimeArtifact: "hq-fleet-runtime-abccac13bd9e.tar",
|
|
44
44
|
runtimeArtifactSha256: "29bcfe718ad7fbd3636afd00623772f2a25bc84c4f6f10d8d57f38e549d528d5",
|
|
45
|
-
manifestSha256: "
|
|
46
|
-
signatureSha256: "
|
|
45
|
+
manifestSha256: "0d8a7970e99dc33ed757b9168d15a484c7db617f1815297ebe9c5a0c42505792",
|
|
46
|
+
signatureSha256: "a6c2c1245555ea2c64b65c988e73ce74b7ab196d46ec8d83110efac4dd81391b",
|
|
47
47
|
runtimeCommit: "abccac13bd9ea593b24c8cd9c0ba28d5c6050cc9",
|
|
48
48
|
};
|
|
49
49
|
export const HQ_FLEET_LOCAL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
50
|
-
|
|
50
|
+
MCowBQYDK2VwAyEAwi1nsHS34c3m1k/hvuqnk+9nEuv5qCHh7iFB9BN6iMY=
|
|
51
51
|
-----END PUBLIC KEY-----
|
|
52
52
|
`;
|
|
53
53
|
function digest(value) {
|
|
@@ -322,14 +322,83 @@ export async function installPinnedFleetLocalDistribution(deps = {}) {
|
|
|
322
322
|
engine: engineMetadata(release),
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
|
+
function profileName(agentUid) {
|
|
326
|
+
return agentUid.toLowerCase();
|
|
327
|
+
}
|
|
325
328
|
function profileRoot(agentUid, root) {
|
|
326
|
-
|
|
329
|
+
const profiles = path.join(root, "profiles");
|
|
330
|
+
const canonicalName = profileName(agentUid);
|
|
331
|
+
const canonical = path.join(profiles, canonicalName);
|
|
332
|
+
if (fs.existsSync(canonical))
|
|
333
|
+
return canonical;
|
|
334
|
+
try {
|
|
335
|
+
const legacy = fs.readdirSync(profiles, { withFileTypes: true })
|
|
336
|
+
.find((entry) => entry.isDirectory() && entry.name.toLowerCase() === canonicalName);
|
|
337
|
+
return legacy ? path.join(profiles, legacy.name) : canonical;
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
return canonical;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function adoptLegacyProfileDirectory(agentUid, root) {
|
|
344
|
+
const profiles = path.join(root, "profiles");
|
|
345
|
+
const canonicalName = profileName(agentUid);
|
|
346
|
+
fs.mkdirSync(profiles, { recursive: true, mode: 0o700 });
|
|
347
|
+
const matches = fs.readdirSync(profiles, { withFileTypes: true })
|
|
348
|
+
.filter((entry) => entry.isDirectory() && entry.name.toLowerCase() === canonicalName)
|
|
349
|
+
.map((entry) => entry.name);
|
|
350
|
+
if (matches.length > 1) {
|
|
351
|
+
throw expectedError(`HQ Fleet has conflicting profile directories for ${agentUid}.`);
|
|
352
|
+
}
|
|
353
|
+
const existing = matches[0];
|
|
354
|
+
const canonical = path.join(profiles, canonicalName);
|
|
355
|
+
if (!existing || existing === canonicalName)
|
|
356
|
+
return canonical;
|
|
357
|
+
const source = path.join(profiles, existing);
|
|
358
|
+
const temporary = path.join(profiles, `.adopt-${canonicalName}-${process.pid}-${crypto.randomUUID()}`);
|
|
359
|
+
fs.renameSync(source, temporary);
|
|
360
|
+
try {
|
|
361
|
+
fs.renameSync(temporary, canonical);
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
fs.renameSync(temporary, source);
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
return canonical;
|
|
327
368
|
}
|
|
328
369
|
function venvExecutable(runtimeDir, name, platform) {
|
|
329
370
|
return platform === "win32"
|
|
330
371
|
? path.join(runtimeDir, "Scripts", `${name}.exe`)
|
|
331
372
|
: path.join(runtimeDir, "bin", name);
|
|
332
373
|
}
|
|
374
|
+
function sharedRuntimeFromMarker(profileDir, root) {
|
|
375
|
+
try {
|
|
376
|
+
const marker = JSON.parse(fs.readFileSync(path.join(profileDir, "bootstrap.json"), "utf8"));
|
|
377
|
+
if (marker.schemaVersion !== 2 || typeof marker.runtimeId !== "string" || !/^[a-f0-9]{64}$/.test(marker.runtimeId))
|
|
378
|
+
return null;
|
|
379
|
+
const sharedRoot = path.join(root, "runtimes", marker.runtimeId);
|
|
380
|
+
return {
|
|
381
|
+
id: marker.runtimeId,
|
|
382
|
+
root: sharedRoot,
|
|
383
|
+
runtimeDir: path.join(sharedRoot, "runtime"),
|
|
384
|
+
sourcesDir: path.join(sharedRoot, "sources"),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function hasEmbeddedRuntime(profileDir, platform) {
|
|
392
|
+
const runtimeDir = path.join(profileDir, "runtime");
|
|
393
|
+
try {
|
|
394
|
+
if (fs.lstatSync(runtimeDir).isSymbolicLink())
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
return ["hq-fleet", "hq-fleet-local"].some((name) => fs.existsSync(venvExecutable(runtimeDir, name, platform)));
|
|
401
|
+
}
|
|
333
402
|
function fleetLocalExecutables(agentUid, deps) {
|
|
334
403
|
if (!/^agt_[A-Za-z0-9_-]+$/.test(agentUid)) {
|
|
335
404
|
throw expectedError(`Cannot use an HQ Fleet profile for invalid bot id ${agentUid}.`);
|
|
@@ -337,14 +406,16 @@ function fleetLocalExecutables(agentUid, deps) {
|
|
|
337
406
|
const root = deps.fleetHome ?? fleetHome();
|
|
338
407
|
const platform = deps.platform ?? process.platform;
|
|
339
408
|
const profileDir = profileRoot(agentUid, root);
|
|
340
|
-
const
|
|
409
|
+
const shared = sharedRuntimeFromMarker(profileDir, root);
|
|
410
|
+
const runtimeDir = shared?.runtimeDir ?? path.join(profileDir, "runtime");
|
|
411
|
+
const sourcesDir = shared?.sourcesDir ?? path.join(profileDir, "sources");
|
|
341
412
|
const profile = path.join(profileDir, "profile.json");
|
|
342
413
|
const runtime = venvExecutable(runtimeDir, "hq-fleet", platform);
|
|
343
414
|
const helper = venvExecutable(runtimeDir, "hq-fleet-local", platform);
|
|
344
415
|
if (![profile, runtime, helper].every((item) => fs.existsSync(item))) {
|
|
345
416
|
throw expectedError(`HQ Fleet Local is not fully installed for ${agentUid}.`);
|
|
346
417
|
}
|
|
347
|
-
return { profileDir, profile, runtime, helper };
|
|
418
|
+
return { profileDir, profile, runtime, helper, runtimeDir, sourcesDir };
|
|
348
419
|
}
|
|
349
420
|
function runJson(run, executable, args, options, label) {
|
|
350
421
|
let output;
|
|
@@ -377,10 +448,39 @@ export function fleetLocalGatewayPid(agentUid, deps = {}) {
|
|
|
377
448
|
return null;
|
|
378
449
|
}
|
|
379
450
|
}
|
|
451
|
+
export function fleetLocalProfileNeedsAdoption(agentUid, deps = {}) {
|
|
452
|
+
if (!/^agt_[A-Za-z0-9_-]+$/.test(agentUid))
|
|
453
|
+
return true;
|
|
454
|
+
const root = deps.fleetHome ?? fleetHome();
|
|
455
|
+
const profiles = path.join(root, "profiles");
|
|
456
|
+
const canonicalName = profileName(agentUid);
|
|
457
|
+
let entries;
|
|
458
|
+
try {
|
|
459
|
+
entries = fs.readdirSync(profiles);
|
|
460
|
+
}
|
|
461
|
+
catch {
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
if (!entries.includes(canonicalName))
|
|
465
|
+
return true;
|
|
466
|
+
const profileDir = path.join(profiles, canonicalName);
|
|
467
|
+
const shared = sharedRuntimeFromMarker(profileDir, root);
|
|
468
|
+
if (!shared)
|
|
469
|
+
return true;
|
|
470
|
+
const platform = deps.platform ?? process.platform;
|
|
471
|
+
if (!["hq-fleet", "hq-fleet-local", "python"].every((name) => fs.existsSync(venvExecutable(shared.runtimeDir, name, platform))))
|
|
472
|
+
return true;
|
|
473
|
+
if (hasEmbeddedRuntime(profileDir, platform) || fs.existsSync(path.join(profileDir, "sources")))
|
|
474
|
+
return true;
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
380
477
|
export function controlFleetLocalBot(agentUid, action, deps = {}) {
|
|
381
478
|
const run = deps.run ?? execFileSync;
|
|
382
479
|
const files = fleetLocalExecutables(agentUid, deps);
|
|
383
|
-
|
|
480
|
+
const result = runJson(run, files.helper, ["service", action, "--profile", files.profileDir, "--runtime", files.runtime], { stdio: ["ignore", "pipe", "pipe"] }, `service ${action}`);
|
|
481
|
+
if (action === "install" && result.ok === true)
|
|
482
|
+
removeEmbeddedRuntime(files.profileDir, deps.platform ?? process.platform);
|
|
483
|
+
return result;
|
|
384
484
|
}
|
|
385
485
|
const providerProfiles = {
|
|
386
486
|
chatgpt: {
|
|
@@ -511,14 +611,15 @@ export function removeFleetLocalBot(agentUid, deps = {}) {
|
|
|
511
611
|
const profileDir = profileRoot(agentUid, deps.fleetHome ?? fleetHome());
|
|
512
612
|
if (!fs.existsSync(profileDir))
|
|
513
613
|
return { removed: false, credentialsRemoved: 0 };
|
|
614
|
+
if (!fs.existsSync(path.join(profileDir, "profile.json"))) {
|
|
615
|
+
fs.rmSync(profileDir, { recursive: true, force: true });
|
|
616
|
+
return { removed: true, credentialsRemoved: 0 };
|
|
617
|
+
}
|
|
514
618
|
const platform = deps.platform ?? process.platform;
|
|
515
|
-
const
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
venvExecutable(runtimeDir, "hq-fleet-local", platform),
|
|
520
|
-
].every((item) => fs.existsSync(item));
|
|
521
|
-
if (partial) {
|
|
619
|
+
const legacyRuntime = path.join(profileDir, "runtime");
|
|
620
|
+
const shared = sharedRuntimeFromMarker(profileDir, deps.fleetHome ?? fleetHome());
|
|
621
|
+
const installedRuntime = shared?.runtimeDir ?? legacyRuntime;
|
|
622
|
+
if (!["hq-fleet", "hq-fleet-local"].every((name) => fs.existsSync(venvExecutable(installedRuntime, name, platform)))) {
|
|
522
623
|
fs.rmSync(profileDir, { recursive: true, force: true });
|
|
523
624
|
return { removed: true, credentialsRemoved: 0 };
|
|
524
625
|
}
|
|
@@ -634,7 +735,9 @@ export function writeFleetLocalProfile(input, deps = {}) {
|
|
|
634
735
|
}
|
|
635
736
|
const root = deps.fleetHome ?? fleetHome();
|
|
636
737
|
const dir = profileRoot(input.agentUid, root);
|
|
637
|
-
const
|
|
738
|
+
const markerRuntime = sharedRuntimeFromMarker(dir, root);
|
|
739
|
+
const runtimeRoot = deps.runtimeRoot ?? markerRuntime?.root ?? dir;
|
|
740
|
+
const runtimeDir = path.join(runtimeRoot, "runtime");
|
|
638
741
|
const destination = path.join(dir, "profile.json");
|
|
639
742
|
const temporary = path.join(dir, `.profile-${process.pid}-${crypto.randomUUID()}`);
|
|
640
743
|
const profile = {
|
|
@@ -647,7 +750,7 @@ export function writeFleetLocalProfile(input, deps = {}) {
|
|
|
647
750
|
profileDir: path.resolve(dir),
|
|
648
751
|
runtime: { commit: input.installation.release.runtimeCommit, path: path.resolve(runtimeDir) },
|
|
649
752
|
paths: {
|
|
650
|
-
pluginSource: path.resolve(path.join(
|
|
753
|
+
pluginSource: path.resolve(path.join(runtimeRoot, "sources", "distribution", "src", "hq_fleet_local", "plugins", "hqdm")),
|
|
651
754
|
statusFile: path.resolve(path.join(input.botDir, "status.json")),
|
|
652
755
|
logsDir: path.resolve(path.join(input.botDir, "logs")),
|
|
653
756
|
},
|
|
@@ -706,9 +809,13 @@ export function scanFleetLocalInstructions(agentUid, text, deps = {}) {
|
|
|
706
809
|
throw expectedError(`Cannot use an HQ Fleet profile for invalid bot id ${agentUid}.`);
|
|
707
810
|
}
|
|
708
811
|
const run = deps.run ?? execFileSync;
|
|
709
|
-
const
|
|
710
|
-
const
|
|
711
|
-
const
|
|
812
|
+
const root = deps.fleetHome ?? fleetHome();
|
|
813
|
+
const profileDir = profileRoot(agentUid, root);
|
|
814
|
+
const shared = sharedRuntimeFromMarker(profileDir, root);
|
|
815
|
+
const runtimeDir = shared?.runtimeDir ?? path.join(profileDir, "runtime");
|
|
816
|
+
const sourcesDir = shared?.sourcesDir ?? path.join(profileDir, "sources");
|
|
817
|
+
const python = venvExecutable(runtimeDir, "python", deps.platform ?? process.platform);
|
|
818
|
+
const source = path.join(sourcesDir, "runtime");
|
|
712
819
|
if (!fs.existsSync(python) || !fs.existsSync(source)) {
|
|
713
820
|
throw expectedError("HQ Fleet Local is not installed for this bot, so its instructions could not be checked.");
|
|
714
821
|
}
|
|
@@ -774,6 +881,12 @@ async function installSharedFleetRuntime(installation, root, python, platform, r
|
|
|
774
881
|
extras: ["mcp", "anthropic"],
|
|
775
882
|
})));
|
|
776
883
|
const shared = path.join(root, "runtimes", identity);
|
|
884
|
+
const descriptor = () => ({
|
|
885
|
+
id: identity,
|
|
886
|
+
root: shared,
|
|
887
|
+
runtimeDir: path.join(shared, "runtime"),
|
|
888
|
+
sourcesDir: path.join(shared, "sources"),
|
|
889
|
+
});
|
|
777
890
|
return withBotLock(identity, async () => {
|
|
778
891
|
const marker = path.join(shared, "ready.json");
|
|
779
892
|
const sources = path.join(shared, "sources");
|
|
@@ -785,7 +898,7 @@ async function installSharedFleetRuntime(installation, root, python, platform, r
|
|
|
785
898
|
if (!executables.every((name) => fs.existsSync(venvExecutable(runtimeDir, name, platform)))) {
|
|
786
899
|
throw expectedError("The shared HQ Fleet Runtime is incomplete. Reinstall it before creating another bot.");
|
|
787
900
|
}
|
|
788
|
-
return
|
|
901
|
+
return descriptor();
|
|
789
902
|
}
|
|
790
903
|
fs.rmSync(shared, { recursive: true, force: true });
|
|
791
904
|
fs.mkdirSync(distributionSource, { recursive: true, mode: 0o700 });
|
|
@@ -827,54 +940,59 @@ async function installSharedFleetRuntime(installation, root, python, platform, r
|
|
|
827
940
|
throw expectedError("HQ Fleet Local installed without its runtime executables.");
|
|
828
941
|
}
|
|
829
942
|
fs.writeFileSync(marker, `${JSON.stringify({ schemaVersion: 1, engine: installation.engine })}\n`, { mode: 0o600 });
|
|
830
|
-
return
|
|
943
|
+
return descriptor();
|
|
831
944
|
}, { root: path.join(root, "runtimes"), command: "HQ Fleet Runtime installation", waitMs: 20 * 60_000, staleMs: 2 * 60 * 60_000 });
|
|
832
945
|
}
|
|
946
|
+
function writeNativeProfileMarker(profileDir, shared, engine) {
|
|
947
|
+
const marker = path.join(profileDir, "bootstrap.json");
|
|
948
|
+
const temporary = `${marker}.${process.pid}.${crypto.randomUUID()}`;
|
|
949
|
+
fs.writeFileSync(temporary, `${JSON.stringify({ schemaVersion: 2, runtimeId: shared.id, engine }, null, 2)}\n`, { mode: 0o600 });
|
|
950
|
+
fs.renameSync(temporary, marker);
|
|
951
|
+
}
|
|
952
|
+
function removeEmbeddedRuntime(profileDir, platform = process.platform) {
|
|
953
|
+
fs.rmSync(path.join(profileDir, "sources"), { recursive: true, force: true });
|
|
954
|
+
if (hasEmbeddedRuntime(profileDir, platform))
|
|
955
|
+
fs.rmSync(path.join(profileDir, "runtime"), { recursive: true, force: true });
|
|
956
|
+
}
|
|
833
957
|
export async function bootstrapFleetLocalBot(input, deps = {}) {
|
|
834
958
|
const run = deps.run ?? execFileSync;
|
|
835
959
|
const platform = deps.platform ?? process.platform;
|
|
836
960
|
const root = deps.fleetHome ?? fleetHome();
|
|
837
961
|
const python = deps.python ?? await ensureFleetPython({ fleetHome: root, platform, run });
|
|
838
|
-
const profileDir =
|
|
839
|
-
const runtimeDir = path.join(profileDir, "runtime");
|
|
840
|
-
const marker = path.join(profileDir, "bootstrap.json");
|
|
962
|
+
const profileDir = adoptLegacyProfileDirectory(input.agentUid, root);
|
|
841
963
|
fs.mkdirSync(profileDir, { recursive: true, mode: 0o700 });
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
const target = path.join(profileDir, name);
|
|
846
|
-
fs.rmSync(target, { recursive: true, force: true });
|
|
847
|
-
fs.symlinkSync(path.join(shared, name), target, platform === "win32" ? "junction" : "dir");
|
|
848
|
-
}
|
|
849
|
-
fs.writeFileSync(marker, `${JSON.stringify({ schemaVersion: 1, engine: input.installation.engine }, null, 2)}\n`, { mode: 0o600 });
|
|
850
|
-
}
|
|
851
|
-
const { systemPrompt, ...profileInput } = input;
|
|
964
|
+
const shared = await installSharedFleetRuntime(input.installation, root, python, platform, run);
|
|
965
|
+
writeNativeProfileMarker(profileDir, shared, input.installation.engine);
|
|
966
|
+
const { systemPrompt, machineCredentials, ...profileInput } = input;
|
|
852
967
|
if (systemPrompt !== undefined)
|
|
853
968
|
refreshFleetLocalInstructions(input.agentUid, systemPrompt, { fleetHome: root, platform, run });
|
|
854
|
-
const profile = writeFleetLocalProfile(profileInput, { fleetHome: root, platform });
|
|
855
|
-
const helper = venvExecutable(runtimeDir, "hq-fleet-local", platform);
|
|
856
|
-
const runtime = venvExecutable(runtimeDir, "hq-fleet", platform);
|
|
969
|
+
const profile = writeFleetLocalProfile(profileInput, { fleetHome: root, platform, runtimeRoot: shared.root });
|
|
970
|
+
const helper = venvExecutable(shared.runtimeDir, "hq-fleet-local", platform);
|
|
971
|
+
const runtime = venvExecutable(shared.runtimeDir, "hq-fleet", platform);
|
|
857
972
|
if (!fs.existsSync(helper) || !fs.existsSync(runtime)) {
|
|
858
973
|
throw expectedError("HQ Fleet Local installed without its runtime executables.");
|
|
859
974
|
}
|
|
860
975
|
checkedRun(run, helper, ["render-profile", "--spec", profile, "--mode", "create"], { stdio: "ignore" }, "profile rendering");
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
976
|
+
if (machineCredentials) {
|
|
977
|
+
const machineValue = fs.readFileSync(machineCredentials, "utf8").trim();
|
|
978
|
+
if (!machineValue) {
|
|
979
|
+
throw expectedError(`HQ Fleet Local machine credential file is empty: ${machineCredentials}`);
|
|
980
|
+
}
|
|
981
|
+
checkedRun(run, helper, [
|
|
982
|
+
"machine-credential",
|
|
983
|
+
"import",
|
|
984
|
+
"--profile",
|
|
985
|
+
profileDir,
|
|
986
|
+
"--bot-id",
|
|
987
|
+
input.agentUid,
|
|
988
|
+
], { input: machineValue, stdio: ["pipe", "ignore", "pipe"] }, "machine credential import");
|
|
989
|
+
fs.rmSync(machineCredentials, { force: true });
|
|
864
990
|
}
|
|
865
|
-
checkedRun(run, helper, [
|
|
866
|
-
"machine-credential",
|
|
867
|
-
"import",
|
|
868
|
-
"--profile",
|
|
869
|
-
profileDir,
|
|
870
|
-
"--bot-id",
|
|
871
|
-
input.agentUid,
|
|
872
|
-
], { input: machineValue, stdio: ["pipe", "ignore", "pipe"] }, "machine credential import");
|
|
873
|
-
fs.rmSync(input.machineCredentials, { force: true });
|
|
874
991
|
checkedRun(run, helper, ["doctor-profile", "--profile", profileDir, "--runtime", runtime], { stdio: "ignore" }, "profile validation");
|
|
875
992
|
const start = deps.start !== false;
|
|
876
993
|
if (start) {
|
|
877
994
|
checkedRun(run, helper, ["service", "install", "--profile", profileDir, "--runtime", runtime], { stdio: ["ignore", 2, 2] }, "service installation");
|
|
995
|
+
removeEmbeddedRuntime(profileDir, platform);
|
|
878
996
|
}
|
|
879
997
|
return { profile, runtime, helper, running: start };
|
|
880
998
|
}
|