pi-fabric 0.77.0 → 0.78.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/README.md +1 -0
- package/dist/capture/catalog.d.ts +3 -0
- package/dist/capture/catalog.d.ts.map +1 -1
- package/dist/chunks/{chunk-PAAXKXWT.js → chunk-2AF5ANEB.js} +16 -2
- package/dist/chunks/chunk-2AF5ANEB.js.map +7 -0
- package/dist/chunks/{chunk-QXB75FLD.js → chunk-2E3CAABA.js} +8 -1
- package/dist/chunks/chunk-2E3CAABA.js.map +7 -0
- package/dist/chunks/{chunk-6ZKYQW33.js → chunk-3QPTSKDG.js} +139 -29
- package/dist/chunks/chunk-3QPTSKDG.js.map +7 -0
- package/dist/chunks/{chunk-SBHF6CVR.js → chunk-DUIHQAIZ.js} +2 -2
- package/dist/chunks/{chunk-6BBFFEPO.js → chunk-DYEOFQ64.js} +15 -1
- package/dist/chunks/{chunk-6BBFFEPO.js.map → chunk-DYEOFQ64.js.map} +2 -2
- package/dist/chunks/{chunk-4DRVOAFY.js → chunk-PFF3X7OO.js} +2 -2
- package/dist/chunks/{fabric-runtime-state-H7UA3DJC.js → fabric-runtime-state-H2NCRJWK.js} +697 -192
- package/dist/chunks/fabric-runtime-state-H2NCRJWK.js.map +7 -0
- package/dist/chunks/{settings-VEXI347I.js → settings-FUL3U3N4.js} +2 -2
- package/dist/commands/fabric.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/core/action-registry.d.ts +1 -0
- package/dist/core/action-registry.d.ts.map +1 -1
- package/dist/core/action-registry.js +1 -1
- package/dist/fabric-runtime-state.d.ts +2 -0
- package/dist/fabric-runtime-state.d.ts.map +1 -1
- package/dist/fabric-state.d.ts +1 -0
- package/dist/fabric-state.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +218 -8
- package/dist/index.js.map +3 -3
- package/dist/providers/arg-normalization.d.ts +3 -0
- package/dist/providers/arg-normalization.d.ts.map +1 -1
- package/dist/providers/memory-provider.js +1 -1
- package/dist/repairs/active.d.ts +7 -0
- package/dist/repairs/active.d.ts.map +1 -0
- package/dist/repairs/apply.d.ts +7 -0
- package/dist/repairs/apply.d.ts.map +1 -0
- package/dist/repairs/catalog-digest.d.ts +5 -0
- package/dist/repairs/catalog-digest.d.ts.map +1 -0
- package/dist/repairs/classify.d.ts +10 -0
- package/dist/repairs/classify.d.ts.map +1 -0
- package/dist/repairs/compiler.d.ts +32 -0
- package/dist/repairs/compiler.d.ts.map +1 -0
- package/dist/repairs/promote.d.ts +4 -0
- package/dist/repairs/promote.d.ts.map +1 -0
- package/dist/repairs/store.d.ts +9 -0
- package/dist/repairs/store.d.ts.map +1 -0
- package/dist/repairs/types.d.ts +49 -0
- package/dist/repairs/types.d.ts.map +1 -0
- package/dist/residency/host.js +3 -3
- package/dist/residency/pi-entry.js +3 -3
- package/dist/speculation/store.d.ts +11 -7
- package/dist/speculation/store.d.ts.map +1 -1
- package/dist/speculation/types.d.ts +2 -1
- package/dist/speculation/types.d.ts.map +1 -1
- package/docs/architecture.md +2 -0
- package/docs/configuration.md +4 -0
- package/docs/interface.md +1 -0
- package/docs/repairs.md +57 -0
- package/package.json +1 -1
- package/dist/chunks/chunk-6ZKYQW33.js.map +0 -7
- package/dist/chunks/chunk-PAAXKXWT.js.map +0 -7
- package/dist/chunks/chunk-QXB75FLD.js.map +0 -7
- package/dist/chunks/fabric-runtime-state-H7UA3DJC.js.map +0 -7
- /package/dist/chunks/{chunk-SBHF6CVR.js.map → chunk-DUIHQAIZ.js.map} +0 -0
- /package/dist/chunks/{chunk-4DRVOAFY.js.map → chunk-PFF3X7OO.js.map} +0 -0
- /package/dist/chunks/{settings-VEXI347I.js.map → settings-FUL3U3N4.js.map} +0 -0
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
} from "./chunk-IGVDD2HT.js";
|
|
8
8
|
import {
|
|
9
9
|
MemoryProvider,
|
|
10
|
-
actionArgNormalizer
|
|
11
|
-
|
|
10
|
+
actionArgNormalizer,
|
|
11
|
+
uniqueDeclaredKeyForSpelling
|
|
12
|
+
} from "./chunk-DYEOFQ64.js";
|
|
12
13
|
import "./chunk-BOIV6E3C.js";
|
|
13
14
|
import "./chunk-NNFA2OIC.js";
|
|
14
15
|
import "./chunk-E3V22XGU.js";
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
repairFabricGuestCode,
|
|
32
33
|
resolveFabricIdentity,
|
|
33
34
|
runFabricHandoffAtBoundary
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-2AF5ANEB.js";
|
|
35
36
|
import {
|
|
36
37
|
AgentTranscriptReader,
|
|
37
38
|
MAX_WRITE_DIFF_BYTES,
|
|
@@ -40,8 +41,11 @@ import {
|
|
|
40
41
|
writeContentForPreview
|
|
41
42
|
} from "./chunk-5XQA7QX2.js";
|
|
42
43
|
import {
|
|
43
|
-
ActionRegistry
|
|
44
|
-
|
|
44
|
+
ActionRegistry,
|
|
45
|
+
clearActiveRepairCompiler,
|
|
46
|
+
repairActionName,
|
|
47
|
+
setActiveRepairCompiler
|
|
48
|
+
} from "./chunk-3QPTSKDG.js";
|
|
45
49
|
import {
|
|
46
50
|
formatFabricEffectConflict
|
|
47
51
|
} from "./chunk-LMAVZN7J.js";
|
|
@@ -79,7 +83,7 @@ import {
|
|
|
79
83
|
resolveAgentCwd,
|
|
80
84
|
resolvePiBinary,
|
|
81
85
|
validateAgentCwdRequest
|
|
82
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-PFF3X7OO.js";
|
|
83
87
|
import "./chunk-PM5I335G.js";
|
|
84
88
|
import "./chunk-VPPIJRNZ.js";
|
|
85
89
|
import {
|
|
@@ -102,7 +106,7 @@ import {
|
|
|
102
106
|
MIN_AGENT_TIMEOUT_MS,
|
|
103
107
|
loadFabricConfig,
|
|
104
108
|
resolveFabricModel
|
|
105
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-2E3CAABA.js";
|
|
106
110
|
import {
|
|
107
111
|
isFabricThinking
|
|
108
112
|
} from "./chunk-7B55UIZL.js";
|
|
@@ -151,7 +155,7 @@ import {
|
|
|
151
155
|
} from "./chunk-IDTQ2B5W.js";
|
|
152
156
|
|
|
153
157
|
// src/fabric-runtime-state.ts
|
|
154
|
-
import
|
|
158
|
+
import path16 from "node:path";
|
|
155
159
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
156
160
|
|
|
157
161
|
// src/actors/global-registry.ts
|
|
@@ -2198,10 +2202,10 @@ var FabricComponentSupervisor = class {
|
|
|
2198
2202
|
adjacent.set(edge.from, targets);
|
|
2199
2203
|
}
|
|
2200
2204
|
const cycles = /* @__PURE__ */ new Map();
|
|
2201
|
-
const visit = (node,
|
|
2205
|
+
const visit = (node, path17, positions) => {
|
|
2202
2206
|
const position = positions.get(node);
|
|
2203
2207
|
if (position !== void 0) {
|
|
2204
|
-
const cycle =
|
|
2208
|
+
const cycle = path17.slice(position);
|
|
2205
2209
|
const rotations = cycle.map((_, index) => [
|
|
2206
2210
|
...cycle.slice(index),
|
|
2207
2211
|
...cycle.slice(0, index)
|
|
@@ -2211,10 +2215,10 @@ var FabricComponentSupervisor = class {
|
|
|
2211
2215
|
cycles.set(canonical.join("\0"), canonical);
|
|
2212
2216
|
return;
|
|
2213
2217
|
}
|
|
2214
|
-
if (
|
|
2215
|
-
const nextPositions = new Map(positions).set(node,
|
|
2218
|
+
if (path17.length > this.#components.size) return;
|
|
2219
|
+
const nextPositions = new Map(positions).set(node, path17.length);
|
|
2216
2220
|
for (const target of adjacent.get(node) ?? []) {
|
|
2217
|
-
visit(target, [...
|
|
2221
|
+
visit(target, [...path17, node], nextPositions);
|
|
2218
2222
|
}
|
|
2219
2223
|
};
|
|
2220
2224
|
for (const id of this.#components.keys()) visit(id, [], /* @__PURE__ */ new Map());
|
|
@@ -3326,6 +3330,473 @@ var FabricExecutionService = class {
|
|
|
3326
3330
|
}
|
|
3327
3331
|
};
|
|
3328
3332
|
|
|
3333
|
+
// src/repairs/apply.ts
|
|
3334
|
+
var strictDeclaredPropertyNames = (schema) => {
|
|
3335
|
+
if (schema.type !== "object" || schema.additionalProperties !== false || schema.patternProperties !== void 0) {
|
|
3336
|
+
return void 0;
|
|
3337
|
+
}
|
|
3338
|
+
const properties = schema.properties;
|
|
3339
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) return void 0;
|
|
3340
|
+
return Object.keys(properties);
|
|
3341
|
+
};
|
|
3342
|
+
var applyKeyAliasRepairs = (ref, args, repairs, schema) => {
|
|
3343
|
+
const declared = strictDeclaredPropertyNames(schema);
|
|
3344
|
+
if (!declared) return { args, changed: false };
|
|
3345
|
+
const declaredSet = new Set(declared);
|
|
3346
|
+
const applicable = repairs.filter(
|
|
3347
|
+
(repair) => repair.kind === "keyAlias" && repair.ref === ref && repair.from in args && repair.from !== repair.to && !declaredSet.has(repair.from) && declaredSet.has(repair.to) && uniqueDeclaredKeyForSpelling(repair.from, declared) === repair.to
|
|
3348
|
+
);
|
|
3349
|
+
const sourceCountByTarget = /* @__PURE__ */ new Map();
|
|
3350
|
+
for (const repair of applicable) {
|
|
3351
|
+
sourceCountByTarget.set(repair.to, (sourceCountByTarget.get(repair.to) ?? 0) + 1);
|
|
3352
|
+
}
|
|
3353
|
+
let out = args;
|
|
3354
|
+
let changed = false;
|
|
3355
|
+
for (const repair of applicable) {
|
|
3356
|
+
const canonicalPresent = repair.to in args;
|
|
3357
|
+
if (!canonicalPresent && sourceCountByTarget.get(repair.to) !== 1) continue;
|
|
3358
|
+
if (out === args) out = { ...args };
|
|
3359
|
+
if (!(repair.to in out)) out[repair.to] = out[repair.from];
|
|
3360
|
+
delete out[repair.from];
|
|
3361
|
+
changed = true;
|
|
3362
|
+
}
|
|
3363
|
+
return { args: out, changed };
|
|
3364
|
+
};
|
|
3365
|
+
var applyActionAliasRepairs = (provider, actionName, repairs, declared) => {
|
|
3366
|
+
if (declared.includes(actionName)) return void 0;
|
|
3367
|
+
const liveTarget = repairActionName(declared, actionName).repaired;
|
|
3368
|
+
if (!liveTarget) return void 0;
|
|
3369
|
+
for (const repair of repairs) {
|
|
3370
|
+
if (repair.kind !== "actionAlias") continue;
|
|
3371
|
+
if (repair.provider !== provider) continue;
|
|
3372
|
+
if (repair.from !== actionName) continue;
|
|
3373
|
+
if (repair.to !== liveTarget) continue;
|
|
3374
|
+
return repair.to;
|
|
3375
|
+
}
|
|
3376
|
+
return void 0;
|
|
3377
|
+
};
|
|
3378
|
+
var applyCatalogArgRepairs = (ref, args, repairs, schema) => applyKeyAliasRepairs(ref, args, repairs, schema);
|
|
3379
|
+
|
|
3380
|
+
// src/repairs/catalog-digest.ts
|
|
3381
|
+
var catalogDigestFromSurface = (surface) => stableJsonHash({
|
|
3382
|
+
v: 1,
|
|
3383
|
+
providers: [...surface.providers].sort(),
|
|
3384
|
+
captured: [...surface.capturedTools].sort()
|
|
3385
|
+
});
|
|
3386
|
+
|
|
3387
|
+
// src/repairs/promote.ts
|
|
3388
|
+
var keyAliasCandidate = (ref, extraKeys, declared) => {
|
|
3389
|
+
if (extraKeys.length !== 1) return void 0;
|
|
3390
|
+
const from = extraKeys[0];
|
|
3391
|
+
const to = uniqueDeclaredKeyForSpelling(from, declared);
|
|
3392
|
+
if (!to) return void 0;
|
|
3393
|
+
return { kind: "keyAlias", ref, from, to };
|
|
3394
|
+
};
|
|
3395
|
+
var actionAliasCandidate = (provider, actionName, declared) => {
|
|
3396
|
+
const repair = repairActionName(declared, actionName);
|
|
3397
|
+
if (!repair.repaired || repair.repaired === actionName) return void 0;
|
|
3398
|
+
return {
|
|
3399
|
+
kind: "actionAlias",
|
|
3400
|
+
provider,
|
|
3401
|
+
from: actionName,
|
|
3402
|
+
to: repair.repaired
|
|
3403
|
+
};
|
|
3404
|
+
};
|
|
3405
|
+
|
|
3406
|
+
// src/repairs/store.ts
|
|
3407
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3408
|
+
import fs2 from "node:fs";
|
|
3409
|
+
import path2 from "node:path";
|
|
3410
|
+
|
|
3411
|
+
// src/repairs/types.ts
|
|
3412
|
+
var REPAIR_TABLE_VERSION = 1;
|
|
3413
|
+
var MAX_CATALOG_REPAIRS = 256;
|
|
3414
|
+
var repairIdentity = (repair) => {
|
|
3415
|
+
if (repair.kind === "keyAlias") {
|
|
3416
|
+
return `keyAlias:${repair.ref}:${repair.from}:${repair.to}`;
|
|
3417
|
+
}
|
|
3418
|
+
return `actionAlias:${repair.provider}:${repair.from}:${repair.to}`;
|
|
3419
|
+
};
|
|
3420
|
+
var emptyRepairTable = (catalogDigest, now = (/* @__PURE__ */ new Date()).toISOString()) => ({
|
|
3421
|
+
version: REPAIR_TABLE_VERSION,
|
|
3422
|
+
catalogDigest,
|
|
3423
|
+
repairs: [],
|
|
3424
|
+
createdAt: now,
|
|
3425
|
+
updatedAt: now
|
|
3426
|
+
});
|
|
3427
|
+
|
|
3428
|
+
// src/repairs/store.ts
|
|
3429
|
+
var REPAIR_LOCK_ATTEMPTS = 50;
|
|
3430
|
+
var REPAIR_LOCK_DELAY_MS = 5;
|
|
3431
|
+
var REPAIR_STALE_LOCK_MS = 3e4;
|
|
3432
|
+
var repairsDirectory = (agentDir) => path2.join(agentDir, "fabric", "repairs");
|
|
3433
|
+
var currentPath = (directory) => path2.join(directory, "current.json");
|
|
3434
|
+
var lockPath = (directory) => path2.join(directory, "current.lock");
|
|
3435
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3436
|
+
var errorCode = (error) => isRecord(error) && typeof error.code === "string" ? error.code : void 0;
|
|
3437
|
+
var sleepSync = (() => {
|
|
3438
|
+
try {
|
|
3439
|
+
const buffer = new Int32Array(new SharedArrayBuffer(4));
|
|
3440
|
+
return (ms) => {
|
|
3441
|
+
Atomics.wait(buffer, 0, 0, ms);
|
|
3442
|
+
};
|
|
3443
|
+
} catch {
|
|
3444
|
+
return () => void 0;
|
|
3445
|
+
}
|
|
3446
|
+
})();
|
|
3447
|
+
var parseRepair = (value) => {
|
|
3448
|
+
if (!isRecord(value) || typeof value.kind !== "string") return void 0;
|
|
3449
|
+
if (value.kind === "keyAlias") {
|
|
3450
|
+
if (typeof value.ref !== "string" || typeof value.from !== "string" || typeof value.to !== "string" || !value.ref.trim() || !value.from.trim() || !value.to.trim()) {
|
|
3451
|
+
return void 0;
|
|
3452
|
+
}
|
|
3453
|
+
return { kind: "keyAlias", ref: value.ref.trim(), from: value.from.trim(), to: value.to.trim() };
|
|
3454
|
+
}
|
|
3455
|
+
if (value.kind === "actionAlias") {
|
|
3456
|
+
if (typeof value.provider !== "string" || typeof value.from !== "string" || typeof value.to !== "string" || !value.provider.trim() || !value.from.trim() || !value.to.trim()) {
|
|
3457
|
+
return void 0;
|
|
3458
|
+
}
|
|
3459
|
+
return {
|
|
3460
|
+
kind: "actionAlias",
|
|
3461
|
+
provider: value.provider.trim(),
|
|
3462
|
+
from: value.from.trim(),
|
|
3463
|
+
to: value.to.trim()
|
|
3464
|
+
};
|
|
3465
|
+
}
|
|
3466
|
+
return "skip";
|
|
3467
|
+
};
|
|
3468
|
+
var parseRepairTable = (value) => {
|
|
3469
|
+
if (!isRecord(value) || value.version !== REPAIR_TABLE_VERSION) return void 0;
|
|
3470
|
+
if (typeof value.catalogDigest !== "string" || !value.catalogDigest.trim()) return void 0;
|
|
3471
|
+
if (!Array.isArray(value.repairs) || value.repairs.length > MAX_CATALOG_REPAIRS) return void 0;
|
|
3472
|
+
const repairs = [];
|
|
3473
|
+
const identities = /* @__PURE__ */ new Set();
|
|
3474
|
+
for (const entry of value.repairs) {
|
|
3475
|
+
const parsed = parseRepair(entry);
|
|
3476
|
+
if (parsed === "skip") continue;
|
|
3477
|
+
if (!parsed) return void 0;
|
|
3478
|
+
const identity = repairIdentity(parsed);
|
|
3479
|
+
if (identities.has(identity)) continue;
|
|
3480
|
+
identities.add(identity);
|
|
3481
|
+
repairs.push(parsed);
|
|
3482
|
+
}
|
|
3483
|
+
if (typeof value.createdAt !== "string" || typeof value.updatedAt !== "string") return void 0;
|
|
3484
|
+
return {
|
|
3485
|
+
version: REPAIR_TABLE_VERSION,
|
|
3486
|
+
catalogDigest: value.catalogDigest.trim(),
|
|
3487
|
+
repairs,
|
|
3488
|
+
createdAt: value.createdAt,
|
|
3489
|
+
updatedAt: value.updatedAt
|
|
3490
|
+
};
|
|
3491
|
+
};
|
|
3492
|
+
var errorText = (error) => (error instanceof Error ? error.message : String(error)).slice(0, 200);
|
|
3493
|
+
var writeTable = (file, table) => {
|
|
3494
|
+
writeJsonAtomic(file, table, { space: 2, newline: true, mode: 384, dirMode: 448 });
|
|
3495
|
+
};
|
|
3496
|
+
var processAlive = (pid) => {
|
|
3497
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
3498
|
+
try {
|
|
3499
|
+
process.kill(pid, 0);
|
|
3500
|
+
return true;
|
|
3501
|
+
} catch {
|
|
3502
|
+
return false;
|
|
3503
|
+
}
|
|
3504
|
+
};
|
|
3505
|
+
var reapStaleLock = (lock, verify) => {
|
|
3506
|
+
const claim = `${lock}.reap-${process.pid}-${randomUUID2()}`;
|
|
3507
|
+
try {
|
|
3508
|
+
fs2.renameSync(lock, claim);
|
|
3509
|
+
} catch {
|
|
3510
|
+
return false;
|
|
3511
|
+
}
|
|
3512
|
+
if (!verify(claim)) {
|
|
3513
|
+
try {
|
|
3514
|
+
fs2.renameSync(claim, lock);
|
|
3515
|
+
} catch {
|
|
3516
|
+
if (verify(claim)) fs2.rmSync(claim, { recursive: true, force: true });
|
|
3517
|
+
}
|
|
3518
|
+
return false;
|
|
3519
|
+
}
|
|
3520
|
+
fs2.rmSync(claim, { recursive: true, force: true });
|
|
3521
|
+
return true;
|
|
3522
|
+
};
|
|
3523
|
+
var withRepairLock = (directory, operation) => {
|
|
3524
|
+
fs2.mkdirSync(directory, { recursive: true, mode: 448 });
|
|
3525
|
+
const lock = lockPath(directory);
|
|
3526
|
+
const ownerPath = path2.join(lock, "owner");
|
|
3527
|
+
const token = randomUUID2();
|
|
3528
|
+
let acquired = false;
|
|
3529
|
+
for (let attempt = 0; attempt < REPAIR_LOCK_ATTEMPTS; attempt++) {
|
|
3530
|
+
try {
|
|
3531
|
+
fs2.mkdirSync(lock, { mode: 448 });
|
|
3532
|
+
try {
|
|
3533
|
+
fs2.writeFileSync(ownerPath, `${token}
|
|
3534
|
+
${process.pid}
|
|
3535
|
+
${Date.now()}
|
|
3536
|
+
`, {
|
|
3537
|
+
encoding: "utf8",
|
|
3538
|
+
mode: 384
|
|
3539
|
+
});
|
|
3540
|
+
} catch (error) {
|
|
3541
|
+
fs2.rmSync(lock, { recursive: true, force: true });
|
|
3542
|
+
throw error;
|
|
3543
|
+
}
|
|
3544
|
+
acquired = true;
|
|
3545
|
+
break;
|
|
3546
|
+
} catch (error) {
|
|
3547
|
+
if (errorCode(error) !== "EEXIST") throw error;
|
|
3548
|
+
try {
|
|
3549
|
+
const firstOwner = fs2.readFileSync(ownerPath, "utf8");
|
|
3550
|
+
const [, pidText, createdText] = firstOwner.trim().split("\n");
|
|
3551
|
+
const stale = Date.now() - Number(createdText) > REPAIR_STALE_LOCK_MS;
|
|
3552
|
+
if (stale && !processAlive(Number(pidText))) {
|
|
3553
|
+
const secondOwner = fs2.readFileSync(ownerPath, "utf8");
|
|
3554
|
+
if (secondOwner === firstOwner && reapStaleLock(lock, (claimed) => {
|
|
3555
|
+
try {
|
|
3556
|
+
const owner = fs2.readFileSync(path2.join(claimed, "owner"), "utf8");
|
|
3557
|
+
const [, pid, created] = owner.trim().split("\n");
|
|
3558
|
+
return Date.now() - Number(created) > REPAIR_STALE_LOCK_MS && !processAlive(Number(pid));
|
|
3559
|
+
} catch {
|
|
3560
|
+
return false;
|
|
3561
|
+
}
|
|
3562
|
+
})) {
|
|
3563
|
+
continue;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
} catch {
|
|
3567
|
+
try {
|
|
3568
|
+
const first = fs2.statSync(lock);
|
|
3569
|
+
if (Date.now() - first.mtimeMs > REPAIR_STALE_LOCK_MS && reapStaleLock(lock, (claimed) => {
|
|
3570
|
+
try {
|
|
3571
|
+
return Date.now() - fs2.statSync(claimed).mtimeMs > REPAIR_STALE_LOCK_MS;
|
|
3572
|
+
} catch {
|
|
3573
|
+
return false;
|
|
3574
|
+
}
|
|
3575
|
+
})) {
|
|
3576
|
+
continue;
|
|
3577
|
+
}
|
|
3578
|
+
} catch {
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
if (attempt === REPAIR_LOCK_ATTEMPTS - 1) break;
|
|
3582
|
+
sleepSync(REPAIR_LOCK_DELAY_MS);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
if (!acquired) throw new Error("Timed out waiting for the Fabric repair table lock");
|
|
3586
|
+
try {
|
|
3587
|
+
return operation();
|
|
3588
|
+
} finally {
|
|
3589
|
+
try {
|
|
3590
|
+
const owner = fs2.readFileSync(ownerPath, "utf8");
|
|
3591
|
+
if (owner.startsWith(`${token}
|
|
3592
|
+
`)) {
|
|
3593
|
+
fs2.rmSync(lock, { recursive: true, force: true });
|
|
3594
|
+
}
|
|
3595
|
+
} catch {
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
};
|
|
3599
|
+
var loadRepairTable = (directory, catalogDigest) => {
|
|
3600
|
+
const file = currentPath(directory);
|
|
3601
|
+
let raw;
|
|
3602
|
+
try {
|
|
3603
|
+
raw = fs2.readFileSync(file, "utf8");
|
|
3604
|
+
} catch (error) {
|
|
3605
|
+
if (errorCode(error) === "ENOENT") return { table: emptyRepairTable(catalogDigest) };
|
|
3606
|
+
return {
|
|
3607
|
+
table: emptyRepairTable(catalogDigest),
|
|
3608
|
+
error: `repair table is unreadable: ${errorText(error)}`
|
|
3609
|
+
};
|
|
3610
|
+
}
|
|
3611
|
+
let parsed;
|
|
3612
|
+
try {
|
|
3613
|
+
parsed = JSON.parse(raw);
|
|
3614
|
+
} catch {
|
|
3615
|
+
return { table: emptyRepairTable(catalogDigest), error: "repair table is malformed JSON" };
|
|
3616
|
+
}
|
|
3617
|
+
const table = parseRepairTable(parsed);
|
|
3618
|
+
if (!table) {
|
|
3619
|
+
return { table: emptyRepairTable(catalogDigest), error: "repair table is invalid" };
|
|
3620
|
+
}
|
|
3621
|
+
if (table.catalogDigest !== catalogDigest) return { table: emptyRepairTable(catalogDigest) };
|
|
3622
|
+
return { table };
|
|
3623
|
+
};
|
|
3624
|
+
var saveRepairTable = (directory, table) => withRepairLock(directory, () => {
|
|
3625
|
+
const loaded = loadRepairTable(directory, table.catalogDigest);
|
|
3626
|
+
if (loaded.error) throw new Error(loaded.error);
|
|
3627
|
+
const persisted = loaded.table;
|
|
3628
|
+
const repairs = [];
|
|
3629
|
+
const identities = /* @__PURE__ */ new Set();
|
|
3630
|
+
for (const repair of [...persisted.repairs, ...table.repairs]) {
|
|
3631
|
+
const identity = repairIdentity(repair);
|
|
3632
|
+
if (identities.has(identity)) continue;
|
|
3633
|
+
if (repairs.length >= MAX_CATALOG_REPAIRS) break;
|
|
3634
|
+
identities.add(identity);
|
|
3635
|
+
repairs.push(repair);
|
|
3636
|
+
}
|
|
3637
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3638
|
+
const merged = {
|
|
3639
|
+
version: REPAIR_TABLE_VERSION,
|
|
3640
|
+
catalogDigest: table.catalogDigest,
|
|
3641
|
+
repairs,
|
|
3642
|
+
createdAt: persisted.repairs.length > 0 ? persisted.createdAt : table.createdAt,
|
|
3643
|
+
updatedAt: now
|
|
3644
|
+
};
|
|
3645
|
+
writeTable(currentPath(directory), merged);
|
|
3646
|
+
return merged;
|
|
3647
|
+
});
|
|
3648
|
+
|
|
3649
|
+
// src/repairs/compiler.ts
|
|
3650
|
+
var errorMessage3 = (error) => (error instanceof Error ? error.message : String(error)).slice(0, 240);
|
|
3651
|
+
var RepairCompiler = class {
|
|
3652
|
+
directory;
|
|
3653
|
+
enabled;
|
|
3654
|
+
#digest = "";
|
|
3655
|
+
#table;
|
|
3656
|
+
#counts = /* @__PURE__ */ new Map();
|
|
3657
|
+
#applyHits = 0;
|
|
3658
|
+
#invocationErrors = 0;
|
|
3659
|
+
#effectDropped = 0;
|
|
3660
|
+
#storeError;
|
|
3661
|
+
constructor(options) {
|
|
3662
|
+
this.directory = repairsDirectory(options.agentDir);
|
|
3663
|
+
this.enabled = options.enabled !== false;
|
|
3664
|
+
this.#table = emptyRepairTable("");
|
|
3665
|
+
}
|
|
3666
|
+
get catalogDigest() {
|
|
3667
|
+
return this.#digest;
|
|
3668
|
+
}
|
|
3669
|
+
get repairs() {
|
|
3670
|
+
return this.#table.repairs;
|
|
3671
|
+
}
|
|
3672
|
+
setCatalogSurface(surface) {
|
|
3673
|
+
const digest3 = catalogDigestFromSurface(surface);
|
|
3674
|
+
if (digest3 === this.#digest && this.#table.catalogDigest === digest3) return;
|
|
3675
|
+
this.#digest = digest3;
|
|
3676
|
+
if (!this.enabled) {
|
|
3677
|
+
this.#table = emptyRepairTable(digest3);
|
|
3678
|
+
this.#storeError = void 0;
|
|
3679
|
+
} else {
|
|
3680
|
+
const loaded = loadRepairTable(this.directory, digest3);
|
|
3681
|
+
this.#table = loaded.table;
|
|
3682
|
+
this.#storeError = loaded.error;
|
|
3683
|
+
}
|
|
3684
|
+
this.#counts.clear();
|
|
3685
|
+
}
|
|
3686
|
+
observe(classification, options) {
|
|
3687
|
+
if (classification.stage === "effect") {
|
|
3688
|
+
this.#effectDropped += 1;
|
|
3689
|
+
return void 0;
|
|
3690
|
+
}
|
|
3691
|
+
if (options?.countError !== false) this.#invocationErrors += 1;
|
|
3692
|
+
const existing = this.#counts.get(classification.fingerprint);
|
|
3693
|
+
const candidate = classification.candidate ?? existing?.candidate;
|
|
3694
|
+
const next = {
|
|
3695
|
+
stage: classification.stage,
|
|
3696
|
+
count: (existing?.count ?? 0) + 1,
|
|
3697
|
+
...candidate ? { candidate } : {}
|
|
3698
|
+
};
|
|
3699
|
+
this.#counts.set(classification.fingerprint, next);
|
|
3700
|
+
if (!this.enabled || !next.candidate) return void 0;
|
|
3701
|
+
return this.#promote(next.candidate);
|
|
3702
|
+
}
|
|
3703
|
+
recordInvocationError() {
|
|
3704
|
+
this.#invocationErrors += 1;
|
|
3705
|
+
}
|
|
3706
|
+
observeInvalidArgs(ref, args, declared, message2, options) {
|
|
3707
|
+
const extra = options?.extraKeys ?? Object.keys(args).filter((key) => !declared.includes(key));
|
|
3708
|
+
const candidate = keyAliasCandidate(ref, extra, declared);
|
|
3709
|
+
return this.observe(
|
|
3710
|
+
{
|
|
3711
|
+
stage: "invocation_args",
|
|
3712
|
+
fingerprint: extra[0] ? `args:${ref}:${extra[0]}` : `args:${ref}:${message2.slice(0, 80)}`,
|
|
3713
|
+
...candidate ? { candidate } : {}
|
|
3714
|
+
},
|
|
3715
|
+
options
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3718
|
+
observeUnknownAction(provider, actionName, declared, options) {
|
|
3719
|
+
const candidate = actionAliasCandidate(provider, actionName, declared);
|
|
3720
|
+
return this.observe(
|
|
3721
|
+
{
|
|
3722
|
+
stage: "invocation_unknown_action",
|
|
3723
|
+
fingerprint: `unknown:${provider}.${actionName}`,
|
|
3724
|
+
...candidate ? { candidate } : {}
|
|
3725
|
+
},
|
|
3726
|
+
options
|
|
3727
|
+
);
|
|
3728
|
+
}
|
|
3729
|
+
applyArgs(ref, args, schema) {
|
|
3730
|
+
if (!this.enabled || this.#table.repairs.length === 0) return args;
|
|
3731
|
+
const result = applyCatalogArgRepairs(ref, args, this.#table.repairs, schema);
|
|
3732
|
+
if (result.changed) this.#applyHits += 1;
|
|
3733
|
+
return result.args;
|
|
3734
|
+
}
|
|
3735
|
+
applyActionName(provider, actionName, declared) {
|
|
3736
|
+
if (!this.enabled || this.#table.repairs.length === 0) return actionName;
|
|
3737
|
+
const repaired = applyActionAliasRepairs(
|
|
3738
|
+
provider,
|
|
3739
|
+
actionName,
|
|
3740
|
+
this.#table.repairs,
|
|
3741
|
+
declared
|
|
3742
|
+
);
|
|
3743
|
+
if (repaired && repaired !== actionName) {
|
|
3744
|
+
this.#applyHits += 1;
|
|
3745
|
+
return repaired;
|
|
3746
|
+
}
|
|
3747
|
+
return actionName;
|
|
3748
|
+
}
|
|
3749
|
+
status() {
|
|
3750
|
+
const fingerprints = [...this.#counts.entries()].map(([fingerprint, state]) => ({
|
|
3751
|
+
fingerprint,
|
|
3752
|
+
stage: state.stage,
|
|
3753
|
+
count: state.count
|
|
3754
|
+
})).sort((left, right) => right.count - left.count || left.fingerprint.localeCompare(right.fingerprint)).slice(0, 20);
|
|
3755
|
+
return {
|
|
3756
|
+
enabled: this.enabled,
|
|
3757
|
+
catalogDigest: this.#digest,
|
|
3758
|
+
repairCount: this.#table.repairs.length,
|
|
3759
|
+
applyHits: this.#applyHits,
|
|
3760
|
+
invocationErrors: this.#invocationErrors,
|
|
3761
|
+
effectDropped: this.#effectDropped,
|
|
3762
|
+
...this.#storeError ? { storeError: this.#storeError } : {},
|
|
3763
|
+
fingerprints,
|
|
3764
|
+
repairs: [...this.#table.repairs]
|
|
3765
|
+
};
|
|
3766
|
+
}
|
|
3767
|
+
#promote(candidate) {
|
|
3768
|
+
if (!this.#digest) return void 0;
|
|
3769
|
+
const identity = repairIdentity(candidate);
|
|
3770
|
+
if (this.#table.repairs.some((repair) => repairIdentity(repair) === identity)) {
|
|
3771
|
+
if (this.#storeError) this.#persist(this.#table);
|
|
3772
|
+
return void 0;
|
|
3773
|
+
}
|
|
3774
|
+
if (this.#table.repairs.length >= MAX_CATALOG_REPAIRS) return void 0;
|
|
3775
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3776
|
+
const next = {
|
|
3777
|
+
...this.#table,
|
|
3778
|
+
catalogDigest: this.#digest || this.#table.catalogDigest,
|
|
3779
|
+
repairs: [...this.#table.repairs, candidate],
|
|
3780
|
+
updatedAt: now,
|
|
3781
|
+
createdAt: this.#table.createdAt || now
|
|
3782
|
+
};
|
|
3783
|
+
const saved = this.#persist(next);
|
|
3784
|
+
if (!saved) return candidate;
|
|
3785
|
+
return saved.repairs.some((repair) => repairIdentity(repair) === identity) ? candidate : void 0;
|
|
3786
|
+
}
|
|
3787
|
+
#persist(table) {
|
|
3788
|
+
try {
|
|
3789
|
+
this.#table = saveRepairTable(this.directory, table);
|
|
3790
|
+
this.#storeError = void 0;
|
|
3791
|
+
return this.#table;
|
|
3792
|
+
} catch (error) {
|
|
3793
|
+
this.#table = table;
|
|
3794
|
+
this.#storeError = errorMessage3(error);
|
|
3795
|
+
return void 0;
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
|
|
3329
3800
|
// src/speculation/eligibility.ts
|
|
3330
3801
|
var TIER_A_SPECULATION_REFS = /* @__PURE__ */ new Set([
|
|
3331
3802
|
"pi.read",
|
|
@@ -3367,11 +3838,11 @@ var isSpeculationEligible = (action, mcpAllowlist) => {
|
|
|
3367
3838
|
};
|
|
3368
3839
|
|
|
3369
3840
|
// src/speculation/freshness.ts
|
|
3370
|
-
import
|
|
3371
|
-
import
|
|
3841
|
+
import fs3 from "node:fs";
|
|
3842
|
+
import path3 from "node:path";
|
|
3372
3843
|
var statSignature = (filePath) => {
|
|
3373
3844
|
try {
|
|
3374
|
-
const stats =
|
|
3845
|
+
const stats = fs3.statSync(filePath);
|
|
3375
3846
|
return { mtimeMs: stats.mtimeMs, size: stats.size };
|
|
3376
3847
|
} catch (error) {
|
|
3377
3848
|
const code = error instanceof Error && "code" in error ? error.code : void 0;
|
|
@@ -3382,7 +3853,7 @@ var signatureEquals = (left, right) => left === "missing" || right === "missing"
|
|
|
3382
3853
|
var readFreshness = (args, cwd) => {
|
|
3383
3854
|
const target = args.path;
|
|
3384
3855
|
if (typeof target !== "string" || target.length === 0) return void 0;
|
|
3385
|
-
const resolved =
|
|
3856
|
+
const resolved = path3.resolve(cwd, target);
|
|
3386
3857
|
const snapshot = statSignature(resolved);
|
|
3387
3858
|
if (snapshot === "error") return void 0;
|
|
3388
3859
|
return () => {
|
|
@@ -3425,23 +3896,24 @@ var FabricSpeculationStore = class _FabricSpeculationStore {
|
|
|
3425
3896
|
bumpEpoch() {
|
|
3426
3897
|
this.#epoch += 1;
|
|
3427
3898
|
}
|
|
3428
|
-
static key(parentToolCallId, ref, preparedArgs) {
|
|
3899
|
+
static key(parentToolCallId, ref, preparedArgs, bindingToken) {
|
|
3429
3900
|
return `${parentToolCallId}
|
|
3430
3901
|
${ref}
|
|
3431
|
-
${stableJsonHash(preparedArgs)}
|
|
3902
|
+
${stableJsonHash(preparedArgs)}
|
|
3903
|
+
${bindingToken}`;
|
|
3432
3904
|
}
|
|
3433
3905
|
/**
|
|
3434
3906
|
* Register and start a speculative invocation. Returns false when at
|
|
3435
3907
|
* capacity; the candidate is dropped silently (a miss costs nothing, the
|
|
3436
3908
|
* real call executes normally later).
|
|
3437
3909
|
*/
|
|
3438
|
-
launch(parentToolCallId, ref, preparedArgs, execute, freshness, replay) {
|
|
3910
|
+
launch(parentToolCallId, ref, preparedArgs, execute, freshness, replay, bindingToken) {
|
|
3439
3911
|
this.#sweepExpired(Date.now());
|
|
3440
3912
|
if (this.#entries.size >= this.#maxEntries || this.#inFlightCount() >= this.#maxConcurrent) {
|
|
3441
3913
|
this.#stats.skipped += 1;
|
|
3442
3914
|
return false;
|
|
3443
3915
|
}
|
|
3444
|
-
const key = _FabricSpeculationStore.key(parentToolCallId, ref, preparedArgs);
|
|
3916
|
+
const key = _FabricSpeculationStore.key(parentToolCallId, ref, preparedArgs, bindingToken);
|
|
3445
3917
|
if (this.#entries.has(key)) {
|
|
3446
3918
|
this.#stats.skipped += 1;
|
|
3447
3919
|
return false;
|
|
@@ -3465,8 +3937,8 @@ ${stableJsonHash(preparedArgs)}`;
|
|
|
3465
3937
|
this.#stats.launched += 1;
|
|
3466
3938
|
return true;
|
|
3467
3939
|
}
|
|
3468
|
-
async tryServe(parentToolCallId, ref, preparedArgs) {
|
|
3469
|
-
const key = _FabricSpeculationStore.key(parentToolCallId, ref, preparedArgs);
|
|
3940
|
+
async tryServe(parentToolCallId, ref, preparedArgs, bindingToken) {
|
|
3941
|
+
const key = _FabricSpeculationStore.key(parentToolCallId, ref, preparedArgs, bindingToken);
|
|
3470
3942
|
const entry = this.#entries.get(key);
|
|
3471
3943
|
if (!entry || entry.parentToolCallId !== parentToolCallId) {
|
|
3472
3944
|
return { hit: false, reason: "absent" };
|
|
@@ -3791,12 +4263,12 @@ var LifecycleDeliveryScheduler = class {
|
|
|
3791
4263
|
|
|
3792
4264
|
// src/core/model-usage.ts
|
|
3793
4265
|
import { readFileSync } from "node:fs";
|
|
3794
|
-
import
|
|
4266
|
+
import path4 from "node:path";
|
|
3795
4267
|
var MODEL_USAGE_FILENAME = "pi-model-sort.json";
|
|
3796
4268
|
var loadModelUsage = (agentDir = resolveAgentDir()) => {
|
|
3797
4269
|
try {
|
|
3798
4270
|
const raw = JSON.parse(
|
|
3799
|
-
readFileSync(
|
|
4271
|
+
readFileSync(path4.join(agentDir, "extensions", MODEL_USAGE_FILENAME), "utf8")
|
|
3800
4272
|
);
|
|
3801
4273
|
const lastUsed = raw?.lastUsed;
|
|
3802
4274
|
if (typeof lastUsed !== "object" || lastUsed === null) return {};
|
|
@@ -4469,9 +4941,9 @@ var AGENTS_ACTION_DESCRIPTORS = [
|
|
|
4469
4941
|
];
|
|
4470
4942
|
|
|
4471
4943
|
// src/residency/client.ts
|
|
4472
|
-
import { randomUUID as
|
|
4473
|
-
import
|
|
4474
|
-
import
|
|
4944
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
4945
|
+
import fs4 from "node:fs";
|
|
4946
|
+
import path5 from "node:path";
|
|
4475
4947
|
import { fileURLToPath } from "node:url";
|
|
4476
4948
|
var STARTUP_TIMEOUT_MS = 3e4;
|
|
4477
4949
|
var COMMAND_TIMEOUT_MS = 3e4;
|
|
@@ -4483,7 +4955,7 @@ var atomicWrite2 = (filePath, value) => {
|
|
|
4483
4955
|
};
|
|
4484
4956
|
var readJson = (filePath) => {
|
|
4485
4957
|
try {
|
|
4486
|
-
return JSON.parse(
|
|
4958
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf8"));
|
|
4487
4959
|
} catch {
|
|
4488
4960
|
return void 0;
|
|
4489
4961
|
}
|
|
@@ -4491,7 +4963,7 @@ var readJson = (filePath) => {
|
|
|
4491
4963
|
var terminal = (status) => status === "completed" || status === "failed" || status === "stopped" || status === "timed_out";
|
|
4492
4964
|
var samePath = (left, right) => {
|
|
4493
4965
|
try {
|
|
4494
|
-
return
|
|
4966
|
+
return path5.relative(fs4.realpathSync.native(left), fs4.realpathSync.native(right)) === "";
|
|
4495
4967
|
} catch {
|
|
4496
4968
|
return false;
|
|
4497
4969
|
}
|
|
@@ -4520,12 +4992,12 @@ var ResidencyClient = class {
|
|
|
4520
4992
|
constructor(options) {
|
|
4521
4993
|
this.options = options;
|
|
4522
4994
|
this.hostId = residentHostId(options.config.rootId);
|
|
4523
|
-
this.#configPath =
|
|
4524
|
-
this.#ownerPath =
|
|
4525
|
-
this.#errorPath =
|
|
4526
|
-
this.#requestsPath =
|
|
4527
|
-
this.#responsesPath =
|
|
4528
|
-
this.#agentsPath =
|
|
4995
|
+
this.#configPath = path5.join(options.config.residencyRoot, "config.json");
|
|
4996
|
+
this.#ownerPath = path5.join(options.config.residencyRoot, "owner.json");
|
|
4997
|
+
this.#errorPath = path5.join(options.config.residencyRoot, "error.json");
|
|
4998
|
+
this.#requestsPath = path5.join(options.config.residencyRoot, "requests");
|
|
4999
|
+
this.#responsesPath = path5.join(options.config.residencyRoot, "responses");
|
|
5000
|
+
this.#agentsPath = path5.join(options.config.residencyRoot, "agents");
|
|
4529
5001
|
this.#deliveryPrefix = residentDeliveryPrefix(options.config.rootId);
|
|
4530
5002
|
this.#hostPath = options.hostPath ?? fileURLToPath(new URL("./launcher.js", import.meta.url));
|
|
4531
5003
|
}
|
|
@@ -4563,7 +5035,7 @@ var ResidencyClient = class {
|
|
|
4563
5035
|
if (serialized === this.#modelGuidanceJson) return;
|
|
4564
5036
|
this.#modelGuidanceJson = serialized;
|
|
4565
5037
|
this.options.config.modelGuidance = snapshot;
|
|
4566
|
-
if (
|
|
5038
|
+
if (fs4.existsSync(this.options.config.residencyRoot)) {
|
|
4567
5039
|
atomicWrite2(this.#configPath, this.options.config);
|
|
4568
5040
|
}
|
|
4569
5041
|
}
|
|
@@ -4572,7 +5044,7 @@ var ResidencyClient = class {
|
|
|
4572
5044
|
atomicWrite2(this.#configPath, this.options.config);
|
|
4573
5045
|
const existing = this.#liveOwner();
|
|
4574
5046
|
if (existing) return existing;
|
|
4575
|
-
|
|
5047
|
+
fs4.rmSync(this.#errorPath, { force: true });
|
|
4576
5048
|
await spawnDetached(
|
|
4577
5049
|
this.#hostPath,
|
|
4578
5050
|
["--config", this.#configPath],
|
|
@@ -4590,7 +5062,7 @@ var ResidencyClient = class {
|
|
|
4590
5062
|
}
|
|
4591
5063
|
const readIfPresent = (name) => {
|
|
4592
5064
|
try {
|
|
4593
|
-
return
|
|
5065
|
+
return fs4.readFileSync(path5.join(this.options.config.residencyRoot, name), "utf8").trim();
|
|
4594
5066
|
} catch {
|
|
4595
5067
|
return "";
|
|
4596
5068
|
}
|
|
@@ -4617,7 +5089,7 @@ var ResidencyClient = class {
|
|
|
4617
5089
|
{
|
|
4618
5090
|
format: RESIDENT_HOST_FORMAT,
|
|
4619
5091
|
operation: "spawn",
|
|
4620
|
-
requestId:
|
|
5092
|
+
requestId: randomUUID3(),
|
|
4621
5093
|
rootId: this.options.config.rootId,
|
|
4622
5094
|
request: { ...resolvedRequest, residency: "durable" },
|
|
4623
5095
|
createdAt: Date.now()
|
|
@@ -4629,18 +5101,18 @@ var ResidencyClient = class {
|
|
|
4629
5101
|
return response.handle;
|
|
4630
5102
|
}
|
|
4631
5103
|
hasAgent(id) {
|
|
4632
|
-
return AGENT_ID_PATTERN.test(id) &&
|
|
5104
|
+
return AGENT_ID_PATTERN.test(id) && fs4.existsSync(this.#metadataPath(id));
|
|
4633
5105
|
}
|
|
4634
5106
|
statusAgent(id) {
|
|
4635
5107
|
const metadata = this.#metadata(id);
|
|
4636
5108
|
if (!metadata) throw new Error(`Unknown durable Fabric agent: ${id}`);
|
|
4637
|
-
const record = readJson(
|
|
5109
|
+
const record = readJson(path5.join(metadata.runDirectory, "status.json"));
|
|
4638
5110
|
if (!record || record.id !== metadata.id) return structuredClone(metadata.handle);
|
|
4639
5111
|
return {
|
|
4640
5112
|
...record,
|
|
4641
5113
|
cwd: metadata.handle.cwd,
|
|
4642
5114
|
residency: "durable",
|
|
4643
|
-
logFile:
|
|
5115
|
+
logFile: path5.join(metadata.runDirectory, "events.jsonl"),
|
|
4644
5116
|
...metadata.handle.sessionId ? { sessionId: metadata.handle.sessionId } : {},
|
|
4645
5117
|
...metadata.handle.attachCommand ? { attachCommand: metadata.handle.attachCommand } : {}
|
|
4646
5118
|
};
|
|
@@ -4648,7 +5120,7 @@ var ResidencyClient = class {
|
|
|
4648
5120
|
listAgents() {
|
|
4649
5121
|
let entries;
|
|
4650
5122
|
try {
|
|
4651
|
-
entries =
|
|
5123
|
+
entries = fs4.readdirSync(this.#agentsPath);
|
|
4652
5124
|
} catch {
|
|
4653
5125
|
return [];
|
|
4654
5126
|
}
|
|
@@ -4665,7 +5137,7 @@ var ResidencyClient = class {
|
|
|
4665
5137
|
await this.#command({
|
|
4666
5138
|
format: RESIDENT_HOST_FORMAT,
|
|
4667
5139
|
operation: "foreground",
|
|
4668
|
-
requestId:
|
|
5140
|
+
requestId: randomUUID3(),
|
|
4669
5141
|
rootId: this.options.config.rootId,
|
|
4670
5142
|
id,
|
|
4671
5143
|
createdAt: Date.now()
|
|
@@ -4681,9 +5153,9 @@ var ResidencyClient = class {
|
|
|
4681
5153
|
readAgentLog(id, options = {}) {
|
|
4682
5154
|
const metadata = this.#metadata(id);
|
|
4683
5155
|
if (!metadata) throw new Error(`Unknown durable Fabric agent: ${id}`);
|
|
4684
|
-
const logFile =
|
|
5156
|
+
const logFile = path5.join(metadata.runDirectory, "events.jsonl");
|
|
4685
5157
|
const page = readJsonlPage(logFile, Math.max(1, Math.min(options.lines ?? 200, 5e3)), options.before);
|
|
4686
|
-
const status = readJson(
|
|
5158
|
+
const status = readJson(path5.join(metadata.runDirectory, "status.json"));
|
|
4687
5159
|
return {
|
|
4688
5160
|
id,
|
|
4689
5161
|
runDirectory: metadata.runDirectory,
|
|
@@ -4699,7 +5171,7 @@ var ResidencyClient = class {
|
|
|
4699
5171
|
await this.#command({
|
|
4700
5172
|
format: RESIDENT_HOST_FORMAT,
|
|
4701
5173
|
operation: "removeActor",
|
|
4702
|
-
requestId:
|
|
5174
|
+
requestId: randomUUID3(),
|
|
4703
5175
|
rootId: this.options.config.rootId,
|
|
4704
5176
|
id,
|
|
4705
5177
|
createdAt: Date.now()
|
|
@@ -4715,7 +5187,7 @@ var ResidencyClient = class {
|
|
|
4715
5187
|
response = await this.#command({
|
|
4716
5188
|
format: RESIDENT_HOST_FORMAT,
|
|
4717
5189
|
operation: "cleanup",
|
|
4718
|
-
requestId:
|
|
5190
|
+
requestId: randomUUID3(),
|
|
4719
5191
|
rootId: this.options.config.rootId,
|
|
4720
5192
|
id,
|
|
4721
5193
|
deleteBranch,
|
|
@@ -4753,19 +5225,19 @@ var ResidencyClient = class {
|
|
|
4753
5225
|
} else if (deleteBranch) {
|
|
4754
5226
|
throw new Error(`Durable Fabric agent ${metadata.id} has no worktree branch to delete`);
|
|
4755
5227
|
}
|
|
4756
|
-
|
|
4757
|
-
|
|
5228
|
+
fs4.rmSync(metadata.runDirectory, { recursive: true, force: true });
|
|
5229
|
+
fs4.rmSync(this.#metadataPath(metadata.id), { force: true });
|
|
4758
5230
|
return { cleaned: true };
|
|
4759
5231
|
}
|
|
4760
5232
|
async #command(command, signal) {
|
|
4761
|
-
const responsePath =
|
|
4762
|
-
atomicWrite2(
|
|
5233
|
+
const responsePath = path5.join(this.#responsesPath, `${command.requestId}.json`);
|
|
5234
|
+
atomicWrite2(path5.join(this.#requestsPath, `${command.requestId}.json`), command);
|
|
4763
5235
|
const deadline = Date.now() + COMMAND_TIMEOUT_MS;
|
|
4764
5236
|
while (Date.now() < deadline) {
|
|
4765
5237
|
if (signal?.aborted) throw new Error("Fabric residency request was aborted");
|
|
4766
5238
|
const response = readJson(responsePath);
|
|
4767
5239
|
if (response?.format === RESIDENT_HOST_FORMAT && response.requestId === command.requestId) {
|
|
4768
|
-
|
|
5240
|
+
fs4.rmSync(responsePath, { force: true });
|
|
4769
5241
|
if (!response.ok) throw new Error(response.error ?? "Fabric resident host rejected request");
|
|
4770
5242
|
return response;
|
|
4771
5243
|
}
|
|
@@ -4787,12 +5259,12 @@ var ResidencyClient = class {
|
|
|
4787
5259
|
throw new Error(`Timed out publishing durable Fabric ${kind} ${id} from ${this.hostId}`);
|
|
4788
5260
|
}
|
|
4789
5261
|
#metadataPath(id) {
|
|
4790
|
-
return
|
|
5262
|
+
return path5.join(this.#agentsPath, `${id}.json`);
|
|
4791
5263
|
}
|
|
4792
5264
|
#metadata(id) {
|
|
4793
5265
|
if (!AGENT_ID_PATTERN.test(id)) return void 0;
|
|
4794
5266
|
const metadata = readJson(this.#metadataPath(id));
|
|
4795
|
-
if (metadata?.format !== RESIDENT_HOST_FORMAT || metadata.rootId !== this.options.config.rootId || metadata.id !== id || metadata.handle.id !== id || metadata.worktreeGitRoot !== void 0 && typeof metadata.worktreeGitRoot !== "string" ||
|
|
5267
|
+
if (metadata?.format !== RESIDENT_HOST_FORMAT || metadata.rootId !== this.options.config.rootId || metadata.id !== id || metadata.handle.id !== id || metadata.worktreeGitRoot !== void 0 && typeof metadata.worktreeGitRoot !== "string" || path5.resolve(metadata.runDirectory) !== path5.resolve(this.options.config.residencyRoot, "runs", id)) {
|
|
4796
5268
|
return void 0;
|
|
4797
5269
|
}
|
|
4798
5270
|
if (metadata.handle.worktree && !isFabricWorktreePath(metadata.handle.worktree, id)) {
|
|
@@ -6099,16 +6571,16 @@ var AgentsProvider = class {
|
|
|
6099
6571
|
};
|
|
6100
6572
|
|
|
6101
6573
|
// src/providers/captured-tools-provider.ts
|
|
6102
|
-
import
|
|
6574
|
+
import path6 from "node:path";
|
|
6103
6575
|
var textFromContent2 = (content) => content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
6104
6576
|
var sourceLabel = (sourceInfo) => {
|
|
6105
6577
|
if (sourceInfo.path.startsWith("<")) return sourceInfo.source;
|
|
6106
6578
|
const segments = sourceInfo.path.split(/[\\/]/);
|
|
6107
6579
|
const packageSegment = [...segments].reverse().find((segment) => segment.startsWith("pi-"));
|
|
6108
6580
|
if (packageSegment) return packageSegment;
|
|
6109
|
-
const filename =
|
|
6581
|
+
const filename = path6.basename(sourceInfo.path).replace(/\.[^.]+$/, "");
|
|
6110
6582
|
if (filename && filename !== "index") return filename;
|
|
6111
|
-
return
|
|
6583
|
+
return path6.basename(path6.dirname(sourceInfo.path)) || sourceInfo.source;
|
|
6112
6584
|
};
|
|
6113
6585
|
var capturedToolNamespace = (entry) => `extension:${sourceLabel(entry.sourceInfo)}`;
|
|
6114
6586
|
var descriptorFrom = (entry) => ({
|
|
@@ -6485,35 +6957,35 @@ var ComponentsProvider = class {
|
|
|
6485
6957
|
};
|
|
6486
6958
|
|
|
6487
6959
|
// src/providers/mcp-descriptor-cache.ts
|
|
6488
|
-
import
|
|
6960
|
+
import fs5 from "node:fs/promises";
|
|
6489
6961
|
import fsSync from "node:fs";
|
|
6490
6962
|
import os from "node:os";
|
|
6491
|
-
import
|
|
6963
|
+
import path7 from "node:path";
|
|
6492
6964
|
var MCP_DESCRIPTOR_CACHE_VERSION = 1;
|
|
6493
6965
|
var expandHome = (input) => {
|
|
6494
6966
|
if (!input.startsWith("~")) return input;
|
|
6495
6967
|
const home = os.homedir();
|
|
6496
6968
|
if (input === "~") return home;
|
|
6497
6969
|
if (input.startsWith("~/") || input.startsWith("~\\")) {
|
|
6498
|
-
return
|
|
6970
|
+
return path7.join(home, input.slice(2));
|
|
6499
6971
|
}
|
|
6500
6972
|
return input;
|
|
6501
6973
|
};
|
|
6502
|
-
var legacyMcporterDir = () =>
|
|
6974
|
+
var legacyMcporterDir = () => path7.join(os.homedir(), ".mcporter");
|
|
6503
6975
|
var mcporterConfigDir = () => {
|
|
6504
6976
|
const raw = process.env.XDG_CONFIG_HOME;
|
|
6505
6977
|
if (raw && raw.trim().length > 0) {
|
|
6506
6978
|
const resolved = expandHome(raw.trim());
|
|
6507
|
-
if (
|
|
6979
|
+
if (path7.isAbsolute(resolved)) return path7.join(resolved, "mcporter");
|
|
6508
6980
|
}
|
|
6509
6981
|
return legacyMcporterDir();
|
|
6510
6982
|
};
|
|
6511
6983
|
var mcporterConfigCandidates = () => {
|
|
6512
6984
|
const base = mcporterConfigDir();
|
|
6513
|
-
const candidates = [
|
|
6985
|
+
const candidates = [path7.join(base, "mcporter.json"), path7.join(base, "mcporter.jsonc")];
|
|
6514
6986
|
const legacy = legacyMcporterDir();
|
|
6515
6987
|
if (base !== legacy) {
|
|
6516
|
-
candidates.push(
|
|
6988
|
+
candidates.push(path7.join(legacy, "mcporter.json"), path7.join(legacy, "mcporter.jsonc"));
|
|
6517
6989
|
}
|
|
6518
6990
|
return candidates;
|
|
6519
6991
|
};
|
|
@@ -6528,12 +7000,12 @@ var pathExists = (filePath) => {
|
|
|
6528
7000
|
var mcpConfigLayerPaths = (rootDir, configPath) => {
|
|
6529
7001
|
const explicitRaw = configPath ?? process.env.MCPORTER_CONFIG;
|
|
6530
7002
|
if (explicitRaw && explicitRaw.trim().length > 0) {
|
|
6531
|
-
return [
|
|
7003
|
+
return [path7.resolve(expandHome(explicitRaw.trim()))];
|
|
6532
7004
|
}
|
|
6533
7005
|
const paths = [];
|
|
6534
7006
|
const home = mcporterConfigCandidates().find(pathExists);
|
|
6535
7007
|
if (home) paths.push(home);
|
|
6536
|
-
const projectPath =
|
|
7008
|
+
const projectPath = path7.resolve(rootDir, "config", "mcporter.json");
|
|
6537
7009
|
if (pathExists(projectPath)) paths.push(projectPath);
|
|
6538
7010
|
return paths;
|
|
6539
7011
|
};
|
|
@@ -6541,7 +7013,7 @@ var statConfigLayers = async (rootDir, configPath) => {
|
|
|
6541
7013
|
const stats = await Promise.all(
|
|
6542
7014
|
mcpConfigLayerPaths(rootDir, configPath).map(async (layerPath) => {
|
|
6543
7015
|
try {
|
|
6544
|
-
const stat2 = await
|
|
7016
|
+
const stat2 = await fs5.stat(layerPath);
|
|
6545
7017
|
return { path: layerPath, mtimeMs: stat2.mtimeMs, size: stat2.size };
|
|
6546
7018
|
} catch {
|
|
6547
7019
|
return void 0;
|
|
@@ -6555,11 +7027,11 @@ var sameConfigLayers = (left, right) => left.length === right.length && left.eve
|
|
|
6555
7027
|
return other !== void 0 && layer.path === other.path && layer.size === other.size && Math.abs(layer.mtimeMs - other.mtimeMs) <= 1;
|
|
6556
7028
|
});
|
|
6557
7029
|
var hashServerDefinition = (definition) => stableJsonHash(definition);
|
|
6558
|
-
var
|
|
7030
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6559
7031
|
var parseCachedServer = (value) => {
|
|
6560
|
-
if (!
|
|
7032
|
+
if (!isRecord2(value)) return void 0;
|
|
6561
7033
|
const tools = Array.isArray(value.tools) ? value.tools.filter(
|
|
6562
|
-
(tool) =>
|
|
7034
|
+
(tool) => isRecord2(tool) && typeof tool.name === "string"
|
|
6563
7035
|
) : void 0;
|
|
6564
7036
|
if (typeof value.definitionHash !== "string" || tools === void 0) return void 0;
|
|
6565
7037
|
return {
|
|
@@ -6572,10 +7044,10 @@ var parseCachedServer = (value) => {
|
|
|
6572
7044
|
};
|
|
6573
7045
|
};
|
|
6574
7046
|
var parseCacheFile = (value) => {
|
|
6575
|
-
if (!
|
|
6576
|
-
if (!Array.isArray(value.layers) || !
|
|
7047
|
+
if (!isRecord2(value) || value.version !== MCP_DESCRIPTOR_CACHE_VERSION) return void 0;
|
|
7048
|
+
if (!Array.isArray(value.layers) || !isRecord2(value.servers)) return void 0;
|
|
6577
7049
|
const layers = value.layers.filter(
|
|
6578
|
-
(layer) =>
|
|
7050
|
+
(layer) => isRecord2(layer) && typeof layer.path === "string" && typeof layer.mtimeMs === "number" && typeof layer.size === "number"
|
|
6579
7051
|
);
|
|
6580
7052
|
return {
|
|
6581
7053
|
version: MCP_DESCRIPTOR_CACHE_VERSION,
|
|
@@ -6591,7 +7063,7 @@ var McpDescriptorCacheStore = class {
|
|
|
6591
7063
|
}
|
|
6592
7064
|
async load() {
|
|
6593
7065
|
try {
|
|
6594
|
-
const raw = await
|
|
7066
|
+
const raw = await fs5.readFile(this.filePath, "utf8");
|
|
6595
7067
|
return parseCacheFile(JSON.parse(raw));
|
|
6596
7068
|
} catch {
|
|
6597
7069
|
return void 0;
|
|
@@ -6600,24 +7072,24 @@ var McpDescriptorCacheStore = class {
|
|
|
6600
7072
|
// Atomic-ish write: temp file then rename, so a concurrent reader either
|
|
6601
7073
|
// sees the previous cache or the next one, never a torn document.
|
|
6602
7074
|
async save(file) {
|
|
6603
|
-
const directory =
|
|
6604
|
-
await
|
|
6605
|
-
const tempPath =
|
|
7075
|
+
const directory = path7.dirname(this.filePath);
|
|
7076
|
+
await fs5.mkdir(directory, { recursive: true });
|
|
7077
|
+
const tempPath = path7.join(
|
|
6606
7078
|
directory,
|
|
6607
7079
|
`.mcp-cache-${process.pid}-${Date.now()}-${tempCounter++}.tmp`
|
|
6608
7080
|
);
|
|
6609
|
-
await
|
|
7081
|
+
await fs5.writeFile(tempPath, JSON.stringify(file, null, 2));
|
|
6610
7082
|
try {
|
|
6611
|
-
await
|
|
7083
|
+
await fs5.rename(tempPath, this.filePath);
|
|
6612
7084
|
} catch (error) {
|
|
6613
|
-
await
|
|
7085
|
+
await fs5.rm(tempPath, { force: true }).catch(() => void 0);
|
|
6614
7086
|
throw error;
|
|
6615
7087
|
}
|
|
6616
7088
|
}
|
|
6617
7089
|
};
|
|
6618
7090
|
|
|
6619
7091
|
// src/providers/mcp-provider.ts
|
|
6620
|
-
import
|
|
7092
|
+
import path8 from "node:path";
|
|
6621
7093
|
var TOOL_METADATA_TTL_MS = 6e4;
|
|
6622
7094
|
var REVALIDATE_CONCURRENCY = 3;
|
|
6623
7095
|
var REVALIDATE_SERVER_TIMEOUT_MS = 2e4;
|
|
@@ -7249,7 +7721,7 @@ var McpProvider = class {
|
|
|
7249
7721
|
kind: "stdio",
|
|
7250
7722
|
command: args.command,
|
|
7251
7723
|
args: commandArgs,
|
|
7252
|
-
cwd:
|
|
7724
|
+
cwd: path8.resolve(this.cwd, typeof args.cwd === "string" ? args.cwd : ".")
|
|
7253
7725
|
},
|
|
7254
7726
|
...env ? { env } : {}
|
|
7255
7727
|
};
|
|
@@ -7616,7 +8088,7 @@ var MeshProvider = class {
|
|
|
7616
8088
|
|
|
7617
8089
|
// src/providers/pi-tools-provider.ts
|
|
7618
8090
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
7619
|
-
import
|
|
8091
|
+
import path11 from "node:path";
|
|
7620
8092
|
import {
|
|
7621
8093
|
createBashToolDefinition as createBashToolDefinition2,
|
|
7622
8094
|
createEditToolDefinition,
|
|
@@ -7627,8 +8099,8 @@ import {
|
|
|
7627
8099
|
} from "@earendil-works/pi-coding-agent";
|
|
7628
8100
|
|
|
7629
8101
|
// src/agents/bash-worktree-add.ts
|
|
7630
|
-
import
|
|
7631
|
-
import
|
|
8102
|
+
import fs6 from "node:fs";
|
|
8103
|
+
import path9 from "node:path";
|
|
7632
8104
|
var BARE_SAFE = /^[A-Za-z0-9_./:@%+=,-]+$/;
|
|
7633
8105
|
var parseGitWorktreeAdd = (command) => {
|
|
7634
8106
|
const trimmed = command.trim();
|
|
@@ -7691,8 +8163,8 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
|
|
|
7691
8163
|
if (typeof command !== "string") return void 0;
|
|
7692
8164
|
const parsed = parseGitWorktreeAdd(command);
|
|
7693
8165
|
if (!parsed) return void 0;
|
|
7694
|
-
const gitCwd = parsed.gitCwd ?
|
|
7695
|
-
const dest =
|
|
8166
|
+
const gitCwd = parsed.gitCwd ? path9.resolve(sessionCwd, parsed.gitCwd) : typeof args.cwd === "string" ? args.cwd : sessionCwd;
|
|
8167
|
+
const dest = path9.resolve(gitCwd, parsed.dest);
|
|
7696
8168
|
let gitRoot;
|
|
7697
8169
|
try {
|
|
7698
8170
|
const root = await executeFile("git", ["rev-parse", "--show-toplevel"], {
|
|
@@ -7701,7 +8173,7 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
|
|
|
7701
8173
|
});
|
|
7702
8174
|
const output = root.stdout.trim();
|
|
7703
8175
|
if (!output) return void 0;
|
|
7704
|
-
gitRoot =
|
|
8176
|
+
gitRoot = fs6.realpathSync(output);
|
|
7705
8177
|
} catch {
|
|
7706
8178
|
return void 0;
|
|
7707
8179
|
}
|
|
@@ -7721,7 +8193,7 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
|
|
|
7721
8193
|
|
|
7722
8194
|
// src/providers/pi-bash-cwd.ts
|
|
7723
8195
|
import { accessSync, constants, statSync } from "node:fs";
|
|
7724
|
-
import
|
|
8196
|
+
import path10 from "node:path";
|
|
7725
8197
|
import { createBashToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
7726
8198
|
import { Type as Type2 } from "typebox";
|
|
7727
8199
|
var PI_BASH_CWD_KEY = "cwd";
|
|
@@ -7731,7 +8203,7 @@ var resolvePiBashCwd = (sessionCwd, requested) => {
|
|
|
7731
8203
|
`Invalid pi.bash cwd ${JSON.stringify(requested)}: path must be a non-empty string`
|
|
7732
8204
|
);
|
|
7733
8205
|
}
|
|
7734
|
-
const resolved =
|
|
8206
|
+
const resolved = path10.isAbsolute(requested) ? path10.resolve(requested) : path10.resolve(sessionCwd, requested);
|
|
7735
8207
|
try {
|
|
7736
8208
|
if (!statSync(resolved).isDirectory()) throw new Error("path is not a directory");
|
|
7737
8209
|
accessSync(resolved, constants.R_OK | constants.X_OK);
|
|
@@ -7747,9 +8219,9 @@ var CWD_PROPERTY = Type2.Optional(
|
|
|
7747
8219
|
description: "Execution directory for this command; relative paths resolve from the session cwd."
|
|
7748
8220
|
})
|
|
7749
8221
|
);
|
|
7750
|
-
var
|
|
8222
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7751
8223
|
var withBashCwdSchema = (schema) => {
|
|
7752
|
-
if (!
|
|
8224
|
+
if (!isRecord3(schema) || !isRecord3(schema.properties)) return schema;
|
|
7753
8225
|
if (Object.hasOwn(schema.properties, PI_BASH_CWD_KEY)) return schema;
|
|
7754
8226
|
const { type: _type, properties, required, ...rest } = schema;
|
|
7755
8227
|
return Type2.Object(
|
|
@@ -7830,14 +8302,14 @@ var createPreviewWriteToolDefinition = (cwd) => {
|
|
|
7830
8302
|
return {
|
|
7831
8303
|
...original,
|
|
7832
8304
|
async execute(_toolCallId, params, signal) {
|
|
7833
|
-
const { path:
|
|
7834
|
-
const absolutePath = resolvePreviewPath(
|
|
8305
|
+
const { path: path17, content } = params;
|
|
8306
|
+
const absolutePath = resolvePreviewPath(path17, cwd);
|
|
7835
8307
|
return withFileMutationQueue(absolutePath, async () => {
|
|
7836
8308
|
const throwIfAborted2 = () => {
|
|
7837
8309
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
7838
8310
|
};
|
|
7839
8311
|
throwIfAborted2();
|
|
7840
|
-
const before = await readExistingFileForPreview(
|
|
8312
|
+
const before = await readExistingFileForPreview(path17, cwd, content);
|
|
7841
8313
|
throwIfAborted2();
|
|
7842
8314
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
7843
8315
|
throwIfAborted2();
|
|
@@ -7847,7 +8319,7 @@ var createPreviewWriteToolDefinition = (cwd) => {
|
|
|
7847
8319
|
content: [
|
|
7848
8320
|
{
|
|
7849
8321
|
type: "text",
|
|
7850
|
-
text: `Successfully wrote ${Buffer.byteLength(content, "utf8")} bytes to ${
|
|
8322
|
+
text: `Successfully wrote ${Buffer.byteLength(content, "utf8")} bytes to ${path17}`
|
|
7851
8323
|
}
|
|
7852
8324
|
],
|
|
7853
8325
|
details: { codePreviewBeforeWrite: before }
|
|
@@ -7881,7 +8353,7 @@ var expandReplaceAllEdit = (cwd, args, allForEveryEdit) => {
|
|
|
7881
8353
|
}
|
|
7882
8354
|
return { oldText, newText, all: allForEveryEdit || record.all === true };
|
|
7883
8355
|
});
|
|
7884
|
-
const resolvedPath =
|
|
8356
|
+
const resolvedPath = path11.resolve(
|
|
7885
8357
|
cwd,
|
|
7886
8358
|
filePath.startsWith("@") ? filePath.slice(1) : filePath
|
|
7887
8359
|
);
|
|
@@ -8249,9 +8721,9 @@ var PiToolsProvider = class {
|
|
|
8249
8721
|
|
|
8250
8722
|
// src/schema/controller.ts
|
|
8251
8723
|
import { spawn } from "node:child_process";
|
|
8252
|
-
import { createHash as createHash3, randomBytes, randomUUID as
|
|
8253
|
-
import
|
|
8254
|
-
import
|
|
8724
|
+
import { createHash as createHash3, randomBytes, randomUUID as randomUUID4 } from "node:crypto";
|
|
8725
|
+
import fs8 from "node:fs";
|
|
8726
|
+
import path13 from "node:path";
|
|
8255
8727
|
|
|
8256
8728
|
// src/schema/types.ts
|
|
8257
8729
|
var stateBinding = (head) => head ? { transitionId: head.transitionId, version: head.version, to: head.to } : null;
|
|
@@ -8259,8 +8731,8 @@ var stateBinding = (head) => head ? { transitionId: head.transitionId, version:
|
|
|
8259
8731
|
// src/schema/workspace.ts
|
|
8260
8732
|
import { execFileSync } from "node:child_process";
|
|
8261
8733
|
import { createHash as createHash2 } from "node:crypto";
|
|
8262
|
-
import
|
|
8263
|
-
import
|
|
8734
|
+
import fs7 from "node:fs";
|
|
8735
|
+
import path12 from "node:path";
|
|
8264
8736
|
var SNAPSHOT_MAX_FILES = 2e4;
|
|
8265
8737
|
var SNAPSHOT_MAX_BYTES = 512 * 1024 * 1024;
|
|
8266
8738
|
var FALLBACK_SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
@@ -8278,16 +8750,16 @@ var git = (cwd, args) => execFileSync("git", ["-C", cwd, ...args], {
|
|
|
8278
8750
|
stdio: ["ignore", "pipe", "ignore"]
|
|
8279
8751
|
});
|
|
8280
8752
|
var nulPaths = (buffer) => buffer.toString("utf8").split("\0").filter((item) => item.length > 0);
|
|
8281
|
-
var normalizeRelative = (value) => value.split(
|
|
8753
|
+
var normalizeRelative = (value) => value.split(path12.sep).join("/");
|
|
8282
8754
|
var isInside = (root, candidate) => {
|
|
8283
|
-
const relative =
|
|
8284
|
-
return relative === "" || !
|
|
8755
|
+
const relative = path12.relative(root, candidate);
|
|
8756
|
+
return relative === "" || !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
|
|
8285
8757
|
};
|
|
8286
8758
|
var excluded = (absolute, exclusions) => exclusions.some((root) => isInside(root, absolute));
|
|
8287
8759
|
var entryDigest = (absolute) => {
|
|
8288
8760
|
let stat2;
|
|
8289
8761
|
try {
|
|
8290
|
-
stat2 =
|
|
8762
|
+
stat2 = fs7.lstatSync(absolute);
|
|
8291
8763
|
} catch (error) {
|
|
8292
8764
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
8293
8765
|
return { marker: "absent", bytes: 0 };
|
|
@@ -8295,24 +8767,24 @@ var entryDigest = (absolute) => {
|
|
|
8295
8767
|
throw error;
|
|
8296
8768
|
}
|
|
8297
8769
|
if (stat2.isSymbolicLink()) {
|
|
8298
|
-
return { marker: `symlink:${digest(
|
|
8770
|
+
return { marker: `symlink:${digest(fs7.readlinkSync(absolute))}`, bytes: 0 };
|
|
8299
8771
|
}
|
|
8300
8772
|
if (!stat2.isFile()) {
|
|
8301
8773
|
throw new Error(`Schema workspace snapshot does not support non-file entry: ${absolute}`);
|
|
8302
8774
|
}
|
|
8303
|
-
return { marker: `file:${stat2.mode & 511}:${digest(
|
|
8775
|
+
return { marker: `file:${stat2.mode & 511}:${digest(fs7.readFileSync(absolute))}`, bytes: stat2.size };
|
|
8304
8776
|
};
|
|
8305
8777
|
var buildSnapshot = (cwd, paths, metadata, exclusions) => {
|
|
8306
8778
|
const entries = {};
|
|
8307
8779
|
let bytes = 0;
|
|
8308
8780
|
const unique = [...new Set(paths)].sort((left, right) => left.localeCompare(right));
|
|
8309
8781
|
for (const relativeInput of unique) {
|
|
8310
|
-
const absolute =
|
|
8782
|
+
const absolute = path12.resolve(cwd, relativeInput);
|
|
8311
8783
|
if (!isInside(cwd, absolute) || excluded(absolute, exclusions)) continue;
|
|
8312
8784
|
if (Object.keys(entries).length >= SNAPSHOT_MAX_FILES) {
|
|
8313
8785
|
throw new Error(`Schema workspace snapshot exceeds ${SNAPSHOT_MAX_FILES} files`);
|
|
8314
8786
|
}
|
|
8315
|
-
const relative = normalizeRelative(
|
|
8787
|
+
const relative = normalizeRelative(path12.relative(cwd, absolute));
|
|
8316
8788
|
const entry = entryDigest(absolute);
|
|
8317
8789
|
bytes += entry.bytes;
|
|
8318
8790
|
if (bytes > SNAPSHOT_MAX_BYTES) {
|
|
@@ -8338,12 +8810,12 @@ var buildSnapshot = (cwd, paths, metadata, exclusions) => {
|
|
|
8338
8810
|
var fallbackPaths = (cwd, exclusions) => {
|
|
8339
8811
|
const paths = [];
|
|
8340
8812
|
const visit = (directory) => {
|
|
8341
|
-
const entries =
|
|
8813
|
+
const entries = fs7.readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
8342
8814
|
for (const entry of entries) {
|
|
8343
8815
|
if (FALLBACK_SKIPPED_DIRECTORIES.has(entry.name)) continue;
|
|
8344
|
-
const absolute =
|
|
8816
|
+
const absolute = path12.join(directory, entry.name);
|
|
8345
8817
|
if (excluded(absolute, exclusions)) continue;
|
|
8346
|
-
const relative = normalizeRelative(
|
|
8818
|
+
const relative = normalizeRelative(path12.relative(cwd, absolute));
|
|
8347
8819
|
if (entry.isDirectory()) visit(absolute);
|
|
8348
8820
|
else paths.push(relative);
|
|
8349
8821
|
if (paths.length > SNAPSHOT_MAX_FILES) {
|
|
@@ -8355,11 +8827,11 @@ var fallbackPaths = (cwd, exclusions) => {
|
|
|
8355
8827
|
return paths;
|
|
8356
8828
|
};
|
|
8357
8829
|
var snapshotWorkspace = (cwdInput, excludedRoots = []) => {
|
|
8358
|
-
const cwd =
|
|
8830
|
+
const cwd = fs7.realpathSync(cwdInput);
|
|
8359
8831
|
const exclusions = excludedRoots.map((root) => {
|
|
8360
|
-
const absolute =
|
|
8832
|
+
const absolute = path12.resolve(root);
|
|
8361
8833
|
try {
|
|
8362
|
-
return
|
|
8834
|
+
return fs7.realpathSync(absolute);
|
|
8363
8835
|
} catch {
|
|
8364
8836
|
return absolute;
|
|
8365
8837
|
}
|
|
@@ -8395,29 +8867,29 @@ var snapshotWorkspace = (cwdInput, excludedRoots = []) => {
|
|
|
8395
8867
|
);
|
|
8396
8868
|
};
|
|
8397
8869
|
var resolveWorkspaceFile = (cwdInput, requestedPath, options) => {
|
|
8398
|
-
if (!requestedPath.trim() ||
|
|
8870
|
+
if (!requestedPath.trim() || path12.isAbsolute(requestedPath)) {
|
|
8399
8871
|
throw new Error(`Schema paths must be non-empty project-relative paths: ${requestedPath}`);
|
|
8400
8872
|
}
|
|
8401
|
-
const cwd =
|
|
8402
|
-
const absolute =
|
|
8873
|
+
const cwd = fs7.realpathSync(cwdInput);
|
|
8874
|
+
const absolute = path12.resolve(cwd, requestedPath);
|
|
8403
8875
|
if (!isInside(cwd, absolute) || absolute === cwd) {
|
|
8404
8876
|
throw new Error(`Schema path escapes the project workspace: ${requestedPath}`);
|
|
8405
8877
|
}
|
|
8406
|
-
const relativeParts =
|
|
8878
|
+
const relativeParts = path12.relative(cwd, absolute).split(path12.sep);
|
|
8407
8879
|
let cursor = cwd;
|
|
8408
8880
|
for (let index = 0; index < relativeParts.length; index++) {
|
|
8409
|
-
cursor =
|
|
8881
|
+
cursor = path12.join(cursor, relativeParts[index]);
|
|
8410
8882
|
let stat2;
|
|
8411
8883
|
try {
|
|
8412
|
-
stat2 =
|
|
8884
|
+
stat2 = fs7.lstatSync(cursor);
|
|
8413
8885
|
} catch (error) {
|
|
8414
8886
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
8415
8887
|
if (index !== relativeParts.length - 1 || !options.allowAbsent) {
|
|
8416
8888
|
throw new Error(`Schema path does not exist: ${requestedPath}`);
|
|
8417
8889
|
}
|
|
8418
|
-
const parentReal =
|
|
8890
|
+
const parentReal = fs7.realpathSync(path12.dirname(cursor));
|
|
8419
8891
|
if (!isInside(cwd, parentReal)) throw new Error(`Schema path parent escapes the workspace: ${requestedPath}`);
|
|
8420
|
-
return { absolute, relative: normalizeRelative(
|
|
8892
|
+
return { absolute, relative: normalizeRelative(path12.relative(cwd, absolute)), exists: false };
|
|
8421
8893
|
}
|
|
8422
8894
|
throw error;
|
|
8423
8895
|
}
|
|
@@ -8429,9 +8901,9 @@ var resolveWorkspaceFile = (cwdInput, requestedPath, options) => {
|
|
|
8429
8901
|
throw new Error(`Schema transaction paths must name regular files: ${requestedPath}`);
|
|
8430
8902
|
}
|
|
8431
8903
|
}
|
|
8432
|
-
return { absolute, relative: normalizeRelative(
|
|
8904
|
+
return { absolute, relative: normalizeRelative(path12.relative(cwd, absolute)), exists: true };
|
|
8433
8905
|
};
|
|
8434
|
-
var sha256File = (absolute) => `sha256:${digest(
|
|
8906
|
+
var sha256File = (absolute) => `sha256:${digest(fs7.readFileSync(absolute))}`;
|
|
8435
8907
|
|
|
8436
8908
|
// src/schema/controller.ts
|
|
8437
8909
|
var SCHEMA_TOPIC = "fabric.schema";
|
|
@@ -8441,7 +8913,7 @@ var CERTIFICATE_PREFIX = "schema/certificate/";
|
|
|
8441
8913
|
var OUTPUT_LIMIT = 64 * 1024;
|
|
8442
8914
|
var hashToken = (token) => createHash3("sha256").update(token).digest("hex");
|
|
8443
8915
|
var sameBinding = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
8444
|
-
var
|
|
8916
|
+
var errorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
8445
8917
|
var atomicJsonWrite = (filePath, value) => {
|
|
8446
8918
|
writeJsonAtomic(filePath, value, { newline: true });
|
|
8447
8919
|
};
|
|
@@ -8479,9 +8951,9 @@ var SchemaController = class {
|
|
|
8479
8951
|
this.mesh = mesh;
|
|
8480
8952
|
this.identity = identity;
|
|
8481
8953
|
this.state = state;
|
|
8482
|
-
this.cwd =
|
|
8483
|
-
this.#journalRoot =
|
|
8484
|
-
this.#lockPath =
|
|
8954
|
+
this.cwd = fs8.realpathSync(cwd);
|
|
8955
|
+
this.#journalRoot = path13.join(mesh.root, "schema-transactions");
|
|
8956
|
+
this.#lockPath = path13.join(this.#journalRoot, ".commit.lock");
|
|
8485
8957
|
this.#recoverJournals();
|
|
8486
8958
|
}
|
|
8487
8959
|
#activeHypotheses = /* @__PURE__ */ new Map();
|
|
@@ -8537,7 +9009,7 @@ var SchemaController = class {
|
|
|
8537
9009
|
const generation = this.#generation();
|
|
8538
9010
|
const now = Date.now();
|
|
8539
9011
|
const record = {
|
|
8540
|
-
id:
|
|
9012
|
+
id: randomUUID4(),
|
|
8541
9013
|
label: input.label,
|
|
8542
9014
|
summary: input.summary,
|
|
8543
9015
|
evidence: input.evidence,
|
|
@@ -8577,7 +9049,7 @@ var SchemaController = class {
|
|
|
8577
9049
|
try {
|
|
8578
9050
|
before = snapshotWorkspace(this.cwd, [this.mesh.root]);
|
|
8579
9051
|
} catch (error) {
|
|
8580
|
-
return this.#failedVerification(record, [], `workspace snapshot failed: ${
|
|
9052
|
+
return this.#failedVerification(record, [], `workspace snapshot failed: ${errorMessage4(error)}`);
|
|
8581
9053
|
}
|
|
8582
9054
|
const currentState = stateBinding(this.state?.getHead() ?? null);
|
|
8583
9055
|
if (!sameBinding(record.state, currentState)) {
|
|
@@ -8594,7 +9066,7 @@ var SchemaController = class {
|
|
|
8594
9066
|
try {
|
|
8595
9067
|
after = snapshotWorkspace(this.cwd, [this.mesh.root]);
|
|
8596
9068
|
} catch (error) {
|
|
8597
|
-
return this.#failedVerification(record, results, `post-evidence snapshot failed: ${
|
|
9069
|
+
return this.#failedVerification(record, results, `post-evidence snapshot failed: ${errorMessage4(error)}`);
|
|
8598
9070
|
}
|
|
8599
9071
|
const allConfirmed = results.length > 0 && results.every((result) => result.status === "confirmed");
|
|
8600
9072
|
if (!allConfirmed || before.fingerprint !== after.fingerprint) {
|
|
@@ -8679,8 +9151,8 @@ var SchemaController = class {
|
|
|
8679
9151
|
}
|
|
8680
9152
|
this.#assertPayloadBound(input);
|
|
8681
9153
|
const release = this.#acquireCommitLock();
|
|
8682
|
-
const transactionId =
|
|
8683
|
-
const journalPath =
|
|
9154
|
+
const transactionId = randomUUID4();
|
|
9155
|
+
const journalPath = path13.join(this.#journalRoot, `${transactionId}.json`);
|
|
8684
9156
|
let journal;
|
|
8685
9157
|
let consumed = false;
|
|
8686
9158
|
let committed = false;
|
|
@@ -8720,14 +9192,14 @@ var SchemaController = class {
|
|
|
8720
9192
|
before.push({ path: resolved.relative, absolute: resolved.absolute, existed: false });
|
|
8721
9193
|
continue;
|
|
8722
9194
|
}
|
|
8723
|
-
const content =
|
|
9195
|
+
const content = fs8.readFileSync(resolved.absolute);
|
|
8724
9196
|
beforeBytes += content.byteLength;
|
|
8725
9197
|
before.push({
|
|
8726
9198
|
path: resolved.relative,
|
|
8727
9199
|
absolute: resolved.absolute,
|
|
8728
9200
|
existed: true,
|
|
8729
9201
|
content: content.toString("base64"),
|
|
8730
|
-
mode:
|
|
9202
|
+
mode: fs8.statSync(resolved.absolute).mode & 511
|
|
8731
9203
|
});
|
|
8732
9204
|
}
|
|
8733
9205
|
if (payloadBytes + beforeBytes > this.config.maxBytes) {
|
|
@@ -8791,7 +9263,7 @@ var SchemaController = class {
|
|
|
8791
9263
|
this.cwd
|
|
8792
9264
|
) : null;
|
|
8793
9265
|
} catch (error) {
|
|
8794
|
-
stateTransition = { error:
|
|
9266
|
+
stateTransition = { error: errorMessage4(error) };
|
|
8795
9267
|
}
|
|
8796
9268
|
try {
|
|
8797
9269
|
await this.mesh.put({
|
|
@@ -8837,18 +9309,18 @@ var SchemaController = class {
|
|
|
8837
9309
|
const outcome = rollbackError ? "quarantined" : "rolled_back";
|
|
8838
9310
|
if (journal) {
|
|
8839
9311
|
journal.status = outcome;
|
|
8840
|
-
journal.error = rollbackError ? `${
|
|
9312
|
+
journal.error = rollbackError ? `${errorMessage4(error)}; rollback failed: ${rollbackError}` : errorMessage4(error);
|
|
8841
9313
|
try {
|
|
8842
9314
|
atomicJsonWrite(journalPath, journal);
|
|
8843
9315
|
} catch {
|
|
8844
9316
|
}
|
|
8845
9317
|
}
|
|
8846
|
-
await this.#recordFailedOutcome(outcome, transactionId,
|
|
9318
|
+
await this.#recordFailedOutcome(outcome, transactionId, errorMessage4(error), rollbackError);
|
|
8847
9319
|
context.update(`Schema transaction ${outcome}`);
|
|
8848
9320
|
return {
|
|
8849
9321
|
outcome,
|
|
8850
9322
|
transactionId,
|
|
8851
|
-
error:
|
|
9323
|
+
error: errorMessage4(error),
|
|
8852
9324
|
...rollbackError ? { rollbackError } : {}
|
|
8853
9325
|
};
|
|
8854
9326
|
} finally {
|
|
@@ -8971,7 +9443,7 @@ var SchemaController = class {
|
|
|
8971
9443
|
observedSha256: sha256File(resolved.absolute)
|
|
8972
9444
|
});
|
|
8973
9445
|
} else if (item.kind === "file_contains") {
|
|
8974
|
-
const confirmed =
|
|
9446
|
+
const confirmed = fs8.readFileSync(resolved.absolute, "utf8").includes(item.literal);
|
|
8975
9447
|
results.push({
|
|
8976
9448
|
evidence: item,
|
|
8977
9449
|
status: confirmed ? "confirmed" : "nonconfirmed",
|
|
@@ -8988,7 +9460,7 @@ var SchemaController = class {
|
|
|
8988
9460
|
});
|
|
8989
9461
|
}
|
|
8990
9462
|
} catch (error) {
|
|
8991
|
-
results.push({ evidence: item, status: "error", detail:
|
|
9463
|
+
results.push({ evidence: item, status: "error", detail: errorMessage4(error) });
|
|
8992
9464
|
}
|
|
8993
9465
|
}
|
|
8994
9466
|
return results;
|
|
@@ -9012,7 +9484,7 @@ var SchemaController = class {
|
|
|
9012
9484
|
...signal ? { signal } : {}
|
|
9013
9485
|
});
|
|
9014
9486
|
} catch (error) {
|
|
9015
|
-
resolve2({ evidence, status: "error", detail:
|
|
9487
|
+
resolve2({ evidence, status: "error", detail: errorMessage4(error), exitCode: null });
|
|
9016
9488
|
return;
|
|
9017
9489
|
}
|
|
9018
9490
|
const append = (chunk) => {
|
|
@@ -9042,22 +9514,22 @@ var SchemaController = class {
|
|
|
9042
9514
|
throw new Error(`Schema precondition SHA-256 mismatch: ${operation.path}`);
|
|
9043
9515
|
}
|
|
9044
9516
|
}
|
|
9045
|
-
|
|
9517
|
+
fs8.writeFileSync(resolved.absolute, operation.content, "utf8");
|
|
9046
9518
|
return;
|
|
9047
9519
|
}
|
|
9048
9520
|
if (sha256File(resolved.absolute) !== operation.expectedSha256) {
|
|
9049
9521
|
throw new Error(`Schema precondition SHA-256 mismatch: ${operation.path}`);
|
|
9050
9522
|
}
|
|
9051
9523
|
if (operation.kind === "delete") {
|
|
9052
|
-
|
|
9524
|
+
fs8.unlinkSync(resolved.absolute);
|
|
9053
9525
|
return;
|
|
9054
9526
|
}
|
|
9055
|
-
const content =
|
|
9527
|
+
const content = fs8.readFileSync(resolved.absolute, "utf8");
|
|
9056
9528
|
const first = content.indexOf(operation.oldText);
|
|
9057
9529
|
if (first < 0 || content.indexOf(operation.oldText, first + operation.oldText.length) >= 0) {
|
|
9058
9530
|
throw new Error(`Schema edit requires oldText to occur exactly once: ${operation.path}`);
|
|
9059
9531
|
}
|
|
9060
|
-
|
|
9532
|
+
fs8.writeFileSync(resolved.absolute, `${content.slice(0, first)}${operation.newText}${content.slice(first + operation.oldText.length)}`, "utf8");
|
|
9061
9533
|
}
|
|
9062
9534
|
#assertNoOutsideDrift(before, after, declared) {
|
|
9063
9535
|
if (before.git !== after.git || before.head !== after.head || before.indexDigest !== after.indexDigest) {
|
|
@@ -9077,13 +9549,13 @@ var SchemaController = class {
|
|
|
9077
9549
|
try {
|
|
9078
9550
|
const resolved = resolveWorkspaceFile(this.cwd, image.path, { allowAbsent: true });
|
|
9079
9551
|
if (!image.existed) {
|
|
9080
|
-
if (resolved.exists)
|
|
9552
|
+
if (resolved.exists) fs8.unlinkSync(resolved.absolute);
|
|
9081
9553
|
} else {
|
|
9082
|
-
|
|
9083
|
-
if (image.mode !== void 0)
|
|
9554
|
+
fs8.writeFileSync(resolved.absolute, Buffer.from(image.content ?? "", "base64"));
|
|
9555
|
+
if (image.mode !== void 0) fs8.chmodSync(resolved.absolute, image.mode);
|
|
9084
9556
|
}
|
|
9085
9557
|
} catch (error) {
|
|
9086
|
-
errors.push(`${image.path}: ${
|
|
9558
|
+
errors.push(`${image.path}: ${errorMessage4(error)}`);
|
|
9087
9559
|
}
|
|
9088
9560
|
}
|
|
9089
9561
|
return errors.length > 0 ? errors.join("; ") : void 0;
|
|
@@ -9128,25 +9600,25 @@ var SchemaController = class {
|
|
|
9128
9600
|
return this.mesh.publish({ topic: SCHEMA_TOPIC, kind, from: this.identity, data });
|
|
9129
9601
|
}
|
|
9130
9602
|
#acquireCommitLock() {
|
|
9131
|
-
|
|
9603
|
+
fs8.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
|
|
9132
9604
|
try {
|
|
9133
|
-
const descriptor =
|
|
9134
|
-
|
|
9605
|
+
const descriptor = fs8.openSync(this.#lockPath, "wx", 384);
|
|
9606
|
+
fs8.writeFileSync(descriptor, `${process.pid}
|
|
9135
9607
|
${Date.now()}
|
|
9136
9608
|
`);
|
|
9137
|
-
|
|
9609
|
+
fs8.closeSync(descriptor);
|
|
9138
9610
|
} catch (error) {
|
|
9139
9611
|
if (error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
9140
9612
|
throw new Error("Another Schema transaction is in progress");
|
|
9141
9613
|
}
|
|
9142
9614
|
throw error;
|
|
9143
9615
|
}
|
|
9144
|
-
return () =>
|
|
9616
|
+
return () => fs8.rmSync(this.#lockPath, { force: true });
|
|
9145
9617
|
}
|
|
9146
9618
|
#recoverJournals() {
|
|
9147
|
-
|
|
9619
|
+
fs8.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
|
|
9148
9620
|
try {
|
|
9149
|
-
const [pidText] =
|
|
9621
|
+
const [pidText] = fs8.readFileSync(this.#lockPath, "utf8").split("\n");
|
|
9150
9622
|
const pid = Number(pidText);
|
|
9151
9623
|
if (Number.isSafeInteger(pid) && pid > 0) {
|
|
9152
9624
|
try {
|
|
@@ -9155,15 +9627,15 @@ ${Date.now()}
|
|
|
9155
9627
|
} catch {
|
|
9156
9628
|
}
|
|
9157
9629
|
}
|
|
9158
|
-
|
|
9630
|
+
fs8.rmSync(this.#lockPath, { force: true });
|
|
9159
9631
|
} catch (error) {
|
|
9160
9632
|
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
|
|
9161
9633
|
}
|
|
9162
|
-
for (const name of
|
|
9634
|
+
for (const name of fs8.readdirSync(this.#journalRoot)) {
|
|
9163
9635
|
if (!name.endsWith(".json")) continue;
|
|
9164
|
-
const filePath =
|
|
9636
|
+
const filePath = path13.join(this.#journalRoot, name);
|
|
9165
9637
|
try {
|
|
9166
|
-
const journal = JSON.parse(
|
|
9638
|
+
const journal = JSON.parse(fs8.readFileSync(filePath, "utf8"));
|
|
9167
9639
|
if (journal.format !== 1 || journal.status !== "applying" || !Array.isArray(journal.before)) continue;
|
|
9168
9640
|
const workspace = this.#workspaceEntry()?.value;
|
|
9169
9641
|
if (workspace?.lastOutcome === "committed" && workspace.lastTransactionId === journal.id) {
|
|
@@ -9415,11 +9887,11 @@ var SchemaProvider = class {
|
|
|
9415
9887
|
|
|
9416
9888
|
// src/state/store.ts
|
|
9417
9889
|
import { createHash as createHash5 } from "node:crypto";
|
|
9418
|
-
import
|
|
9890
|
+
import path15 from "node:path";
|
|
9419
9891
|
|
|
9420
9892
|
// src/state/complexity.ts
|
|
9421
|
-
import
|
|
9422
|
-
import
|
|
9893
|
+
import fs9 from "node:fs";
|
|
9894
|
+
import path14 from "node:path";
|
|
9423
9895
|
var isWordStart = (character) => character !== void 0 && (character >= "a" && character <= "z" || character >= "A" && character <= "Z" || character === "_" || character === "$");
|
|
9424
9896
|
var isWordPart = (character) => isWordStart(character) || character !== void 0 && character >= "0" && character <= "9";
|
|
9425
9897
|
var regularExpressionPrefixWords = /* @__PURE__ */ new Set([
|
|
@@ -9651,7 +10123,7 @@ var languageComplexities = [
|
|
|
9651
10123
|
typeScriptJavaScriptComplexity
|
|
9652
10124
|
];
|
|
9653
10125
|
var complexityForFile = (file, languages = languageComplexities) => {
|
|
9654
|
-
const extension =
|
|
10126
|
+
const extension = path14.extname(file).toLowerCase();
|
|
9655
10127
|
return languages.find((language) => language.extensions.includes(extension));
|
|
9656
10128
|
};
|
|
9657
10129
|
var countFileComplexity = (file) => {
|
|
@@ -9660,7 +10132,7 @@ var countFileComplexity = (file) => {
|
|
|
9660
10132
|
return {
|
|
9661
10133
|
file,
|
|
9662
10134
|
language: language.language,
|
|
9663
|
-
count: language.count(
|
|
10135
|
+
count: language.count(fs9.readFileSync(file, "utf8"))
|
|
9664
10136
|
};
|
|
9665
10137
|
};
|
|
9666
10138
|
|
|
@@ -9668,7 +10140,7 @@ var countFileComplexity = (file) => {
|
|
|
9668
10140
|
import { spawn as spawn2 } from "node:child_process";
|
|
9669
10141
|
import { createHash as createHash4 } from "node:crypto";
|
|
9670
10142
|
var COMMAND_OUTPUT_MAX_BYTES = 32 * 1024;
|
|
9671
|
-
var
|
|
10143
|
+
var errorMessage5 = (error) => error instanceof Error ? error.message : String(error);
|
|
9672
10144
|
var truncateUtf8 = (value, maxBytes) => {
|
|
9673
10145
|
const bytes = Buffer.from(value, "utf8");
|
|
9674
10146
|
if (bytes.length <= maxBytes) return { value, omittedBytes: 0 };
|
|
@@ -9794,12 +10266,12 @@ var runCommand = (command, options) => new Promise((resolve2) => {
|
|
|
9794
10266
|
windowsHide: true
|
|
9795
10267
|
});
|
|
9796
10268
|
} catch (error) {
|
|
9797
|
-
finish("error", null,
|
|
10269
|
+
finish("error", null, errorMessage5(error));
|
|
9798
10270
|
return;
|
|
9799
10271
|
}
|
|
9800
10272
|
child.stdout?.on("data", collect);
|
|
9801
10273
|
child.stderr?.on("data", collect);
|
|
9802
|
-
child.once("error", (error) => finish("error", null,
|
|
10274
|
+
child.once("error", (error) => finish("error", null, errorMessage5(error)));
|
|
9803
10275
|
child.once("close", (code) => {
|
|
9804
10276
|
void (async () => {
|
|
9805
10277
|
if (termination) await termination;
|
|
@@ -9843,7 +10315,7 @@ var EVENT_ROLLBACK_LIMIT = 8;
|
|
|
9843
10315
|
var TRANSITION_PROTOCOL_VERSION = 1;
|
|
9844
10316
|
var DURABLE_HEAD_PROTOCOL_VERSION = 2;
|
|
9845
10317
|
var HEAD_COMMIT_PROOF_VERSION = 1;
|
|
9846
|
-
var
|
|
10318
|
+
var errorMessage6 = (error) => error instanceof Error ? error.message : String(error);
|
|
9847
10319
|
var isCasError = (error) => error instanceof Error && /compare-and-swap failed/.test(error.message);
|
|
9848
10320
|
var toStringArray = (value) => {
|
|
9849
10321
|
if (!Array.isArray(value)) return void 0;
|
|
@@ -9862,9 +10334,9 @@ var truncateUtf82 = (value, maxBytes) => {
|
|
|
9862
10334
|
const bounded = bytes.subarray(0, end).toString("utf8");
|
|
9863
10335
|
return { value: bounded, omittedBytes: bytes.length - end };
|
|
9864
10336
|
};
|
|
9865
|
-
var boundedError = (error) => truncateUtf82(
|
|
10337
|
+
var boundedError = (error) => truncateUtf82(errorMessage6(error), REPORT_TEXT_MAX_BYTES).value;
|
|
9866
10338
|
var casActualVersion = (error) => {
|
|
9867
|
-
const match =
|
|
10339
|
+
const match = errorMessage6(error).match(/found (\d+)$/);
|
|
9868
10340
|
return match ? Number(match[1]) : void 0;
|
|
9869
10341
|
};
|
|
9870
10342
|
var toComplexityRecord = (value) => {
|
|
@@ -10320,7 +10792,7 @@ var StateStore = class {
|
|
|
10320
10792
|
protocolVersion: TRANSITION_PROTOCOL_VERSION,
|
|
10321
10793
|
phase: "rejected",
|
|
10322
10794
|
transitionId: event.id,
|
|
10323
|
-
error: truncateUtf82(
|
|
10795
|
+
error: truncateUtf82(errorMessage6(error), EVENT_TEXT_MAX_BYTES).value,
|
|
10324
10796
|
rollback: {
|
|
10325
10797
|
restored: rollback.errors.length === 0,
|
|
10326
10798
|
deleted: deletedChunks[index],
|
|
@@ -10542,7 +11014,7 @@ var StateStore = class {
|
|
|
10542
11014
|
const files = [];
|
|
10543
11015
|
let netDelta = 0;
|
|
10544
11016
|
for (const file of this.normalizeComplexityFiles(requestedFiles, input.cwd)) {
|
|
10545
|
-
const measured = countFileComplexity(
|
|
11017
|
+
const measured = countFileComplexity(path15.resolve(input.cwd, file));
|
|
10546
11018
|
if (!measured) {
|
|
10547
11019
|
files.push({ file, supported: false });
|
|
10548
11020
|
continue;
|
|
@@ -10569,7 +11041,7 @@ var StateStore = class {
|
|
|
10569
11041
|
const updates = [];
|
|
10570
11042
|
let netDelta = 0;
|
|
10571
11043
|
for (const file of this.normalizeComplexityFiles(files, cwd)) {
|
|
10572
|
-
const measured = countFileComplexity(
|
|
11044
|
+
const measured = countFileComplexity(path15.resolve(cwd, file));
|
|
10573
11045
|
if (!measured) {
|
|
10574
11046
|
deltas.push({ file, supported: false });
|
|
10575
11047
|
continue;
|
|
@@ -10619,11 +11091,11 @@ var StateStore = class {
|
|
|
10619
11091
|
const normalized = /* @__PURE__ */ new Set();
|
|
10620
11092
|
for (const file of files) {
|
|
10621
11093
|
if (!file.trim()) continue;
|
|
10622
|
-
const relative =
|
|
10623
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
11094
|
+
const relative = path15.relative(cwd, path15.resolve(cwd, file));
|
|
11095
|
+
if (relative === ".." || relative.startsWith(`..${path15.sep}`) || path15.isAbsolute(relative)) {
|
|
10624
11096
|
throw new Error(`State complexity file must be inside the project cwd: ${file}`);
|
|
10625
11097
|
}
|
|
10626
|
-
normalized.add(relative.split(
|
|
11098
|
+
normalized.add(relative.split(path15.sep).join("/"));
|
|
10627
11099
|
}
|
|
10628
11100
|
return [...normalized];
|
|
10629
11101
|
}
|
|
@@ -11288,6 +11760,7 @@ var FabricRuntimeState = class {
|
|
|
11288
11760
|
#mcpProvider;
|
|
11289
11761
|
#config;
|
|
11290
11762
|
#execution;
|
|
11763
|
+
#repairs;
|
|
11291
11764
|
#speculationStore;
|
|
11292
11765
|
#speculationTap;
|
|
11293
11766
|
#agents;
|
|
@@ -11397,7 +11870,8 @@ var FabricRuntimeState = class {
|
|
|
11397
11870
|
nestedToolCallId: "fabric-speculation",
|
|
11398
11871
|
extensionContext: context,
|
|
11399
11872
|
update() {
|
|
11400
|
-
}
|
|
11873
|
+
},
|
|
11874
|
+
...this.#sessionCapabilityLease?.view ? { capabilityView: this.#sessionCapabilityLease.view } : {}
|
|
11401
11875
|
};
|
|
11402
11876
|
const speculation = await registry.speculate(
|
|
11403
11877
|
candidate.ref,
|
|
@@ -11412,7 +11886,8 @@ var FabricRuntimeState = class {
|
|
|
11412
11886
|
speculation.preparedArgs,
|
|
11413
11887
|
speculation.execute,
|
|
11414
11888
|
createFreshnessChecker(candidate.ref, speculation.preparedArgs, context.cwd),
|
|
11415
|
-
replay
|
|
11889
|
+
replay,
|
|
11890
|
+
speculation.bindingToken
|
|
11416
11891
|
);
|
|
11417
11892
|
}
|
|
11418
11893
|
get registry() {
|
|
@@ -11476,6 +11951,10 @@ var FabricRuntimeState = class {
|
|
|
11476
11951
|
if (!this.#compact) throw new Error("Pi Fabric has not initialized");
|
|
11477
11952
|
return this.#compact;
|
|
11478
11953
|
}
|
|
11954
|
+
get repairs() {
|
|
11955
|
+
if (!this.#repairs) throw new Error("Pi Fabric has not initialized");
|
|
11956
|
+
return this.#repairs;
|
|
11957
|
+
}
|
|
11479
11958
|
async initialize(context, bootstrapConfig) {
|
|
11480
11959
|
this.#suppressResidentGuidanceSync = true;
|
|
11481
11960
|
try {
|
|
@@ -11505,9 +11984,11 @@ var FabricRuntimeState = class {
|
|
|
11505
11984
|
new FabricToolResultProxy(() => this.capturedTools.runner)
|
|
11506
11985
|
);
|
|
11507
11986
|
this.#wireSpeculation();
|
|
11508
|
-
this.#unsubscribeCapturedCatalog
|
|
11509
|
-
|
|
11510
|
-
|
|
11987
|
+
this.#unsubscribeCapturedCatalog?.();
|
|
11988
|
+
this.#unsubscribeCapturedCatalog = this.capturedTools.subscribe(() => {
|
|
11989
|
+
this.#registry?.notifyCatalogChanged("extensions");
|
|
11990
|
+
this.#refreshRepairCatalog();
|
|
11991
|
+
});
|
|
11511
11992
|
this.#componentSupervisor = new FabricComponentSupervisor(this.#registry, {
|
|
11512
11993
|
invocationContext: () => ({
|
|
11513
11994
|
cwd: context.cwd,
|
|
@@ -11569,7 +12050,7 @@ var FabricRuntimeState = class {
|
|
|
11569
12050
|
create: () => new McpProvider(context.cwd, this.#config.mcp, {
|
|
11570
12051
|
...this.#config.mcp.cache.enabled ? {
|
|
11571
12052
|
cache: new McpDescriptorCacheStore(
|
|
11572
|
-
|
|
12053
|
+
path16.join(
|
|
11573
12054
|
process.env.PI_FABRIC_PROJECT_ROOT ?? context.cwd,
|
|
11574
12055
|
".pi",
|
|
11575
12056
|
"fabric",
|
|
@@ -11613,7 +12094,7 @@ var FabricRuntimeState = class {
|
|
|
11613
12094
|
this.#mainAgent = mainAgent;
|
|
11614
12095
|
const projectRoot = process.env.PI_FABRIC_PROJECT_ROOT ?? context.cwd;
|
|
11615
12096
|
const configuredMeshRoot = this.#config.mesh.root;
|
|
11616
|
-
const meshRoot = process.env.PI_FABRIC_MESH_ROOT ?? (configuredMeshRoot ?
|
|
12097
|
+
const meshRoot = process.env.PI_FABRIC_MESH_ROOT ?? (configuredMeshRoot ? path16.resolve(projectRoot, configuredMeshRoot) : path16.join(projectRoot, ".pi", "fabric", "mesh"));
|
|
11617
12098
|
this.#mesh = new MeshStore(
|
|
11618
12099
|
meshRoot,
|
|
11619
12100
|
this.#config.mesh.maxEventBytes,
|
|
@@ -11731,7 +12212,7 @@ var FabricRuntimeState = class {
|
|
|
11731
12212
|
return participant ? participant.ownerHostId === hostId : void 0;
|
|
11732
12213
|
};
|
|
11733
12214
|
const lineageAlive = (rootId) => this.#participants?.get(rootId) !== void 0;
|
|
11734
|
-
const persistentActorRoot = this.#config.mesh.actorScope === "session" ?
|
|
12215
|
+
const persistentActorRoot = this.#config.mesh.actorScope === "session" ? path16.join(meshRoot, "actors", sessionId) : path16.join(meshRoot, "actors");
|
|
11735
12216
|
const acquireActorCapabilityView = (requirements, signal) => this.#registry.acquireCapabilityView(requirements, {
|
|
11736
12217
|
cwd: context.cwd,
|
|
11737
12218
|
signal,
|
|
@@ -11791,7 +12272,10 @@ ${escapeXmlText(text)}
|
|
|
11791
12272
|
acquireCapabilityView: acquireActorCapabilityView
|
|
11792
12273
|
}
|
|
11793
12274
|
);
|
|
11794
|
-
this.#registry.subscribeProviderChanges(() =>
|
|
12275
|
+
this.#registry.subscribeProviderChanges(() => {
|
|
12276
|
+
this.#actors?.retryCapabilityWaiters();
|
|
12277
|
+
this.#refreshRepairCatalog();
|
|
12278
|
+
});
|
|
11795
12279
|
this.#lifecycle = new LifecycleBroker(
|
|
11796
12280
|
this.#mesh,
|
|
11797
12281
|
identity,
|
|
@@ -11979,6 +12463,12 @@ ${escapeXmlText(text)}
|
|
|
11979
12463
|
this.#sessionCapabilityLease = lease;
|
|
11980
12464
|
this.#execution.setCapabilityView(lease.view);
|
|
11981
12465
|
}
|
|
12466
|
+
this.#repairs = new RepairCompiler({
|
|
12467
|
+
agentDir: resolveAgentDir(),
|
|
12468
|
+
enabled: this.#config.repairs.enabled
|
|
12469
|
+
});
|
|
12470
|
+
this.#refreshRepairCatalog();
|
|
12471
|
+
setActiveRepairCompiler(this.#repairs);
|
|
11982
12472
|
}
|
|
11983
12473
|
async ensure(context) {
|
|
11984
12474
|
if (!this.initialized || this.#cwd !== context.cwd) await this.initialize(context);
|
|
@@ -12187,6 +12677,7 @@ ${escapeXmlText(text)}
|
|
|
12187
12677
|
}
|
|
12188
12678
|
async shutdown() {
|
|
12189
12679
|
this.#suppressResidentGuidanceSync = true;
|
|
12680
|
+
this.#deactivateRepairs();
|
|
12190
12681
|
await this.#participants?.quiesce().catch(() => void 0);
|
|
12191
12682
|
await this.#componentLoader?.close();
|
|
12192
12683
|
await Promise.allSettled([...this.#componentTransitionPublications]);
|
|
@@ -12250,7 +12741,21 @@ ${escapeXmlText(text)}
|
|
|
12250
12741
|
} catch {
|
|
12251
12742
|
}
|
|
12252
12743
|
}
|
|
12744
|
+
#refreshRepairCatalog() {
|
|
12745
|
+
if (!this.#repairs || !this.#registry) return;
|
|
12746
|
+
if (this.capturedTools.suspended) return;
|
|
12747
|
+
this.#repairs.setCatalogSurface({
|
|
12748
|
+
providers: this.#registry.providers().map((provider) => provider.name),
|
|
12749
|
+
capturedTools: this.capturedTools.list().map((entry) => entry.name)
|
|
12750
|
+
});
|
|
12751
|
+
}
|
|
12752
|
+
#deactivateRepairs() {
|
|
12753
|
+
const repairs = this.#repairs;
|
|
12754
|
+
this.#repairs = void 0;
|
|
12755
|
+
clearActiveRepairCompiler(repairs);
|
|
12756
|
+
}
|
|
12253
12757
|
async #closeInternal() {
|
|
12758
|
+
this.#deactivateRepairs();
|
|
12254
12759
|
if (!this.#registry) return;
|
|
12255
12760
|
await this.#participants?.quiesce().catch(() => void 0);
|
|
12256
12761
|
await this.#componentLoader?.close();
|
|
@@ -12350,4 +12855,4 @@ var deepAssign = (target, source) => {
|
|
|
12350
12855
|
export {
|
|
12351
12856
|
FabricRuntimeState
|
|
12352
12857
|
};
|
|
12353
|
-
//# sourceMappingURL=fabric-runtime-state-
|
|
12858
|
+
//# sourceMappingURL=fabric-runtime-state-H2NCRJWK.js.map
|