modelstat 0.0.49 → 0.0.51

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.
package/dist/cli.mjs CHANGED
@@ -77,12 +77,23 @@ var init_git = __esm({
77
77
  }
78
78
  });
79
79
 
80
+ // ../../packages/core/src/billing.ts
81
+ var MILLION, FREE_INCLUDED_TOKENS, TEAM_INCLUDED_PER_SEAT;
82
+ var init_billing = __esm({
83
+ "../../packages/core/src/billing.ts"() {
84
+ "use strict";
85
+ MILLION = 1000000n;
86
+ FREE_INCLUDED_TOKENS = 100n * MILLION;
87
+ TEAM_INCLUDED_PER_SEAT = 250n * MILLION;
88
+ }
89
+ });
90
+
80
91
  // ../../packages/core/src/enums.ts
81
- var TOOLS, PROVIDERS, IDENTITY_OWNER_SCOPES, INSTALL_METHODS, OS_FAMILIES, EVENT_KINDS, TOOL_CALL_STATUSES, COMPANION_PHASES, CLASSIFICATION_CONFIDENCE;
92
+ var AGENTS, PROVIDERS, IDENTITY_OWNER_SCOPES, INSTALL_METHODS, OS_FAMILIES, EVENT_KINDS, TOOL_CALL_STATUSES, COMPANION_PHASES, CLASSIFICATION_CONFIDENCE;
82
93
  var init_enums = __esm({
83
94
  "../../packages/core/src/enums.ts"() {
84
95
  "use strict";
85
- TOOLS = [
96
+ AGENTS = [
86
97
  "claude_code",
87
98
  "claude_desktop",
88
99
  "codex_cli",
@@ -105,12 +116,13 @@ var init_enums = __esm({
105
116
  "crush",
106
117
  "kimi",
107
118
  "openclaw",
119
+ "hermes",
108
120
  "ollama",
109
121
  "raw_sdk_anthropic",
110
122
  "raw_sdk_openai",
111
123
  "raw_sdk_google",
112
124
  // Web chat UIs (Chrome-extension companion). Categorically distinct
113
- // from *_cli / *_desktop tools — same provider, different surface.
125
+ // from *_cli / *_desktop agents — same provider, different surface.
114
126
  "chatgpt_web",
115
127
  "claude_web",
116
128
  "gemini_web",
@@ -194,6 +206,72 @@ var init_enums = __esm({
194
206
  }
195
207
  });
196
208
 
209
+ // ../../packages/core/src/ids.ts
210
+ function ulid(seedTime) {
211
+ const t = seedTime ?? Date.now();
212
+ let timeStr = "";
213
+ let ts = t;
214
+ for (let i = 9; i >= 0; i--) {
215
+ timeStr = ULID_ALPHABET[ts % 32] + timeStr;
216
+ ts = Math.floor(ts / 32);
217
+ }
218
+ const bytes = new Uint8Array(16);
219
+ globalThis.crypto.getRandomValues(bytes);
220
+ let randStr = "";
221
+ for (let i = 0; i < 16; i++) {
222
+ randStr += ULID_ALPHABET[bytes[i] % 32];
223
+ }
224
+ return timeStr + randStr;
225
+ }
226
+ function sourceEventId(deviceId, sourceOrFilePath, byteOffsetMaybe) {
227
+ let key;
228
+ if (typeof sourceOrFilePath === "string") {
229
+ const byteOffset = byteOffsetMaybe ?? 0;
230
+ key = `fs::${sourceOrFilePath}::${byteOffset}`;
231
+ } else if ("file" in sourceOrFilePath) {
232
+ key = `fs::${sourceOrFilePath.file}::${sourceOrFilePath.byteOffset}`;
233
+ } else if ("lineUuid" in sourceOrFilePath) {
234
+ key = `uuid::${sourceOrFilePath.lineUuid}`;
235
+ } else {
236
+ key = `web::${sourceOrFilePath.host}::${sourceOrFilePath.conversationId}::${sourceOrFilePath.messageId}`;
237
+ }
238
+ const s = `${deviceId}::${key}`;
239
+ let h = 5381n;
240
+ for (let i = 0; i < s.length; i++) {
241
+ h = h * 33n ^ BigInt(s.charCodeAt(i));
242
+ h &= 0xffffffffffffffffn;
243
+ }
244
+ return `evt_${h.toString(36)}`;
245
+ }
246
+ function segmentId(sessionId, startedAtMs, endedAtMs, sourceEventIds) {
247
+ const sorted = [...sourceEventIds].sort().join(",");
248
+ const s = `${sessionId}|${startedAtMs}|${endedAtMs}|${sorted}`;
249
+ let h = 5381n;
250
+ for (let i = 0; i < s.length; i++) {
251
+ h = h * 33n ^ BigInt(s.charCodeAt(i));
252
+ h &= 0xffffffffffffffffn;
253
+ }
254
+ return `seg_${h.toString(36)}`;
255
+ }
256
+ function paramShape(args) {
257
+ const MASK = "\xA7";
258
+ return args.split(/[ \t\n\r\f]+/).filter((t) => t.length > 0).map((t) => {
259
+ if (t.startsWith("-")) {
260
+ const eq = t.indexOf("=");
261
+ return eq === -1 ? t : `${t.slice(0, eq + 1)}${MASK}`;
262
+ }
263
+ return MASK;
264
+ }).join(" ");
265
+ }
266
+ var ULID_ALPHABET, batchId;
267
+ var init_ids = __esm({
268
+ "../../packages/core/src/ids.ts"() {
269
+ "use strict";
270
+ ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
271
+ batchId = () => ulid();
272
+ }
273
+ });
274
+
197
275
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
198
276
  var util, objectUtil, ZodParsedType, getParsedType;
199
277
  var init_util = __esm({
@@ -941,9 +1019,9 @@ var init_types2 = __esm({
941
1019
  return this._cachedPath;
942
1020
  }
943
1021
  };
944
- handleResult = (ctx, result) => {
945
- if (isValid(result)) {
946
- return { success: true, data: result.value };
1022
+ handleResult = (ctx, result2) => {
1023
+ if (isValid(result2)) {
1024
+ return { success: true, data: result2.value };
947
1025
  } else {
948
1026
  if (!ctx.common.issues.length) {
949
1027
  throw new Error("Validation failed but no issues detected.");
@@ -991,21 +1069,21 @@ var init_types2 = __esm({
991
1069
  };
992
1070
  }
993
1071
  _parseSync(input) {
994
- const result = this._parse(input);
995
- if (isAsync(result)) {
1072
+ const result2 = this._parse(input);
1073
+ if (isAsync(result2)) {
996
1074
  throw new Error("Synchronous parse encountered promise.");
997
1075
  }
998
- return result;
1076
+ return result2;
999
1077
  }
1000
1078
  _parseAsync(input) {
1001
- const result = this._parse(input);
1002
- return Promise.resolve(result);
1079
+ const result2 = this._parse(input);
1080
+ return Promise.resolve(result2);
1003
1081
  }
1004
1082
  parse(data, params) {
1005
- const result = this.safeParse(data, params);
1006
- if (result.success)
1007
- return result.data;
1008
- throw result.error;
1083
+ const result2 = this.safeParse(data, params);
1084
+ if (result2.success)
1085
+ return result2.data;
1086
+ throw result2.error;
1009
1087
  }
1010
1088
  safeParse(data, params) {
1011
1089
  const ctx = {
@@ -1020,8 +1098,8 @@ var init_types2 = __esm({
1020
1098
  data,
1021
1099
  parsedType: getParsedType(data)
1022
1100
  };
1023
- const result = this._parseSync({ data, path: ctx.path, parent: ctx });
1024
- return handleResult(ctx, result);
1101
+ const result2 = this._parseSync({ data, path: ctx.path, parent: ctx });
1102
+ return handleResult(ctx, result2);
1025
1103
  }
1026
1104
  "~validate"(data) {
1027
1105
  const ctx = {
@@ -1037,9 +1115,9 @@ var init_types2 = __esm({
1037
1115
  };
1038
1116
  if (!this["~standard"].async) {
1039
1117
  try {
1040
- const result = this._parseSync({ data, path: [], parent: ctx });
1041
- return isValid(result) ? {
1042
- value: result.value
1118
+ const result2 = this._parseSync({ data, path: [], parent: ctx });
1119
+ return isValid(result2) ? {
1120
+ value: result2.value
1043
1121
  } : {
1044
1122
  issues: ctx.common.issues
1045
1123
  };
@@ -1053,17 +1131,17 @@ var init_types2 = __esm({
1053
1131
  };
1054
1132
  }
1055
1133
  }
1056
- return this._parseAsync({ data, path: [], parent: ctx }).then((result) => isValid(result) ? {
1057
- value: result.value
1134
+ return this._parseAsync({ data, path: [], parent: ctx }).then((result2) => isValid(result2) ? {
1135
+ value: result2.value
1058
1136
  } : {
1059
1137
  issues: ctx.common.issues
1060
1138
  });
1061
1139
  }
1062
1140
  async parseAsync(data, params) {
1063
- const result = await this.safeParseAsync(data, params);
1064
- if (result.success)
1065
- return result.data;
1066
- throw result.error;
1141
+ const result2 = await this.safeParseAsync(data, params);
1142
+ if (result2.success)
1143
+ return result2.data;
1144
+ throw result2.error;
1067
1145
  }
1068
1146
  async safeParseAsync(data, params) {
1069
1147
  const ctx = {
@@ -1079,8 +1157,8 @@ var init_types2 = __esm({
1079
1157
  parsedType: getParsedType(data)
1080
1158
  };
1081
1159
  const maybeAsyncResult = this._parse({ data, path: ctx.path, parent: ctx });
1082
- const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
1083
- return handleResult(ctx, result);
1160
+ const result2 = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
1161
+ return handleResult(ctx, result2);
1084
1162
  }
1085
1163
  refine(check, message) {
1086
1164
  const getIssueProperties = (val) => {
@@ -1093,13 +1171,13 @@ var init_types2 = __esm({
1093
1171
  }
1094
1172
  };
1095
1173
  return this._refinement((val, ctx) => {
1096
- const result = check(val);
1174
+ const result2 = check(val);
1097
1175
  const setError = () => ctx.addIssue({
1098
1176
  code: ZodIssueCode.custom,
1099
1177
  ...getIssueProperties(val)
1100
1178
  });
1101
- if (typeof Promise !== "undefined" && result instanceof Promise) {
1102
- return result.then((data) => {
1179
+ if (typeof Promise !== "undefined" && result2 instanceof Promise) {
1180
+ return result2.then((data) => {
1103
1181
  if (!data) {
1104
1182
  setError();
1105
1183
  return false;
@@ -1108,7 +1186,7 @@ var init_types2 = __esm({
1108
1186
  }
1109
1187
  });
1110
1188
  }
1111
- if (!result) {
1189
+ if (!result2) {
1112
1190
  setError();
1113
1191
  return false;
1114
1192
  } else {
@@ -2532,14 +2610,14 @@ var init_types2 = __esm({
2532
2610
  if (ctx.common.async) {
2533
2611
  return Promise.all([...ctx.data].map((item, i) => {
2534
2612
  return def.type._parseAsync(new ParseInputLazyPath(ctx, item, ctx.path, i));
2535
- })).then((result2) => {
2536
- return ParseStatus.mergeArray(status2, result2);
2613
+ })).then((result3) => {
2614
+ return ParseStatus.mergeArray(status2, result3);
2537
2615
  });
2538
2616
  }
2539
- const result = [...ctx.data].map((item, i) => {
2617
+ const result2 = [...ctx.data].map((item, i) => {
2540
2618
  return def.type._parseSync(new ParseInputLazyPath(ctx, item, ctx.path, i));
2541
2619
  });
2542
- return ParseStatus.mergeArray(status2, result);
2620
+ return ParseStatus.mergeArray(status2, result2);
2543
2621
  }
2544
2622
  get element() {
2545
2623
  return this._def.type;
@@ -2919,18 +2997,18 @@ var init_types2 = __esm({
2919
2997
  const { ctx } = this._processInputParams(input);
2920
2998
  const options = this._def.options;
2921
2999
  function handleResults(results) {
2922
- for (const result of results) {
2923
- if (result.result.status === "valid") {
2924
- return result.result;
3000
+ for (const result2 of results) {
3001
+ if (result2.result.status === "valid") {
3002
+ return result2.result;
2925
3003
  }
2926
3004
  }
2927
- for (const result of results) {
2928
- if (result.result.status === "dirty") {
2929
- ctx.common.issues.push(...result.ctx.common.issues);
2930
- return result.result;
3005
+ for (const result2 of results) {
3006
+ if (result2.result.status === "dirty") {
3007
+ ctx.common.issues.push(...result2.ctx.common.issues);
3008
+ return result2.result;
2931
3009
  }
2932
3010
  }
2933
- const unionErrors = results.map((result) => new ZodError(result.ctx.common.issues));
3011
+ const unionErrors = results.map((result2) => new ZodError(result2.ctx.common.issues));
2934
3012
  addIssueToContext(ctx, {
2935
3013
  code: ZodIssueCode.invalid_union,
2936
3014
  unionErrors
@@ -2968,15 +3046,15 @@ var init_types2 = __esm({
2968
3046
  },
2969
3047
  parent: null
2970
3048
  };
2971
- const result = option._parseSync({
3049
+ const result2 = option._parseSync({
2972
3050
  data: ctx.data,
2973
3051
  path: ctx.path,
2974
3052
  parent: childCtx
2975
3053
  });
2976
- if (result.status === "valid") {
2977
- return result;
2978
- } else if (result.status === "dirty" && !dirty) {
2979
- dirty = { result, ctx: childCtx };
3054
+ if (result2.status === "valid") {
3055
+ return result2;
3056
+ } else if (result2.status === "dirty" && !dirty) {
3057
+ dirty = { result: result2, ctx: childCtx };
2980
3058
  }
2981
3059
  if (childCtx.common.issues.length) {
2982
3060
  issues.push(childCtx.common.issues);
@@ -3483,9 +3561,9 @@ var init_types2 = __esm({
3483
3561
  error.addIssue(makeArgsIssue(args, e));
3484
3562
  throw error;
3485
3563
  });
3486
- const result = await Reflect.apply(fn, this, parsedArgs);
3487
- const parsedReturns = await me._def.returns._def.type.parseAsync(result, params).catch((e) => {
3488
- error.addIssue(makeReturnsIssue(result, e));
3564
+ const result2 = await Reflect.apply(fn, this, parsedArgs);
3565
+ const parsedReturns = await me._def.returns._def.type.parseAsync(result2, params).catch((e) => {
3566
+ error.addIssue(makeReturnsIssue(result2, e));
3489
3567
  throw error;
3490
3568
  });
3491
3569
  return parsedReturns;
@@ -3497,10 +3575,10 @@ var init_types2 = __esm({
3497
3575
  if (!parsedArgs.success) {
3498
3576
  throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
3499
3577
  }
3500
- const result = Reflect.apply(fn, this, parsedArgs.data);
3501
- const parsedReturns = me._def.returns.safeParse(result, params);
3578
+ const result2 = Reflect.apply(fn, this, parsedArgs.data);
3579
+ const parsedReturns = me._def.returns.safeParse(result2, params);
3502
3580
  if (!parsedReturns.success) {
3503
- throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
3581
+ throw new ZodError([makeReturnsIssue(result2, parsedReturns.error)]);
3504
3582
  }
3505
3583
  return parsedReturns.data;
3506
3584
  });
@@ -3745,43 +3823,43 @@ var init_types2 = __esm({
3745
3823
  return Promise.resolve(processed).then(async (processed2) => {
3746
3824
  if (status2.value === "aborted")
3747
3825
  return INVALID;
3748
- const result = await this._def.schema._parseAsync({
3826
+ const result2 = await this._def.schema._parseAsync({
3749
3827
  data: processed2,
3750
3828
  path: ctx.path,
3751
3829
  parent: ctx
3752
3830
  });
3753
- if (result.status === "aborted")
3831
+ if (result2.status === "aborted")
3754
3832
  return INVALID;
3755
- if (result.status === "dirty")
3756
- return DIRTY(result.value);
3833
+ if (result2.status === "dirty")
3834
+ return DIRTY(result2.value);
3757
3835
  if (status2.value === "dirty")
3758
- return DIRTY(result.value);
3759
- return result;
3836
+ return DIRTY(result2.value);
3837
+ return result2;
3760
3838
  });
3761
3839
  } else {
3762
3840
  if (status2.value === "aborted")
3763
3841
  return INVALID;
3764
- const result = this._def.schema._parseSync({
3842
+ const result2 = this._def.schema._parseSync({
3765
3843
  data: processed,
3766
3844
  path: ctx.path,
3767
3845
  parent: ctx
3768
3846
  });
3769
- if (result.status === "aborted")
3847
+ if (result2.status === "aborted")
3770
3848
  return INVALID;
3771
- if (result.status === "dirty")
3772
- return DIRTY(result.value);
3849
+ if (result2.status === "dirty")
3850
+ return DIRTY(result2.value);
3773
3851
  if (status2.value === "dirty")
3774
- return DIRTY(result.value);
3775
- return result;
3852
+ return DIRTY(result2.value);
3853
+ return result2;
3776
3854
  }
3777
3855
  }
3778
3856
  if (effect.type === "refinement") {
3779
3857
  const executeRefinement = (acc) => {
3780
- const result = effect.refinement(acc, checkCtx);
3858
+ const result2 = effect.refinement(acc, checkCtx);
3781
3859
  if (ctx.common.async) {
3782
- return Promise.resolve(result);
3860
+ return Promise.resolve(result2);
3783
3861
  }
3784
- if (result instanceof Promise) {
3862
+ if (result2 instanceof Promise) {
3785
3863
  throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
3786
3864
  }
3787
3865
  return acc;
@@ -3819,18 +3897,18 @@ var init_types2 = __esm({
3819
3897
  });
3820
3898
  if (!isValid(base))
3821
3899
  return INVALID;
3822
- const result = effect.transform(base.value, checkCtx);
3823
- if (result instanceof Promise) {
3900
+ const result2 = effect.transform(base.value, checkCtx);
3901
+ if (result2 instanceof Promise) {
3824
3902
  throw new Error(`Asynchronous transform encountered during synchronous parse operation. Use .parseAsync instead.`);
3825
3903
  }
3826
- return { status: status2.value, value: result };
3904
+ return { status: status2.value, value: result2 };
3827
3905
  } else {
3828
3906
  return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((base) => {
3829
3907
  if (!isValid(base))
3830
3908
  return INVALID;
3831
- return Promise.resolve(effect.transform(base.value, checkCtx)).then((result) => ({
3909
+ return Promise.resolve(effect.transform(base.value, checkCtx)).then((result2) => ({
3832
3910
  status: status2.value,
3833
- value: result
3911
+ value: result2
3834
3912
  }));
3835
3913
  });
3836
3914
  }
@@ -3927,18 +4005,18 @@ var init_types2 = __esm({
3927
4005
  issues: []
3928
4006
  }
3929
4007
  };
3930
- const result = this._def.innerType._parse({
4008
+ const result2 = this._def.innerType._parse({
3931
4009
  data: newCtx.data,
3932
4010
  path: newCtx.path,
3933
4011
  parent: {
3934
4012
  ...newCtx
3935
4013
  }
3936
4014
  });
3937
- if (isAsync(result)) {
3938
- return result.then((result2) => {
4015
+ if (isAsync(result2)) {
4016
+ return result2.then((result3) => {
3939
4017
  return {
3940
4018
  status: "valid",
3941
- value: result2.status === "valid" ? result2.value : this._def.catchValue({
4019
+ value: result3.status === "valid" ? result3.value : this._def.catchValue({
3942
4020
  get error() {
3943
4021
  return new ZodError(newCtx.common.issues);
3944
4022
  },
@@ -3949,7 +4027,7 @@ var init_types2 = __esm({
3949
4027
  } else {
3950
4028
  return {
3951
4029
  status: "valid",
3952
- value: result.status === "valid" ? result.value : this._def.catchValue({
4030
+ value: result2.status === "valid" ? result2.value : this._def.catchValue({
3953
4031
  get error() {
3954
4032
  return new ZodError(newCtx.common.issues);
3955
4033
  },
@@ -4063,14 +4141,14 @@ var init_types2 = __esm({
4063
4141
  };
4064
4142
  ZodReadonly = class extends ZodType {
4065
4143
  _parse(input) {
4066
- const result = this._def.innerType._parse(input);
4144
+ const result2 = this._def.innerType._parse(input);
4067
4145
  const freeze = (data) => {
4068
4146
  if (isValid(data)) {
4069
4147
  data.value = Object.freeze(data.value);
4070
4148
  }
4071
4149
  return data;
4072
4150
  };
4073
- return isAsync(result) ? result.then((data) => freeze(data)) : freeze(result);
4151
+ return isAsync(result2) ? result2.then((data) => freeze(data)) : freeze(result2);
4074
4152
  }
4075
4153
  unwrap() {
4076
4154
  return this._def.innerType;
@@ -4310,8 +4388,223 @@ var init_zod = __esm({
4310
4388
  }
4311
4389
  });
4312
4390
 
4391
+ // ../../packages/core/src/policies.ts
4392
+ function compilePolicyPatterns(bundle) {
4393
+ const out = [];
4394
+ for (const p of bundle.patterns) {
4395
+ const flags = `g${p.flags ?? ""}`;
4396
+ try {
4397
+ out.push({ name: p.name, pattern: new RegExp(p.regex, flags) });
4398
+ } catch {
4399
+ }
4400
+ }
4401
+ return out;
4402
+ }
4403
+ var RedactionPattern, RedactionPolicyBundle, POLICIES_BUNDLED_FALLBACK, POLICIES_CONFIG_KIND;
4404
+ var init_policies = __esm({
4405
+ "../../packages/core/src/policies.ts"() {
4406
+ "use strict";
4407
+ init_zod();
4408
+ RedactionPattern = external_exports.object({
4409
+ /** Stable label for the `[REDACTED:name]` placeholder. */
4410
+ name: external_exports.string().min(1).max(64).regex(/^[a-z0-9_]+$/, "name must be lowercase a-z0-9_"),
4411
+ /** JS regex source. Compiled with the `g` flag on the client. */
4412
+ regex: external_exports.string().min(1).max(1e3),
4413
+ /** Optional extra flags; `g` is always added. Limited to `i m s u`. */
4414
+ flags: external_exports.string().max(8).regex(/^[imsu]*$/, "only i m s u flags allowed").optional()
4415
+ });
4416
+ RedactionPolicyBundle = external_exports.object({
4417
+ version: external_exports.number().int().nonnegative(),
4418
+ /** Additive patterns unioned ON TOP of the bundled floor. There is, by
4419
+ * design, no way to express removal — only addition. */
4420
+ patterns: external_exports.array(RedactionPattern).max(256)
4421
+ });
4422
+ POLICIES_BUNDLED_FALLBACK = { version: 0, patterns: [] };
4423
+ POLICIES_CONFIG_KIND = {
4424
+ kind: "policies",
4425
+ schema: RedactionPolicyBundle,
4426
+ bundledFallback: POLICIES_BUNDLED_FALLBACK
4427
+ };
4428
+ }
4429
+ });
4430
+
4431
+ // ../../packages/core/src/redact-floor.ts
4432
+ var SECRET_FLOOR;
4433
+ var init_redact_floor = __esm({
4434
+ "../../packages/core/src/redact-floor.ts"() {
4435
+ "use strict";
4436
+ SECRET_FLOOR = [
4437
+ {
4438
+ name: "anthropic_key",
4439
+ pattern: /sk-ant-[A-Za-z0-9_-]{20,}/g,
4440
+ replacement: "<REDACTED:anthropic_key>"
4441
+ },
4442
+ {
4443
+ name: "openai_key",
4444
+ pattern: /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g,
4445
+ replacement: "<REDACTED:openai_key>"
4446
+ },
4447
+ {
4448
+ name: "google_api_key",
4449
+ pattern: /AIza[0-9A-Za-z_-]{35}/g,
4450
+ replacement: "<REDACTED:google_api_key>"
4451
+ },
4452
+ {
4453
+ name: "aws_access_key",
4454
+ pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
4455
+ replacement: "<REDACTED:aws_access_key>"
4456
+ },
4457
+ { name: "github_pat", pattern: /ghp_[A-Za-z0-9]{36,}/g, replacement: "<REDACTED:github_pat>" },
4458
+ {
4459
+ name: "github_oauth",
4460
+ pattern: /gho_[A-Za-z0-9]{36,}/g,
4461
+ replacement: "<REDACTED:github_oauth>"
4462
+ },
4463
+ {
4464
+ name: "github_app",
4465
+ pattern: /gh[sur]_[A-Za-z0-9]{36,}/g,
4466
+ replacement: "<REDACTED:github_app>"
4467
+ },
4468
+ {
4469
+ name: "slack_token",
4470
+ pattern: /xox[aboprs]-[A-Za-z0-9-]{10,}/g,
4471
+ replacement: "<REDACTED:slack_token>"
4472
+ },
4473
+ {
4474
+ name: "stripe_live_key",
4475
+ pattern: /(?:sk|pk|rk)_live_[A-Za-z0-9]{24,}/g,
4476
+ replacement: "<REDACTED:stripe_live_key>"
4477
+ },
4478
+ {
4479
+ name: "stripe_test_key",
4480
+ pattern: /(?:sk|pk|rk)_test_[A-Za-z0-9]{24,}/g,
4481
+ replacement: "<REDACTED:stripe_test_key>"
4482
+ },
4483
+ // Discord bot token (was agent-sdk-only — the canonical drift example).
4484
+ {
4485
+ name: "discord_token",
4486
+ pattern: /[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27}/g,
4487
+ replacement: "<REDACTED:discord_token>"
4488
+ },
4489
+ {
4490
+ name: "jwt",
4491
+ pattern: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
4492
+ replacement: "<REDACTED:jwt>"
4493
+ },
4494
+ // Full PEM block (was header-only in the wire floor — this redacts the body too).
4495
+ {
4496
+ name: "private_key_header",
4497
+ pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,
4498
+ replacement: "<REDACTED:private_key>"
4499
+ },
4500
+ // modelstat's own device bearer — agents must never ship their credential.
4501
+ {
4502
+ name: "modelstat_device_secret",
4503
+ pattern: /ds_live_[A-Za-z0-9_-]{32,}/g,
4504
+ replacement: "<REDACTED:modelstat_device_secret>"
4505
+ },
4506
+ // Generic env-style KEY=VALUE where KEY names a secret. Keeps the var name.
4507
+ {
4508
+ name: "env_secret",
4509
+ pattern: /\b([A-Z][A-Z0-9_]*(?:TOKEN|KEY|SECRET|PASSWORD|PASSWD|API)[A-Z0-9_]*)\s*[:=]\s*['"]?([^\s'"]{12,})['"]?/g,
4510
+ replacement: "$1=<REDACTED:env_secret>"
4511
+ },
4512
+ {
4513
+ name: "bearer_header",
4514
+ pattern: /Bearer\s+[A-Za-z0-9._~+/-]{20,}=*/g,
4515
+ replacement: "Bearer <REDACTED:bearer>"
4516
+ },
4517
+ {
4518
+ name: "db_url_with_password",
4519
+ pattern: /\b(postgres|mysql|mongodb|redis|amqp)(?:\+[a-z]+)?:\/\/[^:\s]+:([^@\s]+)@/gi,
4520
+ replacement: "$1://<user>:<REDACTED:db_password>@"
4521
+ },
4522
+ // Generic 40-char base64-ish blob (e.g. an AWS secret access key on its own).
4523
+ // Most generic ⇒ last, so specific patterns claim their matches first.
4524
+ {
4525
+ name: "aws_secret_key",
4526
+ pattern: /(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])/g,
4527
+ replacement: "<REDACTED:aws_secret_key>"
4528
+ }
4529
+ ];
4530
+ }
4531
+ });
4532
+
4533
+ // ../../packages/core/src/redact.ts
4534
+ function setRemoteRedactionPatterns(patterns) {
4535
+ remotePatterns = patterns;
4536
+ }
4537
+ function entropy(s) {
4538
+ const freq = /* @__PURE__ */ new Map();
4539
+ for (const c of s) freq.set(c, (freq.get(c) ?? 0) + 1);
4540
+ let h = 0;
4541
+ for (const n of freq.values()) {
4542
+ const p = n / s.length;
4543
+ h -= p * Math.log2(p);
4544
+ }
4545
+ return h;
4546
+ }
4547
+ function redact(text, repoRootAbs) {
4548
+ let out = text;
4549
+ const counts = {
4550
+ secrets_found: 0,
4551
+ emails_redacted: 0,
4552
+ paths_redacted_absolute: 0
4553
+ };
4554
+ for (const { name, pattern } of SECRET_FLOOR) {
4555
+ out = out.replace(pattern, () => {
4556
+ counts.secrets_found += 1;
4557
+ return `[REDACTED:${name}]`;
4558
+ });
4559
+ }
4560
+ for (const { name, pattern } of remotePatterns) {
4561
+ out = out.replace(pattern, () => {
4562
+ counts.secrets_found += 1;
4563
+ return `[REDACTED:${name}]`;
4564
+ });
4565
+ }
4566
+ out = out.replace(TOKEN_CANDIDATE, (match) => {
4567
+ if (/^[a-f0-9]+$/i.test(match)) return match;
4568
+ if (/^[A-Z]+$/.test(match)) return match;
4569
+ const hasLetter = /[A-Za-z]/.test(match);
4570
+ const hasDigit = /\d/.test(match);
4571
+ const hasUpper = /[A-Z]/.test(match);
4572
+ const hasLower = /[a-z]/.test(match);
4573
+ if (!(hasLetter && hasDigit && hasUpper && hasLower)) return match;
4574
+ if (entropy(match) < 3.6) return match;
4575
+ counts.secrets_found += 1;
4576
+ return `[REDACTED:hi-entropy]`;
4577
+ });
4578
+ out = out.replace(EMAIL_PATTERN, () => {
4579
+ counts.emails_redacted += 1;
4580
+ return "[REDACTED:email]";
4581
+ });
4582
+ const pathReplacer = (match) => {
4583
+ if (repoRootAbs && match.startsWith(repoRootAbs)) {
4584
+ return match.slice(repoRootAbs.length).replace(/^\/+/, "./");
4585
+ }
4586
+ counts.paths_redacted_absolute += 1;
4587
+ return "[REDACTED:abs-path]";
4588
+ };
4589
+ out = out.replace(ABSOLUTE_PATH_MACOS, pathReplacer);
4590
+ out = out.replace(ABSOLUTE_PATH_LINUX, pathReplacer);
4591
+ return { text: out, counts };
4592
+ }
4593
+ var remotePatterns, EMAIL_PATTERN, ABSOLUTE_PATH_MACOS, ABSOLUTE_PATH_LINUX, TOKEN_CANDIDATE;
4594
+ var init_redact = __esm({
4595
+ "../../packages/core/src/redact.ts"() {
4596
+ "use strict";
4597
+ init_redact_floor();
4598
+ remotePatterns = [];
4599
+ EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
4600
+ ABSOLUTE_PATH_MACOS = /\/Users\/[^\s"'`)]+/g;
4601
+ ABSOLUTE_PATH_LINUX = /\/home\/[^\s"'`)]+/g;
4602
+ TOKEN_CANDIDATE = /[A-Za-z0-9/+=_-]{32,}/g;
4603
+ }
4604
+ });
4605
+
4313
4606
  // ../../packages/core/src/schemas.ts
4314
- var TokenUsage, GitContext, RawEvent, RedactionReport, TaxonomyHintRooted, Segment, ToolCallWire, IngestBatch, HeartbeatPayload, DeviceEnrollment, DeviceSelfRegister, DeviceClaimRequest, ProcessingMetadata, RedactionPolicy, DetectedInstallation, DetectedIdentity, DiscoveryReport, ClassificationConfidenceEnum;
4607
+ var TokenUsage, GitContext, RawEvent, RedactionReport, TaxonomyHintRooted, Segment, ToolAction, ToolCallWire, IngestBatch, HeartbeatPayload, DeviceEnrollment, DeviceSelfRegister, DeviceClaimRequest, ProcessingMetadata, RedactionPolicy, DetectedInstallation, DetectedIdentity, DiscoveryReport, ClassificationConfidenceEnum;
4315
4608
  var init_schemas = __esm({
4316
4609
  "../../packages/core/src/schemas.ts"() {
4317
4610
  "use strict";
@@ -4339,11 +4632,11 @@ var init_schemas = __esm({
4339
4632
  ts: external_exports.string().datetime({ offset: true }),
4340
4633
  kind: external_exports.enum(EVENT_KINDS),
4341
4634
  // Attribution
4342
- tool: external_exports.enum(TOOLS),
4635
+ agent: external_exports.enum(AGENTS),
4343
4636
  provider: external_exports.enum(PROVIDERS),
4344
4637
  model: external_exports.string().max(120).nullable(),
4345
4638
  session_id: external_exports.string().max(120),
4346
- // tool-local session id (UUID in most cases)
4639
+ // agent-local session id (UUID in most cases)
4347
4640
  turn_index: external_exports.number().int().nonnegative().nullable(),
4348
4641
  parent_event_id: external_exports.string().nullable(),
4349
4642
  // for subagent turns
@@ -4372,7 +4665,7 @@ var init_schemas = __esm({
4372
4665
  // Reference to originating file for reparsing
4373
4666
  source_file: external_exports.string().max(1024).nullable(),
4374
4667
  source_byte_offset: external_exports.number().int().nonnegative().nullable(),
4375
- // Billing mode. Tools with a flat-fee subscription tier (Claude
4668
+ // Billing mode. Agents with a flat-fee subscription tier (Claude
4376
4669
  // Code, Cursor Pro, GitHub Copilot, etc) emit events tagged
4377
4670
  // `billing: "subscription"` — the server short-circuits cost to $0
4378
4671
  // for those, since token-level pricing doesn't apply once the user
@@ -4397,39 +4690,72 @@ var init_schemas = __esm({
4397
4690
  /** sha256-based deterministic id — see @modelstat/core/ids.ts segmentId(). */
4398
4691
  segment_id: external_exports.string().max(64),
4399
4692
  session_id: external_exports.string().max(120),
4400
- tool: external_exports.enum(TOOLS),
4693
+ agent: external_exports.enum(AGENTS),
4401
4694
  started_at: external_exports.string().datetime({ offset: true }),
4402
4695
  ended_at: external_exports.string().datetime({ offset: true }),
4403
4696
  /** Pre-redacted abstract, ≤ 512 chars. Never contains PII. */
4404
4697
  abstract: external_exports.string().max(512),
4405
4698
  /** Tokens spent inside this segment only. */
4406
4699
  tokens: TokenUsage,
4407
- /** Tags with strongly-typed root keys. Server merges with its own
4408
- * classifier output and files any novel names as taxonomy proposals. */
4700
+ /** Tags with strongly-typed root keys. The server may merge these with
4701
+ * its own classifier output. */
4409
4702
  tags: external_exports.array(TaxonomyHintRooted).max(40).default([]),
4410
4703
  /** Counts of what was stripped. */
4411
4704
  redaction: RedactionReport,
4412
4705
  /** `source_event_id`s covered by this segment. Used for dedupe + replay. */
4413
4706
  source_event_ids: external_exports.array(external_exports.string()).max(2e3),
4414
4707
  /** Optional embedding of the abstract (BGE-small-en-v1.5, 384 dims).
4415
- * Present when the companion has an Embedder adapter configured.
4416
- * Reserved for server-side similarity / clustering. */
4708
+ * Present when the companion has an Embedder adapter configured. */
4417
4709
  abstract_embedding: external_exports.array(external_exports.number()).length(384).optional()
4418
4710
  });
4711
+ ToolAction = external_exports.object({
4712
+ /** Where it ran: `shell`, `mcp`, `builtin`, `browser`. (tier 0) */
4713
+ surface: external_exports.string().max(40),
4714
+ /** Concrete program/operation, or a generic bucket token. (tier 0 | bucket) */
4715
+ executable: external_exports.string().max(80).nullable().default(null),
4716
+ /** Verb/intent (`restart`, `read`, …). (tier 0) */
4717
+ action: external_exports.string().max(40).nullable().default(null),
4718
+ /** What it acts on (`deployment`, `file`, …). (tier 0) */
4719
+ object: external_exports.string().max(60).nullable().default(null),
4720
+ /** Governed safe flags (`destructive`, `remote`, …). (tier 0) */
4721
+ qualifiers: external_exports.array(external_exports.string().max(40)).max(8).default([]),
4722
+ /** Value-masked argument skeleton (every value → `§`). (tier 1) */
4723
+ param_shape: external_exports.string().max(200).nullable().default(null),
4724
+ /** Relevant non-sensitive keywords (e.g. ["rollout","restart","prod"]),
4725
+ * OpenAI-redacted on-device. (tier 0) */
4726
+ keywords: external_exports.array(external_exports.string().max(40)).max(12).default([]),
4727
+ /** Human-readable command summary (e.g. "redeploying service payments-api"),
4728
+ * OpenAI-redacted on-device. (tier 0) */
4729
+ abstract: external_exports.string().max(200).nullable().default(null),
4730
+ /** The compliance-redacted command text — PII/secrets stripped on-device
4731
+ * (SOC2/GDPR), org-internal infra intact; the server derives semantics from
4732
+ * it. Un-redacted raw never ships. (tier 0, post-redaction) */
4733
+ command_redacted: external_exports.string().max(1e3).nullable().default(null),
4734
+ /** Per-script content abstracts for any script/bash FILES the command runs
4735
+ * — summarized on-device by the local model, then redacted. Ordered by
4736
+ * appearance; `token` is the script's token exactly as it appears in
4737
+ * `command_redacted`, so the backend deterministically zips each `summary`
4738
+ * to its place when ingesting the command + its scripts. (tier 0) */
4739
+ scripts: external_exports.array(external_exports.object({ token: external_exports.string().max(200), summary: external_exports.string().max(200) })).max(8).default([]),
4740
+ /** Extractor confidence in [0, 1]. */
4741
+ confidence: external_exports.number().min(0).max(1).default(0),
4742
+ /** Provenance of the extraction, e.g. `shell.v2`. */
4743
+ extractor: external_exports.string().max(40)
4744
+ }).strict();
4419
4745
  ToolCallWire = external_exports.object({
4420
4746
  /** tool_use block `id` / codex `call_id`; parsers fall back to a
4421
4747
  * deterministic `tc_<djb2-base36>` of `${source_event_id}|${call_index}`
4422
4748
  * when the source line carries no id. */
4423
4749
  external_call_id: external_exports.string().max(120),
4424
- /** Tool-local session id — same id space as RawEvent.session_id. */
4750
+ /** Agent-local session id — same id space as RawEvent.session_id. */
4425
4751
  session_id: external_exports.string().max(120),
4426
4752
  /** The RawEvent that contained the tool_use (dedupe/replay anchor). */
4427
4753
  source_event_id: external_exports.string(),
4428
4754
  /** Segment containing source_event_id — filled by the companion at
4429
4755
  * batch-build time when known, else null. */
4430
4756
  segment_id: external_exports.string().max(64).nullable().default(null),
4431
- /** The agent that made the call (TOOLS enum — "tool" in legacy naming). */
4432
- agent: external_exports.enum(TOOLS),
4757
+ /** The agent that made the call (AGENTS enum). */
4758
+ agent: external_exports.enum(AGENTS),
4433
4759
  /** `builtin` or `mcp:<server>`. */
4434
4760
  server: external_exports.string().max(120),
4435
4761
  /** Bare tool name (`Bash`, `create_pr`) — normalised vendor identifier. */
@@ -4455,20 +4781,20 @@ var init_schemas = __esm({
4455
4781
  /** Model of the assistant message that issued the call. `<synthetic>`
4456
4782
  * kept verbatim per the PR #12 attribution rules. */
4457
4783
  model: external_exports.string().max(120).nullable(),
4458
- /** ONLY for shell-ish tools: command verbs from the fixed allowlist
4459
- * (@modelstat/parsers/shell-families). Never raw command text. */
4460
- command_families: external_exports.array(external_exports.string().max(40)).max(3).default([])
4784
+ /** On-device action decomposition nested + additive, `null` when nothing
4785
+ * was extracted. Replaces `command_families`. */
4786
+ action: ToolAction.nullable().default(null)
4461
4787
  });
4462
4788
  IngestBatch = external_exports.object({
4463
4789
  batch_id: external_exports.string(),
4464
4790
  // ULID
4465
4791
  device_id: external_exports.string(),
4466
- agent_version: external_exports.string().max(40),
4792
+ companion_version: external_exports.string().max(40),
4467
4793
  events: external_exports.array(RawEvent).max(1e4),
4468
4794
  segments: external_exports.array(Segment).max(2e3).default([]),
4469
4795
  /** Per-call tool invocations (additive — old agents omit it, old
4470
4796
  * servers ignore it). See ToolCallWire for the privacy contract:
4471
- * hashes / byte sizes / allowlisted verbs only, never payloads. */
4797
+ * hashes / byte sizes / governed action tokens only, never payloads. */
4472
4798
  tool_calls: external_exports.array(ToolCallWire).max(2e4).default([]),
4473
4799
  /** Optional per-session metadata hint: which installation produced them, etc. */
4474
4800
  session_installs: external_exports.record(
@@ -4480,11 +4806,10 @@ var init_schemas = __esm({
4480
4806
  ).optional(),
4481
4807
  /** Optional per-session titles — session_id → short redacted title
4482
4808
  * (≤120 chars) produced by the companion's local titler from the
4483
- * session's segment abstracts. Server-side this is last-write-wins
4484
- * per session; companions recompute it from the full session view on
4485
- * every upload, so the latest batch always carries the freshest
4486
- * title. Absent for runtimes without a titler (older agents, no-op
4487
- * browser summariser) — the server keeps whatever it has. */
4809
+ * session's segment abstracts. Companions recompute it from the full
4810
+ * session view on every upload, so the latest batch always carries the
4811
+ * freshest title. Absent for runtimes without a titler (older agents,
4812
+ * no-op browser summariser). */
4488
4813
  session_titles: external_exports.record(external_exports.string(), external_exports.string().max(120)).optional()
4489
4814
  });
4490
4815
  HeartbeatPayload = external_exports.object({
@@ -4496,7 +4821,7 @@ var init_schemas = __esm({
4496
4821
  queue_size: external_exports.number().int().nonnegative().default(0),
4497
4822
  stats: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
4498
4823
  last_event_at: external_exports.string().datetime({ offset: true }).nullable(),
4499
- agent_version: external_exports.string().max(40)
4824
+ companion_version: external_exports.string().max(40)
4500
4825
  });
4501
4826
  DeviceEnrollment = external_exports.object({
4502
4827
  machine_id: external_exports.string(),
@@ -4505,7 +4830,7 @@ var init_schemas = __esm({
4505
4830
  os_family: external_exports.enum(OS_FAMILIES),
4506
4831
  os_version: external_exports.string().max(60),
4507
4832
  arch: external_exports.enum(["x86_64", "arm64", "other"]),
4508
- agent_version: external_exports.string().max(40)
4833
+ companion_version: external_exports.string().max(40)
4509
4834
  });
4510
4835
  DeviceSelfRegister = external_exports.object({
4511
4836
  /** Agent-generated UUIDv7 — must pass shape + recent-timestamp checks. */
@@ -4521,8 +4846,8 @@ var init_schemas = __esm({
4521
4846
  os_family: external_exports.enum(OS_FAMILIES).optional(),
4522
4847
  os_version: external_exports.string().max(60).optional(),
4523
4848
  arch: external_exports.enum(["x86_64", "arm64", "other"]).optional(),
4524
- agent: external_exports.string().max(80).optional(),
4525
- agent_version: external_exports.string().max(40).optional()
4849
+ companion: external_exports.string().max(80).optional(),
4850
+ companion_version: external_exports.string().max(40).optional()
4526
4851
  // Allow extra fields for forward-compat without breaking old agents.
4527
4852
  }).catchall(external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()])).default({})
4528
4853
  });
@@ -4553,7 +4878,7 @@ var init_schemas = __esm({
4553
4878
  recommended_for: external_exports.string().max(160).optional()
4554
4879
  });
4555
4880
  DetectedInstallation = external_exports.object({
4556
- tool: external_exports.enum(TOOLS),
4881
+ agent: external_exports.enum(AGENTS),
4557
4882
  install_method: external_exports.enum(INSTALL_METHODS),
4558
4883
  binary_path: external_exports.string().nullable(),
4559
4884
  data_dir: external_exports.string().nullable(),
@@ -4582,304 +4907,136 @@ var init_schemas = __esm({
4582
4907
  }
4583
4908
  });
4584
4909
 
4585
- // ../../packages/core/src/ids.ts
4586
- function ulid(seedTime) {
4587
- const t = seedTime ?? Date.now();
4588
- let timeStr = "";
4589
- let ts = t;
4590
- for (let i = 9; i >= 0; i--) {
4591
- timeStr = ULID_ALPHABET[ts % 32] + timeStr;
4592
- ts = Math.floor(ts / 32);
4593
- }
4594
- const bytes = new Uint8Array(16);
4595
- globalThis.crypto.getRandomValues(bytes);
4596
- let randStr = "";
4597
- for (let i = 0; i < 16; i++) {
4598
- randStr += ULID_ALPHABET[bytes[i] % 32];
4599
- }
4600
- return timeStr + randStr;
4601
- }
4602
- function sourceEventId(deviceId, sourceOrFilePath, byteOffsetMaybe) {
4603
- let key;
4604
- if (typeof sourceOrFilePath === "string") {
4605
- const byteOffset = byteOffsetMaybe ?? 0;
4606
- key = `fs::${sourceOrFilePath}::${byteOffset}`;
4607
- } else if ("file" in sourceOrFilePath) {
4608
- key = `fs::${sourceOrFilePath.file}::${sourceOrFilePath.byteOffset}`;
4609
- } else if ("lineUuid" in sourceOrFilePath) {
4610
- key = `uuid::${sourceOrFilePath.lineUuid}`;
4611
- } else {
4612
- key = `web::${sourceOrFilePath.host}::${sourceOrFilePath.conversationId}::${sourceOrFilePath.messageId}`;
4613
- }
4614
- const s = `${deviceId}::${key}`;
4615
- let h = 5381n;
4616
- for (let i = 0; i < s.length; i++) {
4617
- h = h * 33n ^ BigInt(s.charCodeAt(i));
4618
- h &= 0xffffffffffffffffn;
4619
- }
4620
- return `evt_${h.toString(36)}`;
4621
- }
4622
- function segmentId(sessionId, startedAtMs, endedAtMs, sourceEventIds) {
4623
- const sorted = [...sourceEventIds].sort().join(",");
4624
- const s = `${sessionId}|${startedAtMs}|${endedAtMs}|${sorted}`;
4625
- let h = 5381n;
4626
- for (let i = 0; i < s.length; i++) {
4627
- h = h * 33n ^ BigInt(s.charCodeAt(i));
4628
- h &= 0xffffffffffffffffn;
4629
- }
4630
- return `seg_${h.toString(36)}`;
4631
- }
4632
- var ULID_ALPHABET, batchId;
4633
- var init_ids = __esm({
4634
- "../../packages/core/src/ids.ts"() {
4910
+ // ../../packages/core/src/index.ts
4911
+ var init_src = __esm({
4912
+ "../../packages/core/src/index.ts"() {
4635
4913
  "use strict";
4636
- ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
4637
- batchId = () => ulid();
4914
+ init_billing();
4915
+ init_enums();
4916
+ init_ids();
4917
+ init_policies();
4918
+ init_redact();
4919
+ init_redact_floor();
4920
+ init_schemas();
4638
4921
  }
4639
4922
  });
4640
4923
 
4641
- // ../../packages/core/src/redact.ts
4642
- function entropy(s) {
4643
- const freq = /* @__PURE__ */ new Map();
4644
- for (const c of s) freq.set(c, (freq.get(c) ?? 0) + 1);
4645
- let h = 0;
4646
- for (const n of freq.values()) {
4647
- const p = n / s.length;
4648
- h -= p * Math.log2(p);
4924
+ // ../../packages/parsers/src/tool-action/scripts.ts
4925
+ function detectScriptRefs(command) {
4926
+ const refs = [];
4927
+ for (const segment of command.split(SEGMENT_SEP)) {
4928
+ const tokens = segment.trim().split(/\s+/).filter(Boolean);
4929
+ tokens.forEach((tok, i) => {
4930
+ const t = stripQuotes(tok);
4931
+ if (!t || t.startsWith("-") || t.includes("://")) return;
4932
+ const looksLikeScript = SCRIPT_EXT.test(t) || // ends in a script extension
4933
+ t.startsWith("./") || t.startsWith("../") || // an explicit relative executable
4934
+ i === 0 && t.includes("/");
4935
+ if (looksLikeScript) refs.push(t);
4936
+ });
4649
4937
  }
4650
- return h;
4938
+ return refs;
4651
4939
  }
4652
- function redact(text, repoRootAbs) {
4653
- let out = text;
4654
- const counts = {
4655
- secrets_found: 0,
4656
- emails_redacted: 0,
4657
- paths_redacted_absolute: 0
4940
+ function scriptCandidates(ref, roots) {
4941
+ const out = [];
4942
+ const push = (p) => {
4943
+ if (p && !out.includes(p)) out.push(p);
4658
4944
  };
4659
- for (const { name, pattern } of SECRET_PATTERNS) {
4660
- out = out.replace(pattern, () => {
4661
- counts.secrets_found += 1;
4662
- return `[REDACTED:${name}]`;
4663
- });
4945
+ if (isAbsolute(ref)) push(ref);
4946
+ for (const root of roots) {
4947
+ if (root) push(joinPath(root, ref));
4664
4948
  }
4665
- out = out.replace(TOKEN_CANDIDATE, (match) => {
4666
- if (/^[a-f0-9]+$/i.test(match)) return match;
4667
- if (/^[A-Z]+$/.test(match)) return match;
4668
- const hasLetter = /[A-Za-z]/.test(match);
4669
- const hasDigit = /\d/.test(match);
4670
- const hasUpper = /[A-Z]/.test(match);
4671
- const hasLower = /[a-z]/.test(match);
4672
- if (!(hasLetter && hasDigit && hasUpper && hasLower)) return match;
4673
- if (entropy(match) < 3.6) return match;
4674
- counts.secrets_found += 1;
4675
- return `[REDACTED:hi-entropy]`;
4676
- });
4677
- out = out.replace(EMAIL_PATTERN, () => {
4678
- counts.emails_redacted += 1;
4679
- return "[REDACTED:email]";
4680
- });
4681
- const pathReplacer = (match) => {
4682
- if (repoRootAbs && match.startsWith(repoRootAbs)) {
4683
- return match.slice(repoRootAbs.length).replace(/^\/+/, "./");
4684
- }
4685
- counts.paths_redacted_absolute += 1;
4686
- return "[REDACTED:abs-path]";
4687
- };
4688
- out = out.replace(ABSOLUTE_PATH_MACOS, pathReplacer);
4689
- out = out.replace(ABSOLUTE_PATH_LINUX, pathReplacer);
4690
- return { text: out, counts };
4949
+ push(ref);
4950
+ return out.sort(
4951
+ (a, b) => Number(isAbsolute(b)) - Number(isAbsolute(a)) || b.length - a.length
4952
+ );
4691
4953
  }
4692
- var SECRET_PATTERNS, EMAIL_PATTERN, ABSOLUTE_PATH_MACOS, ABSOLUTE_PATH_LINUX, TOKEN_CANDIDATE;
4693
- var init_redact = __esm({
4694
- "../../packages/core/src/redact.ts"() {
4695
- "use strict";
4696
- SECRET_PATTERNS = [
4697
- { name: "anthropic_key", pattern: /sk-ant-[A-Za-z0-9_-]{20,}/g },
4698
- { name: "openai_key", pattern: /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g },
4699
- { name: "google_api_key", pattern: /AIza[0-9A-Za-z_-]{35}/g },
4700
- { name: "aws_access_key", pattern: /AKIA[0-9A-Z]{16}/g },
4701
- { name: "aws_secret_key", pattern: /(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])/g },
4702
- { name: "github_pat", pattern: /ghp_[A-Za-z0-9]{36}/g },
4703
- { name: "github_oauth", pattern: /gho_[A-Za-z0-9]{36}/g },
4704
- { name: "github_app", pattern: /gh[sur]_[A-Za-z0-9]{36}/g },
4705
- { name: "slack_token", pattern: /xox[baprs]-[A-Za-z0-9-]{10,}/g },
4706
- { name: "stripe_live_key", pattern: /sk_live_[A-Za-z0-9]{24,}/g },
4707
- { name: "stripe_test_key", pattern: /sk_test_[A-Za-z0-9]{24,}/g },
4708
- { name: "jwt", pattern: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
4709
- { name: "private_key_header", pattern: /-----BEGIN [A-Z ]+PRIVATE KEY-----/g }
4710
- ];
4711
- EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
4712
- ABSOLUTE_PATH_MACOS = /\/Users\/[^\s"'`)]+/g;
4713
- ABSOLUTE_PATH_LINUX = /\/home\/[^\s"'`)]+/g;
4714
- TOKEN_CANDIDATE = /[A-Za-z0-9/+=_-]{32,}/g;
4954
+ function resolveScriptPath(ref, roots, exists) {
4955
+ for (const cand of scriptCandidates(ref, roots)) {
4956
+ if (exists(cand)) return cand;
4715
4957
  }
4716
- });
4717
-
4718
- // ../../packages/core/src/billing.ts
4719
- var MILLION, FREE_INCLUDED_TOKENS, TEAM_INCLUDED_PER_SEAT;
4720
- var init_billing = __esm({
4721
- "../../packages/core/src/billing.ts"() {
4722
- "use strict";
4723
- MILLION = 1000000n;
4724
- FREE_INCLUDED_TOKENS = 100n * MILLION;
4725
- TEAM_INCLUDED_PER_SEAT = 250n * MILLION;
4958
+ return null;
4959
+ }
4960
+ function isAbsolute(p) {
4961
+ return p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p);
4962
+ }
4963
+ function joinPath(root, rel) {
4964
+ return `${root.replace(/\/+$/, "")}/${rel.replace(/^\.\//, "")}`;
4965
+ }
4966
+ function stripQuotes(token) {
4967
+ if (token.length >= 2) {
4968
+ const a = token[0];
4969
+ const b = token[token.length - 1];
4970
+ if (a === "'" && b === "'" || a === '"' && b === '"') return token.slice(1, -1);
4726
4971
  }
4727
- });
4728
-
4729
- // ../../packages/core/src/index.ts
4730
- var init_src = __esm({
4731
- "../../packages/core/src/index.ts"() {
4972
+ return token;
4973
+ }
4974
+ var SEGMENT_SEP, SCRIPT_EXT;
4975
+ var init_scripts = __esm({
4976
+ "../../packages/parsers/src/tool-action/scripts.ts"() {
4732
4977
  "use strict";
4733
- init_enums();
4734
- init_schemas();
4735
- init_ids();
4736
- init_redact();
4737
- init_billing();
4978
+ SEGMENT_SEP = /\s*(?:&&|\|\||[;|&\n])\s*/;
4979
+ SCRIPT_EXT = /\.(sh|bash|zsh|ksh|fish|py|rb|js|mjs|cjs|ts|tsx|pl|php|lua|ps1|bat|cmd|r|jl|groovy|kts)$/i;
4738
4980
  }
4739
4981
  });
4740
4982
 
4741
- // ../../packages/parsers/src/shell-families/index.ts
4742
- function extractCommandFamilies(command) {
4743
- const families = [];
4744
- for (const part of splitCommandParts(command)) {
4745
- const verb = leadingVerb(part);
4746
- if (!verb || !ALLOWLIST.has(verb)) continue;
4747
- if (!families.includes(verb)) families.push(verb);
4748
- if (families.length >= MAX_COMMAND_FAMILIES) break;
4983
+ // ../../packages/parsers/src/tool-action/index.ts
4984
+ function extractToolAction(call) {
4985
+ const isMcp = call.server.startsWith("mcp:");
4986
+ const command = isMcp ? null : shellCommandOf(call.input);
4987
+ const surface = isMcp ? "mcp" : command != null ? "shell" : "builtin";
4988
+ let executable = call.name || null;
4989
+ let param_shape = null;
4990
+ let command_redacted = null;
4991
+ if (command != null) {
4992
+ const [head = "", ...rest] = command.trim().split(/\s+/);
4993
+ executable = basename(head) || null;
4994
+ param_shape = paramShape(rest.join(" ")) || null;
4995
+ command_redacted = redact(command, call.cwd ?? void 0).text.slice(0, MAX_COMMAND_REDACTED) || null;
4749
4996
  }
4750
- return families;
4997
+ return {
4998
+ surface,
4999
+ executable,
5000
+ action: null,
5001
+ object: null,
5002
+ qualifiers: [],
5003
+ param_shape,
5004
+ keywords: [],
5005
+ abstract: null,
5006
+ command_redacted,
5007
+ scripts: [],
5008
+ confidence: 0,
5009
+ extractor: `${surface}.v1`
5010
+ };
4751
5011
  }
4752
- function splitCommandParts(command) {
4753
- const parts = [];
4754
- let current = "";
4755
- let inSingle = false;
4756
- let inDouble = false;
4757
- for (let i = 0; i < command.length; i++) {
4758
- const ch = command[i];
4759
- if (!inSingle && ch === "\\") {
4760
- current += ch + (command[i + 1] ?? "");
4761
- i++;
4762
- continue;
4763
- }
4764
- if (ch === "'" && !inDouble) {
4765
- inSingle = !inSingle;
4766
- current += ch;
4767
- continue;
4768
- }
4769
- if (ch === '"' && !inSingle) {
4770
- inDouble = !inDouble;
4771
- current += ch;
4772
- continue;
4773
- }
4774
- if (!inSingle && !inDouble) {
4775
- if (ch === ";" || ch === "|" || ch === "\n") {
4776
- parts.push(current);
4777
- current = "";
4778
- continue;
4779
- }
4780
- if (ch === "&" && command[i + 1] === "&") {
4781
- parts.push(current);
4782
- current = "";
4783
- i++;
4784
- continue;
4785
- }
4786
- }
4787
- current += ch;
4788
- }
4789
- parts.push(current);
4790
- return parts;
5012
+ function extractLocalToolContext(call) {
5013
+ if (call.server.startsWith("mcp:")) return null;
5014
+ const command = shellCommandOf(call.input);
5015
+ if (command == null) return null;
5016
+ return { command, cwd: call.cwd ?? null };
4791
5017
  }
4792
- function leadingVerb(part) {
4793
- const tokens = part.trim().split(/\s+/);
4794
- let i = 0;
4795
- while (i < tokens.length) {
4796
- const tok = stripQuotes(tokens[i] ?? "");
4797
- if (tok === "") {
4798
- i++;
4799
- continue;
4800
- }
4801
- if (VAR_ASSIGNMENT.test(tok)) {
4802
- i++;
4803
- continue;
5018
+ function shellCommandOf(input) {
5019
+ if (typeof input === "string") return input.trim() ? input : null;
5020
+ if (input && typeof input === "object") {
5021
+ const cmd = input.command ?? input.cmd;
5022
+ if (typeof cmd === "string") return cmd.trim() ? cmd : null;
5023
+ if (Array.isArray(cmd)) {
5024
+ const parts = cmd.filter((p) => typeof p === "string");
5025
+ if (parts.length) return parts.join(" ");
4804
5026
  }
4805
- if (WRAPPERS.has(tok)) {
4806
- i++;
4807
- while (i < tokens.length && (tokens[i] ?? "").startsWith("-")) i++;
4808
- continue;
4809
- }
4810
- const base = tok.split("/").pop() ?? tok;
4811
- return base === "" ? null : base;
4812
5027
  }
4813
5028
  return null;
4814
5029
  }
4815
- function stripQuotes(token) {
4816
- if (token.length >= 2) {
4817
- const first = token[0];
4818
- const last = token[token.length - 1];
4819
- if (first === "'" && last === "'" || first === '"' && last === '"') {
4820
- return token.slice(1, -1);
4821
- }
4822
- }
4823
- return token;
5030
+ function basename(token) {
5031
+ return token.split("/").pop() ?? token;
4824
5032
  }
4825
- var SHELL_FAMILY_ALLOWLIST, MAX_COMMAND_FAMILIES, ALLOWLIST, WRAPPERS, VAR_ASSIGNMENT;
4826
- var init_shell_families = __esm({
4827
- "../../packages/parsers/src/shell-families/index.ts"() {
5033
+ var MAX_COMMAND_REDACTED;
5034
+ var init_tool_action = __esm({
5035
+ "../../packages/parsers/src/tool-action/index.ts"() {
4828
5036
  "use strict";
4829
- SHELL_FAMILY_ALLOWLIST = [
4830
- "git",
4831
- "npm",
4832
- "pnpm",
4833
- "npx",
4834
- "yarn",
4835
- "node",
4836
- "python",
4837
- "python3",
4838
- "pytest",
4839
- "pip",
4840
- "pip3",
4841
- "cargo",
4842
- "rustc",
4843
- "go",
4844
- "make",
4845
- "cmake",
4846
- "docker",
4847
- "docker-compose",
4848
- "kubectl",
4849
- "helm",
4850
- "terraform",
4851
- "gh",
4852
- "aws",
4853
- "gcloud",
4854
- "az",
4855
- "curl",
4856
- "wget",
4857
- "rg",
4858
- "grep",
4859
- "find",
4860
- "sed",
4861
- "awk",
4862
- "jq",
4863
- "psql",
4864
- "mysql",
4865
- "redis-cli",
4866
- "brew",
4867
- "apt",
4868
- "tsx",
4869
- "vitest",
4870
- "jest",
4871
- "playwright",
4872
- "ruby",
4873
- "bundle",
4874
- "mvn",
4875
- "gradle",
4876
- "ls",
4877
- "cat"
4878
- ];
4879
- MAX_COMMAND_FAMILIES = 3;
4880
- ALLOWLIST = new Set(SHELL_FAMILY_ALLOWLIST);
4881
- WRAPPERS = /* @__PURE__ */ new Set(["sudo", "env", "time", "nice"]);
4882
- VAR_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
5037
+ init_src();
5038
+ init_scripts();
5039
+ MAX_COMMAND_REDACTED = 1e3;
4883
5040
  }
4884
5041
  });
4885
5042
 
@@ -4976,17 +5133,16 @@ function extractExcerpt(content) {
4976
5133
  const truncated = cleaned.slice(0, 320);
4977
5134
  return truncated.length > 0 ? truncated : void 0;
4978
5135
  }
4979
- function commandFamiliesFor(server, name, input) {
4980
- if (server !== "builtin" || !SHELL_TOOL_NAMES.has(name)) return [];
4981
- if (typeof input !== "object" || input === null) return [];
4982
- const command = input.command;
4983
- return typeof command === "string" ? extractCommandFamilies(command) : [];
4984
- }
4985
5136
  function buildToolCallDraft(opts) {
4986
5137
  const { server, name } = splitObservedToolName(opts.observedName);
4987
5138
  const hashes = hashArgs(opts.input);
5139
+ const external_call_id = typeof opts.rawCallId === "string" && opts.rawCallId.trim() !== "" ? opts.rawCallId.trim().slice(0, 120) : fallbackCallId(opts.sourceEventId, opts.callIndex);
5140
+ if (opts.contexts) {
5141
+ const local = extractLocalToolContext({ server, name, input: opts.input, cwd: opts.cwd });
5142
+ if (local) opts.contexts.push({ external_call_id, ...local });
5143
+ }
4988
5144
  return {
4989
- external_call_id: typeof opts.rawCallId === "string" && opts.rawCallId.trim() !== "" ? opts.rawCallId.trim().slice(0, 120) : fallbackCallId(opts.sourceEventId, opts.callIndex),
5145
+ external_call_id,
4990
5146
  session_id: opts.sessionId,
4991
5147
  source_event_id: opts.sourceEventId,
4992
5148
  agent: "claude_code",
@@ -5004,12 +5160,13 @@ function buildToolCallDraft(opts) {
5004
5160
  args_bytes: hashes.args_bytes,
5005
5161
  result_bytes: 0,
5006
5162
  model: opts.model,
5007
- command_families: commandFamiliesFor(server, name, opts.input)
5163
+ action: extractToolAction({ server, name, input: opts.input, cwd: opts.cwd })
5008
5164
  };
5009
5165
  }
5010
5166
  async function parseClaudeCodeJsonl(ctx) {
5011
5167
  const events = [];
5012
5168
  const toolCalls = [];
5169
+ const scriptContexts = [];
5013
5170
  const pendingByCallId = /* @__PURE__ */ new Map();
5014
5171
  let chunk = [];
5015
5172
  let emitted = 0;
@@ -5132,7 +5289,9 @@ async function parseClaudeCodeJsonl(ctx) {
5132
5289
  startedAt: a.timestamp,
5133
5290
  // Model verbatim from the issuing assistant message —
5134
5291
  // including "<synthetic>" (same rule as the event below).
5135
- model: a.message?.model ?? null
5292
+ model: a.message?.model ?? null,
5293
+ cwd,
5294
+ contexts: scriptContexts
5136
5295
  });
5137
5296
  const identity = toolIdentity(draft.server, draft.name);
5138
5297
  aggregate[identity] = (aggregate[identity] ?? 0) + 1;
@@ -5143,7 +5302,7 @@ async function parseClaudeCodeJsonl(ctx) {
5143
5302
  source_event_id: eventId,
5144
5303
  ts: a.timestamp,
5145
5304
  kind: "assistant_message",
5146
- tool: "claude_code",
5305
+ agent: "claude_code",
5147
5306
  provider: "anthropic",
5148
5307
  model: a.message?.model ?? null,
5149
5308
  session_id: sessionId,
@@ -5206,7 +5365,7 @@ async function parseClaudeCodeJsonl(ctx) {
5206
5365
  source_event_id: eventId,
5207
5366
  ts: u.timestamp,
5208
5367
  kind: "user_message",
5209
- tool: "claude_code",
5368
+ agent: "claude_code",
5210
5369
  provider: "anthropic",
5211
5370
  model: lastModel,
5212
5371
  session_id: sessionId,
@@ -5243,7 +5402,9 @@ async function parseClaudeCodeJsonl(ctx) {
5243
5402
  // No issuing assistant message on this line — attribute to the
5244
5403
  // session's last real model, same as user_message attribution
5245
5404
  // (lastModel never holds "<synthetic>", per the rule above).
5246
- model: lastModel
5405
+ model: lastModel,
5406
+ cwd,
5407
+ contexts: scriptContexts
5247
5408
  });
5248
5409
  toolCalls.push(draft);
5249
5410
  if (typeof t.id === "string" && t.id) pendingByCallId.set(t.id, draft);
@@ -5255,6 +5416,7 @@ async function parseClaudeCodeJsonl(ctx) {
5255
5416
  return {
5256
5417
  events,
5257
5418
  toolCalls,
5419
+ scriptContexts,
5258
5420
  stats: { rawLines, emittedEvents: emitted, skipped },
5259
5421
  sourceFile: ctx.sourceFile
5260
5422
  };
@@ -5273,22 +5435,14 @@ async function quickChecksum(path5) {
5273
5435
  for await (const chunk of stream) h.update(chunk);
5274
5436
  return { size: st.size, mtime: st.mtimeMs, tailHash: h.digest("hex").slice(0, 16) };
5275
5437
  }
5276
- var SHELL_TOOL_NAMES;
5277
5438
  var init_claude_code = __esm({
5278
5439
  "../../packages/parsers/src/claude-code/index.ts"() {
5279
5440
  "use strict";
5280
5441
  init_src();
5281
5442
  init_git();
5282
- init_shell_families();
5443
+ init_tool_action();
5283
5444
  init_tool_hash();
5284
5445
  init_types();
5285
- SHELL_TOOL_NAMES = /* @__PURE__ */ new Set([
5286
- "Bash",
5287
- "shell",
5288
- "local_shell_call",
5289
- "exec_command",
5290
- "run_terminal_cmd"
5291
- ]);
5292
5446
  }
5293
5447
  });
5294
5448
 
@@ -5301,20 +5455,6 @@ function deriveSessionIdFromRolloutPath(path5) {
5301
5455
  );
5302
5456
  return m ? m[1] ?? null : null;
5303
5457
  }
5304
- function commandFieldToString(cmd) {
5305
- if (typeof cmd === "string") return cmd || null;
5306
- if (Array.isArray(cmd)) {
5307
- const parts = cmd.filter((p) => typeof p === "string");
5308
- if (parts.length === 0) return null;
5309
- const head = (parts[0] ?? "").split("/").pop() ?? "";
5310
- const flag = parts[1] ?? "";
5311
- if (parts.length >= 3 && SHELL_WRAPPER_BINARIES.has(head) && /^-[a-z]*c[a-z]*$/i.test(flag)) {
5312
- return parts.slice(2).join("\n");
5313
- }
5314
- return parts.join(" ");
5315
- }
5316
- return null;
5317
- }
5318
5458
  function firstString(...values) {
5319
5459
  for (const v of values) {
5320
5460
  if (typeof v === "string" && v) return v;
@@ -5326,13 +5466,11 @@ function extractToolCallPayload(pt, p) {
5326
5466
  const failed = p.status === "failed";
5327
5467
  if (pt === "local_shell_call") {
5328
5468
  const action = p.action && typeof p.action === "object" ? p.action : null;
5329
- const command = commandFieldToString(action?.command);
5330
5469
  return {
5331
5470
  callId,
5332
5471
  server: "builtin",
5333
5472
  name: "shell",
5334
5473
  input: action,
5335
- commandFamilies: command ? extractCommandFamilies(command) : [],
5336
5474
  failed
5337
5475
  };
5338
5476
  }
@@ -5346,17 +5484,12 @@ function extractToolCallPayload(pt, p) {
5346
5484
  } catch {
5347
5485
  }
5348
5486
  }
5349
- if (SHELL_TOOL_NAMES2.has(observed)) {
5350
- const rec = input && typeof input === "object" && !Array.isArray(input) ? input : null;
5351
- const command = commandFieldToString(
5352
- rec?.command ?? rec?.cmd ?? (typeof input === "string" ? input : null)
5353
- );
5487
+ if (SHELL_TOOL_NAMES.has(observed)) {
5354
5488
  return {
5355
5489
  callId,
5356
5490
  server: "builtin",
5357
5491
  name: "shell",
5358
5492
  input,
5359
- commandFamilies: command ? extractCommandFamilies(command) : [],
5360
5493
  failed
5361
5494
  };
5362
5495
  }
@@ -5367,12 +5500,11 @@ function extractToolCallPayload(pt, p) {
5367
5500
  server: `mcp:${normalizeToolName(p.server).slice(0, 116)}`,
5368
5501
  name: normalizeToolName(observed),
5369
5502
  input,
5370
- commandFamilies: [],
5371
5503
  failed
5372
5504
  };
5373
5505
  }
5374
5506
  const { server, name } = splitObservedToolName(observed);
5375
- return { callId, server, name, input, commandFamilies: [], failed };
5507
+ return { callId, server, name, input, failed };
5376
5508
  }
5377
5509
  function outputIndicatesError(p) {
5378
5510
  const out = p.output ?? p.result;
@@ -5385,6 +5517,7 @@ function outputIndicatesError(p) {
5385
5517
  async function parseCodexRollout(ctx) {
5386
5518
  const events = [];
5387
5519
  const toolCalls = [];
5520
+ const scriptContexts = [];
5388
5521
  let chunk = [];
5389
5522
  let emitted = 0;
5390
5523
  const emit = async (e) => {
@@ -5467,8 +5600,16 @@ async function parseCodexRollout(ctx) {
5467
5600
  }
5468
5601
  const srcId = sourceEventId(ctx.deviceId, ctx.sourceFile, offsetAtLineStart);
5469
5602
  const { args_hash, signature_hash, args_bytes } = hashArgs(extracted.input);
5603
+ const externalCallId = (extracted.callId ?? fallbackCallId(srcId, 0)).slice(0, 120);
5604
+ const localCtx = extractLocalToolContext({
5605
+ server: extracted.server,
5606
+ name: extracted.name,
5607
+ input: extracted.input,
5608
+ cwd
5609
+ });
5610
+ if (localCtx) scriptContexts.push({ external_call_id: externalCallId, ...localCtx });
5470
5611
  const draft = {
5471
- external_call_id: (extracted.callId ?? fallbackCallId(srcId, 0)).slice(0, 120),
5612
+ external_call_id: externalCallId,
5472
5613
  session_id: sessionId,
5473
5614
  source_event_id: srcId,
5474
5615
  agent: "codex_cli",
@@ -5485,7 +5626,12 @@ async function parseCodexRollout(ctx) {
5485
5626
  args_bytes,
5486
5627
  result_bytes: 0,
5487
5628
  model,
5488
- command_families: extracted.commandFamilies
5629
+ action: extractToolAction({
5630
+ server: extracted.server,
5631
+ name: extracted.name,
5632
+ input: extracted.input,
5633
+ cwd
5634
+ })
5489
5635
  };
5490
5636
  toolCalls.push(draft);
5491
5637
  if (extracted.callId) openCalls.set(extracted.callId, draft);
@@ -5531,7 +5677,7 @@ async function parseCodexRollout(ctx) {
5531
5677
  source_event_id: sourceEventId(ctx.deviceId, ctx.sourceFile, offsetAtLineStart),
5532
5678
  ts,
5533
5679
  kind: "assistant_message",
5534
- tool: "codex_cli",
5680
+ agent: "codex_cli",
5535
5681
  provider: "openai",
5536
5682
  model,
5537
5683
  session_id: sessionId,
@@ -5571,7 +5717,7 @@ async function parseCodexRollout(ctx) {
5571
5717
  source_event_id: sourceEventId(ctx.deviceId, ctx.sourceFile, offsetAtLineStart),
5572
5718
  ts,
5573
5719
  kind: "user_message",
5574
- tool: "codex_cli",
5720
+ agent: "codex_cli",
5575
5721
  provider: "openai",
5576
5722
  model,
5577
5723
  session_id: sessionId,
@@ -5597,17 +5743,18 @@ async function parseCodexRollout(ctx) {
5597
5743
  return {
5598
5744
  events,
5599
5745
  toolCalls,
5746
+ scriptContexts,
5600
5747
  stats: { rawLines, emittedEvents: emitted, skipped },
5601
5748
  sourceFile: ctx.sourceFile
5602
5749
  };
5603
5750
  }
5604
- var TOOL_CALL_PAYLOAD_TYPES, TOOL_CALL_OUTPUT_PAYLOAD_TYPES, SHELL_TOOL_NAMES2, SHELL_WRAPPER_BINARIES;
5751
+ var TOOL_CALL_PAYLOAD_TYPES, TOOL_CALL_OUTPUT_PAYLOAD_TYPES, SHELL_TOOL_NAMES;
5605
5752
  var init_codex = __esm({
5606
5753
  "../../packages/parsers/src/codex/index.ts"() {
5607
5754
  "use strict";
5608
5755
  init_src();
5609
5756
  init_git();
5610
- init_shell_families();
5757
+ init_tool_action();
5611
5758
  init_tool_hash();
5612
5759
  init_types();
5613
5760
  TOOL_CALL_PAYLOAD_TYPES = /* @__PURE__ */ new Set([
@@ -5622,13 +5769,12 @@ var init_codex = __esm({
5622
5769
  "custom_tool_call_output",
5623
5770
  "mcp_tool_call_output"
5624
5771
  ]);
5625
- SHELL_TOOL_NAMES2 = /* @__PURE__ */ new Set([
5772
+ SHELL_TOOL_NAMES = /* @__PURE__ */ new Set([
5626
5773
  "shell",
5627
5774
  "local_shell_call",
5628
5775
  "exec_command",
5629
5776
  "run_terminal_cmd"
5630
5777
  ]);
5631
- SHELL_WRAPPER_BINARIES = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
5632
5778
  }
5633
5779
  });
5634
5780
 
@@ -7805,11 +7951,11 @@ async function discover(options = {}) {
7805
7951
  const v = process.env[env2];
7806
7952
  if (v) candidates.add(v);
7807
7953
  }
7808
- for (const extra of options.extraDataDirs?.[spec.tool] ?? []) candidates.add(expandPath(extra));
7954
+ for (const extra of options.extraDataDirs?.[spec.agent] ?? []) candidates.add(expandPath(extra));
7809
7955
  for (const p of candidates) {
7810
7956
  if (existsSync3(p) && statSync(p).isDirectory()) {
7811
7957
  installations.push({
7812
- tool: spec.tool,
7958
+ agent: spec.agent,
7813
7959
  install_method: "manual",
7814
7960
  binary_path: null,
7815
7961
  data_dir: p,
@@ -7828,7 +7974,7 @@ async function discover(options = {}) {
7828
7974
  if (existsSync3(p)) {
7829
7975
  const version = await safeVersionProbe(p);
7830
7976
  installations.push({
7831
- tool: spec.tool,
7977
+ agent: spec.agent,
7832
7978
  install_method: classifyInstallMethod(p, os2),
7833
7979
  binary_path: p,
7834
7980
  data_dir: null,
@@ -7848,7 +7994,7 @@ async function discover(options = {}) {
7848
7994
  const hit = apps.find((a) => a.bundleId === bid);
7849
7995
  if (hit) {
7850
7996
  installations.push({
7851
- tool: spec.tool,
7997
+ agent: spec.agent,
7852
7998
  install_method: "app_bundle",
7853
7999
  binary_path: hit.path,
7854
8000
  data_dir: null,
@@ -8076,7 +8222,7 @@ async function probeIdentities(os2) {
8076
8222
  function dedupeInstalls(list) {
8077
8223
  const seen = /* @__PURE__ */ new Map();
8078
8224
  for (const i of list) {
8079
- const k = `${i.tool}|${i.binary_path ?? ""}|${i.data_dir ?? ""}`;
8225
+ const k = `${i.agent}|${i.binary_path ?? ""}|${i.data_dir ?? ""}`;
8080
8226
  const prev = seen.get(k);
8081
8227
  if (!prev) {
8082
8228
  seen.set(k, i);
@@ -8103,7 +8249,7 @@ var init_discovery = __esm({
8103
8249
  H = (p) => p.startsWith("~") ? p.replace("~", homedir()) : p;
8104
8250
  SOURCES = [
8105
8251
  {
8106
- tool: "claude_code",
8252
+ agent: "claude_code",
8107
8253
  dataDirs: {
8108
8254
  macos: ["~/.claude"],
8109
8255
  linux: ["$XDG_CONFIG_HOME/claude", "~/.claude", "~/.config/claude"]
@@ -8115,7 +8261,7 @@ var init_discovery = __esm({
8115
8261
  ]
8116
8262
  },
8117
8263
  {
8118
- tool: "codex_cli",
8264
+ agent: "codex_cli",
8119
8265
  dataDirs: {
8120
8266
  macos: ["~/.codex"],
8121
8267
  linux: ["$XDG_CONFIG_HOME/codex", "~/.codex"]
@@ -8125,7 +8271,7 @@ var init_discovery = __esm({
8125
8271
  fileSignatures: [{ filenameGlob: "sessions/**/rollout-*.jsonl" }]
8126
8272
  },
8127
8273
  {
8128
- tool: "claude_desktop",
8274
+ agent: "claude_desktop",
8129
8275
  dataDirs: {
8130
8276
  macos: ["~/Library/Application Support/Claude"],
8131
8277
  linux: ["~/.config/Claude"]
@@ -8133,7 +8279,7 @@ var init_discovery = __esm({
8133
8279
  bundleIds: ["com.anthropic.claudeforbrowser", "com.anthropic.claudeelectron"]
8134
8280
  },
8135
8281
  {
8136
- tool: "cursor",
8282
+ agent: "cursor",
8137
8283
  dataDirs: {
8138
8284
  macos: ["~/Library/Application Support/Cursor"],
8139
8285
  linux: ["~/.config/Cursor"]
@@ -8141,7 +8287,7 @@ var init_discovery = __esm({
8141
8287
  bundleIds: ["co.anysphere.cursor", "com.todesktop.230313mzl4w4u92"]
8142
8288
  },
8143
8289
  {
8144
- tool: "windsurf",
8290
+ agent: "windsurf",
8145
8291
  dataDirs: {
8146
8292
  macos: ["~/Library/Application Support/Windsurf"],
8147
8293
  linux: ["~/.config/Windsurf"]
@@ -8149,7 +8295,7 @@ var init_discovery = __esm({
8149
8295
  bundleIds: ["com.codeium.windsurf"]
8150
8296
  },
8151
8297
  {
8152
- tool: "zed",
8298
+ agent: "zed",
8153
8299
  dataDirs: {
8154
8300
  macos: ["~/Library/Application Support/Zed", "~/.config/zed"],
8155
8301
  linux: ["~/.config/zed"]
@@ -8158,7 +8304,7 @@ var init_discovery = __esm({
8158
8304
  bundleIds: ["dev.zed.Zed"]
8159
8305
  },
8160
8306
  {
8161
- tool: "gemini_cli",
8307
+ agent: "gemini_cli",
8162
8308
  dataDirs: {
8163
8309
  macos: ["~/.gemini"],
8164
8310
  linux: ["~/.gemini"]
@@ -8166,18 +8312,18 @@ var init_discovery = __esm({
8166
8312
  binaries: ["gemini"]
8167
8313
  },
8168
8314
  {
8169
- tool: "aider",
8315
+ agent: "aider",
8170
8316
  dataDirs: { macos: ["~/.aider"], linux: ["~/.aider"] },
8171
8317
  binaries: ["aider"]
8172
8318
  },
8173
8319
  {
8174
- tool: "ollama",
8320
+ agent: "ollama",
8175
8321
  dataDirs: { macos: ["~/.ollama"], linux: ["~/.ollama"] },
8176
8322
  binaries: ["ollama"],
8177
8323
  bundleIds: ["com.electron.ollama"]
8178
8324
  },
8179
8325
  {
8180
- tool: "openclaw",
8326
+ agent: "openclaw",
8181
8327
  dataDirs: { macos: ["~/.openclaw", "~/.claw"], linux: ["~/.openclaw", "~/.claw"] },
8182
8328
  binaries: ["openclaw", "claw", "clawdbot", "moltbot"]
8183
8329
  }
@@ -8191,6 +8337,7 @@ var init_src2 = __esm({
8191
8337
  "use strict";
8192
8338
  init_types();
8193
8339
  init_git();
8340
+ init_tool_action();
8194
8341
  init_claude_code();
8195
8342
  init_codex();
8196
8343
  init_cursor();
@@ -12029,12 +12176,12 @@ var require_infra = __commonJS({
12029
12176
  var assert2 = __require("assert");
12030
12177
  var { utf8DecodeBytes } = require_encoding();
12031
12178
  function collectASequenceOfCodePoints(condition, input, position) {
12032
- let result = "";
12179
+ let result2 = "";
12033
12180
  while (position.position < input.length && condition(input[position.position])) {
12034
- result += input[position.position];
12181
+ result2 += input[position.position];
12035
12182
  position.position++;
12036
12183
  }
12037
- return result;
12184
+ return result2;
12038
12185
  }
12039
12186
  function collectASequenceOfCodePointsFast(char, input, position) {
12040
12187
  const idx = input.indexOf(char, position.position);
@@ -12079,16 +12226,16 @@ var require_infra = __commonJS({
12079
12226
  if ((2 << 15) - 1 > length) {
12080
12227
  return String.fromCharCode.apply(null, input);
12081
12228
  }
12082
- let result = "";
12229
+ let result2 = "";
12083
12230
  let i = 0;
12084
12231
  let addition = (2 << 15) - 1;
12085
12232
  while (i < length) {
12086
12233
  if (i + addition > length) {
12087
12234
  addition = length - i;
12088
12235
  }
12089
- result += String.fromCharCode.apply(null, input.subarray(i, i += addition));
12236
+ result2 += String.fromCharCode.apply(null, input.subarray(i, i += addition));
12090
12237
  }
12091
- return result;
12238
+ return result2;
12092
12239
  }
12093
12240
  var invalidIsomorphicEncodeValueRegex = /[^\x00-\xFF]/;
12094
12241
  function isomorphicEncode(input) {
@@ -12113,12 +12260,12 @@ var require_infra = __commonJS({
12113
12260
  return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1);
12114
12261
  }
12115
12262
  function serializeJavascriptValueToJSONString(value) {
12116
- const result = JSON.stringify(value);
12117
- if (result === void 0) {
12263
+ const result2 = JSON.stringify(value);
12264
+ if (result2 === void 0) {
12118
12265
  throw new TypeError("Value is not JSON serializable");
12119
12266
  }
12120
- assert2(typeof result === "string");
12121
- return result;
12267
+ assert2(typeof result2 === "string");
12268
+ return result2;
12122
12269
  }
12123
12270
  module.exports = {
12124
12271
  collectASequenceOfCodePoints,
@@ -12505,9 +12652,9 @@ var require_runtime_features = __commonJS({
12505
12652
  * @returns {boolean}
12506
12653
  */
12507
12654
  #detectRuntimeFeature(feature) {
12508
- const result = detectRuntimeFeature(feature);
12509
- this.#map.set(feature, result);
12510
- return result;
12655
+ const result2 = detectRuntimeFeature(feature);
12656
+ this.#map.set(feature, result2);
12657
+ return result2;
12511
12658
  }
12512
12659
  };
12513
12660
  var instance = new RuntimeFeatures();
@@ -12772,16 +12919,16 @@ var require_webidl = __commonJS({
12772
12919
  message: `${argument} ("${webidl.util.TypeValueToString(O)}") is not an Object.`
12773
12920
  });
12774
12921
  }
12775
- const result = {};
12922
+ const result2 = {};
12776
12923
  if (!types.isProxy(O)) {
12777
12924
  const keys2 = [...Object.getOwnPropertyNames(O), ...Object.getOwnPropertySymbols(O)];
12778
12925
  for (const key of keys2) {
12779
12926
  const keyName = webidl.util.Stringify(key);
12780
12927
  const typedKey = keyConverter(key, prefix, `Key ${keyName} in ${argument}`);
12781
12928
  const typedValue = valueConverter(O[key], prefix, `${argument}[${keyName}]`);
12782
- result[typedKey] = typedValue;
12929
+ result2[typedKey] = typedValue;
12783
12930
  }
12784
- return result;
12931
+ return result2;
12785
12932
  }
12786
12933
  const keys = Reflect.ownKeys(O);
12787
12934
  for (const key of keys) {
@@ -12789,10 +12936,10 @@ var require_webidl = __commonJS({
12789
12936
  if (desc?.enumerable) {
12790
12937
  const typedKey = keyConverter(key, prefix, argument);
12791
12938
  const typedValue = valueConverter(O[key], prefix, argument);
12792
- result[typedKey] = typedValue;
12939
+ result2[typedKey] = typedValue;
12793
12940
  }
12794
12941
  }
12795
- return result;
12942
+ return result2;
12796
12943
  };
12797
12944
  };
12798
12945
  webidl.interfaceConverter = function(TypeCheck, name) {
@@ -13488,20 +13635,20 @@ var require_util2 = __commonJS({
13488
13635
  }
13489
13636
  const { [keyIndex]: key, [valueIndex]: value } = values[index];
13490
13637
  this.#index = index + 1;
13491
- let result;
13638
+ let result2;
13492
13639
  switch (this.#kind) {
13493
13640
  case "key":
13494
- result = key;
13641
+ result2 = key;
13495
13642
  break;
13496
13643
  case "value":
13497
- result = value;
13644
+ result2 = value;
13498
13645
  break;
13499
13646
  case "key+value":
13500
- result = [key, value];
13647
+ result2 = [key, value];
13501
13648
  break;
13502
13649
  }
13503
13650
  return {
13504
- value: result,
13651
+ value: result2,
13505
13652
  done: false
13506
13653
  };
13507
13654
  }
@@ -14108,8 +14255,8 @@ var require_formdata_parser = __commonJS({
14108
14255
  throw parsingError("expected CRLF");
14109
14256
  }
14110
14257
  position.position += 2;
14111
- const result = parseMultipartFormDataHeaders(input, position);
14112
- let { name, filename, contentType, encoding } = result;
14258
+ const result2 = parseMultipartFormDataHeaders(input, position);
14259
+ let { name, filename, contentType, encoding } = result2;
14113
14260
  position.position += 2;
14114
14261
  let body;
14115
14262
  {
@@ -14529,8 +14676,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r
14529
14676
  if (action != null) {
14530
14677
  ;
14531
14678
  (async () => {
14532
- const result = action();
14533
- const iterator = result?.[Symbol.asyncIterator]?.();
14679
+ const result2 = action();
14680
+ const iterator = result2?.[Symbol.asyncIterator]?.();
14534
14681
  if (iterator) {
14535
14682
  for await (const bytes of iterator) {
14536
14683
  if (isErrored(stream)) break;
@@ -14538,8 +14685,8 @@ Content-Type: ${value.type || "application/octet-stream"}\r
14538
14685
  controller.enqueue(new Uint8Array(bytes));
14539
14686
  }
14540
14687
  }
14541
- } else if (result?.length && !isErrored(stream)) {
14542
- controller.enqueue(typeof result === "string" ? textEncoder.encode(result) : new Uint8Array(result));
14688
+ } else if (result2?.length && !isErrored(stream)) {
14689
+ controller.enqueue(typeof result2 === "string" ? textEncoder.encode(result2) : new Uint8Array(result2));
14543
14690
  }
14544
14691
  queueMicrotask(() => readableStreamClose(controller));
14545
14692
  })();
@@ -15905,17 +16052,17 @@ var require_client_h2 = __commonJS({
15905
16052
  }
15906
16053
  } = http2;
15907
16054
  function parseH2Headers(headers) {
15908
- const result = [];
16055
+ const result2 = [];
15909
16056
  for (const [name, value] of Object.entries(headers)) {
15910
16057
  if (Array.isArray(value)) {
15911
16058
  for (const subvalue of value) {
15912
- result.push(Buffer.from(name), Buffer.from(subvalue));
16059
+ result2.push(Buffer.from(name), Buffer.from(subvalue));
15913
16060
  }
15914
16061
  } else {
15915
- result.push(Buffer.from(name), Buffer.from(value));
16062
+ result2.push(Buffer.from(name), Buffer.from(value));
15916
16063
  }
15917
16064
  }
15918
- return result;
16065
+ return result2;
15919
16066
  }
15920
16067
  function connectH2(client, socket) {
15921
16068
  client[kSocket] = socket;
@@ -17525,11 +17672,11 @@ var require_balanced_pool = __commonJS({
17525
17672
  return this;
17526
17673
  }
17527
17674
  _updateBalancedPoolStats() {
17528
- let result = 0;
17675
+ let result2 = 0;
17529
17676
  for (let i = 0; i < this[kClients].length; i++) {
17530
- result = getGreatestCommonDivisor(this[kClients][i][kWeight], result);
17677
+ result2 = getGreatestCommonDivisor(this[kClients][i][kWeight], result2);
17531
17678
  }
17532
- this[kGreatestCommonDivisor] = result;
17679
+ this[kGreatestCommonDivisor] = result2;
17533
17680
  }
17534
17681
  removeUpstream(upstream) {
17535
17682
  const upstreamOrigin = util2.parseOrigin(upstream).origin;
@@ -17771,26 +17918,26 @@ var require_agent = __commonJS({
17771
17918
  if (this[kOrigins].size >= this[kOptions].maxOrigins && !this[kOrigins].has(key)) {
17772
17919
  throw new MaxOriginsReachedError();
17773
17920
  }
17774
- const result = this[kClients].get(key);
17775
- let dispatcher = result && result.dispatcher;
17921
+ const result2 = this[kClients].get(key);
17922
+ let dispatcher = result2 && result2.dispatcher;
17776
17923
  if (!dispatcher) {
17777
17924
  const closeClientIfUnused = (connected) => {
17778
- const result2 = this[kClients].get(key);
17779
- if (result2) {
17780
- if (connected) result2.count -= 1;
17781
- if (result2.count <= 0) {
17925
+ const result3 = this[kClients].get(key);
17926
+ if (result3) {
17927
+ if (connected) result3.count -= 1;
17928
+ if (result3.count <= 0) {
17782
17929
  this[kClients].delete(key);
17783
- if (!result2.dispatcher.destroyed) {
17784
- result2.dispatcher.close();
17930
+ if (!result3.dispatcher.destroyed) {
17931
+ result3.dispatcher.close();
17785
17932
  }
17786
17933
  }
17787
17934
  this[kOrigins].delete(key);
17788
17935
  }
17789
17936
  };
17790
17937
  dispatcher = this[kFactory](opts.origin, this[kOptions]).on("drain", this[kOnDrain]).on("connect", (origin, targets) => {
17791
- const result2 = this[kClients].get(key);
17792
- if (result2) {
17793
- result2.count += 1;
17938
+ const result3 = this[kClients].get(key);
17939
+ if (result3) {
17940
+ result3.count += 1;
17794
17941
  }
17795
17942
  this[kOnConnect](origin, targets);
17796
17943
  }).on("disconnect", (origin, targets, err) => {
@@ -20722,20 +20869,20 @@ var require_mock_utils = __commonJS({
20722
20869
  }
20723
20870
  function generateKeyValues(data) {
20724
20871
  const keys = Object.keys(data);
20725
- const result = [];
20872
+ const result2 = [];
20726
20873
  for (let i = 0; i < keys.length; ++i) {
20727
20874
  const key = keys[i];
20728
20875
  const value = data[key];
20729
20876
  const name = Buffer.from(`${key}`);
20730
20877
  if (Array.isArray(value)) {
20731
20878
  for (let j = 0; j < value.length; ++j) {
20732
- result.push(name, Buffer.from(`${value[j]}`));
20879
+ result2.push(name, Buffer.from(`${value[j]}`));
20733
20880
  }
20734
20881
  } else {
20735
- result.push(name, Buffer.from(`${value}`));
20882
+ result2.push(name, Buffer.from(`${value}`));
20736
20883
  }
20737
20884
  }
20738
- return result;
20885
+ return result2;
20739
20886
  }
20740
20887
  function getStatusText(statusCode) {
20741
20888
  return STATUS_CODES[statusCode] || "unknown";
@@ -21209,16 +21356,16 @@ var require_mock_call_history = __commonJS({
21209
21356
  }
21210
21357
  toString() {
21211
21358
  const options = { betweenKeyValueSeparator: "->", betweenPairSeparator: "|" };
21212
- let result = "";
21359
+ let result2 = "";
21213
21360
  this.toMap().forEach((value, key) => {
21214
21361
  if (typeof value === "string" || value === void 0 || value === null) {
21215
- result = `${result}${key}${options.betweenKeyValueSeparator}${value}${options.betweenPairSeparator}`;
21362
+ result2 = `${result2}${key}${options.betweenKeyValueSeparator}${value}${options.betweenPairSeparator}`;
21216
21363
  }
21217
21364
  if (typeof value === "object" && value !== null || Array.isArray(value)) {
21218
- result = `${result}${key}${options.betweenKeyValueSeparator}${JSON.stringify(value)}${options.betweenPairSeparator}`;
21365
+ result2 = `${result2}${key}${options.betweenKeyValueSeparator}${JSON.stringify(value)}${options.betweenPairSeparator}`;
21219
21366
  }
21220
21367
  });
21221
- return result.slice(0, -1);
21368
+ return result2.slice(0, -1);
21222
21369
  }
21223
21370
  };
21224
21371
  var MockCallHistory = class {
@@ -21561,20 +21708,20 @@ var require_mock_agent = __commonJS({
21561
21708
  return this[kOptions] && this[kOptions].connections === 1 ? new MockClient(origin, mockOptions) : new MockPool(origin, mockOptions);
21562
21709
  }
21563
21710
  [kMockAgentGet](origin) {
21564
- const result = this[kClients].get(origin);
21565
- if (result?.dispatcher) {
21566
- return result.dispatcher;
21711
+ const result2 = this[kClients].get(origin);
21712
+ if (result2?.dispatcher) {
21713
+ return result2.dispatcher;
21567
21714
  }
21568
21715
  if (typeof origin !== "string") {
21569
21716
  const dispatcher = this[kFactory]("http://localhost:9999");
21570
21717
  this[kMockAgentSet](origin, dispatcher);
21571
21718
  return dispatcher;
21572
21719
  }
21573
- for (const [keyMatcher, result2] of Array.from(this[kClients])) {
21574
- if (result2 && typeof keyMatcher !== "string" && matchValue(keyMatcher, origin)) {
21720
+ for (const [keyMatcher, result3] of Array.from(this[kClients])) {
21721
+ if (result3 && typeof keyMatcher !== "string" && matchValue(keyMatcher, origin)) {
21575
21722
  const dispatcher = this[kFactory](origin);
21576
21723
  this[kMockAgentSet](origin, dispatcher);
21577
- dispatcher[kDispatches] = result2.dispatcher[kDispatches];
21724
+ dispatcher[kDispatches] = result3.dispatcher[kDispatches];
21578
21725
  return dispatcher;
21579
21726
  }
21580
21727
  }
@@ -21584,7 +21731,7 @@ var require_mock_agent = __commonJS({
21584
21731
  }
21585
21732
  pendingInterceptors() {
21586
21733
  const mockAgentClients = this[kClients];
21587
- return Array.from(mockAgentClients.entries()).flatMap(([origin, result]) => result.dispatcher[kDispatches].map((dispatch) => ({ ...dispatch, origin }))).filter(({ pending: pending2 }) => pending2);
21734
+ return Array.from(mockAgentClients.entries()).flatMap(([origin, result2]) => result2.dispatcher[kDispatches].map((dispatch) => ({ ...dispatch, origin }))).filter(({ pending: pending2 }) => pending2);
21588
21735
  }
21589
21736
  assertNoPendingInterceptors({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) {
21590
21737
  const pending2 = this.pendingInterceptors();
@@ -21694,7 +21841,7 @@ var require_snapshot_utils = __commonJS({
21694
21841
  var require_snapshot_recorder = __commonJS({
21695
21842
  "../../node_modules/.pnpm/undici@7.25.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
21696
21843
  "use strict";
21697
- var { writeFile, readFile, mkdir: mkdir2 } = __require("fs/promises");
21844
+ var { writeFile: writeFile2, readFile: readFile2, mkdir: mkdir3 } = __require("fs/promises");
21698
21845
  var { dirname: dirname9, resolve: resolve6 } = __require("path");
21699
21846
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
21700
21847
  var { InvalidArgumentError, UndiciError } = require_errors();
@@ -21896,7 +22043,7 @@ var require_snapshot_recorder = __commonJS({
21896
22043
  throw new InvalidArgumentError("Snapshot path is required");
21897
22044
  }
21898
22045
  try {
21899
- const data = await readFile(resolve6(path5), "utf8");
22046
+ const data = await readFile2(resolve6(path5), "utf8");
21900
22047
  const parsed = JSON.parse(data);
21901
22048
  if (Array.isArray(parsed)) {
21902
22049
  this.#snapshots.clear();
@@ -21926,12 +22073,12 @@ var require_snapshot_recorder = __commonJS({
21926
22073
  throw new InvalidArgumentError("Snapshot path is required");
21927
22074
  }
21928
22075
  const resolvedPath = resolve6(path5);
21929
- await mkdir2(dirname9(resolvedPath), { recursive: true });
22076
+ await mkdir3(dirname9(resolvedPath), { recursive: true });
21930
22077
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
21931
22078
  hash,
21932
22079
  snapshot
21933
22080
  }));
21934
- await writeFile(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
22081
+ await writeFile2(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
21935
22082
  }
21936
22083
  /**
21937
22084
  * Clears all recorded snapshots
@@ -23713,8 +23860,8 @@ var require_date = __commonJS({
23713
23860
  }
23714
23861
  second = (code1 - 48) * 10 + (code2 - 48);
23715
23862
  }
23716
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
23717
- return result.getUTCDay() === weekday ? result : void 0;
23863
+ const result2 = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
23864
+ return result2.getUTCDay() === weekday ? result2 : void 0;
23718
23865
  }
23719
23866
  function parseAscTimeDate(date) {
23720
23867
  if (date.length !== 24 || date[7] !== " " || date[10] !== " " || date[19] !== " ") {
@@ -23876,8 +24023,8 @@ var require_date = __commonJS({
23876
24023
  return void 0;
23877
24024
  }
23878
24025
  const year = (yearDigit1 - 48) * 1e3 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48);
23879
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
23880
- return result.getUTCDay() === weekday ? result : void 0;
24026
+ const result2 = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
24027
+ return result2.getUTCDay() === weekday ? result2 : void 0;
23881
24028
  }
23882
24029
  function parseRfc850Date(date) {
23883
24030
  let commaIndex = -1;
@@ -24026,8 +24173,8 @@ var require_date = __commonJS({
24026
24173
  }
24027
24174
  second = (code1 - 48) * 10 + (code2 - 48);
24028
24175
  }
24029
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
24030
- return result.getUTCDay() === weekday ? result : void 0;
24176
+ const result2 = new Date(Date.UTC(year, monthIdx, day, hour, minute, second));
24177
+ return result2.getUTCDay() === weekday ? result2 : void 0;
24031
24178
  }
24032
24179
  module.exports = {
24033
24180
  parseHttpDate
@@ -24231,11 +24378,11 @@ var require_cache_handler = __commonJS({
24231
24378
  });
24232
24379
  }
24233
24380
  };
24234
- const result = this.#store.get(this.#cacheKey);
24235
- if (result && typeof result.then === "function") {
24236
- result.then(handle304);
24381
+ const result2 = this.#store.get(this.#cacheKey);
24382
+ if (result2 && typeof result2.then === "function") {
24383
+ result2.then(handle304);
24237
24384
  } else {
24238
- handle304(result);
24385
+ handle304(result2);
24239
24386
  }
24240
24387
  } else {
24241
24388
  if (typeof resHeaders.etag === "string" && isEtagUsable(resHeaders.etag)) {
@@ -24704,11 +24851,11 @@ var require_cache2 = __commonJS({
24704
24851
  }
24705
24852
  var nop = () => {
24706
24853
  };
24707
- function needsRevalidation(result, cacheControlDirectives, { headers = {} }) {
24854
+ function needsRevalidation(result2, cacheControlDirectives, { headers = {} }) {
24708
24855
  if (cacheControlDirectives?.["no-cache"]) {
24709
24856
  return true;
24710
24857
  }
24711
- if (result.cacheControlDirectives?.["no-cache"] && !Array.isArray(result.cacheControlDirectives["no-cache"])) {
24858
+ if (result2.cacheControlDirectives?.["no-cache"] && !Array.isArray(result2.cacheControlDirectives["no-cache"])) {
24712
24859
  return true;
24713
24860
  }
24714
24861
  if (headers["if-modified-since"] || headers["if-none-match"]) {
@@ -24716,29 +24863,29 @@ var require_cache2 = __commonJS({
24716
24863
  }
24717
24864
  return false;
24718
24865
  }
24719
- function isStale(result, cacheControlDirectives) {
24866
+ function isStale(result2, cacheControlDirectives) {
24720
24867
  const now = Date.now();
24721
- if (now > result.staleAt) {
24868
+ if (now > result2.staleAt) {
24722
24869
  if (cacheControlDirectives?.["max-stale"]) {
24723
- const gracePeriod = result.staleAt + cacheControlDirectives["max-stale"] * 1e3;
24870
+ const gracePeriod = result2.staleAt + cacheControlDirectives["max-stale"] * 1e3;
24724
24871
  return now > gracePeriod;
24725
24872
  }
24726
24873
  return true;
24727
24874
  }
24728
24875
  if (cacheControlDirectives?.["min-fresh"]) {
24729
- const timeLeftTillStale = result.staleAt - now;
24876
+ const timeLeftTillStale = result2.staleAt - now;
24730
24877
  const threshold = cacheControlDirectives["min-fresh"] * 1e3;
24731
24878
  return timeLeftTillStale <= threshold;
24732
24879
  }
24733
24880
  return false;
24734
24881
  }
24735
- function withinStaleWhileRevalidateWindow(result) {
24736
- const staleWhileRevalidate = result.cacheControlDirectives?.["stale-while-revalidate"];
24882
+ function withinStaleWhileRevalidateWindow(result2) {
24883
+ const staleWhileRevalidate = result2.cacheControlDirectives?.["stale-while-revalidate"];
24737
24884
  if (!staleWhileRevalidate) {
24738
24885
  return false;
24739
24886
  }
24740
24887
  const now = Date.now();
24741
- const staleWhileRevalidateExpiry = result.staleAt + staleWhileRevalidate * 1e3;
24888
+ const staleWhileRevalidateExpiry = result2.staleAt + staleWhileRevalidate * 1e3;
24742
24889
  return now <= staleWhileRevalidateExpiry;
24743
24890
  }
24744
24891
  function handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl) {
@@ -24771,8 +24918,8 @@ var require_cache2 = __commonJS({
24771
24918
  }
24772
24919
  return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler));
24773
24920
  }
24774
- function sendCachedValue(handler, opts, result, age, context, isStale2) {
24775
- const stream = util2.isStream(result.body) ? result.body : Readable3.from(result.body ?? []);
24921
+ function sendCachedValue(handler, opts, result2, age, context, isStale2) {
24922
+ const stream = util2.isStream(result2.body) ? result2.body : Readable3.from(result2.body ?? []);
24776
24923
  assert2(!stream.destroyed, "stream should not be destroyed");
24777
24924
  assert2(!stream.readableDidRead, "stream should not be readableDidRead");
24778
24925
  const controller = {
@@ -24812,11 +24959,11 @@ var require_cache2 = __commonJS({
24812
24959
  if (stream.destroyed) {
24813
24960
  return;
24814
24961
  }
24815
- const headers = { ...result.headers, age: String(age) };
24962
+ const headers = { ...result2.headers, age: String(age) };
24816
24963
  if (isStale2) {
24817
24964
  headers.warning = '110 - "response is stale"';
24818
24965
  }
24819
- handler.onResponseStart?.(controller, result.statusCode, headers, result.statusMessage);
24966
+ handler.onResponseStart?.(controller, result2.statusCode, headers, result2.statusMessage);
24820
24967
  if (opts.method === "HEAD") {
24821
24968
  stream.destroy();
24822
24969
  } else {
@@ -24825,38 +24972,38 @@ var require_cache2 = __commonJS({
24825
24972
  });
24826
24973
  }
24827
24974
  }
24828
- function handleResult2(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl, result) {
24829
- if (!result) {
24975
+ function handleResult2(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl, result2) {
24976
+ if (!result2) {
24830
24977
  return handleUncachedResponse(dispatch, globalOpts, cacheKey, handler, opts, reqCacheControl);
24831
24978
  }
24832
24979
  const now = Date.now();
24833
- if (now > result.deleteAt) {
24980
+ if (now > result2.deleteAt) {
24834
24981
  return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler));
24835
24982
  }
24836
- const age = Math.round((now - result.cachedAt) / 1e3);
24983
+ const age = Math.round((now - result2.cachedAt) / 1e3);
24837
24984
  if (reqCacheControl?.["max-age"] && age >= reqCacheControl["max-age"]) {
24838
24985
  return dispatch(opts, handler);
24839
24986
  }
24840
- const stale = isStale(result, reqCacheControl);
24841
- const revalidate = needsRevalidation(result, reqCacheControl, opts);
24987
+ const stale = isStale(result2, reqCacheControl);
24988
+ const revalidate = needsRevalidation(result2, reqCacheControl, opts);
24842
24989
  if (stale || revalidate) {
24843
24990
  if (util2.isStream(opts.body) && util2.bodyLength(opts.body) !== 0) {
24844
24991
  return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler));
24845
24992
  }
24846
- if (!revalidate && withinStaleWhileRevalidateWindow(result)) {
24847
- sendCachedValue(handler, opts, result, age, null, true);
24993
+ if (!revalidate && withinStaleWhileRevalidateWindow(result2)) {
24994
+ sendCachedValue(handler, opts, result2, age, null, true);
24848
24995
  queueMicrotask(() => {
24849
24996
  const headers2 = {
24850
24997
  ...opts.headers,
24851
- "if-modified-since": new Date(result.cachedAt).toUTCString()
24998
+ "if-modified-since": new Date(result2.cachedAt).toUTCString()
24852
24999
  };
24853
- if (result.etag) {
24854
- headers2["if-none-match"] = result.etag;
25000
+ if (result2.etag) {
25001
+ headers2["if-none-match"] = result2.etag;
24855
25002
  }
24856
- if (result.vary) {
24857
- for (const key in result.vary) {
24858
- if (result.vary[key] != null) {
24859
- headers2[key] = result.vary[key];
25003
+ if (result2.vary) {
25004
+ for (const key in result2.vary) {
25005
+ if (result2.vary[key] != null) {
25006
+ headers2[key] = result2.vary[key];
24860
25007
  }
24861
25008
  }
24862
25009
  }
@@ -24885,21 +25032,21 @@ var require_cache2 = __commonJS({
24885
25032
  return true;
24886
25033
  }
24887
25034
  let withinStaleIfErrorThreshold = false;
24888
- const staleIfErrorExpiry = result.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"];
25035
+ const staleIfErrorExpiry = result2.cacheControlDirectives["stale-if-error"] ?? reqCacheControl?.["stale-if-error"];
24889
25036
  if (staleIfErrorExpiry) {
24890
- withinStaleIfErrorThreshold = now < result.staleAt + staleIfErrorExpiry * 1e3;
25037
+ withinStaleIfErrorThreshold = now < result2.staleAt + staleIfErrorExpiry * 1e3;
24891
25038
  }
24892
25039
  const headers = {
24893
25040
  ...opts.headers,
24894
- "if-modified-since": new Date(result.cachedAt).toUTCString()
25041
+ "if-modified-since": new Date(result2.cachedAt).toUTCString()
24895
25042
  };
24896
- if (result.etag) {
24897
- headers["if-none-match"] = result.etag;
25043
+ if (result2.etag) {
25044
+ headers["if-none-match"] = result2.etag;
24898
25045
  }
24899
- if (result.vary) {
24900
- for (const key in result.vary) {
24901
- if (result.vary[key] != null) {
24902
- headers[key] = result.vary[key];
25046
+ if (result2.vary) {
25047
+ for (const key in result2.vary) {
25048
+ if (result2.vary[key] != null) {
25049
+ headers[key] = result2.vary[key];
24903
25050
  }
24904
25051
  }
24905
25052
  }
@@ -24911,9 +25058,9 @@ var require_cache2 = __commonJS({
24911
25058
  new CacheRevalidationHandler(
24912
25059
  (success, context) => {
24913
25060
  if (success) {
24914
- sendCachedValue(handler, opts, result, age, context, stale);
24915
- } else if (util2.isStream(result.body)) {
24916
- result.body.on("error", nop).destroy();
25061
+ sendCachedValue(handler, opts, result2, age, context, stale);
25062
+ } else if (util2.isStream(result2.body)) {
25063
+ result2.body.on("error", nop).destroy();
24917
25064
  }
24918
25065
  },
24919
25066
  new CacheHandler(globalOpts, cacheKey, handler),
@@ -24924,7 +25071,7 @@ var require_cache2 = __commonJS({
24924
25071
  if (util2.isStream(opts.body)) {
24925
25072
  opts.body.on("error", nop).destroy();
24926
25073
  }
24927
- sendCachedValue(handler, opts, result, age, null, false);
25074
+ sendCachedValue(handler, opts, result2, age, null, false);
24928
25075
  }
24929
25076
  module.exports = (opts = {}) => {
24930
25077
  const {
@@ -24986,16 +25133,16 @@ var require_cache2 = __commonJS({
24986
25133
  return dispatch(opts2, handler);
24987
25134
  }
24988
25135
  const cacheKey = makeCacheKey(opts2);
24989
- const result = store2.get(cacheKey);
24990
- if (result && typeof result.then === "function") {
24991
- return result.then((result2) => handleResult2(
25136
+ const result2 = store2.get(cacheKey);
25137
+ if (result2 && typeof result2.then === "function") {
25138
+ return result2.then((result3) => handleResult2(
24992
25139
  dispatch,
24993
25140
  globalOpts,
24994
25141
  cacheKey,
24995
25142
  handler,
24996
25143
  opts2,
24997
25144
  reqCacheControl,
24998
- result2
25145
+ result3
24999
25146
  ));
25000
25147
  } else {
25001
25148
  return handleResult2(
@@ -25005,7 +25152,7 @@ var require_cache2 = __commonJS({
25005
25152
  handler,
25006
25153
  opts2,
25007
25154
  reqCacheControl,
25008
- result
25155
+ result2
25009
25156
  );
25010
25157
  }
25011
25158
  };
@@ -25098,8 +25245,8 @@ var require_decompress = __commonJS({
25098
25245
  decompressor.on("readable", () => {
25099
25246
  let chunk;
25100
25247
  while ((chunk = decompressor.read()) !== null) {
25101
- const result = super.onResponseData(controller, chunk);
25102
- if (result === false) {
25248
+ const result2 = super.onResponseData(controller, chunk);
25249
+ if (result2 === false) {
25103
25250
  break;
25104
25251
  }
25105
25252
  }
@@ -27719,12 +27866,12 @@ var require_subresource_integrity = __commonJS({
27719
27866
  return false;
27720
27867
  };
27721
27868
  function getStrongestMetadata(metadataList) {
27722
- const result = [];
27869
+ const result2 = [];
27723
27870
  let strongest = null;
27724
27871
  for (const item of metadataList) {
27725
27872
  assert2(isValidSRIHashAlgorithm(item.alg), "Invalid SRI hash algorithm token");
27726
- if (result.length === 0) {
27727
- result.push(item);
27873
+ if (result2.length === 0) {
27874
+ result2.push(item);
27728
27875
  strongest = item;
27729
27876
  continue;
27730
27877
  }
@@ -27739,16 +27886,16 @@ var require_subresource_integrity = __commonJS({
27739
27886
  continue;
27740
27887
  } else if (newAlgorithmIndex > currentAlgorithmIndex) {
27741
27888
  strongest = item;
27742
- result[0] = item;
27743
- result.length = 1;
27889
+ result2[0] = item;
27890
+ result2.length = 1;
27744
27891
  } else {
27745
- result.push(item);
27892
+ result2.push(item);
27746
27893
  }
27747
27894
  }
27748
- return result;
27895
+ return result2;
27749
27896
  }
27750
27897
  function parseMetadata(metadata) {
27751
- const result = [];
27898
+ const result2 = [];
27752
27899
  for (const item of metadata.split(" ")) {
27753
27900
  const expressionAndOptions = item.split("?", 1);
27754
27901
  const algorithmExpression = expressionAndOptions[0];
@@ -27765,9 +27912,9 @@ var require_subresource_integrity = __commonJS({
27765
27912
  alg: algorithm,
27766
27913
  val: base64Value
27767
27914
  };
27768
- result.push(metadata2);
27915
+ result2.push(metadata2);
27769
27916
  }
27770
- return result;
27917
+ return result2;
27771
27918
  }
27772
27919
  var applyAlgorithmToBytes = (algorithm, bytes) => {
27773
27920
  return crypto3.hash(algorithm, bytes, "base64");
@@ -31716,10 +31863,10 @@ var require_websocket = __commonJS({
31716
31863
  const wasClean = this.#handler.closeState.has(sentCloseFrameState.SENT) && this.#handler.closeState.has(sentCloseFrameState.RECEIVED);
31717
31864
  let code = 1005;
31718
31865
  let reason = "";
31719
- const result = this.#parser?.closingInfo;
31720
- if (result && !result.error) {
31721
- code = result.code ?? 1005;
31722
- reason = result.reason;
31866
+ const result2 = this.#parser?.closingInfo;
31867
+ if (result2 && !result2.error) {
31868
+ code = result2.code ?? 1005;
31869
+ reason = result2.reason;
31723
31870
  }
31724
31871
  this.#handler.readyState = states.CLOSED;
31725
31872
  if (!this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
@@ -32156,12 +32303,12 @@ var require_websocketstream = __commonJS({
32156
32303
  if (!this.#handler.wasEverConnected) {
32157
32304
  this.#openedPromise.reject(new WebSocketError("Socket never opened"));
32158
32305
  }
32159
- const result = this.#parser?.closingInfo;
32160
- let code = result?.code ?? 1005;
32306
+ const result2 = this.#parser?.closingInfo;
32307
+ let code = result2?.code ?? 1005;
32161
32308
  if (!this.#handler.closeState.has(sentCloseFrameState.SENT) && !this.#handler.closeState.has(sentCloseFrameState.RECEIVED)) {
32162
32309
  code = 1006;
32163
32310
  }
32164
- const reason = result?.reason == null ? "" : utf8DecodeBytes(Buffer.from(result.reason));
32311
+ const reason = result2?.reason == null ? "" : utf8DecodeBytes(Buffer.from(result2.reason));
32165
32312
  if (wasClean) {
32166
32313
  this.#readableStreamController.close();
32167
32314
  if (!this.#writableStream.locked) {
@@ -33006,10 +33153,11 @@ function expBackoff(attempt) {
33006
33153
  const i = Math.min(Math.max(attempt, 0), BACKOFF_MS.length - 1);
33007
33154
  return BACKOFF_MS[i];
33008
33155
  }
33009
- var BACKOFF_MS, BACKSTOP_SCAN_MS;
33156
+ var INGEST_BATCH_MAX_EVENTS, BACKOFF_MS, BACKSTOP_SCAN_MS;
33010
33157
  var init_config = __esm({
33011
33158
  "../../packages/companion-core/src/config/index.ts"() {
33012
33159
  "use strict";
33160
+ INGEST_BATCH_MAX_EVENTS = 1e3;
33013
33161
  BACKOFF_MS = [1e3, 2500, 5e3, 1e4, 2e4, 6e4];
33014
33162
  BACKSTOP_SCAN_MS = 5 * 6e4;
33015
33163
  }
@@ -33132,7 +33280,7 @@ var init_http = __esm({
33132
33280
  },
33133
33281
  // wellFormedStringify, not JSON.stringify: a truncated-emoji
33134
33282
  // lone surrogate in any excerpt 400s the whole batch on the
33135
- // serde_json side. See the helper's doc comment.
33283
+ // ingest server's strict JSON decoder. See the helper's doc comment.
33136
33284
  body: wellFormedStringify(batch)
33137
33285
  });
33138
33286
  } catch (err) {
@@ -33285,8 +33433,8 @@ var require_main = __commonJS({
33285
33433
  options = options || {};
33286
33434
  const vaultPath = _vaultPath(options);
33287
33435
  options.path = vaultPath;
33288
- const result = DotenvModule.configDotenv(options);
33289
- if (!result.parsed) {
33436
+ const result2 = DotenvModule.configDotenv(options);
33437
+ if (!result2.parsed) {
33290
33438
  const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
33291
33439
  err.code = "MISSING_DATA";
33292
33440
  throw err;
@@ -33297,7 +33445,7 @@ var require_main = __commonJS({
33297
33445
  for (let i = 0; i < length; i++) {
33298
33446
  try {
33299
33447
  const key = keys[i].trim();
33300
- const attrs = _instructions(result, key);
33448
+ const attrs = _instructions(result2, key);
33301
33449
  decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
33302
33450
  break;
33303
33451
  } catch (error) {
@@ -33326,7 +33474,7 @@ var require_main = __commonJS({
33326
33474
  }
33327
33475
  return "";
33328
33476
  }
33329
- function _instructions(result, dotenvKey) {
33477
+ function _instructions(result2, dotenvKey) {
33330
33478
  let uri;
33331
33479
  try {
33332
33480
  uri = new URL(dotenvKey);
@@ -33351,7 +33499,7 @@ var require_main = __commonJS({
33351
33499
  throw err;
33352
33500
  }
33353
33501
  const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
33354
- const ciphertext = result.parsed[environmentKey];
33502
+ const ciphertext = result2.parsed[environmentKey];
33355
33503
  if (!ciphertext) {
33356
33504
  const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
33357
33505
  err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
@@ -34239,14 +34387,14 @@ var init_temp = __esm({
34239
34387
  }
34240
34388
  },
34241
34389
  truncate: (filePath) => {
34242
- const basename4 = path2.basename(filePath);
34243
- if (basename4.length <= LIMIT_BASENAME_LENGTH)
34390
+ const basename5 = path2.basename(filePath);
34391
+ if (basename5.length <= LIMIT_BASENAME_LENGTH)
34244
34392
  return filePath;
34245
- const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename4);
34393
+ const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename5);
34246
34394
  if (!truncable)
34247
34395
  return filePath;
34248
- const truncationLength = basename4.length - LIMIT_BASENAME_LENGTH;
34249
- return `${filePath.slice(0, -basename4.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
34396
+ const truncationLength = basename5.length - LIMIT_BASENAME_LENGTH;
34397
+ return `${filePath.slice(0, -basename5.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
34250
34398
  }
34251
34399
  };
34252
34400
  node_default(Temp.purgeSyncAll);
@@ -36238,10 +36386,10 @@ var require_keyword = __commonJS({
36238
36386
  if (def.async && !schemaEnv.$async)
36239
36387
  throw new Error("async keyword in sync schema");
36240
36388
  }
36241
- function useKeyword(gen, keyword, result) {
36242
- if (result === void 0)
36389
+ function useKeyword(gen, keyword, result2) {
36390
+ if (result2 === void 0)
36243
36391
  throw new Error(`keyword "${keyword}" failed to compile`);
36244
- return gen.scopeValue("keyword", typeof result == "function" ? { ref: result } : { ref: result, code: (0, codegen_1.stringify)(result) });
36392
+ return gen.scopeValue("keyword", typeof result2 == "function" ? { ref: result2 } : { ref: result2, code: (0, codegen_1.stringify)(result2) });
36245
36393
  }
36246
36394
  function validSchemaType(schema, schemaType, allowUndefined = false) {
36247
36395
  return !schemaType.length || schemaType.some((st) => st === "array" ? Array.isArray(schema) : st === "object" ? schema && typeof schema == "object" && !Array.isArray(schema) : typeof schema == st || allowUndefined && typeof schema == "undefined");
@@ -42015,7 +42163,7 @@ var init_debounce_fn = __esm({
42015
42163
  }
42016
42164
  let timeout;
42017
42165
  let maxTimeout;
42018
- let result;
42166
+ let result2;
42019
42167
  const debouncedFunction = function(...arguments_) {
42020
42168
  const context = this;
42021
42169
  const later = () => {
@@ -42025,7 +42173,7 @@ var init_debounce_fn = __esm({
42025
42173
  maxTimeout = void 0;
42026
42174
  }
42027
42175
  if (after) {
42028
- result = inputFunction.apply(context, arguments_);
42176
+ result2 = inputFunction.apply(context, arguments_);
42029
42177
  }
42030
42178
  };
42031
42179
  const maxLater = () => {
@@ -42035,7 +42183,7 @@ var init_debounce_fn = __esm({
42035
42183
  timeout = void 0;
42036
42184
  }
42037
42185
  if (after) {
42038
- result = inputFunction.apply(context, arguments_);
42186
+ result2 = inputFunction.apply(context, arguments_);
42039
42187
  }
42040
42188
  };
42041
42189
  const shouldCallNow = before && !timeout;
@@ -42045,9 +42193,9 @@ var init_debounce_fn = __esm({
42045
42193
  maxTimeout = setTimeout(maxLater, maxWait);
42046
42194
  }
42047
42195
  if (shouldCallNow) {
42048
- result = inputFunction.apply(context, arguments_);
42196
+ result2 = inputFunction.apply(context, arguments_);
42049
42197
  }
42050
- return result;
42198
+ return result2;
42051
42199
  };
42052
42200
  mimicFunction(debouncedFunction, inputFunction);
42053
42201
  debouncedFunction.cancel = () => {
@@ -43041,9 +43189,9 @@ var require_range = __commonJS({
43041
43189
  if (rangeMap.size > 1 && rangeMap.has("")) {
43042
43190
  rangeMap.delete("");
43043
43191
  }
43044
- const result = [...rangeMap.values()];
43045
- cache.set(memoKey, result);
43046
- return result;
43192
+ const result2 = [...rangeMap.values()];
43193
+ cache.set(memoKey, result2);
43194
+ return result2;
43047
43195
  }
43048
43196
  intersects(range, options) {
43049
43197
  if (!(range instanceof _Range)) {
@@ -43097,16 +43245,16 @@ var require_range = __commonJS({
43097
43245
  var isNullSet = (c) => c.value === "<0.0.0-0";
43098
43246
  var isAny = (c) => c.value === "";
43099
43247
  var isSatisfiable = (comparators, options) => {
43100
- let result = true;
43248
+ let result2 = true;
43101
43249
  const remainingComparators = comparators.slice();
43102
43250
  let testComparator = remainingComparators.pop();
43103
- while (result && remainingComparators.length) {
43104
- result = remainingComparators.every((otherComparator) => {
43251
+ while (result2 && remainingComparators.length) {
43252
+ result2 = remainingComparators.every((otherComparator) => {
43105
43253
  return testComparator.intersects(otherComparator, options);
43106
43254
  });
43107
43255
  testComparator = remainingComparators.pop();
43108
43256
  }
43109
- return result;
43257
+ return result2;
43110
43258
  };
43111
43259
  var parseComparator = (comp, options) => {
43112
43260
  comp = comp.replace(re[t.BUILD], "");
@@ -44885,15 +45033,15 @@ function ingestClient() {
44885
45033
  return _ingest;
44886
45034
  }
44887
45035
  async function uploadBatch(batch) {
44888
- const result = await ingestClient().upload(batch);
44889
- if (result.kind !== "commit") {
44890
- throw new Error(`upload failed: ${result.reason}`);
45036
+ const result2 = await ingestClient().upload(batch);
45037
+ if (result2.kind !== "commit") {
45038
+ throw new Error(`upload failed: ${result2.reason}`);
44891
45039
  }
44892
45040
  return {
44893
- accepted: result.response.accepted,
44894
- new_sessions: result.response.new_sessions,
44895
- updated_sessions: result.response.updated_sessions,
44896
- batch_id: result.response.batch_id
45041
+ accepted: result2.response.accepted,
45042
+ new_sessions: result2.response.new_sessions,
45043
+ updated_sessions: result2.response.updated_sessions,
45044
+ batch_id: result2.response.batch_id
44897
45045
  };
44898
45046
  }
44899
45047
  var import_undici, DeviceMeUnauthorized, _ingest;
@@ -45209,7 +45357,7 @@ async function buildSessionTitles(segments, entitle) {
45209
45357
  const project = first.tags.find((t) => t.root_key === "projects")?.name;
45210
45358
  const facts = [
45211
45359
  project ? `repo ${project}` : null,
45212
- `${sorted.length} part${sorted.length === 1 ? "" : "s"} on ${first.tool}`
45360
+ `${sorted.length} part${sorted.length === 1 ? "" : "s"} on ${first.agent}`
45213
45361
  ].filter(Boolean).join("; ");
45214
45362
  try {
45215
45363
  title = sanitiseTitle(await entitle({ abstracts: sampleAbstracts(abstracts), facts }));
@@ -45236,6 +45384,38 @@ var init_title = __esm({
45236
45384
  }
45237
45385
  });
45238
45386
 
45387
+ // ../../packages/companion-core/src/pipeline/script-summary.ts
45388
+ function buildScriptSummaryUserPrompt(input) {
45389
+ const body = input.content.slice(0, SCRIPT_SUMMARY_INPUT_MAX_CHARS);
45390
+ return [
45391
+ `Script reference: ${input.ref}`,
45392
+ "Contents:",
45393
+ "```",
45394
+ body,
45395
+ "```",
45396
+ "",
45397
+ "One sentence (\u2264200 chars): what does running this script do?"
45398
+ ].join("\n");
45399
+ }
45400
+ var SCRIPT_SUMMARY_OUTPUT_MAX_CHARS, SCRIPT_SUMMARY_TEMPERATURE, SCRIPT_SUMMARY_MAX_TOKENS, SCRIPT_SUMMARY_INPUT_MAX_CHARS, SCRIPT_SUMMARY_SYSTEM_PROMPT;
45401
+ var init_script_summary = __esm({
45402
+ "../../packages/companion-core/src/pipeline/script-summary.ts"() {
45403
+ "use strict";
45404
+ SCRIPT_SUMMARY_OUTPUT_MAX_CHARS = 200;
45405
+ SCRIPT_SUMMARY_TEMPERATURE = 0.2;
45406
+ SCRIPT_SUMMARY_MAX_TOKENS = 120;
45407
+ SCRIPT_SUMMARY_INPUT_MAX_CHARS = 6e3;
45408
+ SCRIPT_SUMMARY_SYSTEM_PROMPT = `You summarise what a script file does, for an engineer scanning a dashboard.
45409
+
45410
+ Rules:
45411
+ - Output ONE plain sentence (at most 200 characters) stating what the script DOES when it runs.
45412
+ - Be concrete and factual: the actions it performs and the systems it touches.
45413
+ - No preamble ("This script\u2026"), no markdown, no quotes, no line breaks.
45414
+ - Do not invent behaviour that is not in the file. If the file is trivial or unreadable, say so briefly.
45415
+ - Never include secrets, tokens, passwords, or personal data, even if they appear in the file.`;
45416
+ }
45417
+ });
45418
+
45239
45419
  // ../../packages/companion-core/src/pipeline/index.ts
45240
45420
  async function buildSegmentsForSession(events, adapters2, onProgress) {
45241
45421
  if (events.length === 0) return [];
@@ -45364,14 +45544,14 @@ async function summariseSlice(sessionId, slice, adapters2) {
45364
45544
  const promptFacts = [
45365
45545
  first.git?.remote_slug ? `repo ${first.git.remote_slug}` : null,
45366
45546
  first.git?.branch ? `branch ${first.git.branch}` : null,
45367
- `${slice.length} turns on ${first.tool}`,
45547
+ `${slice.length} turns on ${first.agent}`,
45368
45548
  first.files_touched?.length ? `files touched: ${first.files_touched.slice(0, 5).join(", ")}` : null,
45369
45549
  Object.keys(first.tool_calls ?? {}).length ? `tool calls: ${Object.keys(first.tool_calls).slice(0, 5).join(", ")}` : null
45370
45550
  ].filter(Boolean).join("; ");
45371
45551
  const excerpts = sampleAndRedactExcerpts(slice);
45372
45552
  if (excerpts.length === 0) {
45373
45553
  throw new Error(
45374
- `parser produced 0 content excerpts for session ${sessionId} (${slice.length} turns) \u2014 the summariser would only see metadata and produce "${slice.length} turns on ${first.tool}". Check the parser for ${first.tool} (likely extractExcerpt stripped everything as code or the session is pure tool_use).`
45554
+ `parser produced 0 content excerpts for session ${sessionId} (${slice.length} turns) \u2014 the summariser would only see metadata and produce "${slice.length} turns on ${first.agent}". Check the parser for ${first.agent} (likely extractExcerpt stripped everything as code or the session is pure tool_use).`
45375
45555
  );
45376
45556
  }
45377
45557
  const excerptBlock = excerpts.map((e, i) => ` [turn ${i + 1}] "${e.replace(/\s+/g, " ").trim()}"`).join("\n");
@@ -45414,7 +45594,7 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
45414
45594
  }
45415
45595
  }
45416
45596
  const tags = [
45417
- { root_key: "tools", name: first.tool, confidence: 1 },
45597
+ { root_key: "agents", name: first.agent, confidence: 1 },
45418
45598
  { root_key: "providers", name: first.provider, confidence: 1 }
45419
45599
  ];
45420
45600
  if (first.model) tags.push({ root_key: "models", name: first.model, confidence: 1 });
@@ -45465,7 +45645,7 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
45465
45645
  return {
45466
45646
  segment_id: id,
45467
45647
  session_id: sessionId,
45468
- tool: first.tool,
45648
+ agent: first.agent,
45469
45649
  started_at: first.ts,
45470
45650
  ended_at: last.ts,
45471
45651
  // Slice to the user-visible cap (ABSTRACT_OUTPUT_MAX_CHARS, default
@@ -45509,7 +45689,7 @@ function sampleAndRedactExcerpts(slice) {
45509
45689
  return out;
45510
45690
  }
45511
45691
  function turnSurface(e) {
45512
- const parts = [e.kind, e.tool];
45692
+ const parts = [e.kind, e.agent];
45513
45693
  if (e.model) parts.push(e.model);
45514
45694
  const toolCalls = Object.keys(e.tool_calls ?? {});
45515
45695
  if (toolCalls.length) parts.push(`tools:${toolCalls.join(",")}`);
@@ -45548,6 +45728,7 @@ var init_pipeline = __esm({
45548
45728
  init_cognition();
45549
45729
  init_prompts();
45550
45730
  init_title();
45731
+ init_script_summary();
45551
45732
  SEGMENT_TIME_GAP_MS = 15 * 6e4;
45552
45733
  SEGMENT_TOPIC_THRESHOLD = 0.35;
45553
45734
  SEGMENT_MAX_TURNS = 100;
@@ -45594,7 +45775,7 @@ var init_file_queue_store = __esm({
45594
45775
  try {
45595
45776
  const raw = await fs3.readFile(this.filePath, "utf8");
45596
45777
  const parsed = JSON.parse(raw);
45597
- if (parsed.version === 1 && parsed.items) {
45778
+ if (parsed.version === 2 && parsed.items) {
45598
45779
  const now = Date.now();
45599
45780
  for (const [k, v] of Object.entries(parsed.items)) {
45600
45781
  if (v.synced && now - v.last_event_ts_ms > SENT_TTL_MS) continue;
@@ -45606,7 +45787,7 @@ var init_file_queue_store = __esm({
45606
45787
  try {
45607
45788
  const bak = await fs3.readFile(`${this.filePath}.bak`, "utf8");
45608
45789
  const parsed = JSON.parse(bak);
45609
- if (parsed.version === 1 && parsed.items) {
45790
+ if (parsed.version === 2 && parsed.items) {
45610
45791
  for (const [k, v] of Object.entries(parsed.items)) {
45611
45792
  this.items.set(k, v);
45612
45793
  }
@@ -45625,7 +45806,7 @@ var init_file_queue_store = __esm({
45625
45806
  const run = async () => {
45626
45807
  await prior?.catch(() => void 0);
45627
45808
  const snap = {
45628
- version: 1,
45809
+ version: 2,
45629
45810
  items: Object.fromEntries(this.items.entries())
45630
45811
  };
45631
45812
  const tmp = `${this.filePath}.tmp`;
@@ -45805,8 +45986,8 @@ var init_ollama = __esm({
45805
45986
  });
45806
45987
 
45807
45988
  // ../../packages/companion-core/src/node/llama.ts
45808
- import { mkdir } from "fs/promises";
45809
45989
  import { existsSync as existsSync7 } from "fs";
45990
+ import { mkdir } from "fs/promises";
45810
45991
  import { homedir as homedir5 } from "os";
45811
45992
  import { dirname as dirname5, join as join5 } from "path";
45812
45993
  function defaultLlamaConfig() {
@@ -45838,23 +46019,17 @@ async function ensureLlamaModel(cfg = defaultLlamaConfig()) {
45838
46019
  await mkdir(dirname5(cfg.modelPath), { recursive: true });
45839
46020
  const res = await fetch(cfg.modelUrl);
45840
46021
  if (!res.ok || !res.body) {
45841
- throw new Error(
45842
- `model download failed: ${res.status} ${res.statusText} (${cfg.modelUrl})`
45843
- );
46022
+ throw new Error(`model download failed: ${res.status} ${res.statusText} (${cfg.modelUrl})`);
45844
46023
  }
45845
46024
  const total = Number(res.headers.get("content-length") ?? 0);
45846
46025
  const totalMb = total > 0 ? (total / (1024 * 1024)).toFixed(0) : "?";
45847
- console.log(
45848
- `[modelstat] downloading summariser model (~${totalMb} MB) \u2192 ${cfg.modelPath}`
45849
- );
46026
+ console.log(`[modelstat] downloading summariser model (~${totalMb} MB) \u2192 ${cfg.modelPath}`);
45850
46027
  const tmp = `${cfg.modelPath}.partial`;
45851
46028
  const { createWriteStream: createWriteStream2 } = await import("fs");
45852
46029
  const { Readable: Readable3 } = await import("stream");
45853
- const { rename } = await import("fs/promises");
46030
+ const { rename: rename2 } = await import("fs/promises");
45854
46031
  const out = createWriteStream2(tmp);
45855
- const isTty = Boolean(
45856
- process.stdout.isTTY
45857
- );
46032
+ const isTty = Boolean(process.stdout.isTTY);
45858
46033
  let received = 0;
45859
46034
  let lastLog = 0;
45860
46035
  let lastBytes = 0;
@@ -45898,7 +46073,7 @@ async function ensureLlamaModel(cfg = defaultLlamaConfig()) {
45898
46073
  });
45899
46074
  renderProgress(true);
45900
46075
  if (isTty) process.stdout.write("\n");
45901
- await rename(tmp, cfg.modelPath);
46076
+ await rename2(tmp, cfg.modelPath);
45902
46077
  console.log(`[modelstat] summariser model ready (${cfg.modelPath})`);
45903
46078
  return cfg.modelPath;
45904
46079
  }
@@ -45919,6 +46094,9 @@ async function loadOnce(cfg) {
45919
46094
  const entitlerContext = await model.createContext({
45920
46095
  contextSize: cfg.contextSize
45921
46096
  });
46097
+ const scriptContext = await model.createContext({
46098
+ contextSize: cfg.contextSize
46099
+ });
45922
46100
  const summarizer = new llamaMod.LlamaChatSession({
45923
46101
  contextSequence: summariserContext.getSequence(),
45924
46102
  systemPrompt: SUMMARISER_SYSTEM_PROMPT
@@ -45931,7 +46109,11 @@ async function loadOnce(cfg) {
45931
46109
  contextSequence: entitlerContext.getSequence(),
45932
46110
  systemPrompt: TITLER_SYSTEM_PROMPT
45933
46111
  });
45934
- loaded = { summarizer, cognizer, entitler };
46112
+ const scriptSummarizer2 = new llamaMod.LlamaChatSession({
46113
+ contextSequence: scriptContext.getSequence(),
46114
+ systemPrompt: SCRIPT_SUMMARY_SYSTEM_PROMPT
46115
+ });
46116
+ loaded = { summarizer, cognizer, entitler, scriptSummarizer: scriptSummarizer2 };
45935
46117
  return loaded;
45936
46118
  })();
45937
46119
  try {
@@ -46021,12 +46203,42 @@ function llamaEntitle(cfg = defaultLlamaConfig()) {
46021
46203
  }
46022
46204
  };
46023
46205
  }
46206
+ function llamaScriptSummarize(cfg = defaultLlamaConfig()) {
46207
+ return async ({ ref, content }) => {
46208
+ if (!content || content.trim().length === 0) return null;
46209
+ let loadedSessions;
46210
+ try {
46211
+ loadedSessions = await loadOnce(cfg);
46212
+ } catch {
46213
+ return null;
46214
+ }
46215
+ const { scriptSummarizer: scriptSummarizer2 } = loadedSessions;
46216
+ const run = inflight.then(async () => {
46217
+ scriptSummarizer2.resetChatHistory();
46218
+ const raw = await scriptSummarizer2.prompt(buildScriptSummaryUserPrompt({ ref, content }), {
46219
+ temperature: SCRIPT_SUMMARY_TEMPERATURE,
46220
+ // Qwen3.5 reasons before answering — give it room on top of the
46221
+ // one-sentence answer budget; the slice below enforces the cap.
46222
+ maxTokens: SCRIPT_SUMMARY_MAX_TOKENS + 400
46223
+ });
46224
+ const oneLine = stripThinking(raw ?? "").replace(/\s+/g, " ").trim();
46225
+ return oneLine ? oneLine.slice(0, SCRIPT_SUMMARY_OUTPUT_MAX_CHARS) : null;
46226
+ });
46227
+ inflight = run.catch(() => void 0);
46228
+ try {
46229
+ return await run;
46230
+ } catch {
46231
+ return null;
46232
+ }
46233
+ };
46234
+ }
46024
46235
  var DEFAULT_LLAMA_MODEL_URL, LLAMA_MAX_TOKENS, loaded, loadPromise, inflight;
46025
46236
  var init_llama = __esm({
46026
46237
  "../../packages/companion-core/src/node/llama.ts"() {
46027
46238
  "use strict";
46028
- init_prompts();
46029
46239
  init_cognition();
46240
+ init_prompts();
46241
+ init_script_summary();
46030
46242
  init_title();
46031
46243
  DEFAULT_LLAMA_MODEL_URL = "https://huggingface.co/lmstudio-community/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf";
46032
46244
  LLAMA_MAX_TOKENS = 1024;
@@ -46134,6 +46346,7 @@ __export(node_exports, {
46134
46346
  ensureLlamaModel: () => ensureLlamaModel,
46135
46347
  llamaCognize: () => llamaCognize,
46136
46348
  llamaEntitle: () => llamaEntitle,
46349
+ llamaScriptSummarize: () => llamaScriptSummarize,
46137
46350
  llamaSummarize: () => llamaSummarize,
46138
46351
  ollamaCognize: () => ollamaCognize,
46139
46352
  ollamaEmbed: () => ollamaEmbed,
@@ -46263,22 +46476,92 @@ var init_privacy_filter = __esm({
46263
46476
  }
46264
46477
  });
46265
46478
 
46479
+ // src/enrich-scripts.ts
46480
+ function defaultRoots(cwd) {
46481
+ if (!cwd) return [];
46482
+ const seg = cwd.replace(/\/+$/, "").split("/");
46483
+ const ancestors = [];
46484
+ for (let i = seg.length; i >= Math.max(1, seg.length - 3); i--) {
46485
+ ancestors.push(seg.slice(0, i).join("/") || "/");
46486
+ }
46487
+ const subdirs = ["scripts", "bin", "tools", "ci", ".github/scripts"];
46488
+ const roots = [...ancestors];
46489
+ for (const a of ancestors) for (const s of subdirs) roots.push(`${a}/${s}`);
46490
+ return roots;
46491
+ }
46492
+ async function enrichToolCallScripts(drafts, contexts, deps) {
46493
+ if (contexts.length === 0) return;
46494
+ const ctxById = new Map(contexts.map((c) => [c.external_call_id, c]));
46495
+ for (const draft of drafts) {
46496
+ if (!draft.action) continue;
46497
+ const ctx = ctxById.get(draft.external_call_id);
46498
+ if (!ctx) continue;
46499
+ try {
46500
+ await enrichOneAction(draft.action, ctx, deps);
46501
+ } catch {
46502
+ }
46503
+ }
46504
+ }
46505
+ async function enrichOneAction(action, ctx, deps) {
46506
+ const redactedCommand = action.command_redacted;
46507
+ if (!redactedCommand) return;
46508
+ const refs = detectScriptRefs(ctx.command);
46509
+ if (refs.length === 0) return;
46510
+ const roots = (deps.roots ?? defaultRoots)(ctx.cwd);
46511
+ const seen = /* @__PURE__ */ new Set();
46512
+ const out = [];
46513
+ for (const ref of refs) {
46514
+ if (out.length >= MAX_SCRIPTS_PER_CALL) break;
46515
+ const token = redact(ref, ctx.cwd ?? void 0).text.trim();
46516
+ if (!token || token.startsWith("[REDACTED") || seen.has(token)) continue;
46517
+ if (!redactedCommand.includes(token)) continue;
46518
+ const path5 = resolveScriptPath(ref, roots, deps.exists);
46519
+ if (!path5) continue;
46520
+ let content;
46521
+ try {
46522
+ content = await deps.readFile(path5);
46523
+ } catch {
46524
+ continue;
46525
+ }
46526
+ if (!content.trim()) continue;
46527
+ const summaryRaw = await deps.summarize({ ref, content });
46528
+ if (!summaryRaw) continue;
46529
+ const summary = redact(summaryRaw).text.trim().slice(0, MAX_SUMMARY_CHARS);
46530
+ if (!summary) continue;
46531
+ seen.add(token);
46532
+ out.push({ token, summary });
46533
+ }
46534
+ if (out.length > 0) action.scripts = out;
46535
+ }
46536
+ var MAX_SCRIPTS_PER_CALL, MAX_SUMMARY_CHARS;
46537
+ var init_enrich_scripts = __esm({
46538
+ "src/enrich-scripts.ts"() {
46539
+ "use strict";
46540
+ init_src();
46541
+ init_src2();
46542
+ MAX_SCRIPTS_PER_CALL = 8;
46543
+ MAX_SUMMARY_CHARS = 200;
46544
+ }
46545
+ });
46546
+
46266
46547
  // src/pipeline.ts
46267
46548
  var pipeline_exports = {};
46268
46549
  __export(pipeline_exports, {
46269
46550
  buildSegments: () => buildSegments,
46270
46551
  buildSessionTitles: () => buildSessionTitles2,
46552
+ enrichScripts: () => enrichScripts,
46271
46553
  preflightSummariser: () => preflightSummariser
46272
46554
  });
46555
+ import { existsSync as existsSync8 } from "fs";
46556
+ import { readFile as fsReadFile } from "fs/promises";
46273
46557
  async function bundledAdapters() {
46274
46558
  const llamaCfg = defaultLlamaConfig();
46275
46559
  return {
46276
- // transformers.js BGE-small embedder — the same model the server
46277
- // uses, so segment vectors land in the same 384-dim space as
46278
- // leaf-description vectors and cosine similarity is directly
46279
- // meaningful. (This path used to ship vector-less with empty
46280
- // arrays; hooking embeddings here gives proper segment-vs-leaf
46281
- // matching at classify time.)
46560
+ // transformers.js BGE-small embedder — the wire embedding is
46561
+ // 384-dim (BGE-small), so segment vectors are directly comparable
46562
+ // across runtimes via cosine similarity. (This path used to ship
46563
+ // vector-less with empty arrays; hooking embeddings here attaches a
46564
+ // real abstract embedding to each segment.)
46282
46565
  embed: createTransformersJsEmbedder(),
46283
46566
  summarize: llamaSummarize(llamaCfg),
46284
46567
  tokenize: (text) => Math.max(1, Math.ceil(text.length / 4)),
@@ -46308,9 +46591,7 @@ async function getAdapters() {
46308
46591
  `modelstat agent can't start: the bundled summariser (node-llama-cpp) failed to load. Re-run \`modelstat connect\` (or \`npm i -g modelstat\`) so the native runtime is re-staged beside the bundle. Underlying error: ${err.message}`
46309
46592
  );
46310
46593
  }
46311
- console.log(
46312
- "[modelstat] using bundled local summariser (Qwen3.5-4B, runs on this machine)"
46313
- );
46594
+ console.log("[modelstat] using bundled local summariser (Qwen3.5-4B, runs on this machine)");
46314
46595
  adapters = await bundledAdapters();
46315
46596
  return adapters;
46316
46597
  }
@@ -46321,6 +46602,19 @@ async function buildSessionTitles2(segments) {
46321
46602
  const a = await getAdapters();
46322
46603
  return buildSessionTitles(segments, a.entitle);
46323
46604
  }
46605
+ async function enrichScripts(drafts, contexts = []) {
46606
+ if (contexts.length === 0 || drafts.length === 0) return;
46607
+ await getAdapters();
46608
+ if (!scriptSummarizer) scriptSummarizer = llamaScriptSummarize(defaultLlamaConfig());
46609
+ await enrichToolCallScripts(drafts, contexts, {
46610
+ summarize: scriptSummarizer,
46611
+ exists: existsSync8,
46612
+ readFile: async (path5) => {
46613
+ const buf = await fsReadFile(path5);
46614
+ return buf.subarray(0, MAX_SCRIPT_READ_BYTES).toString("utf8");
46615
+ }
46616
+ });
46617
+ }
46324
46618
  async function preflightSummariser() {
46325
46619
  const a = await getAdapters();
46326
46620
  const out = await a.summarize({
@@ -46334,14 +46628,17 @@ async function preflightSummariser() {
46334
46628
  }
46335
46629
  return out.length > 60 ? `${out.slice(0, 57)}\u2026` : out;
46336
46630
  }
46337
- var adapters;
46631
+ var adapters, MAX_SCRIPT_READ_BYTES, scriptSummarizer;
46338
46632
  var init_pipeline2 = __esm({
46339
46633
  "src/pipeline.ts"() {
46340
46634
  "use strict";
46341
- init_pipeline();
46342
46635
  init_node2();
46636
+ init_pipeline();
46343
46637
  init_privacy_filter();
46638
+ init_enrich_scripts();
46344
46639
  adapters = null;
46640
+ MAX_SCRIPT_READ_BYTES = 64 * 1024;
46641
+ scriptSummarizer = null;
46345
46642
  }
46346
46643
  });
46347
46644
 
@@ -46371,7 +46668,7 @@ async function scanAll(cb = {}) {
46371
46668
  path: full,
46372
46669
  parse: async (sink2) => {
46373
46670
  const r = await parseClaudeCodeJsonl({ deviceId, sourceFile: full, onEvents: sink2 });
46374
- return { toolCalls: r.toolCalls ?? [] };
46671
+ return { toolCalls: r.toolCalls ?? [], scriptContexts: r.scriptContexts ?? [] };
46375
46672
  }
46376
46673
  });
46377
46674
  }
@@ -46395,7 +46692,7 @@ async function scanAll(cb = {}) {
46395
46692
  path: full,
46396
46693
  parse: async (sink2) => {
46397
46694
  const r = await parseCodexRollout({ deviceId, sourceFile: full, onEvents: sink2 });
46398
- return { toolCalls: r.toolCalls ?? [] };
46695
+ return { toolCalls: r.toolCalls ?? [], scriptContexts: r.scriptContexts ?? [] };
46399
46696
  }
46400
46697
  });
46401
46698
  }
@@ -46442,7 +46739,7 @@ async function scanAll(cb = {}) {
46442
46739
  const batch = {
46443
46740
  batch_id: batchId(),
46444
46741
  device_id: deviceId,
46445
- agent_version: AGENT_VERSION,
46742
+ companion_version: AGENT_VERSION,
46446
46743
  events,
46447
46744
  segments,
46448
46745
  tool_calls: attachSegmentIdsByMap(toolCallBuffer, callSegmentByEvent),
@@ -46488,6 +46785,14 @@ async function scanAll(cb = {}) {
46488
46785
  filesScanned += 1;
46489
46786
  try {
46490
46787
  const r = await job.parse(sink);
46788
+ try {
46789
+ await enrichScripts(r.toolCalls, r.scriptContexts ?? []);
46790
+ } catch (e) {
46791
+ console.warn(
46792
+ ` ! script-summary enrichment skipped for ${job.path}:`,
46793
+ e.message
46794
+ );
46795
+ }
46491
46796
  await bufferToolCalls(r.toolCalls);
46492
46797
  if (cs) pendingCursors.push({ path: job.path, cs });
46493
46798
  } catch (e) {
@@ -46502,13 +46807,14 @@ var init_scan = __esm({
46502
46807
  "src/scan.ts"() {
46503
46808
  "use strict";
46504
46809
  init_src3();
46810
+ init_config();
46505
46811
  init_queue();
46506
46812
  init_src2();
46507
46813
  init_api();
46508
46814
  init_config2();
46509
46815
  init_pipeline2();
46510
- AGENT_VERSION = true ? "agent-0.0.49" : "agent-dev";
46511
- BATCH_MAX_EVENTS = 2e3;
46816
+ AGENT_VERSION = true ? "agent-0.0.51" : "agent-dev";
46817
+ BATCH_MAX_EVENTS = INGEST_BATCH_MAX_EVENTS;
46512
46818
  BATCH_MAX_TOOL_CALLS = 2e4;
46513
46819
  BATCH_BUFFER_HARD_CAP = BATCH_MAX_EVENTS * 2;
46514
46820
  ZERO_TOKENS = {
@@ -46524,7 +46830,7 @@ var init_scan = __esm({
46524
46830
  // src/lock.ts
46525
46831
  import {
46526
46832
  closeSync,
46527
- existsSync as existsSync9,
46833
+ existsSync as existsSync10,
46528
46834
  mkdirSync as mkdirSync4,
46529
46835
  openSync,
46530
46836
  readFileSync as readFileSync5,
@@ -46554,7 +46860,7 @@ function readDaemonLock(lockFile = LOCK_FILE) {
46554
46860
  return {
46555
46861
  pid: obj.pid,
46556
46862
  startedAt: obj.startedAt ?? "unknown",
46557
- agentVersion: obj.agentVersion ?? "unknown",
46863
+ companionVersion: obj.companionVersion ?? "unknown",
46558
46864
  apiUrl: obj.apiUrl ?? "unknown"
46559
46865
  };
46560
46866
  } catch {
@@ -46596,7 +46902,7 @@ function acquireDaemonLock(opts) {
46596
46902
  const meta = {
46597
46903
  pid: process.pid,
46598
46904
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
46599
- agentVersion: opts.agentVersion,
46905
+ companionVersion: opts.companionVersion,
46600
46906
  apiUrl: opts.apiUrl
46601
46907
  };
46602
46908
  writeLockAtomic(meta);
@@ -46724,6 +47030,250 @@ var init_processing_version = __esm({
46724
47030
  }
46725
47031
  });
46726
47032
 
47033
+ // ../../packages/remote-config/src/loader.ts
47034
+ function getFetch(env2) {
47035
+ return env2.fetch ?? fetch;
47036
+ }
47037
+ async function fetchConfig(kind, env2) {
47038
+ const url = `${env2.apiUrl.replace(/\/+$/, "")}/v1/config/${encodeURIComponent(kind.kind)}`;
47039
+ let body;
47040
+ try {
47041
+ const res = await getFetch(env2)(url);
47042
+ if (!res.ok) throw new Error(`status ${res.status}`);
47043
+ body = await res.json();
47044
+ } catch (e) {
47045
+ env2.logger?.warn?.(`[remote-config] ${kind.kind} fetch failed`, e);
47046
+ return null;
47047
+ }
47048
+ const parsed = kind.schema.safeParse(body);
47049
+ if (!parsed.success) {
47050
+ env2.logger?.warn?.(`[remote-config] ${kind.kind} payload schema invalid`);
47051
+ return null;
47052
+ }
47053
+ return { value: parsed.data, version: parsed.data.version };
47054
+ }
47055
+ async function readCachedConfig(kind, env2) {
47056
+ if (!env2.cache) return null;
47057
+ let raw;
47058
+ try {
47059
+ raw = await env2.cache.read(kind.kind);
47060
+ } catch (e) {
47061
+ env2.logger?.warn?.(`[remote-config] ${kind.kind} cache read failed`, e);
47062
+ return null;
47063
+ }
47064
+ if (raw == null) return null;
47065
+ const parsed = kind.schema.safeParse(raw);
47066
+ if (!parsed.success) {
47067
+ env2.logger?.warn?.(`[remote-config] ${kind.kind} disk cache rejected`);
47068
+ return null;
47069
+ }
47070
+ return { value: parsed.data, version: parsed.data.version };
47071
+ }
47072
+ async function writeCache(kind, env2, value) {
47073
+ if (!env2.cache) return;
47074
+ try {
47075
+ await env2.cache.write(kind.kind, value);
47076
+ } catch (e) {
47077
+ env2.logger?.warn?.(`[remote-config] ${kind.kind} cache write failed`, e);
47078
+ }
47079
+ }
47080
+ function result(kind, value, version, source) {
47081
+ return { kind, value, version, source };
47082
+ }
47083
+ var RemoteConfigStore;
47084
+ var init_loader = __esm({
47085
+ "../../packages/remote-config/src/loader.ts"() {
47086
+ "use strict";
47087
+ RemoteConfigStore = class {
47088
+ env;
47089
+ kinds;
47090
+ state = /* @__PURE__ */ new Map();
47091
+ constructor(env2, kinds) {
47092
+ this.env = env2;
47093
+ this.kinds = new Map(kinds.map((k) => [k.kind, k]));
47094
+ for (const k of kinds) {
47095
+ this.state.set(k.kind, {
47096
+ value: k.bundledFallback,
47097
+ version: k.bundledFallback.version,
47098
+ source: "bundled"
47099
+ });
47100
+ }
47101
+ }
47102
+ /** Seed from the disk cache without touching the network — the instant,
47103
+ * offline-safe startup path. Call once, then `refreshAll` in the
47104
+ * background. Anything not on disk (or rejected) stays on its fallback. */
47105
+ async initFromCache() {
47106
+ await Promise.all(
47107
+ [...this.kinds.values()].map(async (k) => {
47108
+ const cached2 = await readCachedConfig(k, this.env);
47109
+ const current = this.state.get(k.kind);
47110
+ if (cached2 && (!current || cached2.version >= current.version)) {
47111
+ this.state.set(k.kind, { value: cached2.value, version: cached2.version, source: "disk" });
47112
+ }
47113
+ })
47114
+ );
47115
+ }
47116
+ /** Fetch one kind, swapping it in only if strictly newer. Never throws
47117
+ * and never downgrades the held value on failure. */
47118
+ async refresh(kindName) {
47119
+ const kind = this.kinds.get(kindName);
47120
+ if (!kind) throw new Error(`unknown config kind: ${kindName}`);
47121
+ const current = this.state.get(kindName);
47122
+ const currentVersion = current?.version ?? kind.bundledFallback.version;
47123
+ const fetched = await fetchConfig(kind, this.env);
47124
+ if (!fetched) return;
47125
+ if (fetched.version <= currentVersion) return;
47126
+ await writeCache(kind, this.env, fetched.value);
47127
+ this.state.set(kindName, { value: fetched.value, version: fetched.version, source: "remote" });
47128
+ }
47129
+ async refreshAll() {
47130
+ await Promise.all([...this.kinds.keys()].map((k) => this.refresh(k)));
47131
+ }
47132
+ /** The current best value for a kind. Total — falls back to bundled. */
47133
+ get(kindName) {
47134
+ const entry = this.state.get(kindName);
47135
+ if (!entry) throw new Error(`unknown config kind: ${kindName}`);
47136
+ return entry.value;
47137
+ }
47138
+ /** Like `get`, but also reports the version + provenance. */
47139
+ getResult(kindName) {
47140
+ const entry = this.state.get(kindName);
47141
+ if (!entry) throw new Error(`unknown config kind: ${kindName}`);
47142
+ return result(kindName, entry.value, entry.version, entry.source);
47143
+ }
47144
+ };
47145
+ }
47146
+ });
47147
+
47148
+ // ../../packages/remote-config/src/schema.ts
47149
+ var VersionedConfig;
47150
+ var init_schema = __esm({
47151
+ "../../packages/remote-config/src/schema.ts"() {
47152
+ "use strict";
47153
+ init_zod();
47154
+ VersionedConfig = external_exports.object({
47155
+ version: external_exports.number().int().nonnegative()
47156
+ });
47157
+ }
47158
+ });
47159
+
47160
+ // ../../packages/remote-config/src/types.ts
47161
+ var init_types3 = __esm({
47162
+ "../../packages/remote-config/src/types.ts"() {
47163
+ "use strict";
47164
+ }
47165
+ });
47166
+
47167
+ // ../../packages/remote-config/src/index.ts
47168
+ var init_src4 = __esm({
47169
+ "../../packages/remote-config/src/index.ts"() {
47170
+ "use strict";
47171
+ init_loader();
47172
+ init_schema();
47173
+ init_types3();
47174
+ }
47175
+ });
47176
+
47177
+ // ../../packages/remote-config/src/node.ts
47178
+ import { chmod, mkdir as mkdir2, readFile, rename, writeFile } from "fs/promises";
47179
+ import { homedir as homedir10 } from "os";
47180
+ import { join as join10 } from "path";
47181
+ function defaultRoot() {
47182
+ return join10(homedir10(), ".modelstat", "config");
47183
+ }
47184
+ function safeKind(kind) {
47185
+ if (!/^[a-z0-9_-]{1,64}$/.test(kind)) throw new Error(`unsafe config kind: ${kind}`);
47186
+ return kind;
47187
+ }
47188
+ function createNodeDiskCache(opts = {}) {
47189
+ const dir = opts.dir ?? defaultRoot();
47190
+ async function writeAtomic2(path5, data) {
47191
+ const tmp = `${path5}.${process.pid}.tmp`;
47192
+ await writeFile(tmp, data, { mode: 384 });
47193
+ await rename(tmp, path5);
47194
+ try {
47195
+ await chmod(path5, 384);
47196
+ } catch {
47197
+ }
47198
+ }
47199
+ return {
47200
+ async read(kind) {
47201
+ const k = safeKind(kind);
47202
+ try {
47203
+ const raw = await readFile(join10(dir, `${k}.json`), "utf8");
47204
+ return JSON.parse(raw);
47205
+ } catch {
47206
+ return null;
47207
+ }
47208
+ },
47209
+ async write(kind, payload) {
47210
+ const k = safeKind(kind);
47211
+ await mkdir2(dir, { recursive: true, mode: 448 });
47212
+ await writeAtomic2(join10(dir, `${k}.json`), `${JSON.stringify(payload)}
47213
+ `);
47214
+ }
47215
+ };
47216
+ }
47217
+ var init_node3 = __esm({
47218
+ "../../packages/remote-config/src/node.ts"() {
47219
+ "use strict";
47220
+ }
47221
+ });
47222
+
47223
+ // ../../packages/companion-core/src/policies/index.ts
47224
+ var policies_exports = {};
47225
+ __export(policies_exports, {
47226
+ createPolicyRefresher: () => createPolicyRefresher
47227
+ });
47228
+ function createPolicyRefresher(opts) {
47229
+ const env2 = {
47230
+ apiUrl: opts.apiUrl,
47231
+ cache: createNodeDiskCache(opts.cacheDir ? { dir: opts.cacheDir } : {}),
47232
+ ...opts.fetch ? { fetch: opts.fetch } : {},
47233
+ ...opts.logger ? { logger: opts.logger } : {}
47234
+ };
47235
+ const store2 = new RemoteConfigStore(env2, [policiesKind]);
47236
+ let timer = null;
47237
+ const apply = () => {
47238
+ const bundle = store2.get("policies");
47239
+ setRemoteRedactionPatterns(compilePolicyPatterns(bundle));
47240
+ };
47241
+ const refresh = async () => {
47242
+ await store2.refresh("policies");
47243
+ apply();
47244
+ };
47245
+ return {
47246
+ async start() {
47247
+ await store2.initFromCache();
47248
+ apply();
47249
+ void refresh().catch(() => {
47250
+ });
47251
+ timer = setInterval(
47252
+ () => void refresh().catch(() => {
47253
+ }),
47254
+ opts.intervalMs ?? DEFAULT_REFRESH_MS
47255
+ );
47256
+ timer.unref?.();
47257
+ },
47258
+ refresh,
47259
+ stop() {
47260
+ if (timer) clearInterval(timer);
47261
+ timer = null;
47262
+ }
47263
+ };
47264
+ }
47265
+ var DEFAULT_REFRESH_MS, policiesKind;
47266
+ var init_policies2 = __esm({
47267
+ "../../packages/companion-core/src/policies/index.ts"() {
47268
+ "use strict";
47269
+ init_src();
47270
+ init_src4();
47271
+ init_node3();
47272
+ DEFAULT_REFRESH_MS = 15 * 60 * 1e3;
47273
+ policiesKind = POLICIES_CONFIG_KIND;
47274
+ }
47275
+ });
47276
+
46727
47277
  // ../../node_modules/.pnpm/readdirp@4.1.2/node_modules/readdirp/esm/index.js
46728
47278
  import { stat as stat3, lstat, readdir as readdir2, realpath } from "fs/promises";
46729
47279
  import { Readable as Readable2 } from "stream";
@@ -46891,10 +47441,10 @@ var init_esm = __esm({
46891
47441
  }
46892
47442
  async _formatEntry(dirent, path5) {
46893
47443
  let entry;
46894
- const basename4 = this._isDirent ? dirent.name : dirent;
47444
+ const basename5 = this._isDirent ? dirent.name : dirent;
46895
47445
  try {
46896
- const fullPath = presolve(pjoin(path5, basename4));
46897
- entry = { path: prelative(this._root, fullPath), fullPath, basename: basename4 };
47446
+ const fullPath = presolve(pjoin(path5, basename5));
47447
+ entry = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
46898
47448
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
46899
47449
  } catch (err) {
46900
47450
  this._onError(err);
@@ -47423,9 +47973,9 @@ var init_handler = __esm({
47423
47973
  _watchWithNodeFs(path5, listener) {
47424
47974
  const opts = this.fsw.options;
47425
47975
  const directory = sysPath.dirname(path5);
47426
- const basename4 = sysPath.basename(path5);
47976
+ const basename5 = sysPath.basename(path5);
47427
47977
  const parent = this.fsw._getWatchedDir(directory);
47428
- parent.add(basename4);
47978
+ parent.add(basename5);
47429
47979
  const absolutePath = sysPath.resolve(path5);
47430
47980
  const options = {
47431
47981
  persistent: opts.persistent
@@ -47435,7 +47985,7 @@ var init_handler = __esm({
47435
47985
  let closer;
47436
47986
  if (opts.usePolling) {
47437
47987
  const enableBin = opts.interval !== opts.binaryInterval;
47438
- options.interval = enableBin && isBinaryPath(basename4) ? opts.binaryInterval : opts.interval;
47988
+ options.interval = enableBin && isBinaryPath(basename5) ? opts.binaryInterval : opts.interval;
47439
47989
  closer = setFsWatchFileListener(path5, absolutePath, options, {
47440
47990
  listener,
47441
47991
  rawEmitter: this.fsw._emitRaw
@@ -47458,10 +48008,10 @@ var init_handler = __esm({
47458
48008
  return;
47459
48009
  }
47460
48010
  const dirname9 = sysPath.dirname(file);
47461
- const basename4 = sysPath.basename(file);
48011
+ const basename5 = sysPath.basename(file);
47462
48012
  const parent = this.fsw._getWatchedDir(dirname9);
47463
48013
  let prevStats = stats;
47464
- if (parent.has(basename4))
48014
+ if (parent.has(basename5))
47465
48015
  return;
47466
48016
  const listener = async (path5, newStats) => {
47467
48017
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
@@ -47486,9 +48036,9 @@ var init_handler = __esm({
47486
48036
  prevStats = newStats2;
47487
48037
  }
47488
48038
  } catch (error) {
47489
- this.fsw._remove(dirname9, basename4);
48039
+ this.fsw._remove(dirname9, basename5);
47490
48040
  }
47491
- } else if (parent.has(basename4)) {
48041
+ } else if (parent.has(basename5)) {
47492
48042
  const at = newStats.atimeMs;
47493
48043
  const mt = newStats.mtimeMs;
47494
48044
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -48452,7 +49002,7 @@ __export(daemon_exports, {
48452
49002
  setQueue: () => setQueue,
48453
49003
  setStat: () => setStat
48454
49004
  });
48455
- import { existsSync as existsSync10, statSync as statSync2 } from "fs";
49005
+ import { existsSync as existsSync11, statSync as statSync2 } from "fs";
48456
49006
  function setPhase(phase, message) {
48457
49007
  status.phase = phase;
48458
49008
  status.message = message ?? null;
@@ -48494,7 +49044,7 @@ function snapshotBody() {
48494
49044
  queue_size: status.queueSize,
48495
49045
  stats: status.stats,
48496
49046
  last_event_at: status.lastEventAt,
48497
- agent_version: AGENT_VERSION2,
49047
+ companion_version: AGENT_VERSION2,
48498
49048
  machine_id: machineKey()
48499
49049
  };
48500
49050
  }
@@ -48532,12 +49082,12 @@ async function sendHeartbeat() {
48532
49082
  writeLocalStatus(body).catch(() => void 0);
48533
49083
  }
48534
49084
  async function rotateRunawayLogs() {
48535
- const { homedir: homedir11 } = await import("os");
48536
- const { join: join13 } = await import("path");
48537
- const { open: open2, stat: stat6, truncate, writeFile } = await import("fs/promises");
48538
- const dir = join13(homedir11(), ".modelstat", "logs");
49085
+ const { homedir: homedir12 } = await import("os");
49086
+ const { join: join14 } = await import("path");
49087
+ const { open: open2, stat: stat6, truncate, writeFile: writeFile2 } = await import("fs/promises");
49088
+ const dir = join14(homedir12(), ".modelstat", "logs");
48539
49089
  for (const name of ["out.log", "err.log"]) {
48540
- const p = join13(dir, name);
49090
+ const p = join14(dir, name);
48541
49091
  try {
48542
49092
  const st = await stat6(p);
48543
49093
  if (st.size <= LOG_MAX_BYTES) continue;
@@ -48546,7 +49096,7 @@ async function rotateRunawayLogs() {
48546
49096
  try {
48547
49097
  const buf = Buffer.alloc(keep);
48548
49098
  await fh.read(buf, 0, keep, st.size - keep);
48549
- await writeFile(p.replace(/\.log$/, ".old.log"), buf);
49099
+ await writeFile2(p.replace(/\.log$/, ".old.log"), buf);
48550
49100
  } finally {
48551
49101
  await fh.close();
48552
49102
  }
@@ -48559,21 +49109,21 @@ async function rotateRunawayLogs() {
48559
49109
  }
48560
49110
  }
48561
49111
  async function writeLocalStatus(snapshot) {
48562
- const { homedir: homedir11 } = await import("os");
48563
- const { join: join13 } = await import("path");
48564
- const { writeFile, mkdir: mkdir2, rename } = await import("fs/promises");
49112
+ const { homedir: homedir12 } = await import("os");
49113
+ const { join: join14 } = await import("path");
49114
+ const { writeFile: writeFile2, mkdir: mkdir3, rename: rename2 } = await import("fs/promises");
48565
49115
  if (!lastStatusPath) {
48566
- const dir = join13(homedir11(), ".modelstat");
49116
+ const dir = join14(homedir12(), ".modelstat");
48567
49117
  try {
48568
- await mkdir2(dir, { recursive: true });
49118
+ await mkdir3(dir, { recursive: true });
48569
49119
  } catch {
48570
49120
  }
48571
- lastStatusPath = join13(dir, "last-status.json");
49121
+ lastStatusPath = join14(dir, "last-status.json");
48572
49122
  }
48573
49123
  const tmp = `${lastStatusPath}.tmp`;
48574
49124
  try {
48575
- await writeFile(tmp, JSON.stringify({ ...snapshot, written_at: (/* @__PURE__ */ new Date()).toISOString() }));
48576
- await rename(tmp, lastStatusPath);
49125
+ await writeFile2(tmp, JSON.stringify({ ...snapshot, written_at: (/* @__PURE__ */ new Date()).toISOString() }));
49126
+ await rename2(tmp, lastStatusPath);
48577
49127
  } catch {
48578
49128
  }
48579
49129
  }
@@ -48603,7 +49153,7 @@ async function runScanCycle(reason) {
48603
49153
  const r = await scanAll({
48604
49154
  onFile(path5, index, total) {
48605
49155
  setProgress(index + 1, total);
48606
- setMessage(`Scanning ${index + 1}/${total}: ${basename3(path5)}`);
49156
+ setMessage(`Scanning ${index + 1}/${total}: ${basename4(path5)}`);
48607
49157
  },
48608
49158
  onProgress(p) {
48609
49159
  const sess = p.sessionTotal > 1 ? ` \xB7 session ${p.session}/${p.sessionTotal}` : "";
@@ -48637,7 +49187,7 @@ async function runScanCycle(reason) {
48637
49187
  function requestScan(reason) {
48638
49188
  return scanRunner.trigger(reason);
48639
49189
  }
48640
- function basename3(p) {
49190
+ function basename4(p) {
48641
49191
  return p.split("/").pop() ?? p;
48642
49192
  }
48643
49193
  async function runDaemon(opts = {}) {
@@ -48645,7 +49195,7 @@ async function runDaemon(opts = {}) {
48645
49195
  throw new Error("not enrolled \u2014 run `npx modelstat@latest` first");
48646
49196
  }
48647
49197
  const lock = acquireDaemonLock({
48648
- agentVersion: AGENT_VERSION2,
49198
+ companionVersion: AGENT_VERSION2,
48649
49199
  apiUrl: state.apiUrl,
48650
49200
  force: opts.force === true,
48651
49201
  // If a racing daemon out-renamed us for the lock (see lock.ts
@@ -48663,7 +49213,7 @@ async function runDaemon(opts = {}) {
48663
49213
  console.log(
48664
49214
  `modelstat daemon is already running \u2014 PID ${lock.owner.pid}, started ${formatAge(
48665
49215
  lock.ageSec
48666
- )} ago, agent ${lock.owner.agentVersion}.`
49216
+ )} ago, agent ${lock.owner.companionVersion}.`
48667
49217
  );
48668
49218
  console.log(" \u2192 to stop it: kill " + lock.owner.pid);
48669
49219
  console.log(" \u2192 to force-replace it: modelstat start --force");
@@ -48693,20 +49243,26 @@ async function runDaemon(opts = {}) {
48693
49243
  }
48694
49244
  await runDiscovery();
48695
49245
  await requestScan("startup");
49246
+ try {
49247
+ const { createPolicyRefresher: createPolicyRefresher2 } = await Promise.resolve().then(() => (init_policies2(), policies_exports));
49248
+ await createPolicyRefresher2({ apiUrl: state.apiUrl }).start();
49249
+ } catch (err) {
49250
+ setMessage(`policy refresh unavailable: ${err.message}`);
49251
+ }
48696
49252
  const chokidar = (await Promise.resolve().then(() => (init_esm2(), esm_exports))).default;
48697
- const { homedir: homedir11, platform: platform6 } = await import("os");
48698
- const { join: join13 } = await import("path");
48699
- const home2 = homedir11();
49253
+ const { homedir: homedir12, platform: platform6 } = await import("os");
49254
+ const { join: join14 } = await import("path");
49255
+ const home2 = homedir12();
48700
49256
  const dirs = [
48701
- join13(home2, ".claude/projects"),
48702
- join13(home2, ".codex/sessions"),
48703
- join13(home2, ".cursor/ai-tracking"),
48704
- join13(home2, ".gemini"),
49257
+ join14(home2, ".claude/projects"),
49258
+ join14(home2, ".codex/sessions"),
49259
+ join14(home2, ".cursor/ai-tracking"),
49260
+ join14(home2, ".gemini"),
48705
49261
  ...platform6() === "darwin" ? [
48706
- join13(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
48707
- join13(home2, "Library/Application Support/Claude")
48708
- ] : [join13(home2, ".config/Cursor/User/workspaceStorage")]
48709
- ].filter((p) => existsSync10(p) && statSync2(p).isDirectory());
49262
+ join14(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
49263
+ join14(home2, "Library/Application Support/Claude")
49264
+ ] : [join14(home2, ".config/Cursor/User/workspaceStorage")]
49265
+ ].filter((p) => existsSync11(p) && statSync2(p).isDirectory());
48710
49266
  setPhase("watching", `Watching ${dirs.length} directories`);
48711
49267
  const watcher = chokidar.watch(dirs, {
48712
49268
  persistent: true,
@@ -48723,9 +49279,9 @@ async function runDaemon(opts = {}) {
48723
49279
  }, 1e3);
48724
49280
  };
48725
49281
  watcher.on("add", (p) => {
48726
- if (p.endsWith(".jsonl") || p.endsWith(".db")) scheduleScan(`add ${basename3(p)}`);
49282
+ if (p.endsWith(".jsonl") || p.endsWith(".db")) scheduleScan(`add ${basename4(p)}`);
48727
49283
  }).on("change", (p) => {
48728
- if (p.endsWith(".jsonl") || p.endsWith(".db")) scheduleScan(`change ${basename3(p)}`);
49284
+ if (p.endsWith(".jsonl") || p.endsWith(".db")) scheduleScan(`change ${basename4(p)}`);
48729
49285
  }).on("error", (e) => {
48730
49286
  setMessage(`watcher error: ${e.message}`);
48731
49287
  });
@@ -48757,7 +49313,7 @@ var init_daemon = __esm({
48757
49313
  init_machine_key();
48758
49314
  init_scan();
48759
49315
  init_single_flight();
48760
- AGENT_VERSION2 = true ? "agent-0.0.49" : "agent-dev";
49316
+ AGENT_VERSION2 = true ? "agent-0.0.51" : "agent-dev";
48761
49317
  HEARTBEAT_INTERVAL_MS = 1e4;
48762
49318
  SCAN_INTERVAL_MS = 5 * 60 * 1e3;
48763
49319
  DISCOVERY_INTERVAL_MS = 6e4;
@@ -48785,37 +49341,37 @@ var watch_exports = {};
48785
49341
  __export(watch_exports, {
48786
49342
  watchForever: () => watchForever
48787
49343
  });
48788
- import { existsSync as existsSync11 } from "fs";
48789
- import { homedir as homedir10, platform as platform4 } from "os";
48790
- import { join as join12 } from "path";
49344
+ import { existsSync as existsSync12 } from "fs";
49345
+ import { homedir as homedir11, platform as platform4 } from "os";
49346
+ import { join as join13 } from "path";
48791
49347
  function resolveWatchDirs() {
48792
- const home2 = homedir10();
48793
- const xdgConfig = process.env.XDG_CONFIG_HOME ?? join12(home2, ".config");
48794
- const xdgData = process.env.XDG_DATA_HOME ?? join12(home2, ".local/share");
49348
+ const home2 = homedir11();
49349
+ const xdgConfig = process.env.XDG_CONFIG_HOME ?? join13(home2, ".config");
49350
+ const xdgData = process.env.XDG_DATA_HOME ?? join13(home2, ".local/share");
48795
49351
  const candidates = [
48796
49352
  // universal (default HOME-rooted CLI data dirs)
48797
- join12(home2, ".claude/projects"),
48798
- join12(home2, ".codex/sessions"),
48799
- join12(home2, ".cursor/ai-tracking"),
48800
- join12(home2, ".gemini"),
48801
- join12(home2, ".aider"),
49353
+ join13(home2, ".claude/projects"),
49354
+ join13(home2, ".codex/sessions"),
49355
+ join13(home2, ".cursor/ai-tracking"),
49356
+ join13(home2, ".gemini"),
49357
+ join13(home2, ".aider"),
48802
49358
  // XDG / Linux
48803
- join12(xdgConfig, "claude/projects"),
48804
- join12(xdgConfig, "codex/sessions"),
48805
- join12(xdgConfig, "Cursor/User/workspaceStorage"),
48806
- join12(xdgConfig, "Code/User/workspaceStorage"),
48807
- join12(xdgConfig, "Code - Insiders/User/workspaceStorage"),
48808
- join12(xdgData, "claude/projects"),
49359
+ join13(xdgConfig, "claude/projects"),
49360
+ join13(xdgConfig, "codex/sessions"),
49361
+ join13(xdgConfig, "Cursor/User/workspaceStorage"),
49362
+ join13(xdgConfig, "Code/User/workspaceStorage"),
49363
+ join13(xdgConfig, "Code - Insiders/User/workspaceStorage"),
49364
+ join13(xdgData, "claude/projects"),
48809
49365
  // macOS
48810
49366
  ...platform4() === "darwin" ? [
48811
- join12(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
48812
- join12(home2, "Library/Application Support/Claude"),
48813
- join12(home2, "Library/Application Support/Code/User/workspaceStorage"),
48814
- join12(home2, "Library/Application Support/Windsurf/User/workspaceStorage"),
48815
- join12(home2, "Library/Application Support/Zed")
49367
+ join13(home2, "Library/Application Support/Cursor/User/workspaceStorage"),
49368
+ join13(home2, "Library/Application Support/Claude"),
49369
+ join13(home2, "Library/Application Support/Code/User/workspaceStorage"),
49370
+ join13(home2, "Library/Application Support/Windsurf/User/workspaceStorage"),
49371
+ join13(home2, "Library/Application Support/Zed")
48816
49372
  ] : []
48817
49373
  ];
48818
- return Array.from(new Set(candidates)).filter((p) => existsSync11(p));
49374
+ return Array.from(new Set(candidates)).filter((p) => existsSync12(p));
48819
49375
  }
48820
49376
  async function safeScan(reason) {
48821
49377
  if (scanning) {
@@ -48890,7 +49446,7 @@ import { createInterface as createInterface3 } from "readline";
48890
49446
  import { spawnSync as spawnSync2 } from "child_process";
48891
49447
  import {
48892
49448
  copyFileSync,
48893
- existsSync as existsSync8,
49449
+ existsSync as existsSync9,
48894
49450
  mkdirSync as mkdirSync3,
48895
49451
  readFileSync as readFileSync4,
48896
49452
  realpathSync,
@@ -48926,7 +49482,7 @@ function installBundle() {
48926
49482
  mkdirSync3(logDir(), { recursive: true });
48927
49483
  const src = runningCliPath();
48928
49484
  const dest = installedCliPath();
48929
- if (!existsSync8(src)) {
49485
+ if (!existsSync9(src)) {
48930
49486
  throw new Error(
48931
49487
  `Can't find the CLI bundle to install from (${src}). Are you running a local dev build?`
48932
49488
  );
@@ -48945,7 +49501,7 @@ function sourceLlamaVersion(sourceCli) {
48945
49501
  let d = dirname6(realpathSync(req.resolve("node-llama-cpp")));
48946
49502
  for (let i = 0; i < 10; i++) {
48947
49503
  const pj = join7(d, "package.json");
48948
- if (existsSync8(pj)) {
49504
+ if (existsSync9(pj)) {
48949
49505
  const p = JSON.parse(readFileSync4(pj, "utf8"));
48950
49506
  if (p.name === "node-llama-cpp" && p.version) return p.version;
48951
49507
  }
@@ -49012,7 +49568,7 @@ function locateTrayExecutable() {
49012
49568
  "/Applications/ModelstatTray.app/Contents/MacOS/modelstat-tray"
49013
49569
  ];
49014
49570
  for (const p of candidates) {
49015
- if (existsSync8(p)) return p;
49571
+ if (existsSync9(p)) return p;
49016
49572
  }
49017
49573
  return null;
49018
49574
  }
@@ -49084,7 +49640,7 @@ function macUninstall() {
49084
49640
  const target = `gui/${uid}/${SERVICE_LABEL}`;
49085
49641
  launchctl(["bootout", target]);
49086
49642
  const plist = plistPath();
49087
- if (existsSync8(plist)) {
49643
+ if (existsSync9(plist)) {
49088
49644
  try {
49089
49645
  unlinkSync(plist);
49090
49646
  } catch {
@@ -49147,7 +49703,7 @@ function linuxInstall() {
49147
49703
  function linuxUninstall() {
49148
49704
  systemctl(["disable", "--now", `${SYSTEMD_UNIT}.service`]);
49149
49705
  const unit = systemdUnitPath();
49150
- if (existsSync8(unit)) {
49706
+ if (existsSync9(unit)) {
49151
49707
  try {
49152
49708
  unlinkSync(unit);
49153
49709
  } catch {
@@ -49191,7 +49747,7 @@ function logsDir() {
49191
49747
  }
49192
49748
  function installTrayApp(sourceAppPath) {
49193
49749
  if (platform3() !== "darwin") return null;
49194
- if (!existsSync8(sourceAppPath)) return null;
49750
+ if (!existsSync9(sourceAppPath)) return null;
49195
49751
  const dest = join7(home(), "Applications", "ModelstatTray.app");
49196
49752
  mkdirSync3(dirname6(dest), { recursive: true });
49197
49753
  spawnSync2("rm", ["-rf", dest]);
@@ -49211,7 +49767,7 @@ function bundledTrayAppPath() {
49211
49767
  join7(here2, "..", "..", "tray-mac", "build", "ModelstatTray.app")
49212
49768
  ];
49213
49769
  for (const c of candidates) {
49214
- if (existsSync8(c)) return c;
49770
+ if (existsSync9(c)) return c;
49215
49771
  }
49216
49772
  const sourceDirs = [
49217
49773
  join7(here2, "..", "vendor", "tray-mac"),
@@ -49219,12 +49775,12 @@ function bundledTrayAppPath() {
49219
49775
  ];
49220
49776
  for (const src of sourceDirs) {
49221
49777
  const build = join7(src, "build-app.sh");
49222
- if (!existsSync8(build)) continue;
49778
+ if (!existsSync9(build)) continue;
49223
49779
  if (!hasSwift()) return null;
49224
49780
  const r = spawnSync2("bash", [build], { cwd: src, encoding: "utf8" });
49225
49781
  if (r.status === 0) {
49226
49782
  const app = join7(src, "build", "ModelstatTray.app");
49227
- if (existsSync8(app)) return app;
49783
+ if (existsSync9(app)) return app;
49228
49784
  }
49229
49785
  }
49230
49786
  return null;
@@ -49250,7 +49806,7 @@ function decideSupervision(input) {
49250
49806
  const fresh = input.statusFreshMs ?? STATUS_FRESH_MS;
49251
49807
  const grace = input.bootGraceMs ?? BOOT_GRACE_MS;
49252
49808
  if (!input.lock || !input.ownerAlive) return "spawn";
49253
- if (input.myAgentVersion && input.lock.agentVersion !== "unknown" && input.lock.agentVersion !== input.myAgentVersion) {
49809
+ if (input.myCompanionVersion && input.lock.companionVersion !== "unknown" && input.lock.companionVersion !== input.myCompanionVersion) {
49254
49810
  return "replace";
49255
49811
  }
49256
49812
  if (input.statusAgeMs !== null && input.statusAgeMs <= fresh) return "adopt";
@@ -49278,7 +49834,7 @@ function daemonHealth(opts = {}) {
49278
49834
  ownerAlive,
49279
49835
  lockAgeMs,
49280
49836
  statusAgeMs,
49281
- myAgentVersion: opts.myAgentVersion
49837
+ myCompanionVersion: opts.myCompanionVersion
49282
49838
  }),
49283
49839
  lock,
49284
49840
  ownerAlive,
@@ -49322,7 +49878,7 @@ function tryOpenBrowser(url) {
49322
49878
  return false;
49323
49879
  }
49324
49880
  }
49325
- var AGENT_VERSION3 = true ? "agent-0.0.49" : "agent-dev";
49881
+ var AGENT_VERSION3 = true ? "agent-0.0.51" : "agent-dev";
49326
49882
  function osFamily() {
49327
49883
  const p = platform5();
49328
49884
  if (p === "darwin") return "macos";
@@ -49349,8 +49905,8 @@ async function cmdSelfRegister() {
49349
49905
  os_family: osFamily(),
49350
49906
  os_version: release(),
49351
49907
  arch: osArch(),
49352
- agent: "modelstat-agent-dev",
49353
- agent_version: AGENT_VERSION3,
49908
+ companion: "modelstat-agent-dev",
49909
+ companion_version: AGENT_VERSION3,
49354
49910
  // Stable, install-method-independent machine key. The server
49355
49911
  // dedupes self-register on this so the same physical machine can
49356
49912
  // never become two device rows, even if the UUID somehow differs
@@ -49476,9 +50032,10 @@ async function cmdConnect(opts) {
49476
50032
  }
49477
50033
  }
49478
50034
  }
50035
+ const apiBase = state.apiUrl.replace(/\/$/, "");
49479
50036
  const claimCode = state.claimCode ?? "(unknown)";
49480
- const claimUrl = state.claimUrl ?? `https://modelstat.ai/device/${claimCode}`;
49481
- const agentUrl = `https://modelstat.ai/device/${claimCode}/agent`;
50037
+ const claimUrl = state.claimUrl ?? `${apiBase}/device/${claimCode}`;
50038
+ const agentUrl = `${apiBase}/device/${claimCode}/agent`;
49482
50039
  emitEvent(opts, "registered", {
49483
50040
  device_uuid: state.deviceUuid,
49484
50041
  device_id: state.deviceId,
@@ -49704,11 +50261,11 @@ function fmtTokens(v) {
49704
50261
  }
49705
50262
  async function readLocalStatus() {
49706
50263
  try {
49707
- const { homedir: homedir11 } = await import("os");
49708
- const { join: join13 } = await import("path");
49709
- const { readFile } = await import("fs/promises");
49710
- const p = join13(homedir11(), ".modelstat", "last-status.json");
49711
- const txt = await readFile(p, "utf8");
50264
+ const { homedir: homedir12 } = await import("os");
50265
+ const { join: join14 } = await import("path");
50266
+ const { readFile: readFile2 } = await import("fs/promises");
50267
+ const p = join14(homedir12(), ".modelstat", "last-status.json");
50268
+ const txt = await readFile2(p, "utf8");
49712
50269
  return JSON.parse(txt);
49713
50270
  } catch {
49714
50271
  return null;
@@ -49766,9 +50323,9 @@ async function cmdStats(args) {
49766
50323
  }
49767
50324
  console.log(`device: ${view.device.id}`);
49768
50325
  console.log(`host: ${view.device.hostname ?? "(unknown)"} (${view.device.os_family ?? "?"})`);
49769
- console.log(`agent: ${view.device.agent_version ?? "(unknown)"}`);
50326
+ console.log(`companion: ${view.device.companion_version ?? "(unknown)"}`);
49770
50327
  console.log(
49771
- `status: ${view.device.agent_status ?? "(unknown)"}${view.device.last_seen_at ? ` \xB7 last seen ${view.device.last_seen_at}` : ""}`
50328
+ `status: ${view.device.companion_status ?? "(unknown)"}${view.device.last_seen_at ? ` \xB7 last seen ${view.device.last_seen_at}` : ""}`
49772
50329
  );
49773
50330
  console.log(
49774
50331
  `claim: ${view.status}${view.status === "unclaimed" ? ` (at ${view.claim_url})` : ""}`
@@ -49896,7 +50453,7 @@ async function main() {
49896
50453
  }
49897
50454
  case "_daemon-health": {
49898
50455
  try {
49899
- console.log(JSON.stringify(daemonHealth({ myAgentVersion: AGENT_VERSION3 })));
50456
+ console.log(JSON.stringify(daemonHealth({ myCompanionVersion: AGENT_VERSION3 })));
49900
50457
  } catch (e) {
49901
50458
  console.log(JSON.stringify({ decision: "spawn", error: e.message }));
49902
50459
  }