@fml-inc/fml 0.8.9 → 0.8.10

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.
@@ -53,7 +53,7 @@ var PACKAGE_NAME = "@fml-inc/fml";
53
53
  var UPDATE_TIMEOUT_MS = 12e4;
54
54
  var SETUP_TIMEOUT_MS = 3e5;
55
55
  function getCurrentVersion() {
56
- return true ? "0.8.9+6863d154" : "unknown";
56
+ return true ? "0.8.10+45913c27" : "unknown";
57
57
  }
58
58
  function parseVersion(version) {
59
59
  const match = SEMVER_PATTERN.exec(version);
@@ -75,7 +75,8 @@ var HOOK_TARGETS = Object.freeze([
75
75
  "codex",
76
76
  "gemini",
77
77
  "grok",
78
- "pi"
78
+ "pi",
79
+ "mini-swe-agent"
79
80
  ]);
80
81
  function isHookTarget(value) {
81
82
  return typeof value === "string" && HOOK_TARGETS.some((targetId) => targetId === value);
@@ -155,6 +156,14 @@ var hook_events_default = {
155
156
  "PreCompact",
156
157
  "PostCompact",
157
158
  "SessionEnd"
159
+ ],
160
+ "mini-swe-agent": [
161
+ "SessionStart",
162
+ "UserPromptSubmit",
163
+ "BeforeModel",
164
+ "PostToolUse",
165
+ "Stop",
166
+ "SessionEnd"
158
167
  ]
159
168
  };
160
169
 
@@ -172,6 +181,9 @@ var GROK_HOOK_EVENTS = Object.freeze([
172
181
  ...hook_events_default.grok
173
182
  ]);
174
183
  var PI_HOOK_EVENTS = Object.freeze([...hook_events_default.pi]);
184
+ var MINI_SWE_AGENT_HOOK_EVENTS = Object.freeze([
185
+ ...hook_events_default["mini-swe-agent"]
186
+ ]);
175
187
 
176
188
  // ../../packages/agent-targets/src/hooks/read-command.ts
177
189
  import path2 from "path";
@@ -547,9 +559,9 @@ function normalizedEvent(target, payload, context) {
547
559
  "command"
548
560
  );
549
561
  const toolName = firstString(payload, ["tool_name", "toolName", "name"]);
550
- 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);
562
+ const filePath = firstString(payload, ["file_path", "filePath", "path"]) ?? (toolInput ? firstString(toolInput, ["file_path", "filePath", "path"]) : void 0) ?? (target !== "mini-swe-agent" && command && toolName && SHELL_TOOL_NAMES.has(toolName.toLowerCase()) ? extractReadFilePathFromCommand(command) ?? void 0 : void 0);
551
563
  const userPrompt = boundedExtractedText(
552
- firstText(payload, ["prompt", "user_prompt", "userPrompt"]) ?? (target === "gemini" ? geminiUserPrompt(payload) : void 0),
564
+ target === "mini-swe-agent" && eventType !== "UserPromptSubmit" ? void 0 : firstText(payload, ["prompt", "user_prompt", "userPrompt"]) ?? (target === "gemini" ? geminiUserPrompt(payload) : void 0),
553
565
  "user_prompt"
554
566
  );
555
567
  const plan = boundedExtractedText(firstText(payload, ["plan"]), "plan");
@@ -605,7 +617,8 @@ var HOOK_NORMALIZATION_CAPABILITIES = Object.freeze([
605
617
  capability("codex", CODEX_HOOK_EVENTS),
606
618
  capability("gemini", GEMINI_HOOK_EVENTS),
607
619
  capability("grok", GROK_HOOK_EVENTS),
608
- capability("pi", PI_HOOK_EVENTS)
620
+ capability("pi", PI_HOOK_EVENTS),
621
+ capability("mini-swe-agent", MINI_SWE_AGENT_HOOK_EVENTS)
609
622
  ]);
610
623
  function parseHookCaptureRequest(value) {
611
624
  if (!isRecord(value) || !isHookTarget(value.target)) return null;
@@ -695,6 +708,7 @@ var MAX_HOOK_DESTINATION_IDENTITY_BYTES = 4 * 1024;
695
708
  var DEFAULT_OTLP_OUTBOX_BATCH_SIZE = 100;
696
709
  var MAX_OTLP_OUTBOX_BATCH_SIZE = 100;
697
710
  var MAX_OTLP_ENVELOPE_BYTES = 16 * 1024 * 1024;
711
+ var DEFAULT_OTLP_SPOOL_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
698
712
  var DEFAULT_OTLP_SPOOL_MAX_BYTES = 1024 * 1024 * 1024;
699
713
  var MAX_OTLP_ENVELOPE_ID_BYTES = 1024;
700
714
  var MAX_OTLP_OBSERVER_INSTANCE_ID_BYTES = 4 * 1024;
@@ -703,8 +717,6 @@ var MAX_OTLP_DROP_REASON_BYTES = 4 * 1024;
703
717
  var MAX_OTLP_DESTINATION_ORGANIZATION_ID_BYTES = 128;
704
718
  var MAX_OTLP_DESTINATION_ORGANIZATION_SLUG_BYTES = 4 * 1024;
705
719
  var OWNERLESS_OTLP_DROP_REASON = "ownerless";
706
- var OTLP_CAPACITY_DROP_REASON = "spool_capacity";
707
- var OTLP_ENTRY_TOO_LARGE_DROP_REASON = "spool_entry_too_large";
708
720
  var OTLP_ROW_FIXED_LOGICAL_BYTES = 256;
709
721
  var MAX_TIMESTAMP_MS = 864e13;
710
722
  var QUARANTINE_PRUNE_INTERVAL_MS = 5 * 60 * 1e3;
@@ -1002,15 +1014,23 @@ function enforceOwnerOnlyMode(filePath, mode) {
1002
1014
  function openObserverDatabase(databaseFile, options = {}) {
1003
1015
  const maxHookSpoolBytes = options.maxHookSpoolBytes;
1004
1016
  const maxOtlpSpoolBytes = options.maxOtlpSpoolBytes ?? DEFAULT_OTLP_SPOOL_MAX_BYTES;
1005
- const maxHookQuarantineAgeMs = options.maxHookQuarantineAgeMs;
1006
- if (maxHookSpoolBytes !== void 0 && (!Number.isSafeInteger(maxHookSpoolBytes) || maxHookSpoolBytes < 1)) {
1017
+ if (!Number.isSafeInteger(maxOtlpSpoolBytes) || maxOtlpSpoolBytes < 1) {
1007
1018
  throw new Error(
1008
- "Hook spool maximum must be a positive safe integer number of bytes"
1019
+ "OTLP spool maximum must be a positive safe integer number of bytes"
1009
1020
  );
1010
1021
  }
1011
- if (!Number.isSafeInteger(maxOtlpSpoolBytes) || maxOtlpSpoolBytes < 1) {
1022
+ const otlpLowWaterBytes = Math.floor(maxOtlpSpoolBytes * 0.9);
1023
+ let otlpCapacityCleanupActive = false;
1024
+ const maxOtlpSpoolAgeMs = options.maxOtlpSpoolAgeMs ?? DEFAULT_OTLP_SPOOL_MAX_AGE_MS;
1025
+ if (!Number.isSafeInteger(maxOtlpSpoolAgeMs) || maxOtlpSpoolAgeMs < 1) {
1012
1026
  throw new Error(
1013
- "OTLP spool maximum must be a positive safe integer number of bytes"
1027
+ "OTLP spool maximum age must be a positive safe integer number of milliseconds"
1028
+ );
1029
+ }
1030
+ const maxHookQuarantineAgeMs = options.maxHookQuarantineAgeMs;
1031
+ if (maxHookSpoolBytes !== void 0 && (!Number.isSafeInteger(maxHookSpoolBytes) || maxHookSpoolBytes < 1)) {
1032
+ throw new Error(
1033
+ "Hook spool maximum must be a positive safe integer number of bytes"
1014
1034
  );
1015
1035
  }
1016
1036
  if (maxHookQuarantineAgeMs !== void 0 && (!Number.isSafeInteger(maxHookQuarantineAgeMs) || maxHookQuarantineAgeMs < 1)) {
@@ -2031,27 +2051,24 @@ function openObserverDatabase(databaseFile, options = {}) {
2031
2051
  last_drop_reason = ?
2032
2052
  WHERE singleton = 1
2033
2053
  `);
2034
- const otlpCapacityEvictionPlan = database.prepare(`
2035
- WITH ordered AS (
2036
- SELECT
2037
- logical_bytes,
2038
- length(body) AS body_bytes,
2039
- SUM(logical_bytes) OVER (ORDER BY id ASC) - logical_bytes
2040
- AS preceding_bytes
2041
- FROM otlp_envelope_outbox
2042
- )
2043
- SELECT
2044
- COUNT(*) AS record_count,
2045
- COALESCE(SUM(logical_bytes), 0) AS logical_bytes,
2046
- COALESCE(SUM(body_bytes), 0) AS body_bytes
2047
- FROM ordered
2048
- WHERE preceding_bytes < ?
2054
+ const hasExpiredOtlpEnvelopes = database.prepare(`
2055
+ SELECT 1 FROM otlp_envelope_outbox WHERE captured_at_ms < ? LIMIT 1
2049
2056
  `);
2050
- const evictOldestPendingOtlpEnvelopes = database.prepare(`
2051
- DELETE FROM otlp_envelope_outbox
2052
- WHERE id IN (
2053
- SELECT id FROM otlp_envelope_outbox ORDER BY id ASC LIMIT ?
2054
- )
2057
+ const expiredOtlpEnvelopes = database.prepare(`
2058
+ SELECT id, logical_bytes, length(body) AS body_bytes
2059
+ FROM otlp_envelope_outbox
2060
+ WHERE captured_at_ms < ?
2061
+ ORDER BY captured_at_ms, id
2062
+ LIMIT 100
2063
+ `);
2064
+ const oldestOtlpEnvelopes = database.prepare(`
2065
+ SELECT id, logical_bytes, length(body) AS body_bytes
2066
+ FROM otlp_envelope_outbox
2067
+ ORDER BY captured_at_ms, id
2068
+ LIMIT 100
2069
+ `);
2070
+ const deleteExpiredOtlpEnvelope = database.prepare(`
2071
+ DELETE FROM otlp_envelope_outbox WHERE id = ?
2055
2072
  `);
2056
2073
  const getDestinationPendingOtlpEnvelopeAccounting = database.prepare(`
2057
2074
  SELECT logical_bytes, length(body) AS body_bytes
@@ -2652,42 +2669,6 @@ function openObserverDatabase(databaseFile, options = {}) {
2652
2669
  );
2653
2670
  return null;
2654
2671
  }
2655
- if (logicalBytes > maxOtlpSpoolBytes) {
2656
- recordOtlpDrop(
2657
- 1,
2658
- logicalBytes,
2659
- envelope.body.byteLength,
2660
- capturedAtMs,
2661
- OTLP_ENTRY_TOO_LARGE_DROP_REASON
2662
- );
2663
- return null;
2664
- }
2665
- const retainedBytes = requireSpoolInteger(
2666
- getOtlpSpoolState.get(),
2667
- "logical_bytes"
2668
- );
2669
- const bytesToFree = retainedBytes + logicalBytes - maxOtlpSpoolBytes;
2670
- if (bytesToFree > 0) {
2671
- const plan = otlpCapacityEvictionPlan.get(bytesToFree);
2672
- const evictedRecords = requireSpoolInteger(plan, "record_count");
2673
- const evictedLogicalBytes = requireSpoolInteger(
2674
- plan,
2675
- "logical_bytes"
2676
- );
2677
- const evictedBodyBytes = requireSpoolInteger(plan, "body_bytes");
2678
- if (evictedRecords === 0 || evictedLogicalBytes < bytesToFree || evictOldestPendingOtlpEnvelopes.run(evictedRecords).changes !== evictedRecords) {
2679
- throw new Error(
2680
- "FML observer OTLP spool accounting could not enforce its limit"
2681
- );
2682
- }
2683
- recordOtlpDrop(
2684
- evictedRecords,
2685
- evictedLogicalBytes,
2686
- evictedBodyBytes,
2687
- capturedAtMs,
2688
- OTLP_CAPACITY_DROP_REASON
2689
- );
2690
- }
2691
2672
  captureOtlpEnvelope.run(
2692
2673
  envelopeId,
2693
2674
  envelope.observerInstanceId,
@@ -2885,6 +2866,80 @@ function openObserverDatabase(databaseFile, options = {}) {
2885
2866
  return droppedRecords;
2886
2867
  });
2887
2868
  },
2869
+ pruneExpiredOtlpEnvelopes: (nowMs = Date.now()) => {
2870
+ requireTimestamp(nowMs, "OTLP retention timestamp");
2871
+ const cutoffMs = nowMs - maxOtlpSpoolAgeMs;
2872
+ if (!hasExpiredOtlpEnvelopes.get(cutoffMs)) return 0;
2873
+ return runImmediateTransaction(() => {
2874
+ const rows = expiredOtlpEnvelopes.all(cutoffMs);
2875
+ let logicalBytes = 0;
2876
+ let bodyBytes = 0;
2877
+ for (const row of rows) {
2878
+ logicalBytes += requireSpoolInteger(row, "logical_bytes");
2879
+ bodyBytes += requireSpoolInteger(row, "body_bytes");
2880
+ if (deleteExpiredOtlpEnvelope.run(row.id).changes !== 1) {
2881
+ throw new Error(
2882
+ "FML observer OTLP retention deletion was incomplete"
2883
+ );
2884
+ }
2885
+ }
2886
+ recordOtlpDrop(
2887
+ rows.length,
2888
+ logicalBytes,
2889
+ bodyBytes,
2890
+ nowMs,
2891
+ "spool_expired"
2892
+ );
2893
+ return rows.length;
2894
+ });
2895
+ },
2896
+ pruneOtlpCapacity: (nowMs = Date.now()) => {
2897
+ requireTimestamp(nowMs, "OTLP capacity cleanup timestamp");
2898
+ const retainedBytes = requireSpoolInteger(
2899
+ getOtlpSpoolState.get(),
2900
+ "logical_bytes"
2901
+ );
2902
+ if (retainedBytes <= otlpLowWaterBytes)
2903
+ otlpCapacityCleanupActive = false;
2904
+ if (retainedBytes > maxOtlpSpoolBytes) otlpCapacityCleanupActive = true;
2905
+ if (!otlpCapacityCleanupActive) return 0;
2906
+ return runImmediateTransaction(() => {
2907
+ const currentBytes = requireSpoolInteger(
2908
+ getOtlpSpoolState.get(),
2909
+ "logical_bytes"
2910
+ );
2911
+ if (currentBytes <= otlpLowWaterBytes) {
2912
+ otlpCapacityCleanupActive = false;
2913
+ return 0;
2914
+ }
2915
+ let records = 0;
2916
+ let logicalBytes = 0;
2917
+ let bodyBytes = 0;
2918
+ for (const row of oldestOtlpEnvelopes.all()) {
2919
+ logicalBytes += requireSpoolInteger(row, "logical_bytes");
2920
+ bodyBytes += requireSpoolInteger(row, "body_bytes");
2921
+ if (deleteExpiredOtlpEnvelope.run(row.id).changes !== 1) {
2922
+ throw new Error(
2923
+ "FML observer OTLP capacity deletion was incomplete"
2924
+ );
2925
+ }
2926
+ records += 1;
2927
+ if (currentBytes - logicalBytes <= otlpLowWaterBytes) break;
2928
+ }
2929
+ if (records === 0)
2930
+ throw new Error(
2931
+ "FML observer OTLP capacity accounting is inconsistent"
2932
+ );
2933
+ recordOtlpDrop(
2934
+ records,
2935
+ logicalBytes,
2936
+ bodyBytes,
2937
+ nowMs,
2938
+ "spool_capacity"
2939
+ );
2940
+ return records;
2941
+ });
2942
+ },
2888
2943
  getOtlpSpoolStatus: () => {
2889
2944
  const row = getOtlpSpoolState.get();
2890
2945
  const lastDroppedAtMs = row?.last_dropped_at_ms;
@@ -2898,6 +2953,7 @@ function openObserverDatabase(databaseFile, options = {}) {
2898
2953
  return {
2899
2954
  unit: "logical_bytes",
2900
2955
  maxBytes: maxOtlpSpoolBytes,
2956
+ maxAgeMs: maxOtlpSpoolAgeMs,
2901
2957
  logicalBytes: requireSpoolInteger(row, "logical_bytes"),
2902
2958
  bodyBytes: requireSpoolInteger(row, "body_bytes"),
2903
2959
  droppedRecords: requireSpoolInteger(row, "dropped_records"),