pi-fabric 0.76.2 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/bash-worktree-add.d.ts +24 -0
- package/dist/agents/bash-worktree-add.d.ts.map +1 -0
- package/dist/agents/clone-first-worktree.d.ts +17 -0
- package/dist/agents/clone-first-worktree.d.ts.map +1 -0
- package/dist/agents/cow-clone.d.ts +8 -0
- package/dist/agents/cow-clone.d.ts.map +1 -0
- package/dist/agents/worktree-manager.d.ts.map +1 -1
- package/dist/agents/worktree-paths.d.ts +5 -0
- package/dist/agents/worktree-paths.d.ts.map +1 -0
- package/dist/chunks/{chunk-F2GKEXGI.js → chunk-4DRVOAFY.js} +271 -145
- package/dist/chunks/chunk-4DRVOAFY.js.map +7 -0
- package/dist/chunks/{chunk-BT6UELLP.js → chunk-SBHF6CVR.js} +2 -2
- package/dist/chunks/{fabric-runtime-state-VCLWTB55.js → fabric-runtime-state-H7UA3DJC.js} +188 -87
- package/dist/chunks/fabric-runtime-state-H7UA3DJC.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/providers/pi-tools-provider.d.ts.map +1 -1
- package/dist/residency/client.d.ts.map +1 -1
- package/dist/residency/host.js +2 -2
- package/dist/residency/pi-entry.js +2 -2
- package/docs/agents.md +1 -1
- package/docs/architecture.md +1 -1
- package/package.json +1 -1
- package/skills/fabric-exec/references/agents.md +3 -3
- package/dist/chunks/chunk-F2GKEXGI.js.map +0 -7
- package/dist/chunks/fabric-runtime-state-VCLWTB55.js.map +0 -7
- /package/dist/chunks/{chunk-BT6UELLP.js.map → chunk-SBHF6CVR.js.map} +0 -0
|
@@ -905,9 +905,9 @@ function appendBudgetLedger(file, entry) {
|
|
|
905
905
|
|
|
906
906
|
// src/agents/manager.ts
|
|
907
907
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
908
|
-
import
|
|
909
|
-
import
|
|
910
|
-
import
|
|
908
|
+
import fs9 from "node:fs";
|
|
909
|
+
import os3 from "node:os";
|
|
910
|
+
import path10 from "node:path";
|
|
911
911
|
import { fileURLToPath } from "node:url";
|
|
912
912
|
|
|
913
913
|
// src/agents/semaphore.ts
|
|
@@ -1267,13 +1267,137 @@ var TmuxTransport = class {
|
|
|
1267
1267
|
};
|
|
1268
1268
|
|
|
1269
1269
|
// src/agents/worktree-manager.ts
|
|
1270
|
+
import fs7 from "node:fs";
|
|
1271
|
+
import path7 from "node:path";
|
|
1272
|
+
|
|
1273
|
+
// src/agents/clone-first-worktree.ts
|
|
1274
|
+
import fs6 from "node:fs";
|
|
1275
|
+
import path6 from "node:path";
|
|
1276
|
+
|
|
1277
|
+
// src/agents/cow-clone.ts
|
|
1270
1278
|
import fs4 from "node:fs";
|
|
1271
|
-
import os2 from "node:os";
|
|
1272
1279
|
import path4 from "node:path";
|
|
1280
|
+
var CLONE_SKIP_PREFIXES = [".git", ".pi/fabric/worktrees"];
|
|
1281
|
+
var CowUnavailableError = class extends Error {
|
|
1282
|
+
constructor(message, options) {
|
|
1283
|
+
super(message, options);
|
|
1284
|
+
this.name = "CowUnavailableError";
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
var posixRel = (value) => value.replaceAll("\\", "/");
|
|
1288
|
+
var isCowUnavailable = (error) => {
|
|
1289
|
+
if (typeof error !== "object" || error === null || !("code" in error)) return false;
|
|
1290
|
+
const code = error.code;
|
|
1291
|
+
return code === "ENOTSUP" || code === "EOPNOTSUPP" || code === "EXDEV" || code === "ENOTSUPP";
|
|
1292
|
+
};
|
|
1293
|
+
var cloneEntry = async (from, to) => {
|
|
1294
|
+
try {
|
|
1295
|
+
await fs4.promises.cp(from, to, {
|
|
1296
|
+
recursive: true,
|
|
1297
|
+
verbatimSymlinks: true,
|
|
1298
|
+
force: false,
|
|
1299
|
+
mode: fs4.constants.COPYFILE_FICLONE_FORCE
|
|
1300
|
+
});
|
|
1301
|
+
} catch (error) {
|
|
1302
|
+
if (isCowUnavailable(error)) {
|
|
1303
|
+
throw new CowUnavailableError(`copy-on-write clone unavailable: ${from} -> ${to}`, {
|
|
1304
|
+
cause: error
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
throw error;
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
var skipped = (rel, prefixes) => {
|
|
1311
|
+
const value = posixRel(rel);
|
|
1312
|
+
return prefixes.some((prefix) => value === prefix || value.startsWith(`${prefix}/`));
|
|
1313
|
+
};
|
|
1314
|
+
var hasNestedSkip = (rel, prefixes) => {
|
|
1315
|
+
const value = posixRel(rel);
|
|
1316
|
+
return prefixes.some((prefix) => prefix.startsWith(`${value}/`));
|
|
1317
|
+
};
|
|
1318
|
+
var cloneLevel = async (source, dest, relBase, prefixes) => {
|
|
1319
|
+
await fs4.promises.mkdir(dest, { recursive: true });
|
|
1320
|
+
const entries = await fs4.promises.readdir(source, { withFileTypes: true });
|
|
1321
|
+
for (const entry of entries) {
|
|
1322
|
+
const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
1323
|
+
if (skipped(rel, prefixes)) continue;
|
|
1324
|
+
const from = path4.join(source, entry.name);
|
|
1325
|
+
const to = path4.join(dest, entry.name);
|
|
1326
|
+
if (entry.isDirectory() && !entry.isSymbolicLink() && hasNestedSkip(rel, prefixes)) {
|
|
1327
|
+
await cloneLevel(from, to, rel, prefixes);
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
if (!(entry.isFile() || entry.isDirectory() || entry.isSymbolicLink())) continue;
|
|
1331
|
+
await cloneEntry(from, to);
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
var cloneTree = async (source, dest, prefixes = CLONE_SKIP_PREFIXES) => {
|
|
1335
|
+
await cloneLevel(source, dest, "", prefixes);
|
|
1336
|
+
};
|
|
1337
|
+
|
|
1338
|
+
// src/agents/worktree-paths.ts
|
|
1339
|
+
import fs5 from "node:fs";
|
|
1340
|
+
import path5 from "node:path";
|
|
1341
|
+
var FABRIC_WORKTREE_SEGMENTS = [".pi", "fabric", "worktrees"];
|
|
1342
|
+
var FABRIC_WORKTREE_EXCLUDE = ".pi/fabric/worktrees/";
|
|
1343
|
+
var fabricWorktreePath = (gitRoot, id) => path5.join(gitRoot, ...FABRIC_WORKTREE_SEGMENTS, id);
|
|
1344
|
+
var isFabricWorktreePath = (worktree, id) => {
|
|
1345
|
+
const parts = worktree.split(/[\\/]/).filter(Boolean);
|
|
1346
|
+
return parts.length >= 4 && parts.at(-1) === id && parts.at(-2) === "worktrees" && parts.at(-3) === "fabric" && parts.at(-4) === ".pi";
|
|
1347
|
+
};
|
|
1348
|
+
var ensureWorktreeExclude = async (gitRoot) => {
|
|
1349
|
+
const located = await executeFile("git", ["rev-parse", "--git-path", "info/exclude"], {
|
|
1350
|
+
cwd: gitRoot,
|
|
1351
|
+
timeoutMs: 1e4
|
|
1352
|
+
});
|
|
1353
|
+
const excludePath = path5.resolve(gitRoot, located.stdout.trim());
|
|
1354
|
+
fs5.mkdirSync(path5.dirname(excludePath), { recursive: true });
|
|
1355
|
+
let current = "";
|
|
1356
|
+
try {
|
|
1357
|
+
current = fs5.readFileSync(excludePath, "utf8");
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
const code = error instanceof Error && "code" in error ? error.code : void 0;
|
|
1360
|
+
if (code !== "ENOENT") throw error;
|
|
1361
|
+
}
|
|
1362
|
+
const lines = current.split(/\r?\n/);
|
|
1363
|
+
if (lines.some((line) => line.trim() === FABRIC_WORKTREE_EXCLUDE)) return;
|
|
1364
|
+
const prefix = current.length === 0 || current.endsWith("\n") ? "" : "\n";
|
|
1365
|
+
fs5.appendFileSync(excludePath, `${prefix}${FABRIC_WORKTREE_EXCLUDE}
|
|
1366
|
+
`);
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
// src/agents/clone-first-worktree.ts
|
|
1370
|
+
var addCloneFirstWorktree = async (options) => {
|
|
1371
|
+
const dest = options.dest;
|
|
1372
|
+
if (isFabricWorktreePath(dest, path6.basename(dest))) {
|
|
1373
|
+
await ensureWorktreeExclude(options.gitRoot);
|
|
1374
|
+
}
|
|
1375
|
+
fs6.mkdirSync(path6.dirname(dest), { recursive: true });
|
|
1376
|
+
const args = ["worktree", "add", "--no-checkout"];
|
|
1377
|
+
if (options.quiet) args.push("-q");
|
|
1378
|
+
if (options.detach) args.push("--detach");
|
|
1379
|
+
if (options.branch) args.push(options.branch.flag, options.branch.name);
|
|
1380
|
+
args.push(dest);
|
|
1381
|
+
if (options.startPoint) args.push(options.startPoint);
|
|
1382
|
+
const added = await executeFile("git", args, { cwd: options.gitRoot, timeoutMs: 6e4 });
|
|
1383
|
+
let cloned = false;
|
|
1384
|
+
try {
|
|
1385
|
+
await cloneTree(options.gitRoot, dest, CLONE_SKIP_PREFIXES);
|
|
1386
|
+
cloned = true;
|
|
1387
|
+
} catch (error) {
|
|
1388
|
+
cloned = false;
|
|
1389
|
+
if (!(error instanceof CowUnavailableError) && !(error instanceof Error)) throw error;
|
|
1390
|
+
}
|
|
1391
|
+
await executeFile("git", ["reset", "--hard", "HEAD"], { cwd: dest, timeoutMs: 6e4 });
|
|
1392
|
+
await executeFile("git", ["clean", "-fd"], { cwd: dest, timeoutMs: 6e4 });
|
|
1393
|
+
return { cloned, message: added.stdout.trim() };
|
|
1394
|
+
};
|
|
1395
|
+
|
|
1396
|
+
// src/agents/worktree-manager.ts
|
|
1273
1397
|
var safeLabel = (value) => value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 30) || "agent";
|
|
1274
1398
|
var isInside = (root, target) => {
|
|
1275
|
-
const relative =
|
|
1276
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
1399
|
+
const relative = path7.relative(root, target);
|
|
1400
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path7.sep}`) && !path7.isAbsolute(relative);
|
|
1277
1401
|
};
|
|
1278
1402
|
var worktreePrefixParts = (prefix) => {
|
|
1279
1403
|
const parts = prefix.split(/[\\/]+/).filter(Boolean);
|
|
@@ -1291,27 +1415,27 @@ var WorktreeManager = class {
|
|
|
1291
1415
|
]);
|
|
1292
1416
|
const output = root.stdout.trim();
|
|
1293
1417
|
if (!output) throw new Error("Git did not return a worktree root");
|
|
1294
|
-
gitRoot =
|
|
1418
|
+
gitRoot = fs7.realpathSync(output);
|
|
1295
1419
|
sourcePrefix = prefix2.stdout.trim();
|
|
1296
1420
|
} catch {
|
|
1297
1421
|
throw new Error("Worktree isolation requires a Git repository");
|
|
1298
1422
|
}
|
|
1299
1423
|
const branch = `pi-fabric/${safeLabel(name)}-${id.slice(0, 8)}`;
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1424
|
+
const worktreePath = fabricWorktreePath(gitRoot, id);
|
|
1425
|
+
await addCloneFirstWorktree({
|
|
1426
|
+
gitRoot,
|
|
1427
|
+
dest: worktreePath,
|
|
1428
|
+
branch: { flag: "-b", name: branch },
|
|
1429
|
+
startPoint: "HEAD"
|
|
1306
1430
|
});
|
|
1307
|
-
const canonicalWorktreePath =
|
|
1431
|
+
const canonicalWorktreePath = fs7.realpathSync(worktreePath);
|
|
1308
1432
|
const prefix = preserveSourceSubdirectory ? worktreePrefixParts(sourcePrefix) : void 0;
|
|
1309
1433
|
let effectiveCwd = canonicalWorktreePath;
|
|
1310
1434
|
if (prefix && prefix.length > 0) {
|
|
1311
|
-
const candidate =
|
|
1435
|
+
const candidate = path7.resolve(canonicalWorktreePath, ...prefix);
|
|
1312
1436
|
try {
|
|
1313
|
-
const canonicalCandidate =
|
|
1314
|
-
if (
|
|
1437
|
+
const canonicalCandidate = fs7.realpathSync(candidate);
|
|
1438
|
+
if (fs7.statSync(canonicalCandidate).isDirectory() && isInside(canonicalWorktreePath, canonicalCandidate)) {
|
|
1315
1439
|
effectiveCwd = canonicalCandidate;
|
|
1316
1440
|
}
|
|
1317
1441
|
} catch {
|
|
@@ -1343,15 +1467,15 @@ var WorktreeManager = class {
|
|
|
1343
1467
|
};
|
|
1344
1468
|
|
|
1345
1469
|
// src/storage/retention.ts
|
|
1346
|
-
import
|
|
1347
|
-
import
|
|
1470
|
+
import fs8 from "node:fs";
|
|
1471
|
+
import path8 from "node:path";
|
|
1348
1472
|
var FABRIC_RUN_ROOT_PREFIX = "pi-fabric-runs-";
|
|
1349
1473
|
var RUN_ROOT_OWNER_FILE = ".fabric-owner.json";
|
|
1350
1474
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "stopped", "timed_out"]);
|
|
1351
|
-
var ownerPath = (root) =>
|
|
1475
|
+
var ownerPath = (root) => path8.join(root, RUN_ROOT_OWNER_FILE);
|
|
1352
1476
|
var readJson = (filePath) => {
|
|
1353
1477
|
try {
|
|
1354
|
-
return JSON.parse(
|
|
1478
|
+
return JSON.parse(fs8.readFileSync(filePath, "utf8"));
|
|
1355
1479
|
} catch {
|
|
1356
1480
|
return void 0;
|
|
1357
1481
|
}
|
|
@@ -1393,32 +1517,32 @@ var pruneClosedRunRoot = (root, orphanedTempRunRetentionMs, oneShotRunRetentionM
|
|
|
1393
1517
|
const removed = [];
|
|
1394
1518
|
let entries;
|
|
1395
1519
|
try {
|
|
1396
|
-
entries =
|
|
1520
|
+
entries = fs8.readdirSync(root, { withFileTypes: true });
|
|
1397
1521
|
} catch {
|
|
1398
1522
|
return removed;
|
|
1399
1523
|
}
|
|
1400
1524
|
for (const entry of entries) {
|
|
1401
1525
|
if (!entry.isDirectory()) continue;
|
|
1402
|
-
const runDirectory =
|
|
1403
|
-
const record = readJson(
|
|
1526
|
+
const runDirectory = path8.join(root, entry.name);
|
|
1527
|
+
const record = readJson(path8.join(runDirectory, "status.json"));
|
|
1404
1528
|
if (!record?.status || !TERMINAL_STATUSES.has(record.status)) continue;
|
|
1405
1529
|
let fallback = now;
|
|
1406
1530
|
try {
|
|
1407
|
-
fallback =
|
|
1531
|
+
fallback = fs8.statSync(runDirectory).mtimeMs;
|
|
1408
1532
|
} catch {
|
|
1409
1533
|
}
|
|
1410
1534
|
const retentionMs = record.actorId ? orphanedTempRunRetentionMs : oneShotRunRetentionMs;
|
|
1411
1535
|
if (now - recordAgeReference(record, fallback) < retentionMs) continue;
|
|
1412
|
-
|
|
1536
|
+
fs8.rmSync(runDirectory, { recursive: true, force: true });
|
|
1413
1537
|
removed.push(runDirectory);
|
|
1414
1538
|
}
|
|
1415
1539
|
return removed;
|
|
1416
1540
|
};
|
|
1417
1541
|
var removeIfEmpty = (root) => {
|
|
1418
1542
|
try {
|
|
1419
|
-
const remaining =
|
|
1543
|
+
const remaining = fs8.readdirSync(root).filter((name) => name !== RUN_ROOT_OWNER_FILE);
|
|
1420
1544
|
if (remaining.length > 0) return false;
|
|
1421
|
-
|
|
1545
|
+
fs8.rmSync(root, { recursive: true, force: true });
|
|
1422
1546
|
return true;
|
|
1423
1547
|
} catch {
|
|
1424
1548
|
return false;
|
|
@@ -1429,19 +1553,19 @@ var sweepTempRunRoots = (options) => {
|
|
|
1429
1553
|
const result = { removedRoots: [], removedRuns: [] };
|
|
1430
1554
|
let entries;
|
|
1431
1555
|
try {
|
|
1432
|
-
entries =
|
|
1556
|
+
entries = fs8.readdirSync(options.tempRoot, { withFileTypes: true });
|
|
1433
1557
|
} catch {
|
|
1434
1558
|
return result;
|
|
1435
1559
|
}
|
|
1436
1560
|
for (const entry of entries) {
|
|
1437
1561
|
if (!entry.isDirectory() || !entry.name.startsWith(FABRIC_RUN_ROOT_PREFIX)) continue;
|
|
1438
|
-
const root =
|
|
1439
|
-
if (options.currentRoot &&
|
|
1562
|
+
const root = path8.join(options.tempRoot, entry.name);
|
|
1563
|
+
if (options.currentRoot && path8.resolve(root) === path8.resolve(options.currentRoot)) continue;
|
|
1440
1564
|
const owner = readJson(ownerPath(root));
|
|
1441
1565
|
if (!owner) {
|
|
1442
1566
|
try {
|
|
1443
|
-
if (
|
|
1444
|
-
|
|
1567
|
+
if (fs8.readdirSync(root).length === 0 && now - fs8.statSync(root).mtimeMs >= options.orphanedTempRunRetentionMs) {
|
|
1568
|
+
fs8.rmSync(root, { recursive: true, force: true });
|
|
1445
1569
|
result.removedRoots.push(root);
|
|
1446
1570
|
}
|
|
1447
1571
|
} catch {
|
|
@@ -1466,7 +1590,7 @@ var sweepTempRunRoots = (options) => {
|
|
|
1466
1590
|
continue;
|
|
1467
1591
|
}
|
|
1468
1592
|
if (now - owner.orphanedAt < options.orphanedTempRunRetentionMs) continue;
|
|
1469
|
-
|
|
1593
|
+
fs8.rmSync(root, { recursive: true, force: true });
|
|
1470
1594
|
result.removedRoots.push(root);
|
|
1471
1595
|
}
|
|
1472
1596
|
return result;
|
|
@@ -1476,44 +1600,44 @@ var pruneActorRunArchives = (options) => {
|
|
|
1476
1600
|
const removed = [];
|
|
1477
1601
|
let entries;
|
|
1478
1602
|
try {
|
|
1479
|
-
entries =
|
|
1603
|
+
entries = fs8.readdirSync(options.runsDirectory, { withFileTypes: true });
|
|
1480
1604
|
} catch {
|
|
1481
1605
|
return removed;
|
|
1482
1606
|
}
|
|
1483
1607
|
for (const entry of entries) {
|
|
1484
1608
|
if (!entry.isDirectory() || entry.name === options.latestRunId) continue;
|
|
1485
|
-
const runDirectory =
|
|
1486
|
-
const record = readJson(
|
|
1609
|
+
const runDirectory = path8.join(options.runsDirectory, entry.name);
|
|
1610
|
+
const record = readJson(path8.join(runDirectory, "status.json"));
|
|
1487
1611
|
if (!record?.status || !TERMINAL_STATUSES.has(record.status)) continue;
|
|
1488
1612
|
let fallback = now;
|
|
1489
1613
|
try {
|
|
1490
|
-
fallback =
|
|
1614
|
+
fallback = fs8.statSync(runDirectory).mtimeMs;
|
|
1491
1615
|
} catch {
|
|
1492
1616
|
}
|
|
1493
1617
|
if (now - recordAgeReference(record, fallback) < options.retentionMs) continue;
|
|
1494
|
-
|
|
1618
|
+
fs8.rmSync(runDirectory, { recursive: true, force: true });
|
|
1495
1619
|
removed.push(runDirectory);
|
|
1496
1620
|
}
|
|
1497
1621
|
return removed;
|
|
1498
1622
|
};
|
|
1499
1623
|
|
|
1500
1624
|
// src/agents/session-export.ts
|
|
1501
|
-
import
|
|
1502
|
-
import
|
|
1625
|
+
import os2 from "node:os";
|
|
1626
|
+
import path9 from "node:path";
|
|
1503
1627
|
var SESSION_EXPORT_ENV = "PI_FABRIC_AGENT_DIR";
|
|
1504
|
-
var expandHome = (value) => value === "~" ?
|
|
1628
|
+
var expandHome = (value) => value === "~" ? os2.homedir() : value.startsWith("~/") || value.startsWith(`~${path9.win32.sep}`) ? path9.join(os2.homedir(), value.slice(2)) : value;
|
|
1505
1629
|
var encodeSessionExportCwd = (cwd) => {
|
|
1506
|
-
const absolute =
|
|
1630
|
+
const absolute = path9.isAbsolute(cwd) || path9.win32.isAbsolute(cwd) ? cwd : path9.resolve(cwd);
|
|
1507
1631
|
return `--${absolute.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
1508
1632
|
};
|
|
1509
1633
|
var resolveSessionExportDir = (config) => {
|
|
1510
1634
|
if (!config.sessionExport) return void 0;
|
|
1511
|
-
const raw = process.env[SESSION_EXPORT_ENV]?.trim() || config.sessionExportDir.trim() ||
|
|
1635
|
+
const raw = process.env[SESSION_EXPORT_ENV]?.trim() || config.sessionExportDir.trim() || path9.join(os2.homedir(), ".pi", "agent");
|
|
1512
1636
|
return expandHome(raw);
|
|
1513
1637
|
};
|
|
1514
1638
|
var sessionExportFileFor = (root, cwd, runId, at) => {
|
|
1515
1639
|
const fileTimestamp = at.toISOString().replace(/[:.]/g, "-");
|
|
1516
|
-
return
|
|
1640
|
+
return path9.join(
|
|
1517
1641
|
root,
|
|
1518
1642
|
"sessions",
|
|
1519
1643
|
".fabric",
|
|
@@ -1558,11 +1682,11 @@ var resolveAgentCwd = (parentCwd, requestedCwd) => {
|
|
|
1558
1682
|
if (typeof requested !== "string" || requested.trim().length === 0) {
|
|
1559
1683
|
throw new Error(`Invalid Fabric agent cwd ${JSON.stringify(requested)}: path must not be empty`);
|
|
1560
1684
|
}
|
|
1561
|
-
const candidate =
|
|
1685
|
+
const candidate = path10.isAbsolute(requested) ? requested : path10.resolve(parentCwd, requested);
|
|
1562
1686
|
try {
|
|
1563
|
-
const canonical =
|
|
1564
|
-
|
|
1565
|
-
if (!
|
|
1687
|
+
const canonical = fs9.realpathSync(candidate);
|
|
1688
|
+
fs9.accessSync(canonical, fs9.constants.R_OK | fs9.constants.X_OK);
|
|
1689
|
+
if (!fs9.statSync(canonical).isDirectory()) {
|
|
1566
1690
|
throw new Error("path is not a directory");
|
|
1567
1691
|
}
|
|
1568
1692
|
return canonical;
|
|
@@ -1581,7 +1705,7 @@ var retryablePiStartupError = (error) => typeof error === "string" && /\b(?:no|m
|
|
|
1581
1705
|
var safeName = (value) => value.replace(/[\r\n\t]+/g, " ").trim().slice(0, MAX_NAME_LENGTH) || "Fabric agent";
|
|
1582
1706
|
var readRecord = (filePath) => {
|
|
1583
1707
|
try {
|
|
1584
|
-
const parsed = JSON.parse(
|
|
1708
|
+
const parsed = JSON.parse(fs9.readFileSync(filePath, "utf8"));
|
|
1585
1709
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
1586
1710
|
const record = parsed;
|
|
1587
1711
|
return {
|
|
@@ -1621,24 +1745,24 @@ var compactUiRecord = (record) => {
|
|
|
1621
1745
|
};
|
|
1622
1746
|
var readNestedAgents = (runDirectory, depth = 0) => {
|
|
1623
1747
|
if (depth >= 8) return [];
|
|
1624
|
-
const nestedRoot =
|
|
1748
|
+
const nestedRoot = path10.join(runDirectory, "nested");
|
|
1625
1749
|
let entries;
|
|
1626
1750
|
try {
|
|
1627
|
-
entries =
|
|
1751
|
+
entries = fs9.readdirSync(nestedRoot);
|
|
1628
1752
|
} catch {
|
|
1629
1753
|
return [];
|
|
1630
1754
|
}
|
|
1631
1755
|
const agents = [];
|
|
1632
1756
|
for (const entry of entries.slice(0, 200)) {
|
|
1633
|
-
const runDirectory2 =
|
|
1634
|
-
const record = readRecord(
|
|
1757
|
+
const runDirectory2 = path10.join(nestedRoot, entry);
|
|
1758
|
+
const record = readRecord(path10.join(runDirectory2, "status.json"));
|
|
1635
1759
|
if (!record) continue;
|
|
1636
1760
|
const nestedAgents = readNestedAgents(runDirectory2, depth + 1);
|
|
1637
1761
|
const { logFile: _logFile, nestedAgents: _nestedAgents, ...safeRecord } = record;
|
|
1638
1762
|
agents.push(
|
|
1639
1763
|
compactUiRecord({
|
|
1640
1764
|
...safeRecord,
|
|
1641
|
-
logFile:
|
|
1765
|
+
logFile: path10.join(runDirectory2, "events.jsonl"),
|
|
1642
1766
|
...nestedAgents.length > 0 ? { nestedAgents } : {}
|
|
1643
1767
|
})
|
|
1644
1768
|
);
|
|
@@ -1646,7 +1770,7 @@ var readNestedAgents = (runDirectory, depth = 0) => {
|
|
|
1646
1770
|
return agents;
|
|
1647
1771
|
};
|
|
1648
1772
|
var summarizeRunLog = (runDirectory, lines) => {
|
|
1649
|
-
const page = readJsonlPage(
|
|
1773
|
+
const page = readJsonlPage(path10.join(runDirectory, "events.jsonl"), lines);
|
|
1650
1774
|
const summary = [];
|
|
1651
1775
|
for (const entry of page.lines) {
|
|
1652
1776
|
const parsed = entry.parsed;
|
|
@@ -1697,7 +1821,7 @@ var AgentManager = class {
|
|
|
1697
1821
|
this.config = config;
|
|
1698
1822
|
this.#semaphore = new Semaphore(config.maxConcurrent);
|
|
1699
1823
|
this.#managedTempRoot = options.runRoot === void 0 && process.env.PI_FABRIC_RUN_ROOT === void 0;
|
|
1700
|
-
this.#runRoot = options.runRoot ?? process.env.PI_FABRIC_RUN_ROOT ??
|
|
1824
|
+
this.#runRoot = options.runRoot ?? process.env.PI_FABRIC_RUN_ROOT ?? fs9.mkdtempSync(path10.join(os3.tmpdir(), "pi-fabric-runs-"));
|
|
1701
1825
|
this.#retention = options.retention ?? DEFAULT_FABRIC_CONFIG.retention;
|
|
1702
1826
|
this.#workerPath = options.workerPath ?? fileURLToPath(new URL("../worker.js", import.meta.url));
|
|
1703
1827
|
this.#fabricExtensionPath = options.fabricExtensionPath ?? fileURLToPath(new URL("../index.js", import.meta.url));
|
|
@@ -1729,7 +1853,7 @@ var AgentManager = class {
|
|
|
1729
1853
|
if (this.#managedTempRoot) {
|
|
1730
1854
|
markRunRootActive(this.#runRoot);
|
|
1731
1855
|
sweepTempRunRoots({
|
|
1732
|
-
tempRoot:
|
|
1856
|
+
tempRoot: os3.tmpdir(),
|
|
1733
1857
|
currentRoot: this.#runRoot,
|
|
1734
1858
|
orphanedTempRunRetentionMs: this.#retention.orphanedTempRunMs,
|
|
1735
1859
|
oneShotRunRetentionMs: this.#retention.oneShotRunMs
|
|
@@ -1851,24 +1975,24 @@ var AgentManager = class {
|
|
|
1851
1975
|
const release = await this.#semaphore.acquire(signal);
|
|
1852
1976
|
const id = randomUUID4().replaceAll("-", "");
|
|
1853
1977
|
const name = safeName(request.name ?? request.task.split("\n", 1)[0] ?? "Fabric agent");
|
|
1854
|
-
const runDirectory =
|
|
1855
|
-
|
|
1856
|
-
const taskFile =
|
|
1857
|
-
const statusFile =
|
|
1858
|
-
const lifecycleFile =
|
|
1859
|
-
const logFile =
|
|
1860
|
-
const steerFile =
|
|
1861
|
-
const schemaFile = request.schema ?
|
|
1862
|
-
const imagesFile = request.images && request.images.length > 0 ?
|
|
1863
|
-
|
|
1978
|
+
const runDirectory = path10.join(this.#runRoot, id);
|
|
1979
|
+
fs9.mkdirSync(runDirectory, { recursive: true });
|
|
1980
|
+
const taskFile = path10.join(runDirectory, "task.txt");
|
|
1981
|
+
const statusFile = path10.join(runDirectory, "status.json");
|
|
1982
|
+
const lifecycleFile = path10.join(runDirectory, "lifecycle.jsonl");
|
|
1983
|
+
const logFile = path10.join(runDirectory, "events.jsonl");
|
|
1984
|
+
const steerFile = path10.join(runDirectory, "steer.jsonl");
|
|
1985
|
+
const schemaFile = request.schema ? path10.join(runDirectory, "schema.json") : void 0;
|
|
1986
|
+
const imagesFile = request.images && request.images.length > 0 ? path10.join(runDirectory, "images.json") : void 0;
|
|
1987
|
+
fs9.writeFileSync(taskFile, request.task, { encoding: "utf8", mode: 384 });
|
|
1864
1988
|
if (imagesFile) {
|
|
1865
|
-
|
|
1989
|
+
fs9.writeFileSync(imagesFile, JSON.stringify(request.images), {
|
|
1866
1990
|
encoding: "utf8",
|
|
1867
1991
|
mode: 384
|
|
1868
1992
|
});
|
|
1869
1993
|
}
|
|
1870
1994
|
if (schemaFile) {
|
|
1871
|
-
|
|
1995
|
+
fs9.writeFileSync(schemaFile, JSON.stringify(request.schema, null, 2), {
|
|
1872
1996
|
encoding: "utf8",
|
|
1873
1997
|
mode: 384
|
|
1874
1998
|
});
|
|
@@ -1891,7 +2015,7 @@ var AgentManager = class {
|
|
|
1891
2015
|
const sessionFile = request.sessionSeed ? writeHandoffSession(
|
|
1892
2016
|
request.sessionSeed,
|
|
1893
2017
|
agentCwd,
|
|
1894
|
-
|
|
2018
|
+
path10.join(runDirectory, "handoff-session"),
|
|
1895
2019
|
request.thinkingTransfer,
|
|
1896
2020
|
request.handoffCompact
|
|
1897
2021
|
) : request.sessionFile;
|
|
@@ -1968,7 +2092,7 @@ var AgentManager = class {
|
|
|
1968
2092
|
...this.#identityId ? ["--owner-identity-id", this.#identityId] : [],
|
|
1969
2093
|
...request.runnerSessionId ? ["--runner-session-id", request.runnerSessionId] : [],
|
|
1970
2094
|
"--run-root",
|
|
1971
|
-
|
|
2095
|
+
path10.join(runDirectory, "nested"),
|
|
1972
2096
|
"--steer-file",
|
|
1973
2097
|
steerFile,
|
|
1974
2098
|
...schemaFile ? ["--schema-file", schemaFile] : [],
|
|
@@ -2156,15 +2280,15 @@ var AgentManager = class {
|
|
|
2156
2280
|
this.#runs.delete(id);
|
|
2157
2281
|
this.#pruneRetainedUiRecords();
|
|
2158
2282
|
this.#invalidateUiList();
|
|
2159
|
-
return { cleaned: cleaned || !
|
|
2283
|
+
return { cleaned: cleaned || !fs9.existsSync(managed.runDirectory) };
|
|
2160
2284
|
}
|
|
2161
2285
|
readLog(id, opts = {}) {
|
|
2162
2286
|
const managed = this.#requireRun(id);
|
|
2163
2287
|
const runDirectory = managed.runDirectory;
|
|
2164
|
-
const logFile =
|
|
2288
|
+
const logFile = path10.join(runDirectory, "events.jsonl");
|
|
2165
2289
|
const lines = Math.max(1, Math.min(opts.lines ?? 200, 5e3));
|
|
2166
2290
|
const page = readJsonlPage(logFile, lines, opts.before);
|
|
2167
|
-
const statusRecord = readRecord(
|
|
2291
|
+
const statusRecord = readRecord(path10.join(runDirectory, "status.json"));
|
|
2168
2292
|
return {
|
|
2169
2293
|
id,
|
|
2170
2294
|
runDirectory,
|
|
@@ -2225,10 +2349,10 @@ var AgentManager = class {
|
|
|
2225
2349
|
`Fabric agent ${id} already finished (${record.status}); steering has no target`
|
|
2226
2350
|
);
|
|
2227
2351
|
}
|
|
2228
|
-
const steerFile =
|
|
2352
|
+
const steerFile = path10.join(managed.runDirectory, "steer.jsonl");
|
|
2229
2353
|
const messageId = randomUUID4();
|
|
2230
2354
|
const line = JSON.stringify({ ...entry, id: messageId, ts: Date.now() }) + "\n";
|
|
2231
|
-
|
|
2355
|
+
fs9.appendFileSync(steerFile, line, { encoding: "utf8", mode: 384 });
|
|
2232
2356
|
return { queued: true, messageId };
|
|
2233
2357
|
}
|
|
2234
2358
|
async close() {
|
|
@@ -2246,7 +2370,7 @@ var AgentManager = class {
|
|
|
2246
2370
|
await removeTree(this.#runRoot);
|
|
2247
2371
|
}
|
|
2248
2372
|
if (this.#budgetOwned && this.#budget) {
|
|
2249
|
-
await removeTree(
|
|
2373
|
+
await removeTree(path10.dirname(this.#budget.file));
|
|
2250
2374
|
clearOwnedBudgetEnv();
|
|
2251
2375
|
}
|
|
2252
2376
|
}
|
|
@@ -2260,7 +2384,7 @@ var AgentManager = class {
|
|
|
2260
2384
|
if (this.#managedTempRoot) {
|
|
2261
2385
|
heartbeatRunRoot(this.#runRoot, now);
|
|
2262
2386
|
sweepTempRunRoots({
|
|
2263
|
-
tempRoot:
|
|
2387
|
+
tempRoot: os3.tmpdir(),
|
|
2264
2388
|
currentRoot: this.#runRoot,
|
|
2265
2389
|
orphanedTempRunRetentionMs: this.#retention.orphanedTempRunMs,
|
|
2266
2390
|
oneShotRunRetentionMs: this.#retention.oneShotRunMs,
|
|
@@ -2275,7 +2399,7 @@ var AgentManager = class {
|
|
|
2275
2399
|
});
|
|
2276
2400
|
for (const managed of expired) {
|
|
2277
2401
|
await removeTree(managed.runDirectory).catch(() => void 0);
|
|
2278
|
-
if (!
|
|
2402
|
+
if (!fs9.existsSync(managed.runDirectory)) this.#runs.delete(managed.id);
|
|
2279
2403
|
}
|
|
2280
2404
|
if (expired.length > 0) {
|
|
2281
2405
|
this.#pruneRetainedUiRecords();
|
|
@@ -2300,14 +2424,14 @@ var AgentManager = class {
|
|
|
2300
2424
|
if (managed.settled || this.#closing || managed.abortSignal?.aborted) return false;
|
|
2301
2425
|
managed.startupAttempts++;
|
|
2302
2426
|
try {
|
|
2303
|
-
|
|
2427
|
+
fs9.rmSync(managed.statusFile, { force: true });
|
|
2304
2428
|
managed.transport = await managed.adapter.launch(managed.launch);
|
|
2305
2429
|
delete managed.latestRecord;
|
|
2306
2430
|
delete managed.latestUiRecord;
|
|
2307
2431
|
managed.lastLivenessCheckAt = 0;
|
|
2308
2432
|
managed.lifecycleOffset = 0;
|
|
2309
2433
|
managed.lifecycleRemainder = Buffer.alloc(0);
|
|
2310
|
-
|
|
2434
|
+
fs9.rmSync(managed.lifecycleFile, { force: true });
|
|
2311
2435
|
this.#invalidateUiList();
|
|
2312
2436
|
return true;
|
|
2313
2437
|
} catch (error) {
|
|
@@ -2407,7 +2531,7 @@ var AgentManager = class {
|
|
|
2407
2531
|
if (managed.settled) return;
|
|
2408
2532
|
this.#drainLifecycle(managed);
|
|
2409
2533
|
managed.settled = true;
|
|
2410
|
-
|
|
2534
|
+
fs9.rmSync(path10.join(managed.runDirectory, "images.json"), { force: true });
|
|
2411
2535
|
this.#emitLifecycle(managed, `run.${result.status}`, result.finishedAt ?? Date.now(), {
|
|
2412
2536
|
status: result.status
|
|
2413
2537
|
});
|
|
@@ -2448,7 +2572,7 @@ var AgentManager = class {
|
|
|
2448
2572
|
#drainLifecycle(managed) {
|
|
2449
2573
|
let content;
|
|
2450
2574
|
try {
|
|
2451
|
-
content =
|
|
2575
|
+
content = fs9.readFileSync(managed.lifecycleFile);
|
|
2452
2576
|
} catch {
|
|
2453
2577
|
return;
|
|
2454
2578
|
}
|
|
@@ -2639,7 +2763,7 @@ var AgentManager = class {
|
|
|
2639
2763
|
// in the parent run until that parent is explicitly cleaned up.
|
|
2640
2764
|
#nestedAgents(managed, force = false) {
|
|
2641
2765
|
const now = Date.now();
|
|
2642
|
-
const needsInitialDiscovery = managed.nestedSnapshot === void 0 &&
|
|
2766
|
+
const needsInitialDiscovery = managed.nestedSnapshot === void 0 && fs9.existsSync(path10.join(managed.runDirectory, "nested"));
|
|
2643
2767
|
if (!force && !needsInitialDiscovery && managed.nestedSnapshotAt !== void 0 && now - managed.nestedSnapshotAt < NESTED_SNAPSHOT_POLL_MS) {
|
|
2644
2768
|
return managed.nestedSnapshot ? structuredClone(managed.nestedSnapshot) : [];
|
|
2645
2769
|
}
|
|
@@ -2663,7 +2787,7 @@ var AgentManager = class {
|
|
|
2663
2787
|
cwd: managed.cwd,
|
|
2664
2788
|
runner: managed.runner,
|
|
2665
2789
|
...managed.residency === "durable" ? { residency: "durable" } : {},
|
|
2666
|
-
logFile:
|
|
2790
|
+
logFile: path10.join(managed.runDirectory, "events.jsonl"),
|
|
2667
2791
|
...nestedAgents.length > 0 ? { nestedAgents } : {},
|
|
2668
2792
|
...budget ? { budget } : {},
|
|
2669
2793
|
...managed.model ? { model: managed.model } : {},
|
|
@@ -2717,9 +2841,9 @@ var actorDeliveryNotice = (delivery, triggerTurn) => {
|
|
|
2717
2841
|
|
|
2718
2842
|
// src/actors/manager.ts
|
|
2719
2843
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
2720
|
-
import
|
|
2721
|
-
import
|
|
2722
|
-
import
|
|
2844
|
+
import fs11 from "node:fs";
|
|
2845
|
+
import os4 from "node:os";
|
|
2846
|
+
import path12 from "node:path";
|
|
2723
2847
|
|
|
2724
2848
|
// src/actors/predicate.ts
|
|
2725
2849
|
var PREDICATE_VERSION = 1;
|
|
@@ -2790,8 +2914,8 @@ var evaluateActorValidWhile = async (source, facts) => {
|
|
|
2790
2914
|
|
|
2791
2915
|
// src/actors/binding-store.ts
|
|
2792
2916
|
import { createHash, randomUUID as randomUUID5 } from "node:crypto";
|
|
2793
|
-
import
|
|
2794
|
-
import
|
|
2917
|
+
import fs10 from "node:fs";
|
|
2918
|
+
import path11 from "node:path";
|
|
2795
2919
|
var BINDING_LOCK_TIMEOUT_MS = 5e3;
|
|
2796
2920
|
var BINDING_STALE_LOCK_MS = 3e4;
|
|
2797
2921
|
var bindingFileName = (sessionId) => `${createHash("sha256").update(sessionId).digest("hex")}.json`;
|
|
@@ -2801,7 +2925,7 @@ var delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
2801
2925
|
var ActorBindingStore = class {
|
|
2802
2926
|
constructor(sessionId, root) {
|
|
2803
2927
|
this.sessionId = sessionId;
|
|
2804
|
-
this.filePath = root ?
|
|
2928
|
+
this.filePath = root ? path11.join(root, "bindings", bindingFileName(sessionId)) : void 0;
|
|
2805
2929
|
this.#sync(true);
|
|
2806
2930
|
}
|
|
2807
2931
|
#bindings = /* @__PURE__ */ new Map();
|
|
@@ -2867,7 +2991,7 @@ var ActorBindingStore = class {
|
|
|
2867
2991
|
if (!this.filePath) return bindings;
|
|
2868
2992
|
let parsed;
|
|
2869
2993
|
try {
|
|
2870
|
-
parsed = JSON.parse(
|
|
2994
|
+
parsed = JSON.parse(fs10.readFileSync(this.filePath, "utf8"));
|
|
2871
2995
|
} catch {
|
|
2872
2996
|
return bindings;
|
|
2873
2997
|
}
|
|
@@ -2908,7 +3032,7 @@ var ActorBindingStore = class {
|
|
|
2908
3032
|
#currentFingerprint() {
|
|
2909
3033
|
if (!this.filePath) return void 0;
|
|
2910
3034
|
try {
|
|
2911
|
-
const stat =
|
|
3035
|
+
const stat = fs10.statSync(this.filePath);
|
|
2912
3036
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
|
|
2913
3037
|
} catch {
|
|
2914
3038
|
return void 0;
|
|
@@ -2917,7 +3041,7 @@ var ActorBindingStore = class {
|
|
|
2917
3041
|
async #withLock(operation) {
|
|
2918
3042
|
if (!this.filePath) return operation();
|
|
2919
3043
|
const lockPath = `${this.filePath}.lock`;
|
|
2920
|
-
const ownerPath2 =
|
|
3044
|
+
const ownerPath2 = path11.join(lockPath, "owner");
|
|
2921
3045
|
const deadline = Date.now() + BINDING_LOCK_TIMEOUT_MS;
|
|
2922
3046
|
const token = randomUUID5();
|
|
2923
3047
|
const processAlive3 = (pid) => {
|
|
@@ -2929,11 +3053,11 @@ var ActorBindingStore = class {
|
|
|
2929
3053
|
return false;
|
|
2930
3054
|
}
|
|
2931
3055
|
};
|
|
2932
|
-
|
|
3056
|
+
fs10.mkdirSync(path11.dirname(this.filePath), { recursive: true, mode: 448 });
|
|
2933
3057
|
while (true) {
|
|
2934
3058
|
try {
|
|
2935
|
-
|
|
2936
|
-
|
|
3059
|
+
fs10.mkdirSync(lockPath, { mode: 448 });
|
|
3060
|
+
fs10.writeFileSync(ownerPath2, `${token}
|
|
2937
3061
|
${process.pid}
|
|
2938
3062
|
${Date.now()}
|
|
2939
3063
|
`, {
|
|
@@ -2944,13 +3068,13 @@ ${Date.now()}
|
|
|
2944
3068
|
} catch (error) {
|
|
2945
3069
|
if (errorCode2(error) !== "EEXIST") throw error;
|
|
2946
3070
|
try {
|
|
2947
|
-
const firstOwner =
|
|
3071
|
+
const firstOwner = fs10.readFileSync(ownerPath2, "utf8");
|
|
2948
3072
|
const [, pidText, createdText] = firstOwner.trim().split("\n");
|
|
2949
3073
|
const stale = Date.now() - Number(createdText) > BINDING_STALE_LOCK_MS;
|
|
2950
3074
|
if (stale && !processAlive3(Number(pidText))) {
|
|
2951
|
-
const secondOwner =
|
|
3075
|
+
const secondOwner = fs10.readFileSync(ownerPath2, "utf8");
|
|
2952
3076
|
if (secondOwner === firstOwner) {
|
|
2953
|
-
|
|
3077
|
+
fs10.rmSync(lockPath, { recursive: true, force: true });
|
|
2954
3078
|
continue;
|
|
2955
3079
|
}
|
|
2956
3080
|
}
|
|
@@ -2966,10 +3090,10 @@ ${Date.now()}
|
|
|
2966
3090
|
return operation();
|
|
2967
3091
|
} finally {
|
|
2968
3092
|
try {
|
|
2969
|
-
const owner =
|
|
3093
|
+
const owner = fs10.readFileSync(ownerPath2, "utf8");
|
|
2970
3094
|
if (owner.startsWith(`${token}
|
|
2971
3095
|
`)) {
|
|
2972
|
-
|
|
3096
|
+
fs10.rmSync(lockPath, { recursive: true, force: true });
|
|
2973
3097
|
}
|
|
2974
3098
|
} catch {
|
|
2975
3099
|
}
|
|
@@ -3065,7 +3189,7 @@ var atomicWrite2 = (filePath, value) => {
|
|
|
3065
3189
|
};
|
|
3066
3190
|
var readRunRecord = (filePath) => {
|
|
3067
3191
|
try {
|
|
3068
|
-
const parsed = JSON.parse(
|
|
3192
|
+
const parsed = JSON.parse(fs11.readFileSync(filePath, "utf8"));
|
|
3069
3193
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
|
|
3070
3194
|
return parsed;
|
|
3071
3195
|
} catch {
|
|
@@ -3109,7 +3233,7 @@ var ActorManager = class {
|
|
|
3109
3233
|
this.meshConfig = meshConfig;
|
|
3110
3234
|
this.agents = agents;
|
|
3111
3235
|
this.onDeliver = onDeliver;
|
|
3112
|
-
this.#actorRoot = options.actorRoot ??
|
|
3236
|
+
this.#actorRoot = options.actorRoot ?? fs11.mkdtempSync(path12.join(os4.tmpdir(), "pi-fabric-actors-"));
|
|
3113
3237
|
this.#persistent = options.persistent ?? false;
|
|
3114
3238
|
this.#mainAgent = options.mainAgent;
|
|
3115
3239
|
this.#canManageActor = options.canManageActor;
|
|
@@ -3118,7 +3242,7 @@ var ActorManager = class {
|
|
|
3118
3242
|
this.#claimResidency = options.claimResidency;
|
|
3119
3243
|
this.#rootId = options.rootId ?? identity.id;
|
|
3120
3244
|
this.#meshCursorPath = options.meshCursorPath;
|
|
3121
|
-
this.#registryPath =
|
|
3245
|
+
this.#registryPath = path12.join(this.#actorRoot, "actors.json");
|
|
3122
3246
|
this.#bindings = new ActorBindingStore(
|
|
3123
3247
|
sessionId,
|
|
3124
3248
|
this.#persistent && meshConfig.enabled ? this.#actorRoot : void 0
|
|
@@ -3230,8 +3354,8 @@ var ActorManager = class {
|
|
|
3230
3354
|
throw new Error("This Fabric host cannot commit actor capability requirements");
|
|
3231
3355
|
}
|
|
3232
3356
|
const id = randomUUID6().replaceAll("-", "");
|
|
3233
|
-
const actorDirectory =
|
|
3234
|
-
|
|
3357
|
+
const actorDirectory = path12.join(this.#actorRoot, id);
|
|
3358
|
+
fs11.mkdirSync(actorDirectory, { recursive: true, mode: 448 });
|
|
3235
3359
|
const actor = {
|
|
3236
3360
|
id,
|
|
3237
3361
|
name,
|
|
@@ -3255,7 +3379,7 @@ var ActorManager = class {
|
|
|
3255
3379
|
requirements,
|
|
3256
3380
|
...request.validWhile ? { validWhile: structuredClone(request.validWhile) } : {},
|
|
3257
3381
|
latestActivationSequence: 0,
|
|
3258
|
-
sessionFile:
|
|
3382
|
+
sessionFile: path12.join(actorDirectory, "session.jsonl"),
|
|
3259
3383
|
queue: [],
|
|
3260
3384
|
draining: false,
|
|
3261
3385
|
messages: [],
|
|
@@ -3588,17 +3712,17 @@ var ActorManager = class {
|
|
|
3588
3712
|
const type = opts.type ?? "session";
|
|
3589
3713
|
const lines = Math.max(1, Math.min(opts.lines ?? 200, 5e3));
|
|
3590
3714
|
const sessionFile = actor.sessionFile;
|
|
3591
|
-
const logDir =
|
|
3715
|
+
const logDir = path12.join(path12.dirname(sessionFile), "runs");
|
|
3592
3716
|
const sessionPage = type === "run" ? { lines: [], hasMore: false } : readJsonlPage(sessionFile, lines, opts.before);
|
|
3593
3717
|
const session = sessionPage.lines;
|
|
3594
3718
|
let run;
|
|
3595
3719
|
if (type !== "session") {
|
|
3596
3720
|
const targetRunId = opts.runId ?? actor.lastRunId;
|
|
3597
3721
|
if (targetRunId) {
|
|
3598
|
-
const runPath =
|
|
3599
|
-
if (
|
|
3600
|
-
const statusRecord = readRunRecord(
|
|
3601
|
-
const eventsFile =
|
|
3722
|
+
const runPath = path12.join(logDir, targetRunId);
|
|
3723
|
+
if (fs11.existsSync(runPath)) {
|
|
3724
|
+
const statusRecord = readRunRecord(path12.join(runPath, "status.json"));
|
|
3725
|
+
const eventsFile = path12.join(runPath, "events.jsonl");
|
|
3602
3726
|
const page = readJsonlPage(eventsFile, lines, opts.before);
|
|
3603
3727
|
run = {
|
|
3604
3728
|
runId: targetRunId,
|
|
@@ -3714,7 +3838,7 @@ var ActorManager = class {
|
|
|
3714
3838
|
#readMeshCursor() {
|
|
3715
3839
|
if (!this.#meshCursorPath) return void 0;
|
|
3716
3840
|
try {
|
|
3717
|
-
const value = JSON.parse(
|
|
3841
|
+
const value = JSON.parse(fs11.readFileSync(this.#meshCursorPath, "utf8"));
|
|
3718
3842
|
return value.format === 1 && typeof value.cursor === "number" && value.cursor >= 0 ? value.cursor : void 0;
|
|
3719
3843
|
} catch {
|
|
3720
3844
|
return void 0;
|
|
@@ -3815,7 +3939,7 @@ var ActorManager = class {
|
|
|
3815
3939
|
await this.#bindings.delete(actor.id);
|
|
3816
3940
|
this.#actors.delete(actor.id);
|
|
3817
3941
|
this.#emitChange();
|
|
3818
|
-
|
|
3942
|
+
fs11.rmSync(path12.dirname(actor.sessionFile), { recursive: true, force: true });
|
|
3819
3943
|
await this.#saveActors(/* @__PURE__ */ new Set([actor.id]));
|
|
3820
3944
|
await this.mesh.delete({ key: this.#presenceKey(actor.id) }).catch(() => ({ deleted: false }));
|
|
3821
3945
|
if (retainedRunId) await this.agents.cleanup(retainedRunId).catch(() => ({ cleaned: false }));
|
|
@@ -3858,7 +3982,7 @@ var ActorManager = class {
|
|
|
3858
3982
|
await Promise.allSettled(
|
|
3859
3983
|
[...this.#actors.values()].map((actor) => actor.drain ?? Promise.resolve())
|
|
3860
3984
|
);
|
|
3861
|
-
|
|
3985
|
+
fs11.rmSync(this.#actorRoot, { recursive: true, force: true });
|
|
3862
3986
|
}
|
|
3863
3987
|
#enqueue(actor, source, payload, options = {}) {
|
|
3864
3988
|
const canManage = options.ownershipChecked ? this.#canManageCached(actor.id) : this.#canManage(actor.id);
|
|
@@ -4247,8 +4371,8 @@ var ActorManager = class {
|
|
|
4247
4371
|
return;
|
|
4248
4372
|
}
|
|
4249
4373
|
try {
|
|
4250
|
-
const watcher =
|
|
4251
|
-
if (filename !== null &&
|
|
4374
|
+
const watcher = fs11.watch(this.mesh.root, { persistent: false }, (_event, filename) => {
|
|
4375
|
+
if (filename !== null && path12.basename(filename.toString()) !== "events.jsonl") return;
|
|
4252
4376
|
this.#scheduleMeshPoll();
|
|
4253
4377
|
});
|
|
4254
4378
|
this.#meshWatcher = watcher;
|
|
@@ -4357,17 +4481,17 @@ var ActorManager = class {
|
|
|
4357
4481
|
}
|
|
4358
4482
|
async #retainRunLog(actor, runId) {
|
|
4359
4483
|
const runDirectory = this.agents.runDirectory(runId);
|
|
4360
|
-
if (!runDirectory || !
|
|
4361
|
-
const dest =
|
|
4362
|
-
|
|
4484
|
+
if (!runDirectory || !fs11.existsSync(runDirectory)) return;
|
|
4485
|
+
const dest = path12.join(path12.dirname(actor.sessionFile), "runs", runId);
|
|
4486
|
+
fs11.mkdirSync(dest, { recursive: true, mode: 448 });
|
|
4363
4487
|
for (const file of ["events.jsonl", "status.json", "task.txt"]) {
|
|
4364
|
-
const src =
|
|
4365
|
-
if (
|
|
4488
|
+
const src = path12.join(runDirectory, file);
|
|
4489
|
+
if (fs11.existsSync(src)) fs11.copyFileSync(src, path12.join(dest, file));
|
|
4366
4490
|
}
|
|
4367
|
-
const nested =
|
|
4368
|
-
if (
|
|
4491
|
+
const nested = path12.join(runDirectory, "nested");
|
|
4492
|
+
if (fs11.existsSync(nested)) {
|
|
4369
4493
|
try {
|
|
4370
|
-
|
|
4494
|
+
fs11.cpSync(nested, path12.join(dest, "nested"), { recursive: true });
|
|
4371
4495
|
} catch {
|
|
4372
4496
|
}
|
|
4373
4497
|
}
|
|
@@ -4375,7 +4499,7 @@ var ActorManager = class {
|
|
|
4375
4499
|
}
|
|
4376
4500
|
#pruneRetainedRuns(actor, now = Date.now()) {
|
|
4377
4501
|
pruneActorRunArchives({
|
|
4378
|
-
runsDirectory:
|
|
4502
|
+
runsDirectory: path12.join(path12.dirname(actor.sessionFile), "runs"),
|
|
4379
4503
|
...actor.lastRunId ? { latestRunId: actor.lastRunId } : {},
|
|
4380
4504
|
retentionMs: this.#retention.actorRunArchiveMs,
|
|
4381
4505
|
now
|
|
@@ -4389,9 +4513,9 @@ var ActorManager = class {
|
|
|
4389
4513
|
}
|
|
4390
4514
|
}
|
|
4391
4515
|
#retainedRunIds(actor) {
|
|
4392
|
-
const runsDir =
|
|
4516
|
+
const runsDir = path12.join(path12.dirname(actor.sessionFile), "runs");
|
|
4393
4517
|
try {
|
|
4394
|
-
return
|
|
4518
|
+
return fs11.readdirSync(runsDir).sort();
|
|
4395
4519
|
} catch {
|
|
4396
4520
|
return [];
|
|
4397
4521
|
}
|
|
@@ -4507,7 +4631,7 @@ var ActorManager = class {
|
|
|
4507
4631
|
}
|
|
4508
4632
|
#registryRecords() {
|
|
4509
4633
|
try {
|
|
4510
|
-
const parsed = JSON.parse(
|
|
4634
|
+
const parsed = JSON.parse(fs11.readFileSync(this.#registryPath, "utf8"));
|
|
4511
4635
|
if (!Array.isArray(parsed.actors)) return [];
|
|
4512
4636
|
return parsed.actors.flatMap(
|
|
4513
4637
|
(record) => typeof record === "object" && record !== null && !Array.isArray(record) && typeof record.id === "string" ? [record] : []
|
|
@@ -4518,7 +4642,7 @@ var ActorManager = class {
|
|
|
4518
4642
|
}
|
|
4519
4643
|
async #withRegistryLock(operation) {
|
|
4520
4644
|
const lockPath = `${this.#registryPath}.lock`;
|
|
4521
|
-
const ownerPath2 =
|
|
4645
|
+
const ownerPath2 = path12.join(lockPath, "owner");
|
|
4522
4646
|
const deadline = Date.now() + ACTOR_REGISTRY_LOCK_TIMEOUT_MS;
|
|
4523
4647
|
const token = randomUUID6();
|
|
4524
4648
|
const processAlive3 = (pid) => {
|
|
@@ -4530,11 +4654,11 @@ var ActorManager = class {
|
|
|
4530
4654
|
return false;
|
|
4531
4655
|
}
|
|
4532
4656
|
};
|
|
4533
|
-
|
|
4657
|
+
fs11.mkdirSync(this.#actorRoot, { recursive: true, mode: 448 });
|
|
4534
4658
|
while (true) {
|
|
4535
4659
|
try {
|
|
4536
|
-
|
|
4537
|
-
|
|
4660
|
+
fs11.mkdirSync(lockPath, { mode: 448 });
|
|
4661
|
+
fs11.writeFileSync(ownerPath2, `${token}
|
|
4538
4662
|
${process.pid}
|
|
4539
4663
|
${Date.now()}
|
|
4540
4664
|
`, {
|
|
@@ -4545,13 +4669,13 @@ ${Date.now()}
|
|
|
4545
4669
|
} catch (error) {
|
|
4546
4670
|
if (errorCode3(error) !== "EEXIST") throw error;
|
|
4547
4671
|
try {
|
|
4548
|
-
const firstOwner =
|
|
4672
|
+
const firstOwner = fs11.readFileSync(ownerPath2, "utf8");
|
|
4549
4673
|
const [, pidText, createdText] = firstOwner.trim().split("\n");
|
|
4550
4674
|
const stale = Date.now() - Number(createdText) > ACTOR_REGISTRY_STALE_LOCK_MS;
|
|
4551
4675
|
if (stale && !processAlive3(Number(pidText))) {
|
|
4552
|
-
const secondOwner =
|
|
4676
|
+
const secondOwner = fs11.readFileSync(ownerPath2, "utf8");
|
|
4553
4677
|
if (secondOwner === firstOwner) {
|
|
4554
|
-
|
|
4678
|
+
fs11.rmSync(lockPath, { recursive: true, force: true });
|
|
4555
4679
|
continue;
|
|
4556
4680
|
}
|
|
4557
4681
|
}
|
|
@@ -4567,10 +4691,10 @@ ${Date.now()}
|
|
|
4567
4691
|
return operation();
|
|
4568
4692
|
} finally {
|
|
4569
4693
|
try {
|
|
4570
|
-
const owner =
|
|
4694
|
+
const owner = fs11.readFileSync(ownerPath2, "utf8");
|
|
4571
4695
|
if (owner.startsWith(`${token}
|
|
4572
4696
|
`)) {
|
|
4573
|
-
|
|
4697
|
+
fs11.rmSync(lockPath, { recursive: true, force: true });
|
|
4574
4698
|
}
|
|
4575
4699
|
} catch {
|
|
4576
4700
|
}
|
|
@@ -4598,7 +4722,7 @@ ${Date.now()}
|
|
|
4598
4722
|
}
|
|
4599
4723
|
#currentRegistryFingerprint() {
|
|
4600
4724
|
try {
|
|
4601
|
-
const stat =
|
|
4725
|
+
const stat = fs11.statSync(this.#registryPath);
|
|
4602
4726
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
|
|
4603
4727
|
} catch {
|
|
4604
4728
|
return void 0;
|
|
@@ -4643,7 +4767,7 @@ ${Date.now()}
|
|
|
4643
4767
|
let added = 0;
|
|
4644
4768
|
let parsed;
|
|
4645
4769
|
try {
|
|
4646
|
-
parsed = JSON.parse(
|
|
4770
|
+
parsed = JSON.parse(fs11.readFileSync(this.#registryPath, "utf8"));
|
|
4647
4771
|
} catch (error) {
|
|
4648
4772
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
|
|
4649
4773
|
return;
|
|
@@ -4704,7 +4828,7 @@ ${Date.now()}
|
|
|
4704
4828
|
...typeof record.capabilityDigest === "string" ? { capabilityDigest: record.capabilityDigest } : {},
|
|
4705
4829
|
...record.validWhile?.version === 1 && typeof record.validWhile.source === "string" ? { validWhile: record.validWhile } : {},
|
|
4706
4830
|
latestActivationSequence: 0,
|
|
4707
|
-
sessionFile:
|
|
4831
|
+
sessionFile: path12.join(this.#actorRoot, record.id, "session.jsonl"),
|
|
4708
4832
|
queue: [],
|
|
4709
4833
|
draining: false,
|
|
4710
4834
|
messages: [],
|
|
@@ -4789,7 +4913,7 @@ ${Date.now()}
|
|
|
4789
4913
|
...actor.lastRunId ? { lastRunId: actor.lastRunId } : {},
|
|
4790
4914
|
...actor.lastError ? { lastError: actor.lastError } : {},
|
|
4791
4915
|
sessionFile: actor.sessionFile,
|
|
4792
|
-
logDir:
|
|
4916
|
+
logDir: path12.join(path12.dirname(actor.sessionFile), "runs")
|
|
4793
4917
|
};
|
|
4794
4918
|
}
|
|
4795
4919
|
validateDirectMessage(message, data) {
|
|
@@ -6231,6 +6355,8 @@ export {
|
|
|
6231
6355
|
FABRIC_LIFECYCLE_EVENTS,
|
|
6232
6356
|
isFabricLifecycleEventType,
|
|
6233
6357
|
lifecycleSourceIdentity,
|
|
6358
|
+
isFabricWorktreePath,
|
|
6359
|
+
addCloneFirstWorktree,
|
|
6234
6360
|
useBudgetLedger,
|
|
6235
6361
|
effectiveAgentTimeoutMs,
|
|
6236
6362
|
validateAgentCwdRequest,
|
|
@@ -6245,4 +6371,4 @@ export {
|
|
|
6245
6371
|
agentParticipantRecords,
|
|
6246
6372
|
actorParticipantRecord
|
|
6247
6373
|
};
|
|
6248
|
-
//# sourceMappingURL=chunk-
|
|
6374
|
+
//# sourceMappingURL=chunk-4DRVOAFY.js.map
|