pi-fabric 0.84.2 → 0.84.4

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 (110) hide show
  1. package/dist/actors/log-store.d.ts +22 -0
  2. package/dist/actors/log-store.d.ts.map +1 -0
  3. package/dist/actors/manager.d.ts.map +1 -1
  4. package/dist/actors/mesh-monitor.d.ts +22 -0
  5. package/dist/actors/mesh-monitor.d.ts.map +1 -0
  6. package/dist/actors/registry-store.d.ts +15 -0
  7. package/dist/actors/registry-store.d.ts.map +1 -0
  8. package/dist/chunks/{chunk-2NI5YMKK.js → chunk-257ES5IL.js} +432 -371
  9. package/dist/chunks/{chunk-2NI5YMKK.js.map → chunk-257ES5IL.js.map} +4 -4
  10. package/dist/chunks/chunk-AB5JTS5M.js +397 -0
  11. package/dist/chunks/chunk-AB5JTS5M.js.map +7 -0
  12. package/dist/chunks/{chunk-66WTXNRP.js → chunk-AIN5KTE6.js} +1034 -1015
  13. package/dist/chunks/chunk-AIN5KTE6.js.map +7 -0
  14. package/dist/chunks/chunk-I2LDU6BS.js +817 -0
  15. package/dist/chunks/chunk-I2LDU6BS.js.map +7 -0
  16. package/dist/chunks/{chunk-D6BNJP5M.js → chunk-J4XMXVU2.js} +171 -165
  17. package/dist/chunks/chunk-J4XMXVU2.js.map +7 -0
  18. package/dist/chunks/{chunk-X7NUHPPE.js → chunk-K7U4B6ZQ.js} +2 -2
  19. package/dist/chunks/{chunk-XLGMWNCB.js → chunk-L6R3Y7XI.js} +912 -1714
  20. package/dist/chunks/chunk-L6R3Y7XI.js.map +7 -0
  21. package/dist/chunks/{chunk-QCHHE3GO.js → chunk-MPNEVZIH.js} +5 -3
  22. package/dist/chunks/{chunk-QCHHE3GO.js.map → chunk-MPNEVZIH.js.map} +1 -1
  23. package/dist/chunks/{chunk-KKM7TKIM.js → chunk-T3GPMH5E.js} +158 -229
  24. package/dist/chunks/chunk-T3GPMH5E.js.map +7 -0
  25. package/dist/chunks/chunk-VE5LH2Z7.js +74 -0
  26. package/dist/chunks/chunk-VE5LH2Z7.js.map +7 -0
  27. package/dist/components/effect-policy.d.ts +21 -0
  28. package/dist/components/effect-policy.d.ts.map +1 -0
  29. package/dist/components/supervisor.d.ts.map +1 -1
  30. package/dist/core/action-arguments.d.ts +10 -0
  31. package/dist/core/action-arguments.d.ts.map +1 -0
  32. package/dist/core/action-registry.d.ts.map +1 -1
  33. package/dist/core/action-registry.js +1 -1
  34. package/dist/core/action-result.d.ts +13 -0
  35. package/dist/core/action-result.d.ts.map +1 -0
  36. package/dist/fabric-runtime-state.d.ts +1 -1
  37. package/dist/fabric-runtime-state.d.ts.map +1 -1
  38. package/dist/fabric-runtime-state.js +6253 -6175
  39. package/dist/fabric-runtime-state.js.map +4 -4
  40. package/dist/index.js +27 -409
  41. package/dist/index.js.map +4 -4
  42. package/dist/memory/expand-service.d.ts +4 -0
  43. package/dist/memory/expand-service.d.ts.map +1 -0
  44. package/dist/memory/recall-service.d.ts +5 -0
  45. package/dist/memory/recall-service.d.ts.map +1 -0
  46. package/dist/memory/request-cache.d.ts +49 -0
  47. package/dist/memory/request-cache.d.ts.map +1 -0
  48. package/dist/memory/request-context.d.ts +54 -0
  49. package/dist/memory/request-context.d.ts.map +1 -0
  50. package/dist/memory/request-limits.d.ts +8 -0
  51. package/dist/memory/request-limits.d.ts.map +1 -0
  52. package/dist/memory/sessions-service.d.ts +3 -0
  53. package/dist/memory/sessions-service.d.ts.map +1 -0
  54. package/dist/memory/source-observation.d.ts +22 -0
  55. package/dist/memory/source-observation.d.ts.map +1 -0
  56. package/dist/providers/agents-message-router.d.ts +29 -0
  57. package/dist/providers/agents-message-router.d.ts.map +1 -0
  58. package/dist/providers/agents-progress.d.ts +18 -0
  59. package/dist/providers/agents-progress.d.ts.map +1 -0
  60. package/dist/providers/agents-provider.d.ts +2 -10
  61. package/dist/providers/agents-provider.d.ts.map +1 -1
  62. package/dist/providers/memory-provider.d.ts +3 -22
  63. package/dist/providers/memory-provider.d.ts.map +1 -1
  64. package/dist/providers/memory-provider.js +1 -1
  65. package/dist/residency/host.js +2 -2
  66. package/dist/residency/pi-entry.js +2 -2
  67. package/dist/runtime-state-builtins.d.ts +20 -0
  68. package/dist/runtime-state-builtins.d.ts.map +1 -0
  69. package/dist/runtime-state-speculation.d.ts +15 -0
  70. package/dist/runtime-state-speculation.d.ts.map +1 -0
  71. package/dist/ui/dashboard-graph-controller.d.ts +52 -0
  72. package/dist/ui/dashboard-graph-controller.d.ts.map +1 -0
  73. package/dist/ui/dashboard-modal-controller.d.ts +36 -0
  74. package/dist/ui/dashboard-modal-controller.d.ts.map +1 -0
  75. package/dist/ui/dashboard.d.ts +3 -35
  76. package/dist/ui/dashboard.d.ts.map +1 -1
  77. package/dist/ui/dashboard.js +367 -340
  78. package/dist/ui/dashboard.js.map +4 -4
  79. package/dist/ui/settings-component.d.ts +26 -0
  80. package/dist/ui/settings-component.d.ts.map +1 -0
  81. package/dist/ui/settings-rpc.d.ts +15 -0
  82. package/dist/ui/settings-rpc.d.ts.map +1 -0
  83. package/dist/ui/settings-section-context.d.ts +18 -0
  84. package/dist/ui/settings-section-context.d.ts.map +1 -0
  85. package/dist/ui/settings-sections-agents.d.ts +5 -0
  86. package/dist/ui/settings-sections-agents.d.ts.map +1 -0
  87. package/dist/ui/settings-sections-execution.d.ts +8 -0
  88. package/dist/ui/settings-sections-execution.d.ts.map +1 -0
  89. package/dist/ui/settings-sections-lifecycle.d.ts +6 -0
  90. package/dist/ui/settings-sections-lifecycle.d.ts.map +1 -0
  91. package/dist/ui/settings-sections-presentation.d.ts +6 -0
  92. package/dist/ui/settings-sections-presentation.d.ts.map +1 -0
  93. package/dist/ui/settings-sections.d.ts +12 -0
  94. package/dist/ui/settings-sections.d.ts.map +1 -0
  95. package/dist/ui/settings-submenus.d.ts +74 -0
  96. package/dist/ui/settings-submenus.d.ts.map +1 -0
  97. package/dist/ui/settings-values.d.ts +61 -0
  98. package/dist/ui/settings-values.d.ts.map +1 -0
  99. package/dist/ui/settings.d.ts +12 -48
  100. package/dist/ui/settings.d.ts.map +1 -1
  101. package/dist/ui/settings.js +986 -903
  102. package/dist/ui/settings.js.map +4 -4
  103. package/package.json +4 -5
  104. package/dist/chunks/chunk-66WTXNRP.js.map +0 -7
  105. package/dist/chunks/chunk-D6BNJP5M.js.map +0 -7
  106. package/dist/chunks/chunk-KKM7TKIM.js.map +0 -7
  107. package/dist/chunks/chunk-XB3RJVT4.js +0 -17
  108. package/dist/chunks/chunk-XB3RJVT4.js.map +0 -7
  109. package/dist/chunks/chunk-XLGMWNCB.js.map +0 -7
  110. /package/dist/chunks/{chunk-X7NUHPPE.js.map → chunk-K7U4B6ZQ.js.map} +0 -0
@@ -2885,13 +2885,253 @@ var actorDeliveryNotice = (delivery, triggerTurn) => {
2885
2885
  };
2886
2886
 
2887
2887
  // src/actors/directory.ts
2888
- import fs12 from "node:fs";
2888
+ import fs15 from "node:fs";
2889
+
2890
+ // src/actors/manager.ts
2891
+ import { randomUUID as randomUUID7 } from "node:crypto";
2892
+ import fs14 from "node:fs";
2893
+
2894
+ // src/actors/mesh-monitor.ts
2895
+ import fs10 from "node:fs";
2896
+ import path12 from "node:path";
2897
+ var MESH_WATCH_RECONCILE_MS = 2e3;
2898
+ var ActorMeshMonitor = class {
2899
+ constructor(mesh, config, callbacks) {
2900
+ this.mesh = mesh;
2901
+ this.config = config;
2902
+ this.callbacks = callbacks;
2903
+ this.#offset = this.#readCursor() ?? mesh.latestOffset();
2904
+ }
2905
+ #timer;
2906
+ #watcher;
2907
+ #offset;
2908
+ #scheduled = false;
2909
+ #polling = false;
2910
+ #closed = false;
2911
+ #started = false;
2912
+ start() {
2913
+ if (this.#started || this.#closed || !this.config.enabled) return;
2914
+ this.#started = true;
2915
+ if (process.platform === "win32") {
2916
+ this.#startTimer(this.config.actorPollMs);
2917
+ this.schedule();
2918
+ return;
2919
+ }
2920
+ try {
2921
+ const watcher = fs10.watch(this.mesh.root, { persistent: false }, (_event, filename) => {
2922
+ if (filename !== null && path12.basename(filename.toString()) !== "events.jsonl") return;
2923
+ this.schedule();
2924
+ });
2925
+ this.#watcher = watcher;
2926
+ watcher.on("error", () => this.#fallback(watcher));
2927
+ this.#startTimer(Math.max(MESH_WATCH_RECONCILE_MS, this.config.actorPollMs));
2928
+ } catch {
2929
+ this.#startTimer(this.config.actorPollMs);
2930
+ }
2931
+ this.schedule();
2932
+ }
2933
+ close() {
2934
+ this.#closed = true;
2935
+ if (this.#timer) clearInterval(this.#timer);
2936
+ this.#timer = void 0;
2937
+ this.#watcher?.close();
2938
+ this.#watcher = void 0;
2939
+ }
2940
+ schedule() {
2941
+ if (this.#scheduled || this.#closed || !this.config.enabled) return;
2942
+ this.#scheduled = true;
2943
+ queueMicrotask(() => {
2944
+ this.#scheduled = false;
2945
+ if (this.#closed) return;
2946
+ void this.#poll().catch(() => void 0);
2947
+ });
2948
+ }
2949
+ #fallback(watcher) {
2950
+ if (this.#closed || this.#watcher !== watcher) return;
2951
+ watcher.close();
2952
+ this.#watcher = void 0;
2953
+ this.#startTimer(this.config.actorPollMs);
2954
+ this.schedule();
2955
+ }
2956
+ #startTimer(delay5) {
2957
+ if (this.#timer) clearInterval(this.#timer);
2958
+ this.#timer = setInterval(() => this.schedule(), delay5);
2959
+ this.#timer.unref();
2960
+ }
2961
+ async #poll() {
2962
+ if (this.#polling || this.#closed || !this.config.enabled) return;
2963
+ if (!this.callbacks.beforePoll()) return;
2964
+ this.#polling = true;
2965
+ try {
2966
+ const tail = this.mesh.tail(this.#offset, this.config.maxReadEvents);
2967
+ this.#offset = tail.nextOffset;
2968
+ for (const event of tail.events) this.callbacks.onEvent(event);
2969
+ this.#writeCursor();
2970
+ } finally {
2971
+ this.#polling = false;
2972
+ }
2973
+ }
2974
+ #readCursor() {
2975
+ if (!this.callbacks.cursorPath) return void 0;
2976
+ try {
2977
+ const value = JSON.parse(fs10.readFileSync(this.callbacks.cursorPath, "utf8"));
2978
+ return value.format === 1 && typeof value.cursor === "number" && value.cursor >= 0 ? value.cursor : void 0;
2979
+ } catch {
2980
+ return void 0;
2981
+ }
2982
+ }
2983
+ #writeCursor() {
2984
+ if (!this.callbacks.cursorPath) return;
2985
+ try {
2986
+ writeJsonAtomic(this.callbacks.cursorPath, { format: 1, cursor: this.#offset }, { space: 2 });
2987
+ } catch {
2988
+ }
2989
+ }
2990
+ };
2889
2991
 
2890
2992
  // src/actors/manager.ts
2891
- import { randomUUID as randomUUID6 } from "node:crypto";
2892
- import fs11 from "node:fs";
2893
2993
  import os4 from "node:os";
2994
+ import path16 from "node:path";
2995
+
2996
+ // src/actors/log-store.ts
2997
+ import fs11 from "node:fs";
2894
2998
  import path13 from "node:path";
2999
+ var ACTOR_MESSAGE_HISTORY_LIMIT = 100;
3000
+ var ACTOR_MESSAGE_ENVELOPE_BYTES = 4096;
3001
+ var ACTOR_TRUNCATION_SUFFIX = "\n[actor message truncated]";
3002
+ var serializedBytes = (value) => Buffer.byteLength(JSON.stringify(value), "utf8");
3003
+ var truncateUtf8 = (value, maxBytes, suffix = "") => {
3004
+ if (Buffer.byteLength(value, "utf8") <= maxBytes) return value;
3005
+ const boundedSuffix = Buffer.byteLength(suffix, "utf8") <= maxBytes ? suffix : truncateUtf8(suffix, maxBytes);
3006
+ const available = Math.max(0, maxBytes - Buffer.byteLength(boundedSuffix, "utf8"));
3007
+ let low = 0;
3008
+ let high = value.length;
3009
+ while (low < high) {
3010
+ const middle = Math.ceil((low + high) / 2);
3011
+ if (Buffer.byteLength(value.slice(0, middle), "utf8") <= available) low = middle;
3012
+ else high = middle - 1;
3013
+ }
3014
+ return `${value.slice(0, low)}${boundedSuffix}`;
3015
+ };
3016
+ var boundedActorText = (value, maxBytes) => {
3017
+ if (serializedBytes({ text: value }) <= maxBytes) return value;
3018
+ const suffix = serializedBytes({ text: ACTOR_TRUNCATION_SUFFIX }) <= maxBytes ? ACTOR_TRUNCATION_SUFFIX : "";
3019
+ let low = 0;
3020
+ let high = value.length;
3021
+ while (low < high) {
3022
+ const middle = Math.ceil((low + high) / 2);
3023
+ if (serializedBytes({ text: `${value.slice(0, middle)}${suffix}` }) <= maxBytes) {
3024
+ low = middle;
3025
+ } else {
3026
+ high = middle - 1;
3027
+ }
3028
+ }
3029
+ return `${value.slice(0, low)}${suffix}`;
3030
+ };
3031
+ var boundedActorData = (data, maxBytes) => {
3032
+ let serialized;
3033
+ try {
3034
+ const encoded = JSON.stringify(data);
3035
+ serialized = typeof encoded === "string" ? encoded : String(data);
3036
+ if (serializedBytes({ data }) <= maxBytes) return data;
3037
+ } catch {
3038
+ serialized = String(data);
3039
+ }
3040
+ const originalBytes = Buffer.byteLength(serialized, "utf8");
3041
+ let preview = truncateUtf8(serialized, Math.max(0, maxBytes - 256));
3042
+ let bounded = { fabricTruncated: true, originalBytes, preview };
3043
+ while (preview && serializedBytes({ data: bounded }) > maxBytes) {
3044
+ preview = truncateUtf8(preview, Math.floor(Buffer.byteLength(preview, "utf8") / 2));
3045
+ bounded = { fabricTruncated: true, originalBytes, preview };
3046
+ }
3047
+ return serializedBytes({ data: bounded }) <= maxBytes ? bounded : { fabricTruncated: true, originalBytes };
3048
+ };
3049
+ var ActorLogStore = class {
3050
+ constructor(mesh, config, retention) {
3051
+ this.mesh = mesh;
3052
+ this.config = config;
3053
+ this.retention = retention;
3054
+ }
3055
+ async retainRun(actor, runId, runDirectory) {
3056
+ if (!runDirectory || !fs11.existsSync(runDirectory)) return;
3057
+ const dest = path13.join(path13.dirname(actor.sessionFile), "runs", runId);
3058
+ fs11.mkdirSync(dest, { recursive: true, mode: 448 });
3059
+ for (const file of ["events.jsonl", "status.json", "task.txt"]) {
3060
+ const src = path13.join(runDirectory, file);
3061
+ if (fs11.existsSync(src)) fs11.copyFileSync(src, path13.join(dest, file));
3062
+ }
3063
+ const nested = path13.join(runDirectory, "nested");
3064
+ if (fs11.existsSync(nested)) {
3065
+ try {
3066
+ fs11.cpSync(nested, path13.join(dest, "nested"), { recursive: true });
3067
+ } catch {
3068
+ }
3069
+ }
3070
+ this.pruneRuns(actor);
3071
+ }
3072
+ pruneRuns(actor, now = Date.now()) {
3073
+ pruneActorRunArchives({
3074
+ runsDirectory: path13.join(path13.dirname(actor.sessionFile), "runs"),
3075
+ ...actor.lastRunId ? { latestRunId: actor.lastRunId } : {},
3076
+ retentionMs: this.retention.actorRunArchiveMs,
3077
+ now
3078
+ });
3079
+ }
3080
+ retainedRunIds(actor) {
3081
+ const runsDir = path13.join(path13.dirname(actor.sessionFile), "runs");
3082
+ try {
3083
+ return fs11.readdirSync(runsDir).sort();
3084
+ } catch {
3085
+ return [];
3086
+ }
3087
+ }
3088
+ recordMessage(messages, message) {
3089
+ let bounded = structuredClone(message);
3090
+ const maxPayloadBytes = Math.max(1, this.mesh.maxEventBytes - ACTOR_MESSAGE_ENVELOPE_BYTES);
3091
+ const fixed = structuredClone(bounded);
3092
+ delete fixed.text;
3093
+ delete fixed.data;
3094
+ const contentBytes = Math.max(1, maxPayloadBytes - serializedBytes(fixed) - 128);
3095
+ const hasText = Boolean(bounded.text);
3096
+ const hasData = bounded.data !== void 0;
3097
+ const textBytes = hasText && hasData ? Math.floor(contentBytes / 2) : contentBytes;
3098
+ const dataBytes = hasText && hasData ? contentBytes - textBytes : contentBytes;
3099
+ if (bounded.text) {
3100
+ const contextBounded = bounded.text.length > this.config.eventContextChars ? `${bounded.text.slice(0, this.config.eventContextChars)}${ACTOR_TRUNCATION_SUFFIX}` : bounded.text;
3101
+ bounded.text = boundedActorText(contextBounded, textBytes);
3102
+ }
3103
+ if (bounded.data !== void 0) {
3104
+ bounded.data = boundedActorData(bounded.data, dataBytes);
3105
+ }
3106
+ if (serializedBytes(bounded) > maxPayloadBytes) {
3107
+ delete bounded.data;
3108
+ if (bounded.text) {
3109
+ bounded.text = boundedActorText(bounded.text, contentBytes);
3110
+ }
3111
+ }
3112
+ if (serializedBytes(bounded) > maxPayloadBytes) {
3113
+ bounded = {
3114
+ id: bounded.id,
3115
+ actorId: bounded.actorId,
3116
+ actorName: bounded.actorName,
3117
+ direction: bounded.direction,
3118
+ source: boundedActorText(bounded.source, 1024),
3119
+ createdAt: bounded.createdAt,
3120
+ ...bounded.action ? { action: bounded.action } : {},
3121
+ ...bounded.runId ? { runId: bounded.runId } : {},
3122
+ error: "Actor message content exceeded the mesh event limit"
3123
+ };
3124
+ }
3125
+ for (const key of Object.keys(message)) {
3126
+ delete message[key];
3127
+ }
3128
+ Object.assign(message, bounded);
3129
+ messages.push(bounded);
3130
+ if (messages.length > ACTOR_MESSAGE_HISTORY_LIMIT) {
3131
+ messages.splice(0, messages.length - ACTOR_MESSAGE_HISTORY_LIMIT);
3132
+ }
3133
+ }
3134
+ };
2895
3135
 
2896
3136
  // src/actors/predicate.ts
2897
3137
  var PREDICATE_VERSION = 1;
@@ -2962,8 +3202,8 @@ var evaluateActorValidWhile = async (source, facts) => {
2962
3202
 
2963
3203
  // src/actors/binding-store.ts
2964
3204
  import { createHash, randomUUID as randomUUID5 } from "node:crypto";
2965
- import fs10 from "node:fs";
2966
- import path12 from "node:path";
3205
+ import fs12 from "node:fs";
3206
+ import path14 from "node:path";
2967
3207
  var BINDING_LOCK_TIMEOUT_MS = 5e3;
2968
3208
  var BINDING_STALE_LOCK_MS = 3e4;
2969
3209
  var bindingFileName = (sessionId) => `${createHash("sha256").update(sessionId).digest("hex")}.json`;
@@ -2973,7 +3213,7 @@ var delay3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2973
3213
  var ActorBindingStore = class {
2974
3214
  constructor(sessionId, root) {
2975
3215
  this.sessionId = sessionId;
2976
- this.filePath = root ? path12.join(root, "bindings", bindingFileName(sessionId)) : void 0;
3216
+ this.filePath = root ? path14.join(root, "bindings", bindingFileName(sessionId)) : void 0;
2977
3217
  this.#sync(true);
2978
3218
  }
2979
3219
  #bindings = /* @__PURE__ */ new Map();
@@ -3039,7 +3279,7 @@ var ActorBindingStore = class {
3039
3279
  if (!this.filePath) return bindings;
3040
3280
  let parsed;
3041
3281
  try {
3042
- parsed = JSON.parse(fs10.readFileSync(this.filePath, "utf8"));
3282
+ parsed = JSON.parse(fs12.readFileSync(this.filePath, "utf8"));
3043
3283
  } catch {
3044
3284
  return bindings;
3045
3285
  }
@@ -3080,7 +3320,7 @@ var ActorBindingStore = class {
3080
3320
  #currentFingerprint() {
3081
3321
  if (!this.filePath) return void 0;
3082
3322
  try {
3083
- const stat = fs10.statSync(this.filePath);
3323
+ const stat = fs12.statSync(this.filePath);
3084
3324
  return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
3085
3325
  } catch {
3086
3326
  return void 0;
@@ -3089,7 +3329,7 @@ var ActorBindingStore = class {
3089
3329
  async #withLock(operation) {
3090
3330
  if (!this.filePath) return operation();
3091
3331
  const lockPath = `${this.filePath}.lock`;
3092
- const ownerPath2 = path12.join(lockPath, "owner");
3332
+ const ownerPath2 = path14.join(lockPath, "owner");
3093
3333
  const deadline = Date.now() + BINDING_LOCK_TIMEOUT_MS;
3094
3334
  const token = randomUUID5();
3095
3335
  const processAlive3 = (pid) => {
@@ -3101,11 +3341,11 @@ var ActorBindingStore = class {
3101
3341
  return false;
3102
3342
  }
3103
3343
  };
3104
- fs10.mkdirSync(path12.dirname(this.filePath), { recursive: true, mode: 448 });
3344
+ fs12.mkdirSync(path14.dirname(this.filePath), { recursive: true, mode: 448 });
3105
3345
  while (true) {
3106
3346
  try {
3107
- fs10.mkdirSync(lockPath, { mode: 448 });
3108
- fs10.writeFileSync(ownerPath2, `${token}
3347
+ fs12.mkdirSync(lockPath, { mode: 448 });
3348
+ fs12.writeFileSync(ownerPath2, `${token}
3109
3349
  ${process.pid}
3110
3350
  ${Date.now()}
3111
3351
  `, {
@@ -3116,13 +3356,13 @@ ${Date.now()}
3116
3356
  } catch (error) {
3117
3357
  if (errorCode2(error) !== "EEXIST") throw error;
3118
3358
  try {
3119
- const firstOwner = fs10.readFileSync(ownerPath2, "utf8");
3359
+ const firstOwner = fs12.readFileSync(ownerPath2, "utf8");
3120
3360
  const [, pidText, createdText] = firstOwner.trim().split("\n");
3121
3361
  const stale = Date.now() - Number(createdText) > BINDING_STALE_LOCK_MS;
3122
3362
  if (stale && !processAlive3(Number(pidText))) {
3123
- const secondOwner = fs10.readFileSync(ownerPath2, "utf8");
3363
+ const secondOwner = fs12.readFileSync(ownerPath2, "utf8");
3124
3364
  if (secondOwner === firstOwner) {
3125
- fs10.rmSync(lockPath, { recursive: true, force: true });
3365
+ fs12.rmSync(lockPath, { recursive: true, force: true });
3126
3366
  continue;
3127
3367
  }
3128
3368
  }
@@ -3138,10 +3378,10 @@ ${Date.now()}
3138
3378
  return operation();
3139
3379
  } finally {
3140
3380
  try {
3141
- const owner = fs10.readFileSync(ownerPath2, "utf8");
3381
+ const owner = fs12.readFileSync(ownerPath2, "utf8");
3142
3382
  if (owner.startsWith(`${token}
3143
3383
  `)) {
3144
- fs10.rmSync(lockPath, { recursive: true, force: true });
3384
+ fs12.rmSync(lockPath, { recursive: true, force: true });
3145
3385
  }
3146
3386
  } catch {
3147
3387
  }
@@ -3149,6 +3389,110 @@ ${Date.now()}
3149
3389
  }
3150
3390
  };
3151
3391
 
3392
+ // src/actors/registry-store.ts
3393
+ import { randomUUID as randomUUID6 } from "node:crypto";
3394
+ import fs13 from "node:fs";
3395
+ import path15 from "node:path";
3396
+ var ACTOR_REGISTRY_LOCK_TIMEOUT_MS = 5e3;
3397
+ var ACTOR_REGISTRY_STALE_LOCK_MS = 3e4;
3398
+ var delay4 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3399
+ var errorCode3 = (error) => error instanceof Error && "code" in error ? String(error.code) : void 0;
3400
+ var ActorRegistryStore = class {
3401
+ #registryPath;
3402
+ #actorRoot;
3403
+ constructor(actorRoot) {
3404
+ this.#actorRoot = actorRoot;
3405
+ this.#registryPath = path15.join(actorRoot, "actors.json");
3406
+ }
3407
+ records() {
3408
+ try {
3409
+ const parsed = JSON.parse(fs13.readFileSync(this.#registryPath, "utf8"));
3410
+ if (!Array.isArray(parsed.actors)) return [];
3411
+ return parsed.actors.flatMap(
3412
+ (record) => typeof record === "object" && record !== null && !Array.isArray(record) && typeof record.id === "string" ? [record] : []
3413
+ );
3414
+ } catch {
3415
+ return [];
3416
+ }
3417
+ }
3418
+ /** The callback must be synchronous: release precedes promise assimilation. */
3419
+ async withLock(operation) {
3420
+ const lockPath = `${this.#registryPath}.lock`;
3421
+ const ownerPath2 = path15.join(lockPath, "owner");
3422
+ const deadline = Date.now() + ACTOR_REGISTRY_LOCK_TIMEOUT_MS;
3423
+ const token = randomUUID6();
3424
+ const processAlive3 = (pid) => {
3425
+ if (!Number.isSafeInteger(pid) || pid <= 0) return false;
3426
+ try {
3427
+ process.kill(pid, 0);
3428
+ return true;
3429
+ } catch {
3430
+ return false;
3431
+ }
3432
+ };
3433
+ fs13.mkdirSync(this.#actorRoot, { recursive: true, mode: 448 });
3434
+ while (true) {
3435
+ try {
3436
+ fs13.mkdirSync(lockPath, { mode: 448 });
3437
+ fs13.writeFileSync(ownerPath2, `${token}
3438
+ ${process.pid}
3439
+ ${Date.now()}
3440
+ `, {
3441
+ encoding: "utf8",
3442
+ mode: 384
3443
+ });
3444
+ break;
3445
+ } catch (error) {
3446
+ if (errorCode3(error) !== "EEXIST") throw error;
3447
+ try {
3448
+ const firstOwner = fs13.readFileSync(ownerPath2, "utf8");
3449
+ const [, pidText, createdText] = firstOwner.trim().split("\n");
3450
+ const stale = Date.now() - Number(createdText) > ACTOR_REGISTRY_STALE_LOCK_MS;
3451
+ if (stale && !processAlive3(Number(pidText))) {
3452
+ const secondOwner = fs13.readFileSync(ownerPath2, "utf8");
3453
+ if (secondOwner === firstOwner) {
3454
+ fs13.rmSync(lockPath, { recursive: true, force: true });
3455
+ continue;
3456
+ }
3457
+ }
3458
+ } catch {
3459
+ }
3460
+ if (Date.now() >= deadline) {
3461
+ throw new Error("Timed out waiting for the Fabric actor registry lock");
3462
+ }
3463
+ await delay4(10);
3464
+ }
3465
+ }
3466
+ try {
3467
+ return operation();
3468
+ } finally {
3469
+ try {
3470
+ const owner = fs13.readFileSync(ownerPath2, "utf8");
3471
+ if (owner.startsWith(`${token}
3472
+ `)) {
3473
+ fs13.rmSync(lockPath, { recursive: true, force: true });
3474
+ }
3475
+ } catch {
3476
+ }
3477
+ }
3478
+ }
3479
+ fingerprint() {
3480
+ try {
3481
+ const stat = fs13.statSync(this.#registryPath);
3482
+ return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
3483
+ } catch {
3484
+ return void 0;
3485
+ }
3486
+ }
3487
+ read() {
3488
+ return JSON.parse(fs13.readFileSync(this.#registryPath, "utf8"));
3489
+ }
3490
+ /** Call within withLock for read-modify-write operations. */
3491
+ write(actors) {
3492
+ writeJsonAtomic(this.#registryPath, { format: 1, actors }, { space: 2 });
3493
+ }
3494
+ };
3495
+
3152
3496
  // src/actors/manager.ts
3153
3497
  var ACTOR_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9 _.-]{0,59}$/;
3154
3498
  var TOPIC_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,127}$/;
@@ -3160,62 +3504,9 @@ var MAIN_REVISION_EVENTS = /* @__PURE__ */ new Set([
3160
3504
  "tool_error",
3161
3505
  "session_compact"
3162
3506
  ]);
3163
- var MESSAGE_HISTORY_LIMIT = 100;
3164
- var MESH_WATCH_RECONCILE_MS = 2e3;
3165
- var ACTOR_REGISTRY_LOCK_TIMEOUT_MS = 5e3;
3166
3507
  var ORPHAN_ADOPTION_RETRY_MS = 3e4;
3167
- var ACTOR_REGISTRY_STALE_LOCK_MS = 3e4;
3168
3508
  var RETENTION_SWEEP_INTERVAL_MS2 = 15 * 60 * 1e3;
3169
3509
  var RESIDENT_HOST_EVENT_TOPIC = "fabric.actor.host-event";
3170
- var ACTOR_MESSAGE_ENVELOPE_BYTES = 4096;
3171
- var ACTOR_TRUNCATION_SUFFIX = "\n[actor message truncated]";
3172
- var serializedBytes = (value) => Buffer.byteLength(JSON.stringify(value), "utf8");
3173
- var truncateUtf8 = (value, maxBytes, suffix = "") => {
3174
- if (Buffer.byteLength(value, "utf8") <= maxBytes) return value;
3175
- const boundedSuffix = Buffer.byteLength(suffix, "utf8") <= maxBytes ? suffix : truncateUtf8(suffix, maxBytes);
3176
- const available = Math.max(0, maxBytes - Buffer.byteLength(boundedSuffix, "utf8"));
3177
- let low = 0;
3178
- let high = value.length;
3179
- while (low < high) {
3180
- const middle = Math.ceil((low + high) / 2);
3181
- if (Buffer.byteLength(value.slice(0, middle), "utf8") <= available) low = middle;
3182
- else high = middle - 1;
3183
- }
3184
- return `${value.slice(0, low)}${boundedSuffix}`;
3185
- };
3186
- var boundedActorText = (value, maxBytes) => {
3187
- if (serializedBytes({ text: value }) <= maxBytes) return value;
3188
- const suffix = serializedBytes({ text: ACTOR_TRUNCATION_SUFFIX }) <= maxBytes ? ACTOR_TRUNCATION_SUFFIX : "";
3189
- let low = 0;
3190
- let high = value.length;
3191
- while (low < high) {
3192
- const middle = Math.ceil((low + high) / 2);
3193
- if (serializedBytes({ text: `${value.slice(0, middle)}${suffix}` }) <= maxBytes) {
3194
- low = middle;
3195
- } else {
3196
- high = middle - 1;
3197
- }
3198
- }
3199
- return `${value.slice(0, low)}${suffix}`;
3200
- };
3201
- var boundedActorData = (data, maxBytes) => {
3202
- let serialized;
3203
- try {
3204
- const encoded = JSON.stringify(data);
3205
- serialized = typeof encoded === "string" ? encoded : String(data);
3206
- if (serializedBytes({ data }) <= maxBytes) return data;
3207
- } catch {
3208
- serialized = String(data);
3209
- }
3210
- const originalBytes = Buffer.byteLength(serialized, "utf8");
3211
- let preview = truncateUtf8(serialized, Math.max(0, maxBytes - 256));
3212
- let bounded = { fabricTruncated: true, originalBytes, preview };
3213
- while (preview && serializedBytes({ data: bounded }) > maxBytes) {
3214
- preview = truncateUtf8(preview, Math.floor(Buffer.byteLength(preview, "utf8") / 2));
3215
- bounded = { fabricTruncated: true, originalBytes, preview };
3216
- }
3217
- return serializedBytes({ data: bounded }) <= maxBytes ? bounded : { fabricTruncated: true, originalBytes };
3218
- };
3219
3510
  var normalizeCapabilityRequirements = (requirements = []) => {
3220
3511
  const normalized = /* @__PURE__ */ new Map();
3221
3512
  for (const requirement of requirements) {
@@ -3230,14 +3521,9 @@ var normalizeCapabilityRequirements = (requirements = []) => {
3230
3521
  if (normalized.size > 128) throw new Error("Actors may require at most 128 Fabric capabilities");
3231
3522
  return [...normalized].sort(([left], [right]) => left.localeCompare(right)).map(([ref, optional]) => ({ ref, ...optional ? { optional: true } : {} }));
3232
3523
  };
3233
- var delay4 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3234
- var errorCode3 = (error) => error instanceof Error && "code" in error ? String(error.code) : void 0;
3235
- var atomicWrite2 = (filePath, value) => {
3236
- writeJsonAtomic(filePath, value, { space: 2 });
3237
- };
3238
3524
  var readRunRecord = (filePath) => {
3239
3525
  try {
3240
- const parsed = JSON.parse(fs11.readFileSync(filePath, "utf8"));
3526
+ const parsed = JSON.parse(fs14.readFileSync(filePath, "utf8"));
3241
3527
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return void 0;
3242
3528
  return parsed;
3243
3529
  } catch {
@@ -3287,7 +3573,7 @@ var ActorManager = class {
3287
3573
  this.meshConfig = meshConfig;
3288
3574
  this.agents = agents;
3289
3575
  this.onDeliver = onDeliver;
3290
- this.#actorRoot = options.actorRoot ?? fs11.mkdtempSync(path13.join(os4.tmpdir(), "pi-fabric-actors-"));
3576
+ this.#actorRoot = options.actorRoot ?? fs14.mkdtempSync(path16.join(os4.tmpdir(), "pi-fabric-actors-"));
3291
3577
  this.#actorScope = options.actorScope ?? meshConfig.actorScope;
3292
3578
  this.#persistent = options.persistent ?? false;
3293
3579
  this.#mainAgent = options.mainAgent;
@@ -3297,30 +3583,44 @@ var ActorManager = class {
3297
3583
  this.#adoptionGraceMs = options.adoptionGraceMs ?? ORPHAN_ADOPTION_RETRY_MS;
3298
3584
  this.#claimResidency = options.claimResidency;
3299
3585
  this.#rootId = options.rootId ?? identity.id;
3300
- this.#meshCursorPath = options.meshCursorPath;
3301
3586
  this.#relayParticipantSteering = options.relayParticipantSteering ?? true;
3302
- this.#registryPath = path13.join(this.#actorRoot, "actors.json");
3587
+ this.#logs = new ActorLogStore(
3588
+ mesh,
3589
+ meshConfig,
3590
+ options.retention ?? DEFAULT_FABRIC_CONFIG.retention
3591
+ );
3592
+ this.#registry = new ActorRegistryStore(this.#actorRoot);
3303
3593
  this.#bindings = new ActorBindingStore(
3304
3594
  sessionId,
3305
3595
  this.#persistent && meshConfig.enabled ? this.#actorRoot : void 0
3306
3596
  );
3307
3597
  if (this.#persistent && meshConfig.enabled) this.#loadActors();
3308
- this.#registryFingerprint = this.#currentRegistryFingerprint();
3598
+ this.#registryFingerprint = this.#registry.fingerprint();
3309
3599
  for (const actor of this.#actors.values()) {
3310
3600
  this.#ownership.set(actor.id, this.#ownershipDecision(actor.id));
3311
3601
  }
3312
- this.#retention = options.retention ?? DEFAULT_FABRIC_CONFIG.retention;
3313
3602
  this.#acquireCapabilityView = options.acquireCapabilityView;
3314
3603
  this.#sweepRetainedRuns();
3315
3604
  this.#retentionTimer = setInterval(() => this.#sweepRetainedRuns(), RETENTION_SWEEP_INTERVAL_MS2);
3316
3605
  this.#retentionTimer.unref();
3317
- this.#meshOffset = this.#readMeshCursor() ?? mesh.latestOffset();
3318
- this.#startMeshMonitor();
3606
+ this.#meshMonitor = new ActorMeshMonitor(mesh, meshConfig, {
3607
+ cursorPath: options.meshCursorPath,
3608
+ beforePoll: () => {
3609
+ this.#syncActorsFromRegistry();
3610
+ this.#refreshOwnership();
3611
+ return !this.#halted;
3612
+ },
3613
+ onEvent: (event) => {
3614
+ if (event.topic === "fabric.steer") this.#relaySteer(event);
3615
+ else if (!event.topic.startsWith("fabric.control.")) this.#dispatchMeshEvent(event);
3616
+ }
3617
+ });
3618
+ this.#meshMonitor.start();
3319
3619
  }
3320
3620
  #actors = /* @__PURE__ */ new Map();
3321
3621
  #actorRoot;
3322
3622
  #actorScope;
3323
- #registryPath;
3623
+ #registry;
3324
3624
  #persistent;
3325
3625
  #bindings;
3326
3626
  #mainAgent;
@@ -3329,9 +3629,9 @@ var ActorManager = class {
3329
3629
  #lineageAlive;
3330
3630
  #claimResidency;
3331
3631
  #rootId;
3332
- #meshCursorPath;
3632
+ #meshMonitor;
3333
3633
  #relayParticipantSteering;
3334
- #retention;
3634
+ #logs;
3335
3635
  #acquireCapabilityView;
3336
3636
  #locallyCreated = /* @__PURE__ */ new Set();
3337
3637
  #ceded = /* @__PURE__ */ new Set();
@@ -3344,12 +3644,7 @@ var ActorManager = class {
3344
3644
  #adoptionPending = /* @__PURE__ */ new Set();
3345
3645
  #adoptionGraceMs;
3346
3646
  #listeners = /* @__PURE__ */ new Set();
3347
- #pollTimer;
3348
3647
  #retentionTimer;
3349
- #meshWatcher;
3350
- #meshOffset;
3351
- #meshPollScheduled = false;
3352
- #polling = false;
3353
3648
  #closing = false;
3354
3649
  // Stop-the-world gate armed by haltAll() (ESC): while true, host-event and
3355
3650
  // mesh dispatch are frozen so interrupted actors are not re-armed by the
@@ -3423,9 +3718,9 @@ var ActorManager = class {
3423
3718
  if (requirements.length > 0 && !this.#acquireCapabilityView) {
3424
3719
  throw new Error("This Fabric host cannot commit actor capability requirements");
3425
3720
  }
3426
- const id = randomUUID6().replaceAll("-", "");
3427
- const actorDirectory = path13.join(this.#actorRoot, id);
3428
- fs11.mkdirSync(actorDirectory, { recursive: true, mode: 448 });
3721
+ const id = randomUUID7().replaceAll("-", "");
3722
+ const actorDirectory = path16.join(this.#actorRoot, id);
3723
+ fs14.mkdirSync(actorDirectory, { recursive: true, mode: 448 });
3429
3724
  const actor = {
3430
3725
  id,
3431
3726
  name,
@@ -3449,7 +3744,7 @@ var ActorManager = class {
3449
3744
  requirements,
3450
3745
  ...request.validWhile ? { validWhile: structuredClone(request.validWhile) } : {},
3451
3746
  latestActivationSequence: 0,
3452
- sessionFile: path13.join(actorDirectory, "session.jsonl"),
3747
+ sessionFile: path16.join(actorDirectory, "session.jsonl"),
3453
3748
  queue: [],
3454
3749
  draining: false,
3455
3750
  messages: [],
@@ -3733,7 +4028,7 @@ var ActorManager = class {
3733
4028
  messages(id, limit = 50) {
3734
4029
  this.#syncActorsFromRegistry();
3735
4030
  const actor = this.#requireActor(id);
3736
- const bounded = Math.max(1, Math.min(Math.floor(limit), MESSAGE_HISTORY_LIMIT));
4031
+ const bounded = Math.max(1, Math.min(Math.floor(limit), ACTOR_MESSAGE_HISTORY_LIMIT));
3737
4032
  return actor.messages.slice(-bounded).map((message) => structuredClone(message));
3738
4033
  }
3739
4034
  /**
@@ -3782,17 +4077,17 @@ var ActorManager = class {
3782
4077
  const type = opts.type ?? "session";
3783
4078
  const lines = Math.max(1, Math.min(opts.lines ?? 200, 5e3));
3784
4079
  const sessionFile = actor.sessionFile;
3785
- const logDir = path13.join(path13.dirname(sessionFile), "runs");
4080
+ const logDir = path16.join(path16.dirname(sessionFile), "runs");
3786
4081
  const sessionPage = type === "run" ? { lines: [], hasMore: false } : readJsonlPage(sessionFile, lines, opts.before);
3787
4082
  const session = sessionPage.lines;
3788
4083
  let run;
3789
4084
  if (type !== "session") {
3790
4085
  const targetRunId = opts.runId ?? actor.lastRunId;
3791
4086
  if (targetRunId) {
3792
- const runPath = path13.join(logDir, targetRunId);
3793
- if (fs11.existsSync(runPath)) {
3794
- const statusRecord = readRunRecord(path13.join(runPath, "status.json"));
3795
- const eventsFile = path13.join(runPath, "events.jsonl");
4087
+ const runPath = path16.join(logDir, targetRunId);
4088
+ if (fs14.existsSync(runPath)) {
4089
+ const statusRecord = readRunRecord(path16.join(runPath, "status.json"));
4090
+ const eventsFile = path16.join(runPath, "events.jsonl");
3796
4091
  const page = readJsonlPage(eventsFile, lines, opts.before);
3797
4092
  run = {
3798
4093
  runId: targetRunId,
@@ -3814,7 +4109,7 @@ var ActorManager = class {
3814
4109
  sessionHasMore: sessionPage.hasMore,
3815
4110
  ...sessionPage.before !== void 0 ? { sessionBefore: sessionPage.before } : {},
3816
4111
  ...run ? { run } : {},
3817
- retainedRuns: this.#retainedRunIds(actor)
4112
+ retainedRuns: this.#logs.retainedRunIds(actor)
3818
4113
  };
3819
4114
  }
3820
4115
  noteMainActivity(idle = false) {
@@ -3905,22 +4200,6 @@ var ActorManager = class {
3905
4200
  ownershipChecked: true
3906
4201
  });
3907
4202
  }
3908
- #readMeshCursor() {
3909
- if (!this.#meshCursorPath) return void 0;
3910
- try {
3911
- const value = JSON.parse(fs11.readFileSync(this.#meshCursorPath, "utf8"));
3912
- return value.format === 1 && typeof value.cursor === "number" && value.cursor >= 0 ? value.cursor : void 0;
3913
- } catch {
3914
- return void 0;
3915
- }
3916
- }
3917
- #writeMeshCursor() {
3918
- if (!this.#meshCursorPath) return;
3919
- try {
3920
- atomicWrite2(this.#meshCursorPath, { format: 1, cursor: this.#meshOffset });
3921
- } catch {
3922
- }
3923
- }
3924
4203
  #beginHostEvent(event, idle) {
3925
4204
  if (this.#closing || !this.meshConfig.enabled) return false;
3926
4205
  if (!MAIN_REVISION_EVENTS.has(event) && ![...this.#actors.values()].some((actor) => this.#observesHostEvent(actor, event))) return false;
@@ -3928,7 +4207,7 @@ var ActorManager = class {
3928
4207
  this.#refreshOwnership();
3929
4208
  if (event === "input" && this.#halted) {
3930
4209
  this.#halted = false;
3931
- this.#scheduleMeshPoll();
4210
+ this.#meshMonitor.schedule();
3932
4211
  }
3933
4212
  if (this.#halted) return false;
3934
4213
  if (MAIN_REVISION_EVENTS.has(event)) this.#mainRevision++;
@@ -4009,7 +4288,7 @@ var ActorManager = class {
4009
4288
  await this.#bindings.delete(actor.id);
4010
4289
  this.#actors.delete(actor.id);
4011
4290
  this.#emitChange();
4012
- fs11.rmSync(path13.dirname(actor.sessionFile), { recursive: true, force: true });
4291
+ fs14.rmSync(path16.dirname(actor.sessionFile), { recursive: true, force: true });
4013
4292
  await this.#saveActors(/* @__PURE__ */ new Set([actor.id]));
4014
4293
  await this.mesh.delete({ key: this.#presenceKey(actor.id) }).catch(() => ({ deleted: false }));
4015
4294
  if (retainedRunId) await this.agents.cleanup(retainedRunId).catch(() => ({ cleaned: false }));
@@ -4018,12 +4297,9 @@ var ActorManager = class {
4018
4297
  async close() {
4019
4298
  if (this.#closing) return;
4020
4299
  this.#closing = true;
4021
- if (this.#pollTimer) clearInterval(this.#pollTimer);
4022
- this.#pollTimer = void 0;
4300
+ this.#meshMonitor.close();
4023
4301
  if (this.#retentionTimer) clearInterval(this.#retentionTimer);
4024
4302
  this.#retentionTimer = void 0;
4025
- this.#meshWatcher?.close();
4026
- this.#meshWatcher = void 0;
4027
4303
  this.#listeners.clear();
4028
4304
  if (this.#persistent) {
4029
4305
  this.#refreshOwnership();
@@ -4052,7 +4328,7 @@ var ActorManager = class {
4052
4328
  await Promise.allSettled(
4053
4329
  [...this.#actors.values()].map((actor) => actor.drain ?? Promise.resolve())
4054
4330
  );
4055
- fs11.rmSync(this.#actorRoot, { recursive: true, force: true });
4331
+ fs14.rmSync(this.#actorRoot, { recursive: true, force: true });
4056
4332
  }
4057
4333
  #enqueue(actor, source, payload, options = {}) {
4058
4334
  const canManage = options.ownershipChecked ? this.#canManageCached(actor.id) : this.#canManage(actor.id);
@@ -4092,7 +4368,7 @@ var ActorManager = class {
4092
4368
  `Fabric actor queue limit reached for ${actor.name} (${this.meshConfig.actorQueueLimit})`
4093
4369
  );
4094
4370
  }
4095
- const itemId = randomUUID6();
4371
+ const itemId = randomUUID7();
4096
4372
  const item = {
4097
4373
  id: itemId,
4098
4374
  source,
@@ -4205,7 +4481,7 @@ var ActorManager = class {
4205
4481
  if (actor.responseMode === "directive") {
4206
4482
  const reason = result.error || `Actor run ${result.status}`;
4207
4483
  const silent = {
4208
- id: randomUUID6(),
4484
+ id: randomUUID7(),
4209
4485
  actorId: actor.id,
4210
4486
  actorName: actor.name,
4211
4487
  direction: "out",
@@ -4270,7 +4546,7 @@ var ActorManager = class {
4270
4546
  }
4271
4547
  actor.lastError = message;
4272
4548
  const failed = {
4273
- id: randomUUID6(),
4549
+ id: randomUUID7(),
4274
4550
  actorId: actor.id,
4275
4551
  actorName: actor.name,
4276
4552
  direction: "out",
@@ -4352,7 +4628,7 @@ var ActorManager = class {
4352
4628
  if (actor.responseMode === "directive") {
4353
4629
  const directive = asDirective(result);
4354
4630
  return {
4355
- id: randomUUID6(),
4631
+ id: randomUUID7(),
4356
4632
  actorId: actor.id,
4357
4633
  actorName: actor.name,
4358
4634
  direction: "out",
@@ -4366,7 +4642,7 @@ var ActorManager = class {
4366
4642
  };
4367
4643
  }
4368
4644
  return {
4369
- id: randomUUID6(),
4645
+ id: randomUUID7(),
4370
4646
  actorId: actor.id,
4371
4647
  actorName: actor.name,
4372
4648
  direction: "out",
@@ -4421,7 +4697,7 @@ var ActorManager = class {
4421
4697
  }
4422
4698
  #recordStale(actor, item, reason = "validWhile returned false", runId, usage) {
4423
4699
  const message = {
4424
- id: randomUUID6(),
4700
+ id: randomUUID7(),
4425
4701
  actorId: actor.id,
4426
4702
  actorName: actor.name,
4427
4703
  direction: "out",
@@ -4436,65 +4712,6 @@ var ActorManager = class {
4436
4712
  this.#recordMessage(actor, message);
4437
4713
  item.reject?.(new Error(`Fabric actor activation invalidated: ${reason}`));
4438
4714
  }
4439
- #startMeshMonitor() {
4440
- if (!this.meshConfig.enabled || this.#closing) return;
4441
- if (process.platform === "win32") {
4442
- this.#startPollTimer(this.meshConfig.actorPollMs);
4443
- this.#scheduleMeshPoll();
4444
- return;
4445
- }
4446
- try {
4447
- const watcher = fs11.watch(this.mesh.root, { persistent: false }, (_event, filename) => {
4448
- if (filename !== null && path13.basename(filename.toString()) !== "events.jsonl") return;
4449
- this.#scheduleMeshPoll();
4450
- });
4451
- this.#meshWatcher = watcher;
4452
- watcher.on("error", () => this.#fallBackToMeshPolling(watcher));
4453
- this.#startPollTimer(Math.max(MESH_WATCH_RECONCILE_MS, this.meshConfig.actorPollMs));
4454
- } catch {
4455
- this.#startPollTimer(this.meshConfig.actorPollMs);
4456
- }
4457
- this.#scheduleMeshPoll();
4458
- }
4459
- #fallBackToMeshPolling(watcher) {
4460
- if (this.#closing || this.#meshWatcher !== watcher) return;
4461
- watcher.close();
4462
- this.#meshWatcher = void 0;
4463
- this.#startPollTimer(this.meshConfig.actorPollMs);
4464
- this.#scheduleMeshPoll();
4465
- }
4466
- #startPollTimer(delay5) {
4467
- if (this.#pollTimer) clearInterval(this.#pollTimer);
4468
- this.#pollTimer = setInterval(() => this.#scheduleMeshPoll(), delay5);
4469
- this.#pollTimer.unref();
4470
- }
4471
- #scheduleMeshPoll() {
4472
- if (this.#meshPollScheduled || this.#closing || !this.meshConfig.enabled) return;
4473
- this.#meshPollScheduled = true;
4474
- queueMicrotask(() => {
4475
- this.#meshPollScheduled = false;
4476
- if (this.#closing) return;
4477
- void this.#pollMesh().catch(() => void 0);
4478
- });
4479
- }
4480
- async #pollMesh() {
4481
- if (this.#polling || this.#closing || !this.meshConfig.enabled) return;
4482
- this.#syncActorsFromRegistry();
4483
- this.#refreshOwnership();
4484
- if (this.#halted) return;
4485
- this.#polling = true;
4486
- try {
4487
- const tail = this.mesh.tail(this.#meshOffset, this.meshConfig.maxReadEvents);
4488
- this.#meshOffset = tail.nextOffset;
4489
- for (const event of tail.events) {
4490
- if (event.topic === "fabric.steer") this.#relaySteer(event);
4491
- else if (!event.topic.startsWith("fabric.control.")) this.#dispatchMeshEvent(event);
4492
- }
4493
- this.#writeMeshCursor();
4494
- } finally {
4495
- this.#polling = false;
4496
- }
4497
- }
4498
4715
  /**
4499
4716
  * Receive legacy fabric.steer events from older Fabric writers. This path is
4500
4717
  * intentionally best-effort; current writers use acknowledged owner-addressed
@@ -4555,91 +4772,17 @@ var ActorManager = class {
4555
4772
  }
4556
4773
  }
4557
4774
  async #retainRunLog(actor, runId) {
4558
- const runDirectory = this.agents.runDirectory(runId);
4559
- if (!runDirectory || !fs11.existsSync(runDirectory)) return;
4560
- const dest = path13.join(path13.dirname(actor.sessionFile), "runs", runId);
4561
- fs11.mkdirSync(dest, { recursive: true, mode: 448 });
4562
- for (const file of ["events.jsonl", "status.json", "task.txt"]) {
4563
- const src = path13.join(runDirectory, file);
4564
- if (fs11.existsSync(src)) fs11.copyFileSync(src, path13.join(dest, file));
4565
- }
4566
- const nested = path13.join(runDirectory, "nested");
4567
- if (fs11.existsSync(nested)) {
4568
- try {
4569
- fs11.cpSync(nested, path13.join(dest, "nested"), { recursive: true });
4570
- } catch {
4571
- }
4572
- }
4573
- this.#pruneRetainedRuns(actor);
4574
- }
4575
- #pruneRetainedRuns(actor, now = Date.now()) {
4576
- pruneActorRunArchives({
4577
- runsDirectory: path13.join(path13.dirname(actor.sessionFile), "runs"),
4578
- ...actor.lastRunId ? { latestRunId: actor.lastRunId } : {},
4579
- retentionMs: this.#retention.actorRunArchiveMs,
4580
- now
4581
- });
4775
+ await this.#logs.retainRun(actor, runId, this.agents.runDirectory(runId));
4582
4776
  }
4583
4777
  #sweepRetainedRuns(now = Date.now()) {
4584
4778
  if (this.#closing) return;
4585
4779
  this.#refreshOwnership();
4586
4780
  for (const actor of this.#actors.values()) {
4587
- if (this.#canManage(actor.id)) this.#pruneRetainedRuns(actor, now);
4588
- }
4589
- }
4590
- #retainedRunIds(actor) {
4591
- const runsDir = path13.join(path13.dirname(actor.sessionFile), "runs");
4592
- try {
4593
- return fs11.readdirSync(runsDir).sort();
4594
- } catch {
4595
- return [];
4781
+ if (this.#canManage(actor.id)) this.#logs.pruneRuns(actor, now);
4596
4782
  }
4597
4783
  }
4598
4784
  #recordMessage(actor, message) {
4599
- let bounded = structuredClone(message);
4600
- const maxPayloadBytes = Math.max(1, this.mesh.maxEventBytes - ACTOR_MESSAGE_ENVELOPE_BYTES);
4601
- const fixed = structuredClone(bounded);
4602
- delete fixed.text;
4603
- delete fixed.data;
4604
- const contentBytes = Math.max(1, maxPayloadBytes - serializedBytes(fixed) - 128);
4605
- const hasText = Boolean(bounded.text);
4606
- const hasData = bounded.data !== void 0;
4607
- const textBytes = hasText && hasData ? Math.floor(contentBytes / 2) : contentBytes;
4608
- const dataBytes = hasText && hasData ? contentBytes - textBytes : contentBytes;
4609
- if (bounded.text) {
4610
- const contextBounded = bounded.text.length > this.meshConfig.eventContextChars ? `${bounded.text.slice(0, this.meshConfig.eventContextChars)}${ACTOR_TRUNCATION_SUFFIX}` : bounded.text;
4611
- bounded.text = boundedActorText(contextBounded, textBytes);
4612
- }
4613
- if (bounded.data !== void 0) {
4614
- bounded.data = boundedActorData(bounded.data, dataBytes);
4615
- }
4616
- if (serializedBytes(bounded) > maxPayloadBytes) {
4617
- delete bounded.data;
4618
- if (bounded.text) {
4619
- bounded.text = boundedActorText(bounded.text, contentBytes);
4620
- }
4621
- }
4622
- if (serializedBytes(bounded) > maxPayloadBytes) {
4623
- bounded = {
4624
- id: bounded.id,
4625
- actorId: bounded.actorId,
4626
- actorName: bounded.actorName,
4627
- direction: bounded.direction,
4628
- source: boundedActorText(bounded.source, 1024),
4629
- createdAt: bounded.createdAt,
4630
- ...bounded.action ? { action: bounded.action } : {},
4631
- ...bounded.runId ? { runId: bounded.runId } : {},
4632
- error: "Actor message content exceeded the mesh event limit"
4633
- };
4634
- }
4635
- for (const key of Object.keys(message)) {
4636
- delete message[key];
4637
- }
4638
- Object.assign(message, bounded);
4639
- actor.messages.push(bounded);
4640
- if (actor.messages.length > MESSAGE_HISTORY_LIMIT) {
4641
- actor.messages.splice(0, actor.messages.length - MESSAGE_HISTORY_LIMIT);
4642
- }
4785
+ this.#logs.recordMessage(actor.messages, message);
4643
4786
  }
4644
4787
  async #publishPresence(actor) {
4645
4788
  if (!this.#canManage(actor.id)) return;
@@ -4704,88 +4847,17 @@ var ActorManager = class {
4704
4847
  ...actor.lastRunId ? { lastRunId: actor.lastRunId } : {}
4705
4848
  };
4706
4849
  }
4707
- #registryRecords() {
4708
- try {
4709
- const parsed = JSON.parse(fs11.readFileSync(this.#registryPath, "utf8"));
4710
- if (!Array.isArray(parsed.actors)) return [];
4711
- return parsed.actors.flatMap(
4712
- (record) => typeof record === "object" && record !== null && !Array.isArray(record) && typeof record.id === "string" ? [record] : []
4713
- );
4714
- } catch {
4715
- return [];
4716
- }
4717
- }
4718
- async #withRegistryLock(operation) {
4719
- const lockPath = `${this.#registryPath}.lock`;
4720
- const ownerPath2 = path13.join(lockPath, "owner");
4721
- const deadline = Date.now() + ACTOR_REGISTRY_LOCK_TIMEOUT_MS;
4722
- const token = randomUUID6();
4723
- const processAlive3 = (pid) => {
4724
- if (!Number.isSafeInteger(pid) || pid <= 0) return false;
4725
- try {
4726
- process.kill(pid, 0);
4727
- return true;
4728
- } catch {
4729
- return false;
4730
- }
4731
- };
4732
- fs11.mkdirSync(this.#actorRoot, { recursive: true, mode: 448 });
4733
- while (true) {
4734
- try {
4735
- fs11.mkdirSync(lockPath, { mode: 448 });
4736
- fs11.writeFileSync(ownerPath2, `${token}
4737
- ${process.pid}
4738
- ${Date.now()}
4739
- `, {
4740
- encoding: "utf8",
4741
- mode: 384
4742
- });
4743
- break;
4744
- } catch (error) {
4745
- if (errorCode3(error) !== "EEXIST") throw error;
4746
- try {
4747
- const firstOwner = fs11.readFileSync(ownerPath2, "utf8");
4748
- const [, pidText, createdText] = firstOwner.trim().split("\n");
4749
- const stale = Date.now() - Number(createdText) > ACTOR_REGISTRY_STALE_LOCK_MS;
4750
- if (stale && !processAlive3(Number(pidText))) {
4751
- const secondOwner = fs11.readFileSync(ownerPath2, "utf8");
4752
- if (secondOwner === firstOwner) {
4753
- fs11.rmSync(lockPath, { recursive: true, force: true });
4754
- continue;
4755
- }
4756
- }
4757
- } catch {
4758
- }
4759
- if (Date.now() >= deadline) {
4760
- throw new Error("Timed out waiting for the Fabric actor registry lock");
4761
- }
4762
- await delay4(10);
4763
- }
4764
- }
4765
- try {
4766
- return operation();
4767
- } finally {
4768
- try {
4769
- const owner = fs11.readFileSync(ownerPath2, "utf8");
4770
- if (owner.startsWith(`${token}
4771
- `)) {
4772
- fs11.rmSync(lockPath, { recursive: true, force: true });
4773
- }
4774
- } catch {
4775
- }
4776
- }
4777
- }
4778
4850
  async #saveActors(removedIds = /* @__PURE__ */ new Set()) {
4779
4851
  if (!this.#persistent || !this.meshConfig.enabled) return;
4780
- await this.#withRegistryLock(() => {
4852
+ await this.#registry.withLock(() => {
4781
4853
  const owned = [...this.#actors.values()].filter(
4782
4854
  (actor) => this.#ownershipDecision(actor.id)
4783
4855
  );
4784
4856
  const replaced = /* @__PURE__ */ new Set([...removedIds, ...owned.map((actor) => actor.id)]);
4785
- const preserved = this.#registryRecords().filter((record) => !replaced.has(record.id));
4857
+ const preserved = this.#registry.records().filter((record) => !replaced.has(record.id));
4786
4858
  const actors = [...preserved, ...owned.map((actor) => this.#serializedActor(actor))];
4787
- atomicWrite2(this.#registryPath, { format: 1, actors });
4788
- this.#registryFingerprint = this.#currentRegistryFingerprint();
4859
+ this.#registry.write(actors);
4860
+ this.#registryFingerprint = this.#registry.fingerprint();
4789
4861
  for (const id of removedIds) this.#persistedRoots.delete(id);
4790
4862
  for (const actor of owned) this.#persistedRoots.set(actor.id, actor.rootId);
4791
4863
  for (const record of preserved) {
@@ -4795,17 +4867,9 @@ ${Date.now()}
4795
4867
  this.#registryFingerprint = void 0;
4796
4868
  this.#syncActorsFromRegistry();
4797
4869
  }
4798
- #currentRegistryFingerprint() {
4799
- try {
4800
- const stat = fs11.statSync(this.#registryPath);
4801
- return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
4802
- } catch {
4803
- return void 0;
4804
- }
4805
- }
4806
4870
  #syncActorsFromRegistry() {
4807
4871
  if (!this.#persistent || this.#closing || this.#reloadingOwnership) return;
4808
- const fingerprint = this.#currentRegistryFingerprint();
4872
+ const fingerprint = this.#registry.fingerprint();
4809
4873
  if (!fingerprint || fingerprint === this.#registryFingerprint) return;
4810
4874
  this.#registryFingerprint = fingerprint;
4811
4875
  const ownsAny = [...this.#actors.keys()].some((id) => this.#ownershipDecision(id));
@@ -4842,7 +4906,7 @@ ${Date.now()}
4842
4906
  let added = 0;
4843
4907
  let parsed;
4844
4908
  try {
4845
- parsed = JSON.parse(fs11.readFileSync(this.#registryPath, "utf8"));
4909
+ parsed = this.#registry.read();
4846
4910
  } catch (error) {
4847
4911
  if (error instanceof Error && "code" in error && error.code === "ENOENT") return;
4848
4912
  return;
@@ -4903,7 +4967,7 @@ ${Date.now()}
4903
4967
  ...typeof record.capabilityDigest === "string" ? { capabilityDigest: record.capabilityDigest } : {},
4904
4968
  ...record.validWhile?.version === 1 && typeof record.validWhile.source === "string" ? { validWhile: record.validWhile } : {},
4905
4969
  latestActivationSequence: 0,
4906
- sessionFile: path13.join(this.#actorRoot, record.id, "session.jsonl"),
4970
+ sessionFile: path16.join(this.#actorRoot, record.id, "session.jsonl"),
4907
4971
  queue: [],
4908
4972
  draining: false,
4909
4973
  messages: [],
@@ -4912,7 +4976,7 @@ ${Date.now()}
4912
4976
  ...typeof record.lastRunId === "string" ? { lastRunId: record.lastRunId } : {}
4913
4977
  };
4914
4978
  if (Array.isArray(record.messages)) {
4915
- for (const candidate of record.messages.slice(-MESSAGE_HISTORY_LIMIT)) {
4979
+ for (const candidate of record.messages.slice(-ACTOR_MESSAGE_HISTORY_LIMIT)) {
4916
4980
  if (typeof candidate === "object" && candidate !== null && !Array.isArray(candidate) && typeof candidate.id === "string" && typeof candidate.source === "string" && typeof candidate.createdAt === "number") {
4917
4981
  this.#recordMessage(actor, candidate);
4918
4982
  }
@@ -4995,7 +5059,7 @@ ${Date.now()}
4995
5059
  ...actor.lastRunId ? { lastRunId: actor.lastRunId } : {},
4996
5060
  ...actor.lastError ? { lastError: actor.lastError } : {},
4997
5061
  sessionFile: actor.sessionFile,
4998
- logDir: path13.join(path13.dirname(actor.sessionFile), "runs")
5062
+ logDir: path16.join(path16.dirname(actor.sessionFile), "runs")
4999
5063
  };
5000
5064
  }
5001
5065
  validateDirectMessage(message, data) {
@@ -5042,8 +5106,8 @@ ${Date.now()}
5042
5106
  this.#adoptionPending.add(actor.id);
5043
5107
  try {
5044
5108
  const expectedRootId = actor.rootId;
5045
- const adopted = await this.#withRegistryLock(() => {
5046
- const records = this.#registryRecords();
5109
+ const adopted = await this.#registry.withLock(() => {
5110
+ const records = this.#registry.records();
5047
5111
  const current = records.find((record) => record.id === actor.id);
5048
5112
  if (!current || current.rootId !== expectedRootId) return false;
5049
5113
  if (this.#canManageActor?.(actor.id) !== void 0) return false;
@@ -5058,17 +5122,14 @@ ${Date.now()}
5058
5122
  actor.adoptedAt = Date.now();
5059
5123
  actor.updatedAt = Date.now();
5060
5124
  const preserved = records.filter((record) => record.id !== actor.id);
5061
- atomicWrite2(this.#registryPath, {
5062
- format: 1,
5063
- actors: [...preserved, this.#serializedActor(actor)]
5064
- });
5065
- this.#registryFingerprint = this.#currentRegistryFingerprint();
5125
+ this.#registry.write([...preserved, this.#serializedActor(actor)]);
5126
+ this.#registryFingerprint = this.#registry.fingerprint();
5066
5127
  return true;
5067
5128
  });
5068
5129
  if (adopted) {
5069
5130
  this.#persistedRoots.set(actor.id, this.#rootId);
5070
5131
  } else {
5071
- const current = this.#registryRecords().find((record) => record.id === actor.id);
5132
+ const current = this.#registry.records().find((record) => record.id === actor.id);
5072
5133
  if (!current) {
5073
5134
  this.#persistedRoots.delete(actor.id);
5074
5135
  } else if (typeof current.rootId === "string" && current.rootId !== this.#rootId) {
@@ -5166,10 +5227,10 @@ var ActorDirectory = class extends ActorManager {
5166
5227
  delete options.actorRoot;
5167
5228
  delete options.meshCursorPath;
5168
5229
  const cursorPaths = meshCursorPath ? { project: `${meshCursorPath}.project`, session: `${meshCursorPath}.session` } : void 0;
5169
- if (meshCursorPath && fs12.existsSync(meshCursorPath)) {
5230
+ if (meshCursorPath && fs15.existsSync(meshCursorPath)) {
5170
5231
  for (const cursorPath of Object.values(cursorPaths)) {
5171
5232
  try {
5172
- if (!fs12.existsSync(cursorPath)) fs12.copyFileSync(meshCursorPath, cursorPath);
5233
+ if (!fs15.existsSync(cursorPath)) fs15.copyFileSync(meshCursorPath, cursorPath);
5173
5234
  } catch {
5174
5235
  }
5175
5236
  }
@@ -5325,7 +5386,7 @@ var ActorDirectory = class extends ActorManager {
5325
5386
  };
5326
5387
 
5327
5388
  // src/lifecycle/broker.ts
5328
- import { randomUUID as randomUUID7 } from "node:crypto";
5389
+ import { randomUUID as randomUUID8 } from "node:crypto";
5329
5390
  var subscriptionKey = (id) => FABRIC_LIFECYCLE_SUBSCRIPTION_PREFIX + id;
5330
5391
  var LifecycleBroker = class {
5331
5392
  constructor(mesh, identity, participants, options, deliver) {
@@ -5404,7 +5465,7 @@ var LifecycleBroker = class {
5404
5465
  const now = Date.now();
5405
5466
  const subscription = {
5406
5467
  format: 1,
5407
- id: randomUUID7().replaceAll("-", ""),
5468
+ id: randomUUID8().replaceAll("-", ""),
5408
5469
  from,
5409
5470
  events,
5410
5471
  to,
@@ -5569,7 +5630,7 @@ var LifecycleBroker = class {
5569
5630
  };
5570
5631
 
5571
5632
  // src/topology/control-plane.ts
5572
- import { createHash as createHash2, randomUUID as randomUUID8 } from "node:crypto";
5633
+ import { createHash as createHash2, randomUUID as randomUUID9 } from "node:crypto";
5573
5634
  var CONTROL_TOPIC = "fabric.control.command";
5574
5635
  var ACK_TOPIC = "fabric.control.ack";
5575
5636
  var CONTROL_SEEN_PREFIX = "topology/control-seen/";
@@ -5664,7 +5725,7 @@ var FabricControlPlane = class {
5664
5725
  this.#pollMs * 4,
5665
5726
  Math.min(MAX_CONTROL_TIMEOUT_MS, Math.floor(options.timeoutMs ?? this.#ackTimeoutMs))
5666
5727
  );
5667
- const commandId = randomUUID8();
5728
+ const commandId = randomUUID9();
5668
5729
  const requestedAt = Date.now();
5669
5730
  let pendingRequest;
5670
5731
  const acceptance = new Promise((resolve, reject) => {
@@ -5756,7 +5817,7 @@ var FabricControlPlane = class {
5756
5817
  to: pending.ownerHostId,
5757
5818
  data: {
5758
5819
  version: 1,
5759
- commandId: randomUUID8(),
5820
+ commandId: randomUUID9(),
5760
5821
  targetId: pending.targetId,
5761
5822
  operation: "cancel",
5762
5823
  cancelCommandId: commandId,
@@ -6626,4 +6687,4 @@ export {
6626
6687
  agentParticipantRecords,
6627
6688
  actorParticipantRecord
6628
6689
  };
6629
- //# sourceMappingURL=chunk-2NI5YMKK.js.map
6690
+ //# sourceMappingURL=chunk-257ES5IL.js.map