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.
Files changed (66) hide show
  1. package/README.md +1 -0
  2. package/dist/capture/catalog.d.ts +3 -0
  3. package/dist/capture/catalog.d.ts.map +1 -1
  4. package/dist/chunks/{chunk-PAAXKXWT.js → chunk-2AF5ANEB.js} +16 -2
  5. package/dist/chunks/chunk-2AF5ANEB.js.map +7 -0
  6. package/dist/chunks/{chunk-QXB75FLD.js → chunk-2E3CAABA.js} +8 -1
  7. package/dist/chunks/chunk-2E3CAABA.js.map +7 -0
  8. package/dist/chunks/{chunk-6ZKYQW33.js → chunk-3QPTSKDG.js} +139 -29
  9. package/dist/chunks/chunk-3QPTSKDG.js.map +7 -0
  10. package/dist/chunks/{chunk-SBHF6CVR.js → chunk-DUIHQAIZ.js} +2 -2
  11. package/dist/chunks/{chunk-6BBFFEPO.js → chunk-DYEOFQ64.js} +15 -1
  12. package/dist/chunks/{chunk-6BBFFEPO.js.map → chunk-DYEOFQ64.js.map} +2 -2
  13. package/dist/chunks/{chunk-4DRVOAFY.js → chunk-PFF3X7OO.js} +2 -2
  14. package/dist/chunks/{fabric-runtime-state-H7UA3DJC.js → fabric-runtime-state-H2NCRJWK.js} +697 -192
  15. package/dist/chunks/fabric-runtime-state-H2NCRJWK.js.map +7 -0
  16. package/dist/chunks/{settings-VEXI347I.js → settings-FUL3U3N4.js} +2 -2
  17. package/dist/commands/fabric.d.ts.map +1 -1
  18. package/dist/config.d.ts +4 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/core/action-registry.d.ts +1 -0
  21. package/dist/core/action-registry.d.ts.map +1 -1
  22. package/dist/core/action-registry.js +1 -1
  23. package/dist/fabric-runtime-state.d.ts +2 -0
  24. package/dist/fabric-runtime-state.d.ts.map +1 -1
  25. package/dist/fabric-state.d.ts +1 -0
  26. package/dist/fabric-state.d.ts.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +218 -8
  29. package/dist/index.js.map +3 -3
  30. package/dist/providers/arg-normalization.d.ts +3 -0
  31. package/dist/providers/arg-normalization.d.ts.map +1 -1
  32. package/dist/providers/memory-provider.js +1 -1
  33. package/dist/repairs/active.d.ts +7 -0
  34. package/dist/repairs/active.d.ts.map +1 -0
  35. package/dist/repairs/apply.d.ts +7 -0
  36. package/dist/repairs/apply.d.ts.map +1 -0
  37. package/dist/repairs/catalog-digest.d.ts +5 -0
  38. package/dist/repairs/catalog-digest.d.ts.map +1 -0
  39. package/dist/repairs/classify.d.ts +10 -0
  40. package/dist/repairs/classify.d.ts.map +1 -0
  41. package/dist/repairs/compiler.d.ts +32 -0
  42. package/dist/repairs/compiler.d.ts.map +1 -0
  43. package/dist/repairs/promote.d.ts +4 -0
  44. package/dist/repairs/promote.d.ts.map +1 -0
  45. package/dist/repairs/store.d.ts +9 -0
  46. package/dist/repairs/store.d.ts.map +1 -0
  47. package/dist/repairs/types.d.ts +49 -0
  48. package/dist/repairs/types.d.ts.map +1 -0
  49. package/dist/residency/host.js +3 -3
  50. package/dist/residency/pi-entry.js +3 -3
  51. package/dist/speculation/store.d.ts +11 -7
  52. package/dist/speculation/store.d.ts.map +1 -1
  53. package/dist/speculation/types.d.ts +2 -1
  54. package/dist/speculation/types.d.ts.map +1 -1
  55. package/docs/architecture.md +2 -0
  56. package/docs/configuration.md +4 -0
  57. package/docs/interface.md +1 -0
  58. package/docs/repairs.md +57 -0
  59. package/package.json +1 -1
  60. package/dist/chunks/chunk-6ZKYQW33.js.map +0 -7
  61. package/dist/chunks/chunk-PAAXKXWT.js.map +0 -7
  62. package/dist/chunks/chunk-QXB75FLD.js.map +0 -7
  63. package/dist/chunks/fabric-runtime-state-H7UA3DJC.js.map +0 -7
  64. /package/dist/chunks/{chunk-SBHF6CVR.js.map → chunk-DUIHQAIZ.js.map} +0 -0
  65. /package/dist/chunks/{chunk-4DRVOAFY.js.map → chunk-PFF3X7OO.js.map} +0 -0
  66. /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
- } from "./chunk-6BBFFEPO.js";
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-PAAXKXWT.js";
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
- } from "./chunk-6ZKYQW33.js";
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-4DRVOAFY.js";
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-QXB75FLD.js";
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 path15 from "node:path";
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, path16, positions) => {
2205
+ const visit = (node, path17, positions) => {
2202
2206
  const position = positions.get(node);
2203
2207
  if (position !== void 0) {
2204
- const cycle = path16.slice(position);
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 (path16.length > this.#components.size) return;
2215
- const nextPositions = new Map(positions).set(node, path16.length);
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, [...path16, node], nextPositions);
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 fs2 from "node:fs";
3371
- import path2 from "node:path";
3841
+ import fs3 from "node:fs";
3842
+ import path3 from "node:path";
3372
3843
  var statSignature = (filePath) => {
3373
3844
  try {
3374
- const stats = fs2.statSync(filePath);
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 = path2.resolve(cwd, target);
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 path3 from "node:path";
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(path3.join(agentDir, "extensions", MODEL_USAGE_FILENAME), "utf8")
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 randomUUID2 } from "node:crypto";
4473
- import fs3 from "node:fs";
4474
- import path4 from "node:path";
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(fs3.readFileSync(filePath, "utf8"));
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 path4.relative(fs3.realpathSync.native(left), fs3.realpathSync.native(right)) === "";
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 = path4.join(options.config.residencyRoot, "config.json");
4524
- this.#ownerPath = path4.join(options.config.residencyRoot, "owner.json");
4525
- this.#errorPath = path4.join(options.config.residencyRoot, "error.json");
4526
- this.#requestsPath = path4.join(options.config.residencyRoot, "requests");
4527
- this.#responsesPath = path4.join(options.config.residencyRoot, "responses");
4528
- this.#agentsPath = path4.join(options.config.residencyRoot, "agents");
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 (fs3.existsSync(this.options.config.residencyRoot)) {
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
- fs3.rmSync(this.#errorPath, { force: true });
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 fs3.readFileSync(path4.join(this.options.config.residencyRoot, name), "utf8").trim();
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: randomUUID2(),
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) && fs3.existsSync(this.#metadataPath(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(path4.join(metadata.runDirectory, "status.json"));
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: path4.join(metadata.runDirectory, "events.jsonl"),
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 = fs3.readdirSync(this.#agentsPath);
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: randomUUID2(),
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 = path4.join(metadata.runDirectory, "events.jsonl");
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(path4.join(metadata.runDirectory, "status.json"));
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: randomUUID2(),
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: randomUUID2(),
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
- fs3.rmSync(metadata.runDirectory, { recursive: true, force: true });
4757
- fs3.rmSync(this.#metadataPath(metadata.id), { force: true });
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 = path4.join(this.#responsesPath, `${command.requestId}.json`);
4762
- atomicWrite2(path4.join(this.#requestsPath, `${command.requestId}.json`), command);
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
- fs3.rmSync(responsePath, { force: true });
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 path4.join(this.#agentsPath, `${id}.json`);
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" || path4.resolve(metadata.runDirectory) !== path4.resolve(this.options.config.residencyRoot, "runs", id)) {
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 path5 from "node:path";
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 = path5.basename(sourceInfo.path).replace(/\.[^.]+$/, "");
6581
+ const filename = path6.basename(sourceInfo.path).replace(/\.[^.]+$/, "");
6110
6582
  if (filename && filename !== "index") return filename;
6111
- return path5.basename(path5.dirname(sourceInfo.path)) || sourceInfo.source;
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 fs4 from "node:fs/promises";
6960
+ import fs5 from "node:fs/promises";
6489
6961
  import fsSync from "node:fs";
6490
6962
  import os from "node:os";
6491
- import path6 from "node:path";
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 path6.join(home, input.slice(2));
6970
+ return path7.join(home, input.slice(2));
6499
6971
  }
6500
6972
  return input;
6501
6973
  };
6502
- var legacyMcporterDir = () => path6.join(os.homedir(), ".mcporter");
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 (path6.isAbsolute(resolved)) return path6.join(resolved, "mcporter");
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 = [path6.join(base, "mcporter.json"), path6.join(base, "mcporter.jsonc")];
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(path6.join(legacy, "mcporter.json"), path6.join(legacy, "mcporter.jsonc"));
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 [path6.resolve(expandHome(explicitRaw.trim()))];
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 = path6.resolve(rootDir, "config", "mcporter.json");
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 fs4.stat(layerPath);
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 isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7030
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6559
7031
  var parseCachedServer = (value) => {
6560
- if (!isRecord(value)) return void 0;
7032
+ if (!isRecord2(value)) return void 0;
6561
7033
  const tools = Array.isArray(value.tools) ? value.tools.filter(
6562
- (tool) => isRecord(tool) && typeof tool.name === "string"
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 (!isRecord(value) || value.version !== MCP_DESCRIPTOR_CACHE_VERSION) return void 0;
6576
- if (!Array.isArray(value.layers) || !isRecord(value.servers)) return void 0;
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) => isRecord(layer) && typeof layer.path === "string" && typeof layer.mtimeMs === "number" && typeof layer.size === "number"
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 fs4.readFile(this.filePath, "utf8");
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 = path6.dirname(this.filePath);
6604
- await fs4.mkdir(directory, { recursive: true });
6605
- const tempPath = path6.join(
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 fs4.writeFile(tempPath, JSON.stringify(file, null, 2));
7081
+ await fs5.writeFile(tempPath, JSON.stringify(file, null, 2));
6610
7082
  try {
6611
- await fs4.rename(tempPath, this.filePath);
7083
+ await fs5.rename(tempPath, this.filePath);
6612
7084
  } catch (error) {
6613
- await fs4.rm(tempPath, { force: true }).catch(() => void 0);
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 path7 from "node:path";
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: path7.resolve(this.cwd, typeof args.cwd === "string" ? args.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 path10 from "node:path";
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 fs5 from "node:fs";
7631
- import path8 from "node:path";
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 ? path8.resolve(sessionCwd, parsed.gitCwd) : typeof args.cwd === "string" ? args.cwd : sessionCwd;
7695
- const dest = path8.resolve(gitCwd, parsed.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 = fs5.realpathSync(output);
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 path9 from "node:path";
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 = path9.isAbsolute(requested) ? path9.resolve(requested) : path9.resolve(sessionCwd, requested);
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 isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8222
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
7751
8223
  var withBashCwdSchema = (schema) => {
7752
- if (!isRecord2(schema) || !isRecord2(schema.properties)) return schema;
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: path16, content } = params;
7834
- const absolutePath = resolvePreviewPath(path16, cwd);
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(path16, cwd, content);
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 ${path16}`
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 = path10.resolve(
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 randomUUID3 } from "node:crypto";
8253
- import fs7 from "node:fs";
8254
- import path12 from "node:path";
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 fs6 from "node:fs";
8263
- import path11 from "node:path";
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(path11.sep).join("/");
8753
+ var normalizeRelative = (value) => value.split(path12.sep).join("/");
8282
8754
  var isInside = (root, candidate) => {
8283
- const relative = path11.relative(root, candidate);
8284
- return relative === "" || !path11.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path11.sep}`);
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 = fs6.lstatSync(absolute);
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(fs6.readlinkSync(absolute))}`, bytes: 0 };
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(fs6.readFileSync(absolute))}`, bytes: stat2.size };
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 = path11.resolve(cwd, relativeInput);
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(path11.relative(cwd, absolute));
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 = fs6.readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
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 = path11.join(directory, entry.name);
8816
+ const absolute = path12.join(directory, entry.name);
8345
8817
  if (excluded(absolute, exclusions)) continue;
8346
- const relative = normalizeRelative(path11.relative(cwd, absolute));
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 = fs6.realpathSync(cwdInput);
8830
+ const cwd = fs7.realpathSync(cwdInput);
8359
8831
  const exclusions = excludedRoots.map((root) => {
8360
- const absolute = path11.resolve(root);
8832
+ const absolute = path12.resolve(root);
8361
8833
  try {
8362
- return fs6.realpathSync(absolute);
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() || path11.isAbsolute(requestedPath)) {
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 = fs6.realpathSync(cwdInput);
8402
- const absolute = path11.resolve(cwd, requestedPath);
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 = path11.relative(cwd, absolute).split(path11.sep);
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 = path11.join(cursor, relativeParts[index]);
8881
+ cursor = path12.join(cursor, relativeParts[index]);
8410
8882
  let stat2;
8411
8883
  try {
8412
- stat2 = fs6.lstatSync(cursor);
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 = fs6.realpathSync(path11.dirname(cursor));
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(path11.relative(cwd, absolute)), exists: false };
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(path11.relative(cwd, absolute)), exists: true };
8904
+ return { absolute, relative: normalizeRelative(path12.relative(cwd, absolute)), exists: true };
8433
8905
  };
8434
- var sha256File = (absolute) => `sha256:${digest(fs6.readFileSync(absolute))}`;
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 errorMessage3 = (error) => error instanceof Error ? error.message : String(error);
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 = fs7.realpathSync(cwd);
8483
- this.#journalRoot = path12.join(mesh.root, "schema-transactions");
8484
- this.#lockPath = path12.join(this.#journalRoot, ".commit.lock");
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: randomUUID3(),
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: ${errorMessage3(error)}`);
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: ${errorMessage3(error)}`);
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 = randomUUID3();
8683
- const journalPath = path12.join(this.#journalRoot, `${transactionId}.json`);
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 = fs7.readFileSync(resolved.absolute);
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: fs7.statSync(resolved.absolute).mode & 511
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: errorMessage3(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 ? `${errorMessage3(error)}; rollback failed: ${rollbackError}` : errorMessage3(error);
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, errorMessage3(error), rollbackError);
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: errorMessage3(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 = fs7.readFileSync(resolved.absolute, "utf8").includes(item.literal);
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: errorMessage3(error) });
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: errorMessage3(error), exitCode: null });
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
- fs7.writeFileSync(resolved.absolute, operation.content, "utf8");
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
- fs7.unlinkSync(resolved.absolute);
9524
+ fs8.unlinkSync(resolved.absolute);
9053
9525
  return;
9054
9526
  }
9055
- const content = fs7.readFileSync(resolved.absolute, "utf8");
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
- fs7.writeFileSync(resolved.absolute, `${content.slice(0, first)}${operation.newText}${content.slice(first + operation.oldText.length)}`, "utf8");
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) fs7.unlinkSync(resolved.absolute);
9552
+ if (resolved.exists) fs8.unlinkSync(resolved.absolute);
9081
9553
  } else {
9082
- fs7.writeFileSync(resolved.absolute, Buffer.from(image.content ?? "", "base64"));
9083
- if (image.mode !== void 0) fs7.chmodSync(resolved.absolute, image.mode);
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}: ${errorMessage3(error)}`);
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
- fs7.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
9603
+ fs8.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
9132
9604
  try {
9133
- const descriptor = fs7.openSync(this.#lockPath, "wx", 384);
9134
- fs7.writeFileSync(descriptor, `${process.pid}
9605
+ const descriptor = fs8.openSync(this.#lockPath, "wx", 384);
9606
+ fs8.writeFileSync(descriptor, `${process.pid}
9135
9607
  ${Date.now()}
9136
9608
  `);
9137
- fs7.closeSync(descriptor);
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 () => fs7.rmSync(this.#lockPath, { force: true });
9616
+ return () => fs8.rmSync(this.#lockPath, { force: true });
9145
9617
  }
9146
9618
  #recoverJournals() {
9147
- fs7.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
9619
+ fs8.mkdirSync(this.#journalRoot, { recursive: true, mode: 448 });
9148
9620
  try {
9149
- const [pidText] = fs7.readFileSync(this.#lockPath, "utf8").split("\n");
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
- fs7.rmSync(this.#lockPath, { force: true });
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 fs7.readdirSync(this.#journalRoot)) {
9634
+ for (const name of fs8.readdirSync(this.#journalRoot)) {
9163
9635
  if (!name.endsWith(".json")) continue;
9164
- const filePath = path12.join(this.#journalRoot, name);
9636
+ const filePath = path13.join(this.#journalRoot, name);
9165
9637
  try {
9166
- const journal = JSON.parse(fs7.readFileSync(filePath, "utf8"));
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 path14 from "node:path";
9890
+ import path15 from "node:path";
9419
9891
 
9420
9892
  // src/state/complexity.ts
9421
- import fs8 from "node:fs";
9422
- import path13 from "node:path";
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 = path13.extname(file).toLowerCase();
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(fs8.readFileSync(file, "utf8"))
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 errorMessage4 = (error) => error instanceof Error ? error.message : String(error);
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, errorMessage4(error));
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, errorMessage4(error)));
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 errorMessage5 = (error) => error instanceof Error ? error.message : String(error);
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(errorMessage5(error), REPORT_TEXT_MAX_BYTES).value;
10337
+ var boundedError = (error) => truncateUtf82(errorMessage6(error), REPORT_TEXT_MAX_BYTES).value;
9866
10338
  var casActualVersion = (error) => {
9867
- const match = errorMessage5(error).match(/found (\d+)$/);
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(errorMessage5(error), EVENT_TEXT_MAX_BYTES).value,
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(path14.resolve(input.cwd, file));
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(path14.resolve(cwd, file));
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 = path14.relative(cwd, path14.resolve(cwd, file));
10623
- if (relative === ".." || relative.startsWith(`..${path14.sep}`) || path14.isAbsolute(relative)) {
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(path14.sep).join("/"));
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 = this.capturedTools.subscribe(
11509
- () => this.#registry?.notifyCatalogChanged("extensions")
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
- path15.join(
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 ? path15.resolve(projectRoot, configuredMeshRoot) : path15.join(projectRoot, ".pi", "fabric", "mesh"));
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" ? path15.join(meshRoot, "actors", sessionId) : path15.join(meshRoot, "actors");
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(() => this.#actors?.retryCapabilityWaiters());
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-H7UA3DJC.js.map
12858
+ //# sourceMappingURL=fabric-runtime-state-H2NCRJWK.js.map