@fml-inc/fml 0.8.0-rc.1 → 0.8.0-rc.3

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fml",
3
- "version": "0.8.0-rc.1",
3
+ "version": "0.8.0-rc.3",
4
4
  "description": "FML agent tools for Claude Code",
5
5
  "mcpServers": {
6
6
  "fml": {
package/README.md CHANGED
@@ -10,25 +10,34 @@ not install or run a second Panopticon package.
10
10
 
11
11
  ## Install
12
12
 
13
- Node.js 22.15 or newer and pnpm are required.
13
+ Node.js 22.15 or newer and npm are required.
14
+
15
+ On macOS, Linux, and compatible Bash environments, install with:
14
16
 
15
17
  ```bash
16
- pnpm add --global @fml-inc/fml
17
- fml install
18
- fml login
19
- fml org
20
- fml start
18
+ curl -fsSL https://fml.inc/install.sh | bash
21
19
  ```
22
20
 
21
+ For Windows or manual installation, run:
22
+
23
+ ```bash
24
+ npm install --global @fml-inc/fml
25
+ fml setup
26
+ ```
27
+
28
+ Run `fml update` to upgrade the global package with npm. Stable releases stay
29
+ on npm's `latest` channel; prerelease versions stay on `next`.
30
+
23
31
  Installing the package does not change agent configuration. Run `fml install`
24
- explicitly to register the FML Claude Code plugin, install the agent-native FML
25
- skill, configure the FML MCP server, and register capture-only lifecycle hooks
26
- for supported agents. Invoke the skill as `/fml review` in Claude, Gemini, or
27
- Grok, and as `$fml review` in Codex. Review runs inside the agent from the
28
- packaged skill; it is not an `fml review` CLI command. Start a new agent session
29
- after installing so it picks up the integration. FML pre-approves only the
30
- isolated command hooks it installs for Codex; use `/hooks` to review or disable
31
- them.
32
+ to register the FML Claude Code plugin, install the agent-native FML skill,
33
+ configure the FML MCP server, register capture-only lifecycle hooks for
34
+ supported agents, and install the FML extension for Pi. `fml setup` performs
35
+ this installation, signs in when needed, and restarts the observer. Invoke the
36
+ skill as `/fml review` in Claude, Gemini, or Grok, and as `$fml review` in
37
+ Codex. Review runs inside the agent from the packaged skill; it is not an
38
+ `fml review` CLI command. Start a new agent session after installing so it
39
+ picks up the integration. FML pre-approves only the isolated command hooks it
40
+ installs for Codex; use `/hooks` to review or disable them.
32
41
 
33
42
  The Claude plugin is MCP-only. FML installs the workflow through each host's
34
43
  native skill directory so it keeps the bare `fml` name without a second,
@@ -59,7 +68,8 @@ Windows: `%APPDATA%\panopticon`), and remove any leftover `panopticon` entries
59
68
  from the Claude plugin registration (`~/.claude/settings.json` and
60
69
  `~/.claude/plugins/`), agent hook configs (`~/.codex/config.toml`,
61
70
  `~/.codex/hooks.json`, `~/.gemini/settings.json`, `~/.grok/hooks/`), and MCP
62
- server registrations in those same agent config files.
71
+ server registrations in those same agent config files. Also remove the legacy
72
+ Pi extension at `~/.pi/agent/extensions/panopticon.js`.
63
73
 
64
74
  ## Raw artifact sync
65
75
 
@@ -84,6 +94,7 @@ fml sync disable # Stop discovery and upload
84
94
  fml sync enable # Allow discovery and upload again
85
95
  fml sync reset # Clear watermarks and replay every local artifact from byte zero
86
96
  fml start # Start the observer and continuously run enabled raw sync
97
+ fml restart # Stop and start the observer
87
98
  fml stop # Stop the observer and disable raw sync
88
99
  ```
89
100
 
@@ -262,11 +273,13 @@ fml tools call <tool-name> --args '{"key":"value"}'
262
273
  ## CLI overview
263
274
 
264
275
  ```text
276
+ fml setup Install integrations, sign in if needed, and start FML
265
277
  fml install Register FML agent integrations and the MCP server
266
278
  fml uninstall Remove agent integration; add --purge to remove local state
267
- fml update Update @fml-inc/fml with pnpm
279
+ fml update Update @fml-inc/fml with npm (stable: latest; prerelease: next)
268
280
 
269
281
  fml start Start the local observer and continuous raw sync
282
+ fml restart Stop and start the local observer
270
283
  fml stop Stop the local observer and disable raw sync
271
284
 
272
285
  fml login Sign in to FML
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  resolvePackageRoot,
3
3
  runRawSyncOnce
4
- } from "./chunk-JXSSPQ5B.js";
4
+ } from "./chunk-YSU5CS2V.js";
5
5
 
6
6
  // src/observer/sync-cycle.ts
7
7
  import { fork } from "child_process";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  OBSERVER_SERVICE_NAME
3
- } from "./chunk-DEMVOVVY.js";
3
+ } from "./chunk-KBT5RMAU.js";
4
4
  import {
5
5
  FML_OBSERVER_LOCK_FILE,
6
6
  FML_OBSERVER_PORT,
7
7
  FML_OBSERVER_STATE_FILE
8
- } from "./chunk-7DR5X7XI.js";
8
+ } from "./chunk-A6HAEVJX.js";
9
9
 
10
10
  // src/observer/state.ts
11
11
  import { randomUUID } from "crypto";
@@ -99,6 +99,9 @@ function resolveRepositorySlugFromCwd(cwd, timeoutMs = GIT_TIMEOUT_MS) {
99
99
  const remote = git(cwd, ["remote", "get-url", "origin"], timeoutMs);
100
100
  return remote ? repositorySlug(remote) : null;
101
101
  }
102
+ function resolveRepositoryRootFromCwd(cwd, timeoutMs = GIT_TIMEOUT_MS) {
103
+ return git(cwd, ["rev-parse", "--show-toplevel"], timeoutMs);
104
+ }
102
105
  async function resolveRepoFromCwdAsync(cwd, signal) {
103
106
  if (signal?.aborted) {
104
107
  throw signal.reason ?? new Error("Repository lookup aborted");
@@ -134,5 +137,6 @@ async function resolveRepoFromCwdAsync(cwd, signal) {
134
137
  export {
135
138
  resolveRepoFromCwd,
136
139
  resolveRepositorySlugFromCwd,
140
+ resolveRepositoryRootFromCwd,
137
141
  resolveRepoFromCwdAsync
138
142
  };
@@ -162,6 +162,10 @@ var FML_LEGACY_OBSERVER_DB_FILE = path.join(
162
162
  "observer.db"
163
163
  );
164
164
  var FML_HOOK_INBOX_DIR = path.join(FML_OBSERVER_DIR, "hook-inbox");
165
+ var FML_HOOK_CONTEXT_STATE_DIR = path.join(
166
+ FML_OBSERVER_DIR,
167
+ "hook-context-state"
168
+ );
165
169
  var FML_HOOK_CAPTURE_DISABLED_FILE = path.join(
166
170
  FML_OBSERVER_DIR,
167
171
  "hook-capture.disabled"
@@ -180,6 +184,10 @@ function ensureDirs() {
180
184
  fs.mkdirSync(FML_LOG_DIR, { recursive: true, mode: 448 });
181
185
  fs.mkdirSync(FML_OBSERVER_DIR, { recursive: true, mode: 448 });
182
186
  fs.mkdirSync(FML_HOOK_INBOX_DIR, { recursive: true, mode: 448 });
187
+ fs.mkdirSync(FML_HOOK_CONTEXT_STATE_DIR, {
188
+ recursive: true,
189
+ mode: 448
190
+ });
183
191
  }
184
192
 
185
193
  // src/config.ts
@@ -540,10 +548,32 @@ var serviceTokenCaches = /* @__PURE__ */ new Map();
540
548
  var serviceRefreshPromises = /* @__PURE__ */ new Map();
541
549
  var oauthRefreshPromises = /* @__PURE__ */ new Map();
542
550
  var cacheKey = (envName) => envName;
543
- function getOrStartTokenRefresh(flights, key, forceRefresh, refresh) {
551
+ function waitForTokenRefresh(promise, signal) {
552
+ if (!signal) return promise;
553
+ if (signal.aborted) return Promise.resolve(null);
554
+ return new Promise((resolve, reject) => {
555
+ const onAbort = () => {
556
+ cleanup();
557
+ resolve(null);
558
+ };
559
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
560
+ signal.addEventListener("abort", onAbort, { once: true });
561
+ void promise.then(
562
+ (value) => {
563
+ cleanup();
564
+ resolve(value);
565
+ },
566
+ (error) => {
567
+ cleanup();
568
+ reject(error);
569
+ }
570
+ );
571
+ });
572
+ }
573
+ function getOrStartTokenRefresh(flights, key, forceRefresh, refresh, signal) {
544
574
  const existing = flights.get(key);
545
575
  if (existing && (!forceRefresh || existing.forceRefresh)) {
546
- return existing.promise;
576
+ return waitForTokenRefresh(existing.promise, signal);
547
577
  }
548
578
  const operation = existing ? existing.promise.then(refresh, refresh) : refresh();
549
579
  let flight;
@@ -552,7 +582,7 @@ function getOrStartTokenRefresh(flights, key, forceRefresh, refresh) {
552
582
  });
553
583
  flight = { forceRefresh, promise };
554
584
  flights.set(key, flight);
555
- return promise;
585
+ return waitForTokenRefresh(promise, signal);
556
586
  }
557
587
  function refreshLockPath(envName) {
558
588
  return `${storePathFor(envName)}.refresh.lock`;
@@ -848,8 +878,30 @@ function releaseOwnedLease(filePath, claimedStat, owner, parseOwner, description
848
878
  );
849
879
  }
850
880
  }
851
- function sleep(milliseconds) {
852
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
881
+ function sleep(milliseconds, signal) {
882
+ if (!signal) {
883
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
884
+ }
885
+ if (signal.aborted) {
886
+ return Promise.reject(
887
+ signal.reason ?? new DOMException("The operation was aborted", "AbortError")
888
+ );
889
+ }
890
+ return new Promise((resolve, reject) => {
891
+ const timeout = setTimeout(() => {
892
+ cleanup();
893
+ resolve();
894
+ }, milliseconds);
895
+ const onAbort = () => {
896
+ clearTimeout(timeout);
897
+ cleanup();
898
+ reject(
899
+ signal.reason ?? new DOMException("The operation was aborted", "AbortError")
900
+ );
901
+ };
902
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
903
+ signal.addEventListener("abort", onAbort, { once: true });
904
+ });
853
905
  }
854
906
  function isProcessAlive(pid) {
855
907
  try {
@@ -998,7 +1050,7 @@ function recoverStaleRefreshLock(lockPath) {
998
1050
  recovery.release();
999
1051
  }
1000
1052
  }
1001
- async function acquireRefreshLock(envName) {
1053
+ async function acquireRefreshLock(envName, signal) {
1002
1054
  try {
1003
1055
  ensureDir(envName);
1004
1056
  } catch (error) {
@@ -1011,6 +1063,9 @@ async function acquireRefreshLock(envName) {
1011
1063
  const recoveryPath = `${lockPath}.recovery`;
1012
1064
  const deadline = Date.now() + OAUTH_REFRESH_LOCK_WAIT_MS;
1013
1065
  while (Date.now() < deadline) {
1066
+ if (signal?.aborted) {
1067
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
1068
+ }
1014
1069
  if (fs3.existsSync(recoveryPath)) {
1015
1070
  try {
1016
1071
  recoverAbandonedRecoveryMarker(recoveryPath);
@@ -1020,7 +1075,7 @@ async function acquireRefreshLock(envName) {
1020
1075
  );
1021
1076
  return null;
1022
1077
  }
1023
- await sleep(OAUTH_REFRESH_LOCK_POLL_MS);
1078
+ await sleep(OAUTH_REFRESH_LOCK_POLL_MS, signal);
1024
1079
  continue;
1025
1080
  }
1026
1081
  let descriptor;
@@ -1041,7 +1096,7 @@ async function acquireRefreshLock(envName) {
1041
1096
  );
1042
1097
  return null;
1043
1098
  }
1044
- await sleep(OAUTH_REFRESH_LOCK_POLL_MS);
1099
+ await sleep(OAUTH_REFRESH_LOCK_POLL_MS, signal);
1045
1100
  continue;
1046
1101
  }
1047
1102
  const ownerId = randomUUID();
@@ -1076,6 +1131,10 @@ async function acquireRefreshLock(envName) {
1076
1131
  parseRefreshLockOwner,
1077
1132
  "credential lock"
1078
1133
  );
1134
+ if (signal?.aborted) {
1135
+ releaseClaim();
1136
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
1137
+ }
1079
1138
  let entryBlocked;
1080
1139
  try {
1081
1140
  entryBlocked = fs3.existsSync(recoveryPath) || !isOwned();
@@ -1090,13 +1149,16 @@ async function acquireRefreshLock(envName) {
1090
1149
  return null;
1091
1150
  }
1092
1151
  if (entryBlocked) {
1093
- await sleep(OAUTH_REFRESH_LOCK_POLL_MS);
1094
1152
  try {
1095
- if (isOwned()) releaseClaim();
1096
- } catch (error) {
1097
- console.error(
1098
- `[fml] Auth: unable to release a blocked refresh lock claim: ${describeError(error)}`
1099
- );
1153
+ await sleep(OAUTH_REFRESH_LOCK_POLL_MS, signal);
1154
+ } finally {
1155
+ try {
1156
+ if (isOwned()) releaseClaim();
1157
+ } catch (error) {
1158
+ console.error(
1159
+ `[fml] Auth: unable to release a blocked refresh lock claim: ${describeError(error)}`
1160
+ );
1161
+ }
1100
1162
  }
1101
1163
  continue;
1102
1164
  }
@@ -1142,7 +1204,7 @@ function isLockOwnedSafely(lock) {
1142
1204
  }
1143
1205
  }
1144
1206
  async function withRefreshLock(envName, mutation, options) {
1145
- const lock = await acquireRefreshLock(envName);
1207
+ const lock = await acquireRefreshLock(envName, options?.signal);
1146
1208
  if (!lock) {
1147
1209
  throw new Error("Unable to acquire the credential mutation lock");
1148
1210
  }
@@ -1181,9 +1243,13 @@ async function clearStoredCredentials(envName) {
1181
1243
  serviceRefreshPromises.delete(key);
1182
1244
  oauthRefreshPromises.delete(key);
1183
1245
  }
1184
- async function refreshServiceToken(refreshToken2, envName, siteUrl) {
1246
+ async function refreshServiceToken(refreshToken2, envName, siteUrl, signal) {
1185
1247
  try {
1248
+ if (signal?.aborted) return null;
1186
1249
  const convexUrl = (envName ? resolveEnvConvexUrl(envName) : null) ?? CONVEX_URL;
1250
+ const requestTimeout = AbortSignal.timeout(
1251
+ OAUTH_REFRESH_REQUEST_TIMEOUT_MS
1252
+ );
1187
1253
  const response = await fetch(
1188
1254
  `${siteUrl ?? getSiteUrlForConvexUrl(convexUrl)}/api/tokens/refresh`,
1189
1255
  {
@@ -1192,7 +1258,7 @@ async function refreshServiceToken(refreshToken2, envName, siteUrl) {
1192
1258
  "Content-Type": "application/json",
1193
1259
  Authorization: `Bearer ${refreshToken2}`
1194
1260
  },
1195
- signal: AbortSignal.timeout(OAUTH_REFRESH_REQUEST_TIMEOUT_MS)
1261
+ signal: signal ? AbortSignal.any([signal, requestTimeout]) : requestTimeout
1196
1262
  }
1197
1263
  );
1198
1264
  if (!response.ok) {
@@ -1212,6 +1278,7 @@ async function refreshServiceToken(refreshToken2, envName, siteUrl) {
1212
1278
  });
1213
1279
  return data.accessToken;
1214
1280
  } catch (err) {
1281
+ if (signal?.aborted) return null;
1215
1282
  Sentry.captureException(err);
1216
1283
  console.error(`[fml] Service token refresh error: ${err}`);
1217
1284
  return null;
@@ -1248,6 +1315,7 @@ async function storeServiceRefreshToken(refreshToken2, opts) {
1248
1315
  return true;
1249
1316
  }
1250
1317
  async function getValidToken(opts) {
1318
+ if (opts?.signal?.aborted) return null;
1251
1319
  const envName = resolveEnvName(opts?.env);
1252
1320
  const forceRefresh = opts?.forceRefresh === true;
1253
1321
  const key = cacheKey(envName);
@@ -1261,7 +1329,8 @@ async function getValidToken(opts) {
1261
1329
  serviceRefreshPromises,
1262
1330
  key,
1263
1331
  forceRefresh,
1264
- () => refreshServiceToken(envToken, envName)
1332
+ () => refreshServiceToken(envToken, envName, void 0, opts?.signal),
1333
+ opts?.signal
1265
1334
  );
1266
1335
  }
1267
1336
  if (envToken?.startsWith("fml_st_")) return envToken;
@@ -1286,39 +1355,47 @@ async function getValidToken(opts) {
1286
1355
  serviceRefreshPromises,
1287
1356
  key,
1288
1357
  forceRefresh,
1289
- () => withRefreshLock(envName, async (lock) => {
1290
- const current = readTokens(envName);
1291
- if (!current) return null;
1292
- if (!forceRefresh && current.expiresAt > Date.now() + TOKEN_REFRESH_WINDOW_MS) {
1293
- return current.accessToken;
1294
- }
1295
- if (current.tokenType !== "service") {
1296
- return current.accessToken;
1297
- }
1298
- if (!lock.isOwned()) return null;
1299
- const newAccessToken = await refreshServiceToken(
1300
- current.refreshToken,
1301
- envName
1302
- );
1303
- if (!lock.isOwned()) return null;
1304
- const cached = serviceTokenCaches.get(key);
1305
- if (newAccessToken && cached) {
1306
- writeTokensUnlocked(
1307
- {
1308
- ...current,
1309
- accessToken: newAccessToken,
1310
- expiresAt: cached.expiresAt
1311
- },
1312
- envName
1358
+ () => withRefreshLock(
1359
+ envName,
1360
+ async (lock) => {
1361
+ const current = readTokens(envName);
1362
+ if (!current) return null;
1363
+ if (!forceRefresh && current.expiresAt > Date.now() + TOKEN_REFRESH_WINDOW_MS) {
1364
+ return current.accessToken;
1365
+ }
1366
+ if (current.tokenType !== "service") {
1367
+ return current.accessToken;
1368
+ }
1369
+ if (!lock.isOwned()) return null;
1370
+ const newAccessToken = await refreshServiceToken(
1371
+ current.refreshToken,
1372
+ envName,
1373
+ void 0,
1374
+ opts?.signal
1313
1375
  );
1314
- }
1315
- return newAccessToken;
1316
- }).catch((error) => {
1376
+ if (!lock.isOwned()) return null;
1377
+ const cached = serviceTokenCaches.get(key);
1378
+ if (newAccessToken && cached) {
1379
+ writeTokensUnlocked(
1380
+ {
1381
+ ...current,
1382
+ accessToken: newAccessToken,
1383
+ expiresAt: cached.expiresAt
1384
+ },
1385
+ envName
1386
+ );
1387
+ }
1388
+ return newAccessToken;
1389
+ },
1390
+ { signal: opts?.signal }
1391
+ ).catch((error) => {
1392
+ if (opts?.signal?.aborted) return null;
1317
1393
  console.error(
1318
1394
  `[fml] Auth: unable to refresh stored service credentials: ${error instanceof Error ? error.message : String(error)}`
1319
1395
  );
1320
1396
  return null;
1321
- })
1397
+ }),
1398
+ opts?.signal
1322
1399
  );
1323
1400
  }
1324
1401
  if (stored.refreshInvalidAt) {
@@ -1331,11 +1408,12 @@ async function getValidToken(opts) {
1331
1408
  oauthRefreshPromises,
1332
1409
  key,
1333
1410
  forceRefresh,
1334
- () => refreshTokenWithLock(envName, forceRefresh)
1411
+ () => refreshTokenWithLock(envName, forceRefresh, opts?.signal),
1412
+ opts?.signal
1335
1413
  );
1336
1414
  }
1337
- async function refreshTokenWithLock(envName, forceRefresh = false) {
1338
- const lock = await acquireRefreshLock(envName);
1415
+ async function refreshTokenWithLock(envName, forceRefresh = false, signal) {
1416
+ const lock = await acquireRefreshLock(envName, signal);
1339
1417
  if (!lock) return null;
1340
1418
  try {
1341
1419
  if (!isLockOwnedSafely(lock)) return null;
@@ -1366,12 +1444,12 @@ async function refreshTokenWithLock(envName, forceRefresh = false) {
1366
1444
  return null;
1367
1445
  }
1368
1446
  if (!isLockOwnedSafely(lock)) return null;
1369
- return await refreshToken(current, lock, envName);
1447
+ return await refreshToken(current, lock, envName, signal);
1370
1448
  } finally {
1371
1449
  lock.release();
1372
1450
  }
1373
1451
  }
1374
- async function refreshToken(stored, lock, envName) {
1452
+ async function refreshToken(stored, lock, envName, signal) {
1375
1453
  if (!stored.workosClientId) {
1376
1454
  console.error(
1377
1455
  "[fml] Auth: token expired, missing workosClientId \u2014 run `fml login`"
@@ -1379,7 +1457,11 @@ async function refreshToken(stored, lock, envName) {
1379
1457
  return null;
1380
1458
  }
1381
1459
  try {
1460
+ if (signal?.aborted) return null;
1382
1461
  if (!lock.isOwned()) return null;
1462
+ const requestTimeout = AbortSignal.timeout(
1463
+ OAUTH_REFRESH_REQUEST_TIMEOUT_MS
1464
+ );
1383
1465
  const response = await fetch(
1384
1466
  `${WORKOS_API_URL}/user_management/authenticate`,
1385
1467
  {
@@ -1390,7 +1472,7 @@ async function refreshToken(stored, lock, envName) {
1390
1472
  client_id: stored.workosClientId,
1391
1473
  refresh_token: stored.refreshToken
1392
1474
  }),
1393
- signal: AbortSignal.timeout(OAUTH_REFRESH_REQUEST_TIMEOUT_MS)
1475
+ signal: signal ? AbortSignal.any([signal, requestTimeout]) : requestTimeout
1394
1476
  }
1395
1477
  );
1396
1478
  if (!response.ok) {
@@ -1460,6 +1542,7 @@ async function refreshToken(stored, lock, envName) {
1460
1542
  }
1461
1543
  return refreshed.accessToken;
1462
1544
  } catch (err) {
1545
+ if (signal?.aborted) return null;
1463
1546
  const msg = err instanceof Error ? err.message : String(err);
1464
1547
  console.error(
1465
1548
  `[fml] Auth: refresh failed (network error: ${msg}) \u2014 token preserved`
@@ -1490,6 +1573,7 @@ export {
1490
1573
  FML_PANOPTICON_DB_OBSERVER_LOCK_FILE,
1491
1574
  FML_LEGACY_OBSERVER_DB_FILE,
1492
1575
  FML_HOOK_INBOX_DIR,
1576
+ FML_HOOK_CONTEXT_STATE_DIR,
1493
1577
  FML_HOOK_CAPTURE_DISABLED_FILE,
1494
1578
  observerOnlyOverrideWarning,
1495
1579
  ensureDirs,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  resolveRepoFromCwdAsync
3
- } from "./chunk-T5YVLSUC.js";
3
+ } from "./chunk-7V7G7NVF.js";
4
4
  import {
5
5
  getActiveEnv,
6
6
  getSiteUrlForConvexUrl,
7
7
  getSyncDestinationIdentity,
8
8
  getValidToken
9
- } from "./chunk-7DR5X7XI.js";
9
+ } from "./chunk-A6HAEVJX.js";
10
10
 
11
11
  // src/hooks/sync-loop.ts
12
12
  import { createHash } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  FML_HOOK_CAPTURE_DISABLED_FILE
3
- } from "./chunk-7DR5X7XI.js";
3
+ } from "./chunk-A6HAEVJX.js";
4
4
 
5
5
  // src/json-file.ts
6
6
  import { randomUUID } from "crypto";