@rallycry/conveyor-agent 10.13.18 → 10.13.51
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/dist/{boot-YZCOIV3Q.js → boot-BZE36LT6.js} +156 -125
- package/dist/boot-BZE36LT6.js.map +1 -0
- package/dist/chunk-5OQQSDVT.js +142 -0
- package/dist/chunk-5OQQSDVT.js.map +1 -0
- package/dist/{chunk-3GDXX3OX.js → chunk-EQO7QFGN.js} +6201 -2125
- package/dist/chunk-EQO7QFGN.js.map +1 -0
- package/dist/{chunk-AGGVNADW.js → chunk-HVSPADKP.js} +59 -13
- package/dist/chunk-HVSPADKP.js.map +1 -0
- package/dist/{chunk-UZTJJD7Y.js → chunk-KCB7CSWJ.js} +43 -2
- package/dist/chunk-KCB7CSWJ.js.map +1 -0
- package/dist/{chunk-72AEN6LB.js → chunk-KZQBYSMN.js} +137 -2
- package/dist/chunk-KZQBYSMN.js.map +1 -0
- package/dist/{chunk-UDSRAHKP.js → chunk-QOJTJCYZ.js} +67 -19
- package/dist/chunk-QOJTJCYZ.js.map +1 -0
- package/dist/chunk-ULS4QPRE.js +138 -0
- package/dist/chunk-ULS4QPRE.js.map +1 -0
- package/dist/cli.js +245 -551
- package/dist/cli.js.map +1 -1
- package/dist/{client-BU4XA7CV.js → client-LRVVHTNG.js} +2 -2
- package/dist/heartbeat-worker.js +10 -12
- package/dist/heartbeat-worker.js.map +1 -1
- package/dist/index.d.ts +153 -8
- package/dist/index.js +5 -5
- package/dist/oom-watchdog-U7JERHA2.js +11 -0
- package/dist/server-PPTELJWY.js +10 -0
- package/dist/server-PPTELJWY.js.map +1 -0
- package/package.json +3 -3
- package/runtime/entrypoint.sh +5 -4
- package/dist/boot-YZCOIV3Q.js.map +0 -1
- package/dist/chunk-3GDXX3OX.js.map +0 -1
- package/dist/chunk-72AEN6LB.js.map +0 -1
- package/dist/chunk-7TQO4ZF4.js +0 -60
- package/dist/chunk-7TQO4ZF4.js.map +0 -1
- package/dist/chunk-AGGVNADW.js.map +0 -1
- package/dist/chunk-UDSRAHKP.js.map +0 -1
- package/dist/chunk-UZTJJD7Y.js.map +0 -1
- package/dist/server-BXAFMYDM.js +0 -9
- /package/dist/{client-BU4XA7CV.js.map → client-LRVVHTNG.js.map} +0 -0
- /package/dist/{server-BXAFMYDM.js.map → oom-watchdog-U7JERHA2.js.map} +0 -0
|
@@ -7,22 +7,26 @@ import {
|
|
|
7
7
|
defaultGit,
|
|
8
8
|
ensureDir,
|
|
9
9
|
readAgentVersion,
|
|
10
|
-
redactToken
|
|
11
|
-
|
|
10
|
+
redactToken,
|
|
11
|
+
reportBootMilestone
|
|
12
|
+
} from "./chunk-KCB7CSWJ.js";
|
|
12
13
|
import {
|
|
13
14
|
workbenchPort
|
|
14
15
|
} from "./chunk-4VUQ2NPF.js";
|
|
15
16
|
import {
|
|
16
17
|
startWorkbenchServer
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-HVSPADKP.js";
|
|
19
|
+
import "./chunk-KZQBYSMN.js";
|
|
19
20
|
import {
|
|
20
21
|
DEFAULT_WORKBENCH_PORT
|
|
21
22
|
} from "./chunk-JIGG755T.js";
|
|
23
|
+
import {
|
|
24
|
+
oomWatchdogOptionsFromEnv
|
|
25
|
+
} from "./chunk-ULS4QPRE.js";
|
|
22
26
|
|
|
23
27
|
// src/boot/index.ts
|
|
24
28
|
import { spawn } from "child_process";
|
|
25
|
-
import { statSync as
|
|
29
|
+
import { statSync as statSync4 } from "fs";
|
|
26
30
|
import { hostname as osHostname } from "os";
|
|
27
31
|
|
|
28
32
|
// src/boot/bundle.ts
|
|
@@ -262,96 +266,17 @@ async function pollBootstrapBundle(apiUrl, token, deps) {
|
|
|
262
266
|
}
|
|
263
267
|
}
|
|
264
268
|
|
|
265
|
-
// src/boot/
|
|
269
|
+
// src/boot/exec.ts
|
|
266
270
|
import { execFile } from "child_process";
|
|
267
271
|
import { promisify } from "util";
|
|
268
|
-
var AGENT_PACKAGE = "@rallycry/conveyor-agent";
|
|
269
|
-
var NPM_VIEW_TIMEOUT_MS = 3e3;
|
|
270
|
-
var NPM_INSTALL_TIMEOUT_MS = 12e4;
|
|
271
|
-
var NPM_CACHE_DIR = "/tmp/npm-cache";
|
|
272
|
-
var NPM_REGISTRY_ARG = "--@rallycry:registry=https://registry.npmjs.org/";
|
|
273
|
-
var SEMVER_RE = /^\d+\.\d+\.\d+([-+][A-Za-z0-9.-]+)?$/;
|
|
274
|
-
function isValidSemver(value) {
|
|
275
|
-
return SEMVER_RE.test(value);
|
|
276
|
-
}
|
|
277
|
-
function isStrictlyNewer(candidate, installed) {
|
|
278
|
-
const num = (v) => (v.split(/[-+]/)[0] ?? "").split(".").map((p) => Number(p));
|
|
279
|
-
const [a, b] = [num(candidate), num(installed)];
|
|
280
|
-
for (let i = 0; i < 3; i++) {
|
|
281
|
-
const av = a[i] ?? 0;
|
|
282
|
-
const bv = b[i] ?? 0;
|
|
283
|
-
if (av !== bv) return av > bv;
|
|
284
|
-
}
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
272
|
var execFileAsync = promisify(execFile);
|
|
288
273
|
function defaultExec(cmd, args, opts) {
|
|
289
274
|
return execFileAsync(cmd, args, { timeout: opts.timeoutMs });
|
|
290
275
|
}
|
|
291
|
-
async function runPreflightUpdate(deps) {
|
|
292
|
-
let latest = "";
|
|
293
|
-
try {
|
|
294
|
-
const { stdout } = await deps.exec(
|
|
295
|
-
"npm",
|
|
296
|
-
["view", "--cache", NPM_CACHE_DIR, NPM_REGISTRY_ARG, AGENT_PACKAGE, "version"],
|
|
297
|
-
{ timeoutMs: NPM_VIEW_TIMEOUT_MS }
|
|
298
|
-
);
|
|
299
|
-
latest = stdout.replace(/\s+/g, "");
|
|
300
|
-
} catch (err) {
|
|
301
|
-
deps.log.warn(
|
|
302
|
-
`[boot] WARN preflight npm view failed (${err instanceof Error ? err.message : err}); keeping baked version`
|
|
303
|
-
);
|
|
304
|
-
return "skipped";
|
|
305
|
-
}
|
|
306
|
-
if (!isValidSemver(latest)) {
|
|
307
|
-
deps.log.warn(
|
|
308
|
-
`[boot] WARN preflight got non-semver '${latest}' from npm; keeping baked version`
|
|
309
|
-
);
|
|
310
|
-
return "skipped";
|
|
311
|
-
}
|
|
312
|
-
let installed = "";
|
|
313
|
-
try {
|
|
314
|
-
installed = (await deps.installedVersion()).trim();
|
|
315
|
-
} catch (err) {
|
|
316
|
-
deps.log.warn(
|
|
317
|
-
`[boot] WARN preflight installed-version lookup failed (${err instanceof Error ? err.message : err}); keeping baked version`
|
|
318
|
-
);
|
|
319
|
-
return "skipped";
|
|
320
|
-
}
|
|
321
|
-
if (!isValidSemver(installed) || isStrictlyNewer(latest, installed)) {
|
|
322
|
-
deps.log.info(
|
|
323
|
-
`[boot] preflight updating ${AGENT_PACKAGE} ${installed || "unknown"} -> ${latest}`
|
|
324
|
-
);
|
|
325
|
-
try {
|
|
326
|
-
await deps.exec(
|
|
327
|
-
"sudo",
|
|
328
|
-
[
|
|
329
|
-
"npm",
|
|
330
|
-
"install",
|
|
331
|
-
"-g",
|
|
332
|
-
"--cache",
|
|
333
|
-
NPM_CACHE_DIR,
|
|
334
|
-
"--silent",
|
|
335
|
-
`${AGENT_PACKAGE}@${latest}`
|
|
336
|
-
],
|
|
337
|
-
{ timeoutMs: NPM_INSTALL_TIMEOUT_MS }
|
|
338
|
-
);
|
|
339
|
-
await deps.exec("sudo", ["rm", "-rf", NPM_CACHE_DIR], { timeoutMs: NPM_VIEW_TIMEOUT_MS }).catch(() => void 0);
|
|
340
|
-
return "updated";
|
|
341
|
-
} catch (err) {
|
|
342
|
-
deps.log.warn(
|
|
343
|
-
`[boot] WARN preflight install failed (${err instanceof Error ? err.message : err}); keeping baked version`
|
|
344
|
-
);
|
|
345
|
-
return "skipped";
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
deps.log.info(`[boot] preflight agent ${installed} is current (registry ${latest})`);
|
|
349
|
-
return "current";
|
|
350
|
-
}
|
|
351
276
|
|
|
352
277
|
// src/boot/supervisor.ts
|
|
353
278
|
import { spawn as spawnChildProcess } from "child_process";
|
|
354
|
-
import { appendFileSync as appendFileSync2, writeFileSync } from "fs";
|
|
279
|
+
import { appendFileSync as appendFileSync2, statSync, writeFileSync } from "fs";
|
|
355
280
|
import { join } from "path";
|
|
356
281
|
|
|
357
282
|
// src/boot/crash-report.ts
|
|
@@ -378,6 +303,7 @@ async function reportAgentCrash(apiUrl, bootstrapToken, report, fetchFn = fetch)
|
|
|
378
303
|
// src/boot/supervisor.ts
|
|
379
304
|
var AGENT_CRASH_MAX = 3;
|
|
380
305
|
var AGENT_LOG_PATH = "/tmp/claudespace-agent.log";
|
|
306
|
+
var AGENT_LOG_MAX_BYTES = 16 * 1024 * 1024;
|
|
381
307
|
var LAUNCH_MARKER_NAME = "conveyor-agent-launching";
|
|
382
308
|
var RESTARTING_MARKER_NAME = "conveyor-agent-restarting";
|
|
383
309
|
var LAUNCH_MARKER = `/tmp/${LAUNCH_MARKER_NAME}`;
|
|
@@ -394,14 +320,31 @@ function touchMarker(path, log) {
|
|
|
394
320
|
);
|
|
395
321
|
}
|
|
396
322
|
}
|
|
397
|
-
function
|
|
398
|
-
|
|
399
|
-
|
|
323
|
+
function createLogAppender(path, maxBytes) {
|
|
324
|
+
let size = 0;
|
|
325
|
+
try {
|
|
326
|
+
size = statSync(path).size;
|
|
327
|
+
} catch {
|
|
328
|
+
size = 0;
|
|
329
|
+
}
|
|
330
|
+
return (chunk) => {
|
|
400
331
|
try {
|
|
401
|
-
|
|
332
|
+
if (size + chunk.length > maxBytes) {
|
|
333
|
+
writeFileSync(path, chunk);
|
|
334
|
+
size = chunk.length;
|
|
335
|
+
} else {
|
|
336
|
+
appendFileSync2(path, chunk);
|
|
337
|
+
size += chunk.length;
|
|
338
|
+
}
|
|
402
339
|
} catch {
|
|
403
340
|
}
|
|
404
341
|
};
|
|
342
|
+
}
|
|
343
|
+
function teeChildOutput(child, appendLog) {
|
|
344
|
+
const onData = (chunk) => {
|
|
345
|
+
process.stdout.write(chunk);
|
|
346
|
+
appendLog(chunk);
|
|
347
|
+
};
|
|
405
348
|
child.stdout?.on("data", onData);
|
|
406
349
|
child.stderr?.on("data", onData);
|
|
407
350
|
}
|
|
@@ -475,12 +418,13 @@ async function superviseRunner(opts) {
|
|
|
475
418
|
const launchMarkerPath = join(markerDir, LAUNCH_MARKER_NAME);
|
|
476
419
|
const restartingMarkerPath = join(markerDir, RESTARTING_MARKER_NAME);
|
|
477
420
|
touchMarker(launchMarkerPath, opts.log);
|
|
421
|
+
const appendLog = createLogAppender(AGENT_LOG_PATH, AGENT_LOG_MAX_BYTES);
|
|
478
422
|
let attempt = 0;
|
|
479
423
|
while (true) {
|
|
480
424
|
attempt++;
|
|
481
425
|
opts.log.info("[boot] Launching agent...");
|
|
482
426
|
const child = spawnAgent(spawnFn, opts);
|
|
483
|
-
teeChildOutput(child);
|
|
427
|
+
teeChildOutput(child, appendLog);
|
|
484
428
|
const exitPromise = waitForExit(child);
|
|
485
429
|
const winner = await Promise.race([
|
|
486
430
|
exitPromise.then((code) => ({ type: "exit", code })),
|
|
@@ -517,11 +461,13 @@ async function superviseRunner(opts) {
|
|
|
517
461
|
import {
|
|
518
462
|
chmodSync,
|
|
519
463
|
copyFileSync,
|
|
464
|
+
existsSync,
|
|
520
465
|
lstatSync,
|
|
521
466
|
mkdirSync,
|
|
522
467
|
readFileSync,
|
|
468
|
+
readdirSync,
|
|
523
469
|
rmSync,
|
|
524
|
-
statSync,
|
|
470
|
+
statSync as statSync2,
|
|
525
471
|
symlinkSync,
|
|
526
472
|
writeFileSync as writeFileSync2
|
|
527
473
|
} from "fs";
|
|
@@ -575,7 +521,7 @@ function seedClaudeJson(targetPath) {
|
|
|
575
521
|
}
|
|
576
522
|
function isDir(path) {
|
|
577
523
|
try {
|
|
578
|
-
return
|
|
524
|
+
return statSync2(path).isDirectory();
|
|
579
525
|
} catch {
|
|
580
526
|
return false;
|
|
581
527
|
}
|
|
@@ -609,6 +555,29 @@ function wireCredentials(opts) {
|
|
|
609
555
|
safely(log, "repoint credentials symlink", () => relink(podLocal, shared));
|
|
610
556
|
safely(log, "chmod pod-local credentials", () => chmodSync(podLocal, 384));
|
|
611
557
|
}
|
|
558
|
+
var AGENT_MEMORY_PROJECT_DIR = "-workspaces-repo";
|
|
559
|
+
function migrateMemories(from, to, log) {
|
|
560
|
+
let entries;
|
|
561
|
+
try {
|
|
562
|
+
entries = readdirSync(from);
|
|
563
|
+
} catch {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
for (const entry of entries) {
|
|
567
|
+
const target = join2(to, entry);
|
|
568
|
+
if (existsSync(target)) continue;
|
|
569
|
+
safely(log, `migrate memory ${entry}`, () => copyFileSync(join2(from, entry), target));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function wireSharedMemory(root, userHomeMount, projectId, log) {
|
|
573
|
+
const shared = join2(userHomeMount, "users", "_shared", "memory", projectId);
|
|
574
|
+
const link = join2(root, ".claude", "projects", AGENT_MEMORY_PROJECT_DIR, "memory");
|
|
575
|
+
safely(log, "mkdir shared memory dir", () => mkdirSync(shared, { recursive: true }));
|
|
576
|
+
safely(log, "migrate per-user memories", () => {
|
|
577
|
+
if (existsSync(link) && !lstatSync(link).isSymbolicLink()) migrateMemories(link, shared, log);
|
|
578
|
+
});
|
|
579
|
+
safely(log, "wire shared memory symlink", () => relink(shared, link));
|
|
580
|
+
}
|
|
612
581
|
function wireMountedUserHome(opts) {
|
|
613
582
|
const { home, userHomeMount, userId, projectId, sharedDir, log } = opts;
|
|
614
583
|
const root = join2(userHomeMount, "users", userId, projectId);
|
|
@@ -626,6 +595,7 @@ function wireMountedUserHome(opts) {
|
|
|
626
595
|
rmSync(join2(home, ".claude.json"), { recursive: true, force: true });
|
|
627
596
|
seedClaudeJson(join2(home, ".claude.json"));
|
|
628
597
|
});
|
|
598
|
+
wireSharedMemory(root, userHomeMount, projectId, log);
|
|
629
599
|
wireCredentials({ home, root, sharedDir, log });
|
|
630
600
|
safely(log, "mkdir opencode root", () => {
|
|
631
601
|
mkdirSync(join2(root, ".local", "share", "opencode"), { recursive: true });
|
|
@@ -659,6 +629,11 @@ function wireNoMountUserHome(opts) {
|
|
|
659
629
|
}
|
|
660
630
|
function wireUserHome(opts) {
|
|
661
631
|
const { home, userHomeMount, userId, projectId, sharedDir, log } = opts;
|
|
632
|
+
safely(
|
|
633
|
+
log,
|
|
634
|
+
"mkdir agent scratch dir",
|
|
635
|
+
() => mkdirSync(opts.scratchDir ?? "/tmp/claude-cmd", { recursive: true })
|
|
636
|
+
);
|
|
662
637
|
if (userId && projectId && isDir(userHomeMount)) {
|
|
663
638
|
wireMountedUserHome({ home, userHomeMount, userId, projectId, sharedDir, log });
|
|
664
639
|
} else {
|
|
@@ -696,15 +671,27 @@ async function reclaimHomeOwnership(home, exec, log) {
|
|
|
696
671
|
}
|
|
697
672
|
|
|
698
673
|
// src/boot/sshd.ts
|
|
699
|
-
import { chmodSync as chmodSync2, closeSync, existsSync, mkdirSync as mkdirSync2, openSync } from "fs";
|
|
674
|
+
import { chmodSync as chmodSync2, closeSync, copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync } from "fs";
|
|
700
675
|
import { join as join3 } from "path";
|
|
676
|
+
function persistedAuthorizedKeys() {
|
|
677
|
+
return join3(
|
|
678
|
+
process.env.CONVEYOR_SHARED_DIR || "/var/run/conveyor-workbench",
|
|
679
|
+
"ssh",
|
|
680
|
+
"authorized_keys"
|
|
681
|
+
);
|
|
682
|
+
}
|
|
701
683
|
async function startWorkspaceSshd(exec, log, port = process.env.CONVEYOR_WORKSPACE_SSH_PORT || "2222", home = "/home/conveyor") {
|
|
702
684
|
try {
|
|
703
685
|
const sshDir = join3(home, ".ssh");
|
|
704
686
|
mkdirSync2(sshDir, { recursive: true });
|
|
705
687
|
chmodSync2(sshDir, 448);
|
|
706
688
|
const authorizedKeys = join3(sshDir, "authorized_keys");
|
|
707
|
-
|
|
689
|
+
const persisted = persistedAuthorizedKeys();
|
|
690
|
+
if (existsSync2(persisted)) {
|
|
691
|
+
copyFileSync2(persisted, authorizedKeys);
|
|
692
|
+
} else if (!existsSync2(authorizedKeys)) {
|
|
693
|
+
closeSync(openSync(authorizedKeys, "a"));
|
|
694
|
+
}
|
|
708
695
|
chmodSync2(authorizedKeys, 384);
|
|
709
696
|
} catch (err) {
|
|
710
697
|
log.warn(
|
|
@@ -712,7 +699,7 @@ async function startWorkspaceSshd(exec, log, port = process.env.CONVEYOR_WORKSPA
|
|
|
712
699
|
);
|
|
713
700
|
return;
|
|
714
701
|
}
|
|
715
|
-
if (!
|
|
702
|
+
if (!existsSync2("/usr/sbin/sshd")) {
|
|
716
703
|
log.warn("[boot] WARN: workspace SSHD unavailable");
|
|
717
704
|
return;
|
|
718
705
|
}
|
|
@@ -729,12 +716,15 @@ async function startWorkspaceSshd(exec, log, port = process.env.CONVEYOR_WORKSPA
|
|
|
729
716
|
|
|
730
717
|
// src/boot/workspace-extras.ts
|
|
731
718
|
import {
|
|
732
|
-
|
|
719
|
+
appendFileSync as appendFileSync3,
|
|
720
|
+
existsSync as existsSync3,
|
|
733
721
|
lstatSync as lstatSync2,
|
|
734
722
|
mkdirSync as mkdirSync3,
|
|
735
|
-
readdirSync,
|
|
723
|
+
readdirSync as readdirSync2,
|
|
724
|
+
readFileSync as readFileSync2,
|
|
725
|
+
readlinkSync,
|
|
736
726
|
rmSync as rmSync2,
|
|
737
|
-
statSync as
|
|
727
|
+
statSync as statSync3,
|
|
738
728
|
symlinkSync as symlinkSync2
|
|
739
729
|
} from "fs";
|
|
740
730
|
import { join as join4 } from "path";
|
|
@@ -743,7 +733,7 @@ function errText(err) {
|
|
|
743
733
|
}
|
|
744
734
|
function isDir2(path) {
|
|
745
735
|
try {
|
|
746
|
-
return
|
|
736
|
+
return statSync3(path).isDirectory();
|
|
747
737
|
} catch {
|
|
748
738
|
return false;
|
|
749
739
|
}
|
|
@@ -769,7 +759,7 @@ function bindGraphifyBundle(workspace, graphifyEnv, log) {
|
|
|
769
759
|
const sourceDir = graphifyEnv.CONVEYOR_GRAPHIFY_DIR;
|
|
770
760
|
const graphFile = graphifyEnv.CONVEYOR_GRAPHIFY_GRAPH;
|
|
771
761
|
if (!slug || !sourceDir || !graphFile) return;
|
|
772
|
-
if (!
|
|
762
|
+
if (!existsSync3(graphFile)) {
|
|
773
763
|
log.info(`[boot] Graphify bundle not found for '${slug}' at ${sourceDir}`);
|
|
774
764
|
return;
|
|
775
765
|
}
|
|
@@ -783,8 +773,8 @@ function bindGraphifyBundle(workspace, graphifyEnv, log) {
|
|
|
783
773
|
for (const rel of GRAPHIFY_BUNDLE_FILES) {
|
|
784
774
|
const source = join4(sourceDir, rel);
|
|
785
775
|
const target = join4(targetDir, rel);
|
|
786
|
-
if (!
|
|
787
|
-
if (
|
|
776
|
+
if (!existsSync3(source)) continue;
|
|
777
|
+
if (existsSync3(target) || isSymlink(target)) continue;
|
|
788
778
|
try {
|
|
789
779
|
symlinkSync2(source, target);
|
|
790
780
|
} catch {
|
|
@@ -794,7 +784,7 @@ function bindGraphifyBundle(workspace, graphifyEnv, log) {
|
|
|
794
784
|
}
|
|
795
785
|
async function ensureGrimoireSubmodule(workspace, githubToken, git, log) {
|
|
796
786
|
try {
|
|
797
|
-
if (!
|
|
787
|
+
if (!existsSync3(join4(workspace, ".gitmodules"))) return;
|
|
798
788
|
let paths = "";
|
|
799
789
|
try {
|
|
800
790
|
({ stdout: paths } = await git(
|
|
@@ -832,6 +822,30 @@ async function ensureGrimoireSubmodule(workspace, githubToken, git, log) {
|
|
|
832
822
|
log.warn(`[boot] WARN: grimoire submodule check failed: ${errText(err)}`);
|
|
833
823
|
}
|
|
834
824
|
}
|
|
825
|
+
function excludeLinkedSkills(workspace, names, log) {
|
|
826
|
+
if (names.length === 0) return;
|
|
827
|
+
const infoDir = join4(workspace, ".git", "info");
|
|
828
|
+
if (!isDir2(join4(workspace, ".git"))) return;
|
|
829
|
+
try {
|
|
830
|
+
mkdirSync3(infoDir, { recursive: true });
|
|
831
|
+
const excludePath = join4(infoDir, "exclude");
|
|
832
|
+
const existing = existsSync3(excludePath) ? readFileSync2(excludePath, "utf8") : "";
|
|
833
|
+
const missing = names.map((name) => `.claude/skills/${name}`).filter((line) => !existing.split("\n").includes(line));
|
|
834
|
+
if (missing.length === 0) return;
|
|
835
|
+
const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
836
|
+
appendFileSync3(excludePath, `${prefix}${missing.join("\n")}
|
|
837
|
+
`);
|
|
838
|
+
} catch (err) {
|
|
839
|
+
log.warn(`[boot] WARN: unable to exclude grimoire skill links: ${errText(err)}`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function symlinkTargetsGrimoire(path) {
|
|
843
|
+
try {
|
|
844
|
+
return readlinkSync(path).includes(join4("grimoire", "skills"));
|
|
845
|
+
} catch {
|
|
846
|
+
return false;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
835
849
|
function linkGrimoireSkills(workspace, log) {
|
|
836
850
|
const sourceDir = join4(workspace, ".claude", "grimoire", "skills");
|
|
837
851
|
const targetDir = join4(workspace, ".claude", "skills");
|
|
@@ -842,28 +856,42 @@ function linkGrimoireSkills(workspace, log) {
|
|
|
842
856
|
log.warn(`[boot] WARN: unable to create ${targetDir}; skipping grimoire skill links`);
|
|
843
857
|
return;
|
|
844
858
|
}
|
|
845
|
-
|
|
859
|
+
const linkedNames = [];
|
|
846
860
|
let names = [];
|
|
847
861
|
try {
|
|
848
|
-
names =
|
|
862
|
+
names = readdirSync2(sourceDir);
|
|
849
863
|
} catch {
|
|
850
864
|
return;
|
|
851
865
|
}
|
|
852
866
|
for (const name of names) {
|
|
853
867
|
if (!isDir2(join4(sourceDir, name))) continue;
|
|
854
868
|
const target = join4(targetDir, name);
|
|
855
|
-
if (
|
|
869
|
+
if (existsSync3(target) && !isSymlink(target)) {
|
|
856
870
|
log.warn(`[boot] WARN: ${target} exists and is not a symlink; skipping`);
|
|
857
871
|
continue;
|
|
858
872
|
}
|
|
873
|
+
if (isSymlink(target) && !symlinkTargetsGrimoire(target)) continue;
|
|
859
874
|
try {
|
|
860
875
|
rmSync2(target, { force: true });
|
|
861
876
|
symlinkSync2(join4("..", "grimoire", "skills", name), target);
|
|
862
|
-
|
|
877
|
+
linkedNames.push(name);
|
|
863
878
|
} catch {
|
|
864
879
|
}
|
|
865
880
|
}
|
|
866
|
-
|
|
881
|
+
excludeLinkedSkills(workspace, linkedNames, log);
|
|
882
|
+
log.info(`[boot] Linked ${linkedNames.length} grimoire skills into ${targetDir}`);
|
|
883
|
+
}
|
|
884
|
+
async function neutralizeGrimoirePointer(workspace, git, log) {
|
|
885
|
+
if (!existsSync3(join4(workspace, ".claude", "grimoire"))) return;
|
|
886
|
+
try {
|
|
887
|
+
await git(["update-index", "--assume-unchanged", ".claude/grimoire"], {
|
|
888
|
+
cwd: workspace,
|
|
889
|
+
timeoutMs: 1e4
|
|
890
|
+
});
|
|
891
|
+
log.info("[boot] Marked .claude/grimoire assume-unchanged (submodule pointer drift is noise)");
|
|
892
|
+
} catch (err) {
|
|
893
|
+
log.warn(`[boot] WARN: grimoire assume-unchanged failed: ${errText(err)}`);
|
|
894
|
+
}
|
|
867
895
|
}
|
|
868
896
|
function parseReferenceRepos(refsJson) {
|
|
869
897
|
let parsed;
|
|
@@ -894,6 +922,7 @@ async function runPreReadyBinds(workspace, bundle, git, log) {
|
|
|
894
922
|
bindGraphifyBundle(workspace, graphifyEnv, log);
|
|
895
923
|
await ensureGrimoireSubmodule(workspace, bundle.githubToken, git, log);
|
|
896
924
|
linkGrimoireSkills(workspace, log);
|
|
925
|
+
await neutralizeGrimoirePointer(workspace, git, log);
|
|
897
926
|
}
|
|
898
927
|
async function cloneReferenceRepos(refsJson, git, log, referencesDir = "/workspaces/references") {
|
|
899
928
|
if (!refsJson) return;
|
|
@@ -906,7 +935,7 @@ async function cloneReferenceRepos(refsJson, git, log, referencesDir = "/workspa
|
|
|
906
935
|
}
|
|
907
936
|
for (const ref of refs) {
|
|
908
937
|
const dest = join4(referencesDir, ref.slug);
|
|
909
|
-
if (
|
|
938
|
+
if (existsSync3(join4(dest, ".git"))) continue;
|
|
910
939
|
try {
|
|
911
940
|
await git(
|
|
912
941
|
[
|
|
@@ -1015,16 +1044,22 @@ async function runWorkbenchBoot(ctx, overrides = {}) {
|
|
|
1015
1044
|
const job = new GitPrepJob(deps.gitPrepDeps(ctx, bundle), {
|
|
1016
1045
|
// Order pinned by the old entrypoint-grimoire test: binds BEFORE the
|
|
1017
1046
|
// ready flip (Claude must not spawn before skills exist), references after.
|
|
1018
|
-
onReady: () =>
|
|
1047
|
+
onReady: () => {
|
|
1048
|
+
const binds = deps.bindsBeforeReady(ctx, bundle);
|
|
1049
|
+
void reportBootMilestone({ key: "repo_synced" });
|
|
1050
|
+
return binds;
|
|
1051
|
+
},
|
|
1019
1052
|
afterReady: () => deps.cloneReferences(ctx, bundle)
|
|
1020
1053
|
});
|
|
1021
1054
|
await deps.startDaemon({
|
|
1022
1055
|
port: workbenchPort() ?? DEFAULT_WORKBENCH_PORT,
|
|
1023
1056
|
token: ctx.bootstrapToken,
|
|
1024
1057
|
version: readAgentVersion() ?? "unknown",
|
|
1025
|
-
getGitStatus: () => toGitStatusFrame(job.status)
|
|
1058
|
+
getGitStatus: () => toGitStatusFrame(job.status),
|
|
1059
|
+
oomWatchdog: oomWatchdogOptionsFromEnv(ctx.log)
|
|
1026
1060
|
});
|
|
1027
1061
|
ctx.log.info("[boot] step=startDaemon listen socket up (startupProbe gate open)");
|
|
1062
|
+
void reportBootMilestone({ key: "workbench_ready" });
|
|
1028
1063
|
try {
|
|
1029
1064
|
deps.ensureWorkspaceDir(ctx);
|
|
1030
1065
|
} catch (err) {
|
|
@@ -1052,13 +1087,9 @@ function defaultBootDeps() {
|
|
|
1052
1087
|
}),
|
|
1053
1088
|
spawnFn: spawn,
|
|
1054
1089
|
exec: defaultExec,
|
|
1055
|
-
installedVersion: () => {
|
|
1056
|
-
const version = readAgentVersion();
|
|
1057
|
-
return version ? Promise.resolve(version) : Promise.reject(new Error("could not read installed agent version"));
|
|
1058
|
-
},
|
|
1059
1090
|
dirExists: (path) => {
|
|
1060
1091
|
try {
|
|
1061
|
-
return
|
|
1092
|
+
return statSync4(path).isDirectory();
|
|
1062
1093
|
} catch {
|
|
1063
1094
|
return false;
|
|
1064
1095
|
}
|
|
@@ -1080,11 +1111,13 @@ function whenAborted2(signal) {
|
|
|
1080
1111
|
});
|
|
1081
1112
|
}
|
|
1082
1113
|
function agentBootSteps(deps = defaultBootDeps(), signal = new AbortController().signal) {
|
|
1114
|
+
let reclaim;
|
|
1083
1115
|
return [
|
|
1084
1116
|
{
|
|
1085
1117
|
name: "pollBootstrap",
|
|
1086
1118
|
critical: true,
|
|
1087
1119
|
run: async (ctx) => {
|
|
1120
|
+
reclaim = reclaimHomeOwnership(HOME_DIR2, deps.exec, ctx.log).catch(() => void 0);
|
|
1088
1121
|
const bundle = await pollBootstrapBundle(ctx.apiUrl, ctx.bootstrapToken, {
|
|
1089
1122
|
fetchFn: deps.fetchFn,
|
|
1090
1123
|
sleepFn: deps.sleepFn,
|
|
@@ -1123,7 +1156,7 @@ function agentBootSteps(deps = defaultBootDeps(), signal = new AbortController()
|
|
|
1123
1156
|
critical: false,
|
|
1124
1157
|
run: async (ctx) => {
|
|
1125
1158
|
if (!ctx.bundle) return;
|
|
1126
|
-
await reclaimHomeOwnership(HOME_DIR2, deps.exec, ctx.log);
|
|
1159
|
+
await (reclaim ?? reclaimHomeOwnership(HOME_DIR2, deps.exec, ctx.log));
|
|
1127
1160
|
}
|
|
1128
1161
|
},
|
|
1129
1162
|
{
|
|
@@ -1227,11 +1260,7 @@ async function runWorkbenchRole(ctx, deps, signal) {
|
|
|
1227
1260
|
async function runBoot(argv, deps = defaultBootDeps()) {
|
|
1228
1261
|
const { log } = deps;
|
|
1229
1262
|
if (argv.includes("--preflight-update")) {
|
|
1230
|
-
|
|
1231
|
-
exec: deps.exec,
|
|
1232
|
-
installedVersion: deps.installedVersion,
|
|
1233
|
-
log
|
|
1234
|
-
});
|
|
1263
|
+
log.info("[boot] --preflight-update is a no-op (baked agent, no runtime self-update)");
|
|
1235
1264
|
return 0;
|
|
1236
1265
|
}
|
|
1237
1266
|
const role = process.env.CONVEYOR_CONTAINER_ROLE;
|
|
@@ -1256,7 +1285,9 @@ async function runBoot(argv, deps = defaultBootDeps()) {
|
|
|
1256
1285
|
hostname: deps.hostname,
|
|
1257
1286
|
log
|
|
1258
1287
|
};
|
|
1259
|
-
|
|
1288
|
+
const code = await (role === "workbench" ? runWorkbenchRole(ctx, deps, controller.signal) : runAgentRole(ctx, deps, controller.signal));
|
|
1289
|
+
controller.abort();
|
|
1290
|
+
return code;
|
|
1260
1291
|
}
|
|
1261
1292
|
export {
|
|
1262
1293
|
TOMBSTONE_MESSAGE,
|
|
@@ -1266,4 +1297,4 @@ export {
|
|
|
1266
1297
|
runBoot,
|
|
1267
1298
|
workbenchBootSteps
|
|
1268
1299
|
};
|
|
1269
|
-
//# sourceMappingURL=boot-
|
|
1300
|
+
//# sourceMappingURL=boot-BZE36LT6.js.map
|