@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
  import {
2
2
  FML_HOOK_INBOX_DIR
3
- } from "./chunk-7DR5X7XI.js";
3
+ } from "./chunk-A6HAEVJX.js";
4
4
 
5
5
  // ../../packages/panopticon/src/observer/auth.ts
6
6
  import crypto from "crypto";
@@ -71,7 +71,8 @@ var HOOK_TARGETS = Object.freeze([
71
71
  "claude",
72
72
  "codex",
73
73
  "gemini",
74
- "grok"
74
+ "grok",
75
+ "pi"
75
76
  ]);
76
77
  function isHookTarget(value) {
77
78
  return typeof value === "string" && HOOK_TARGETS.some((targetId) => targetId === value);
@@ -137,6 +138,20 @@ var hook_events_default = {
137
138
  "PreCompact",
138
139
  "PostCompact",
139
140
  "SessionEnd"
141
+ ],
142
+ pi: [
143
+ "SessionStart",
144
+ "UserPromptSubmit",
145
+ "TurnStart",
146
+ "PreToolUse",
147
+ "PostToolUse",
148
+ "PostToolUseFailure",
149
+ "Stop",
150
+ "Notification",
151
+ "ConfigChange",
152
+ "PreCompact",
153
+ "PostCompact",
154
+ "SessionEnd"
140
155
  ]
141
156
  };
142
157
 
@@ -153,6 +168,221 @@ var GEMINI_HOOK_EVENTS = Object.freeze([
153
168
  var GROK_HOOK_EVENTS = Object.freeze([
154
169
  ...hook_events_default.grok
155
170
  ]);
171
+ var PI_HOOK_EVENTS = Object.freeze([...hook_events_default.pi]);
172
+
173
+ // ../../packages/agent-targets/src/hooks/read-command.ts
174
+ import path2 from "path";
175
+ var SHELL_TOOL_NAMES = /* @__PURE__ */ new Set([
176
+ "bash",
177
+ "exec_command",
178
+ "shell"
179
+ ]);
180
+ var COMMAND_SEPARATORS = /* @__PURE__ */ new Set([
181
+ ";",
182
+ "&",
183
+ "&&",
184
+ "|",
185
+ "||",
186
+ "<",
187
+ "<<",
188
+ ">",
189
+ ">>",
190
+ ">&1",
191
+ ">&2",
192
+ "1>",
193
+ "1>>",
194
+ "1>&1",
195
+ "1>&2",
196
+ "2>",
197
+ "2>>",
198
+ "2>&1",
199
+ "2>&2"
200
+ ]);
201
+ function tokenizeShellLikeCommand(command) {
202
+ const tokens = [];
203
+ let current = "";
204
+ let quote = null;
205
+ let escaping = false;
206
+ for (let index = 0; index < command.length; index += 1) {
207
+ const character = command[index];
208
+ if (escaping) {
209
+ current += character;
210
+ escaping = false;
211
+ continue;
212
+ }
213
+ if (character === "\\") {
214
+ escaping = true;
215
+ continue;
216
+ }
217
+ if (quote) {
218
+ if (character === quote) quote = null;
219
+ else current += character;
220
+ continue;
221
+ }
222
+ if (character === "'" || character === '"') {
223
+ quote = character;
224
+ continue;
225
+ }
226
+ if (current === "" && (character === "1" || character === "2") && command[index + 1] === ">") {
227
+ if (command[index + 2] === ">") {
228
+ tokens.push(`${character}>>`);
229
+ index += 2;
230
+ } else if (command[index + 2] === "&" && (command[index + 3] === "1" || command[index + 3] === "2")) {
231
+ tokens.push(`${character}>&${command[index + 3]}`);
232
+ index += 3;
233
+ } else {
234
+ tokens.push(`${character}>`);
235
+ index += 1;
236
+ }
237
+ continue;
238
+ }
239
+ if (/[;&|<>]/.test(character)) {
240
+ if (current) {
241
+ tokens.push(current);
242
+ current = "";
243
+ }
244
+ const next = command[index + 1];
245
+ if (character === ">" && next === "&" && (command[index + 2] === "1" || command[index + 2] === "2")) {
246
+ tokens.push(`>&${command[index + 2]}`);
247
+ index += 2;
248
+ continue;
249
+ }
250
+ if (character === "&" && next === "&" || character === "|" && next === "|" || character === "<" && next === "<" || character === ">" && next === ">") {
251
+ tokens.push(`${character}${next}`);
252
+ index += 1;
253
+ continue;
254
+ }
255
+ tokens.push(character);
256
+ continue;
257
+ }
258
+ if (/\s/.test(character)) {
259
+ if (current) {
260
+ tokens.push(current);
261
+ current = "";
262
+ }
263
+ continue;
264
+ }
265
+ current += character;
266
+ }
267
+ if (quote || escaping) return [];
268
+ if (current) tokens.push(current);
269
+ return tokens;
270
+ }
271
+ function splitCommandSegments(tokens) {
272
+ const segments = [];
273
+ let current = [];
274
+ for (let index = 0; index < tokens.length; index += 1) {
275
+ const token = tokens[index];
276
+ if (COMMAND_SEPARATORS.has(token)) {
277
+ if (current.length > 0) {
278
+ segments.push(current);
279
+ current = [];
280
+ }
281
+ if (token === "<" || token === "<<") index += 1;
282
+ continue;
283
+ }
284
+ current.push(token);
285
+ }
286
+ if (current.length > 0) segments.push(current);
287
+ return segments;
288
+ }
289
+ function stripSimpleOptions(args, flagsWithValues = /* @__PURE__ */ new Set(), patternFlags = /* @__PURE__ */ new Set()) {
290
+ const remaining = [];
291
+ let consumedPatternFlag = false;
292
+ for (let index = 0; index < args.length; index += 1) {
293
+ const argument = args[index];
294
+ if (argument === "--") {
295
+ remaining.push(...args.slice(index + 1));
296
+ break;
297
+ }
298
+ if (argument.startsWith("-") && argument.length > 1) {
299
+ if (flagsWithValues.has(argument)) {
300
+ if (patternFlags.has(argument)) consumedPatternFlag = true;
301
+ if (!argument.includes("=")) index += 1;
302
+ }
303
+ continue;
304
+ }
305
+ remaining.push(argument);
306
+ }
307
+ return { args: remaining, consumedPatternFlag };
308
+ }
309
+ function readCommandFileArgs(args, flagsWithValues, patternFlags = flagsWithValues) {
310
+ const stripped = stripSimpleOptions(args, flagsWithValues, patternFlags);
311
+ return stripped.consumedPatternFlag ? stripped.args : stripped.args.slice(1);
312
+ }
313
+ function isPlausibleReadPath(argument) {
314
+ if (!argument || argument === "-" || argument.startsWith("-")) return false;
315
+ if (COMMAND_SEPARATORS.has(argument)) return false;
316
+ if (/[\0*?[{}`$]/.test(argument)) return false;
317
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(argument)) return false;
318
+ return path2.posix.isAbsolute(argument) || path2.win32.isAbsolute(argument) || argument.startsWith("~/") || argument.startsWith("./") || argument.startsWith("../") || argument.includes("/") || /\.[A-Za-z0-9][A-Za-z0-9_-]*$/.test(argument) || /^[A-Z][A-Za-z0-9_.-]*$/.test(argument);
319
+ }
320
+ function filePathFromSegment(tokens) {
321
+ const commandTokens = [...tokens];
322
+ while (commandTokens[0]?.includes("=") && /^[A-Za-z_][A-Za-z0-9_]*=/.test(commandTokens[0])) {
323
+ commandTokens.shift();
324
+ }
325
+ const commandName = commandTokens.shift()?.split("/").pop();
326
+ if (!commandName) return null;
327
+ let args;
328
+ switch (commandName) {
329
+ case "bat":
330
+ case "batcat":
331
+ case "cat":
332
+ case "file":
333
+ case "less":
334
+ case "more":
335
+ case "nl":
336
+ case "stat":
337
+ case "wc":
338
+ args = stripSimpleOptions(commandTokens).args;
339
+ break;
340
+ case "head":
341
+ case "tail":
342
+ args = stripSimpleOptions(commandTokens, /* @__PURE__ */ new Set(["-n", "-c"])).args;
343
+ break;
344
+ case "sed":
345
+ if (commandTokens.some(
346
+ (argument) => argument.startsWith("-i") || argument === "--in-place" || argument.startsWith("--in-place=")
347
+ )) {
348
+ return null;
349
+ }
350
+ args = readCommandFileArgs(commandTokens, /* @__PURE__ */ new Set(["-e", "-f"]));
351
+ break;
352
+ case "awk":
353
+ args = readCommandFileArgs(
354
+ commandTokens,
355
+ /* @__PURE__ */ new Set(["-f", "-v"]),
356
+ /* @__PURE__ */ new Set(["-f"])
357
+ );
358
+ break;
359
+ case "grep":
360
+ case "rg":
361
+ args = readCommandFileArgs(
362
+ commandTokens,
363
+ /* @__PURE__ */ new Set(["-A", "-B", "-C", "-e", "-f", "-g", "-m", "-t"]),
364
+ /* @__PURE__ */ new Set(["-e", "-f"])
365
+ );
366
+ break;
367
+ default:
368
+ return null;
369
+ }
370
+ return args.find(isPlausibleReadPath) ?? null;
371
+ }
372
+ function extractReadFilePathFromCommand(command) {
373
+ const tokens = tokenizeShellLikeCommand(command);
374
+ if (tokens.length === 0) return null;
375
+ for (let index = 0; index < tokens.length - 1; index += 1) {
376
+ if (tokens[index] === "<" && isPlausibleReadPath(tokens[index + 1])) {
377
+ return tokens[index + 1];
378
+ }
379
+ }
380
+ for (const segment of splitCommandSegments(tokens)) {
381
+ const filePath = filePathFromSegment(segment);
382
+ if (filePath) return filePath;
383
+ }
384
+ return null;
385
+ }
156
386
 
157
387
  // ../../packages/agent-targets/src/hooks/normalize.ts
158
388
  var MAX_EXTRACTED_TEXT_BYTES = 64 * 1024;
@@ -309,12 +539,12 @@ function normalizedEvent(target, payload, context) {
309
539
  "workingDirectory",
310
540
  "workspaceRoot"
311
541
  ]) ?? context.cwd;
312
- const filePath = firstString(payload, ["file_path", "filePath", "path"]) ?? (toolInput ? firstString(toolInput, ["file_path", "filePath", "path"]) : void 0);
313
542
  const command = boundedExtractedText(
314
543
  firstText(payload, ["command"]) ?? (toolInput ? firstText(toolInput, ["command", "cmd"]) : void 0),
315
544
  "command"
316
545
  );
317
546
  const toolName = firstString(payload, ["tool_name", "toolName", "name"]);
547
+ const filePath = firstString(payload, ["file_path", "filePath", "path"]) ?? (toolInput ? firstString(toolInput, ["file_path", "filePath", "path"]) : void 0) ?? (command && toolName && SHELL_TOOL_NAMES.has(toolName.toLowerCase()) ? extractReadFilePathFromCommand(command) ?? void 0 : void 0);
318
548
  const userPrompt = boundedExtractedText(
319
549
  firstText(payload, ["prompt", "user_prompt", "userPrompt"]) ?? (target === "gemini" ? geminiUserPrompt(payload) : void 0),
320
550
  "user_prompt"
@@ -371,7 +601,8 @@ var HOOK_NORMALIZATION_CAPABILITIES = Object.freeze([
371
601
  capability("claude", CLAUDE_HOOK_EVENTS),
372
602
  capability("codex", CODEX_HOOK_EVENTS),
373
603
  capability("gemini", GEMINI_HOOK_EVENTS),
374
- capability("grok", GROK_HOOK_EVENTS)
604
+ capability("grok", GROK_HOOK_EVENTS),
605
+ capability("pi", PI_HOOK_EVENTS)
375
606
  ]);
376
607
  function parseHookCaptureRequest(value) {
377
608
  if (!isRecord(value) || !isHookTarget(value.target)) return null;
@@ -434,7 +665,7 @@ function normalizeObserverHookCapture(request, options = {}) {
434
665
  // ../../packages/panopticon/src/observer/database.ts
435
666
  import crypto2 from "crypto";
436
667
  import fs2 from "fs";
437
- import path2 from "path";
668
+ import path3 from "path";
438
669
  var ObserverHookSpoolEntryTooLargeError = class extends Error {
439
670
  constructor(logicalBytes, maxBytes) {
440
671
  super(
@@ -789,7 +1020,7 @@ function openObserverDatabase(databaseFile, options = {}) {
789
1020
  if (!sqlite?.DatabaseSync) {
790
1021
  throw new Error("FML observer requires the Node.js built-in SQLite module");
791
1022
  }
792
- const databaseDirectory = path2.dirname(databaseFile);
1023
+ const databaseDirectory = path3.dirname(databaseFile);
793
1024
  fs2.mkdirSync(databaseDirectory, { recursive: true, mode: 448 });
794
1025
  if (options.restrictDatabaseDirectory !== false) {
795
1026
  enforceOwnerOnlyMode(databaseDirectory, 448);
@@ -3068,7 +3299,7 @@ function createObserverHttpServer(opts) {
3068
3299
  // src/hooks/inbox.ts
3069
3300
  import { randomUUID as randomUUID2 } from "crypto";
3070
3301
  import fs3 from "fs";
3071
- import path3 from "path";
3302
+ import path4 from "path";
3072
3303
 
3073
3304
  // src/hooks/inbox-config.ts
3074
3305
  var BYTE_SUFFIXES = {
@@ -3210,7 +3441,7 @@ function entryFileName(id) {
3210
3441
  return `${id}.json`;
3211
3442
  }
3212
3443
  function entryPath(inboxDir, id) {
3213
- return path3.join(inboxDir, entryFileName(id));
3444
+ return path4.join(inboxDir, entryFileName(id));
3214
3445
  }
3215
3446
  function enforceOwnerOnlyDirectory(inboxDir) {
3216
3447
  fs3.mkdirSync(inboxDir, { recursive: true, mode: 448 });
@@ -3320,7 +3551,7 @@ function parseCapacityState(value) {
3320
3551
  };
3321
3552
  }
3322
3553
  function capacityStatePath(inboxDir) {
3323
- return path3.join(inboxDir, CAPACITY_STATE_FILE);
3554
+ return path4.join(inboxDir, CAPACITY_STATE_FILE);
3324
3555
  }
3325
3556
  function readCapacityStateFile(inboxDir) {
3326
3557
  try {
@@ -3348,7 +3579,7 @@ function writeCapacityState(inboxDir, state, capacityLock) {
3348
3579
  enforceOwnerOnlyDirectory(inboxDir);
3349
3580
  capacityLock.assertOwned();
3350
3581
  const destination = capacityStatePath(inboxDir);
3351
- const temporary = path3.join(
3582
+ const temporary = path4.join(
3352
3583
  inboxDir,
3353
3584
  `${CAPACITY_STATE_FILE}.${process.pid}.${randomUUID2()}.tmp`
3354
3585
  );
@@ -3457,7 +3688,7 @@ function recoverStaleCapacityLock(lockPath, nowMs) {
3457
3688
  return;
3458
3689
  }
3459
3690
  fs3.rmSync(abandoned, { force: true });
3460
- fsyncDirectory(path3.dirname(lockPath));
3691
+ fsyncDirectory(path4.dirname(lockPath));
3461
3692
  } catch (error) {
3462
3693
  if (!capacityLockRaceError(error)) throw error;
3463
3694
  }
@@ -3468,7 +3699,7 @@ function sleepSync(milliseconds) {
3468
3699
  }
3469
3700
  function acquireCapacityLock(inboxDir, waitMs = CAPACITY_LOCK_WAIT_MS) {
3470
3701
  enforceOwnerOnlyDirectory(inboxDir);
3471
- const lockPath = path3.join(inboxDir, CAPACITY_LOCK_FILE);
3702
+ const lockPath = path4.join(inboxDir, CAPACITY_LOCK_FILE);
3472
3703
  const deadlineMs = Date.now() + Math.max(0, waitMs);
3473
3704
  while (true) {
3474
3705
  let descriptor;
@@ -3541,19 +3772,19 @@ function capacityMutationEvidence(inboxDir, pending, includeTemporary) {
3541
3772
  const prefix = `.${id}.`;
3542
3773
  const candidates = [];
3543
3774
  if (includeTemporary && pending.temporaryFileName) {
3544
- candidates.push(path3.join(inboxDir, pending.temporaryFileName));
3775
+ candidates.push(path4.join(inboxDir, pending.temporaryFileName));
3545
3776
  } else if (includeTemporary) {
3546
3777
  try {
3547
3778
  for (const name of fs3.readdirSync(inboxDir)) {
3548
3779
  if (name.startsWith(prefix) && name.endsWith(".tmp")) {
3549
- candidates.push(path3.join(inboxDir, name));
3780
+ candidates.push(path4.join(inboxDir, name));
3550
3781
  }
3551
3782
  }
3552
3783
  } catch (error) {
3553
3784
  return error.code === "ENOENT" ? { kind: "missing" } : { kind: "unavailable" };
3554
3785
  }
3555
3786
  }
3556
- candidates.push(path3.join(inboxDir, fileName));
3787
+ candidates.push(path4.join(inboxDir, fileName));
3557
3788
  let presentBytes;
3558
3789
  for (const candidate of candidates) {
3559
3790
  try {
@@ -3665,7 +3896,7 @@ function removeCapacityTrackedEntry(filePath, inboxDir, expectedBytes, missingIs
3665
3896
  }
3666
3897
  if (bytes === void 0) return false;
3667
3898
  const pendingRemoval = {
3668
- fileName: path3.basename(filePath),
3899
+ fileName: path4.basename(filePath),
3669
3900
  bytes,
3670
3901
  startedAtMs: Date.now()
3671
3902
  };
@@ -3746,7 +3977,7 @@ function readRetirementState(inboxDir) {
3746
3977
  try {
3747
3978
  return parseRetirementState(
3748
3979
  JSON.parse(
3749
- fs3.readFileSync(path3.join(inboxDir, RETIREMENT_STATE_FILE), "utf8")
3980
+ fs3.readFileSync(path4.join(inboxDir, RETIREMENT_STATE_FILE), "utf8")
3750
3981
  )
3751
3982
  ) ?? defaultRetirementState();
3752
3983
  } catch {
@@ -3755,8 +3986,8 @@ function readRetirementState(inboxDir) {
3755
3986
  }
3756
3987
  function writeRetirementState(inboxDir, state) {
3757
3988
  enforceOwnerOnlyDirectory(inboxDir);
3758
- const destination = path3.join(inboxDir, RETIREMENT_STATE_FILE);
3759
- const temporary = path3.join(
3989
+ const destination = path4.join(inboxDir, RETIREMENT_STATE_FILE);
3990
+ const temporary = path4.join(
3760
3991
  inboxDir,
3761
3992
  `${RETIREMENT_STATE_FILE}.${process.pid}.${randomUUID2()}.tmp`
3762
3993
  );
@@ -3783,7 +4014,7 @@ function completePendingRetirement(inboxDir, state) {
3783
4014
  const pending = state.pending;
3784
4015
  if (!pending) return state;
3785
4016
  if (!removeCapacityTrackedEntry(
3786
- path3.join(inboxDir, pending.fileName),
4017
+ path4.join(inboxDir, pending.fileName),
3787
4018
  inboxDir,
3788
4019
  pending.bytes,
3789
4020
  true
@@ -3819,7 +4050,7 @@ function retireEntry(filePath, reason, inboxDir) {
3819
4050
  const pending = {
3820
4051
  ...current,
3821
4052
  pending: {
3822
- fileName: path3.basename(filePath),
4053
+ fileName: path4.basename(filePath),
3823
4054
  bytes,
3824
4055
  reason,
3825
4056
  retiredAtMs: Date.now()
@@ -3870,7 +4101,7 @@ function persistHookInboxEntry(entry, inboxDir = FML_HOOK_INBOX_DIR, limits = ho
3870
4101
  throw new Error("FML hook inbox admission is busy");
3871
4102
  }
3872
4103
  const destination = entryPath(inboxDir, entry.id);
3873
- const temporary = path3.join(
4104
+ const temporary = path4.join(
3874
4105
  inboxDir,
3875
4106
  `.${entry.id}.${process.pid}.${randomUUID2()}.tmp`
3876
4107
  );
@@ -3900,8 +4131,8 @@ function persistHookInboxEntry(entry, inboxDir = FML_HOOK_INBOX_DIR, limits = ho
3900
4131
  }
3901
4132
  try {
3902
4133
  const pendingPersist = {
3903
- fileName: path3.basename(destination),
3904
- temporaryFileName: path3.basename(temporary),
4134
+ fileName: path4.basename(destination),
4135
+ temporaryFileName: path4.basename(temporary),
3905
4136
  bytes: serializedBytes,
3906
4137
  startedAtMs: Date.now()
3907
4138
  };
@@ -4059,7 +4290,7 @@ async function scanDrainEntryNames(inboxDir, maximumEntries, skipThrough, exclud
4059
4290
  const abandonedLockMatch = ABANDONED_CAPACITY_LOCK_PATTERN.exec(name);
4060
4291
  if (INBOX_STATE_TEMP_PATTERN.test(name) || abandonedLockMatch !== null) {
4061
4292
  try {
4062
- const orphanPath = path3.join(inboxDir, name);
4293
+ const orphanPath = path4.join(inboxDir, name);
4063
4294
  const stat = await fs3.promises.lstat(orphanPath);
4064
4295
  const abandonedAtMs = abandonedLockMatch ? Number(abandonedLockMatch[1]) : void 0;
4065
4296
  const isStale = abandonedLockMatch ? validTimestamp(abandonedAtMs) && abandonedAtMs <= cutoffMs : stat.mtimeMs <= cutoffMs;
@@ -4082,8 +4313,8 @@ async function scanDrainEntryNames(inboxDir, maximumEntries, skipThrough, exclud
4082
4313
  const id = match?.[1];
4083
4314
  if (!id) continue;
4084
4315
  const destination = entryPath(inboxDir, id);
4085
- const destinationName = path3.basename(destination);
4086
- const temporary = path3.join(inboxDir, name);
4316
+ const destinationName = path4.basename(destination);
4317
+ const temporary = path4.join(inboxDir, name);
4087
4318
  try {
4088
4319
  const stat = await fs3.promises.lstat(temporary);
4089
4320
  if (!stat.isFile()) continue;
@@ -4136,7 +4367,7 @@ async function scanDrainEntryNames(inboxDir, maximumEntries, skipThrough, exclud
4136
4367
  return { names, failed, resetCursor, blockCursorAdvance };
4137
4368
  }
4138
4369
  function drainCursor(inboxDir) {
4139
- const key = path3.resolve(inboxDir);
4370
+ const key = path4.resolve(inboxDir);
4140
4371
  const existing = HOOK_INBOX_DRAIN_CURSORS.get(key);
4141
4372
  if (existing) {
4142
4373
  HOOK_INBOX_DRAIN_CURSORS.delete(key);
@@ -4173,7 +4404,7 @@ async function pendingInboxSizeAsync(inboxDir) {
4173
4404
  for (let dirent = await directory.read(); dirent !== null; dirent = await directory.read()) {
4174
4405
  if (!isPendingEntryName(dirent.name)) continue;
4175
4406
  try {
4176
- const stat = await fs3.promises.lstat(path3.join(inboxDir, dirent.name));
4407
+ const stat = await fs3.promises.lstat(path4.join(inboxDir, dirent.name));
4177
4408
  if (stat.isFile()) {
4178
4409
  pendingEntries += 1;
4179
4410
  pendingBytes += stat.size;
@@ -4197,7 +4428,7 @@ function pendingInboxSize(inboxDir, includeTemporary = false) {
4197
4428
  continue;
4198
4429
  }
4199
4430
  try {
4200
- const stat = fs3.lstatSync(path3.join(inboxDir, dirent.name));
4431
+ const stat = fs3.lstatSync(path4.join(inboxDir, dirent.name));
4201
4432
  if (stat.isFile()) {
4202
4433
  pendingEntries += 1;
4203
4434
  pendingBytes += stat.size;
@@ -4352,7 +4583,7 @@ async function drainHookInbox(capture, inboxDir = FML_HOOK_INBOX_DIR) {
4352
4583
  safeThrough = name;
4353
4584
  };
4354
4585
  for (const name of names) {
4355
- const filePath = path3.join(inboxDir, name);
4586
+ const filePath = path4.join(inboxDir, name);
4356
4587
  const readResult = readEntryResult(filePath);
4357
4588
  if (readResult.kind === "missing") {
4358
4589
  markResolved(name, false);
@@ -4418,10 +4649,10 @@ async function drainHookInbox(capture, inboxDir = FML_HOOK_INBOX_DIR) {
4418
4649
  export {
4419
4650
  readObserverAuthToken,
4420
4651
  getOrCreateObserverAuthToken,
4421
- HOOK_TARGETS,
4422
4652
  CODEX_HOOK_EVENTS,
4423
4653
  GEMINI_HOOK_EVENTS,
4424
4654
  GROK_HOOK_EVENTS,
4655
+ SHELL_TOOL_NAMES,
4425
4656
  parseHookCaptureRequest,
4426
4657
  normalizeObserverHookCapture,
4427
4658
  ObserverHookSpoolEntryTooLargeError,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  resolveRepoFromCwd
3
- } from "./chunk-T5YVLSUC.js";
3
+ } from "./chunk-7V7G7NVF.js";
4
4
  import {
5
5
  CONVEX_URL,
6
6
  getActiveEnv,
7
7
  getSelectedOrg,
8
8
  getSiteUrlForConvexUrl,
9
9
  getValidToken
10
- } from "./chunk-7DR5X7XI.js";
10
+ } from "./chunk-A6HAEVJX.js";
11
11
 
12
12
  // src/fml-client.ts
13
13
  var LOGIN_EXPIRED_MESSAGE = "Authentication expired. Run `fml login` to sign in again, then restart Claude Code.";
@@ -79,7 +79,7 @@ function createFmlClient(token, options = {}) {
79
79
  const repo = resolveRepoFromCwd(process.cwd());
80
80
  if (repo) body.repo = repo.repo;
81
81
  if (isServiceToken) {
82
- const { readTokens, SERVICE_TOKEN_LOGIN_USER_ID } = await import("./token-store-R7WXEPLI.js");
82
+ const { readTokens, SERVICE_TOKEN_LOGIN_USER_ID } = await import("./token-store-BT5THIAJ.js");
83
83
  const stored = readTokens(options.envName);
84
84
  const storedUserExternalId = stored?.tokenType === "service" && stored.user.id !== SERVICE_TOKEN_LOGIN_USER_ID ? stored.user.id : void 0;
85
85
  const userExternalId = process.env.FML_USER_EXTERNAL_ID ?? storedUserExternalId;
@@ -6,7 +6,7 @@ import {
6
6
  getSiteUrlForConvexUrl,
7
7
  getSyncDestinationIdentity,
8
8
  getValidToken
9
- } from "./chunk-7DR5X7XI.js";
9
+ } from "./chunk-A6HAEVJX.js";
10
10
 
11
11
  // ../../packages/panopticon/src/artifact.ts
12
12
  import {