eminiar 0.13.4 → 0.13.5

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.js CHANGED
@@ -16309,8 +16309,8 @@ var init_to_json_schema = __esm({
16309
16309
  function aggregateChecks(schema) {
16310
16310
  const agg = {};
16311
16311
  const def = schema._zod.def;
16312
- const list2 = schema._zod.traits.has("$ZodCheck") ? [schema, ...def.checks ?? []] : def.checks ?? [];
16313
- for (const ch of list2)
16312
+ const list3 = schema._zod.traits.has("$ZodCheck") ? [schema, ...def.checks ?? []] : def.checks ?? [];
16313
+ for (const ch of list3)
16314
16314
  contributors[ch._zod.def.check]?.(agg, ch._zod.def);
16315
16315
  const bag = schema._zod.bag;
16316
16316
  if (bag.minimum !== void 0)
@@ -24758,6 +24758,57 @@ var init_storage = __esm({
24758
24758
  }
24759
24759
  });
24760
24760
 
24761
+ // src/search/typo.ts
24762
+ function editDistance(a, b, max = 3) {
24763
+ if (Math.abs(a.length - b.length) > max) return max + 1;
24764
+ const prev2 = [];
24765
+ let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
24766
+ let cur = new Array(b.length + 1).fill(0);
24767
+ for (let i = 1; i <= a.length; i++) {
24768
+ cur[0] = i;
24769
+ let rowMin = cur[0];
24770
+ for (let j = 1; j <= b.length; j++) {
24771
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
24772
+ let v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
24773
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
24774
+ v = Math.min(v, prev2[j - 2] + 1);
24775
+ }
24776
+ cur[j] = v;
24777
+ if (v < rowMin) rowMin = v;
24778
+ }
24779
+ if (rowMin > max) return max + 1;
24780
+ prev2.splice(0, prev2.length, ...prev);
24781
+ [prev, cur] = [cur, prev];
24782
+ }
24783
+ return prev[b.length];
24784
+ }
24785
+ function correctTerms(db, terms) {
24786
+ const corrections = [];
24787
+ const out = terms.map((term) => {
24788
+ if (term.length < 4 || /[^a-z0-9]/.test(term) || db.termExists(term)) return term;
24789
+ const max = term.length >= 7 ? 2 : 1;
24790
+ const candidates2 = db.vocabCandidates(term[0], 3e3);
24791
+ let best;
24792
+ for (const c of candidates2) {
24793
+ if (c.term.length < 3) continue;
24794
+ const d = editDistance(term, c.term, max);
24795
+ if (d > max) continue;
24796
+ if (!best || d < best.d || d === best.d && c.df > best.df)
24797
+ best = { term: c.term, d, df: c.df };
24798
+ }
24799
+ if (!best) return term;
24800
+ corrections.push({ from: term, to: best.term });
24801
+ return `${best.term}*`;
24802
+ });
24803
+ return { terms: out, corrections };
24804
+ }
24805
+ var init_typo = __esm({
24806
+ "src/search/typo.ts"() {
24807
+ "use strict";
24808
+ init_esm_shims();
24809
+ }
24810
+ });
24811
+
24761
24812
  // src/swarm/glob.ts
24762
24813
  function normalize(g) {
24763
24814
  let s = g.trim().replace(/\\/g, "/");
@@ -24893,6 +24944,52 @@ function mergeContext(...layers) {
24893
24944
  }
24894
24945
  return out;
24895
24946
  }
24947
+ function unknownKeys(v, s = RawFile, at = []) {
24948
+ if (s instanceof external_exports.ZodOptional) s = s.unwrap();
24949
+ if (Array.isArray(v))
24950
+ return s instanceof external_exports.ZodArray ? v.flatMap((x, i) => unknownKeys(x, s.element, [...at, String(i)])) : [];
24951
+ if (!v || typeof v !== "object") return [];
24952
+ const entries = Object.entries(v);
24953
+ if (s instanceof external_exports.ZodRecord)
24954
+ return entries.flatMap(([k, x]) => unknownKeys(x, s.valueType, [...at, k]));
24955
+ if (!(s instanceof external_exports.ZodObject)) return [];
24956
+ const known = Object.keys(s.shape);
24957
+ return entries.flatMap(
24958
+ ([k, x]) => Object.hasOwn(s.shape, k) ? unknownKeys(x, s.shape[k], [...at, k]) : at.length === 0 && (k.startsWith("x-") || k === "<<") ? [] : [{ at, key: k, known }]
24959
+ );
24960
+ }
24961
+ function schemaKeys(s = RawFile, out = /* @__PURE__ */ new Set()) {
24962
+ if (s instanceof external_exports.ZodOptional) s = s.unwrap();
24963
+ if (s instanceof external_exports.ZodArray) schemaKeys(s.element, out);
24964
+ else if (s instanceof external_exports.ZodRecord) schemaKeys(s.valueType, out);
24965
+ else if (s instanceof external_exports.ZodObject) {
24966
+ for (const [k, v] of Object.entries(s.shape))
24967
+ if (!out.has(k)) {
24968
+ out.add(k);
24969
+ schemaKeys(v, out);
24970
+ }
24971
+ }
24972
+ return out;
24973
+ }
24974
+ function restrictionLike(key, known) {
24975
+ let best;
24976
+ for (const k of known) {
24977
+ if (!RESTRICTION_KEY.test(k)) continue;
24978
+ const d = editDistance(key.toLowerCase(), k.toLowerCase(), 2);
24979
+ if (d <= 2 && key.length >= 3 && (!best || d < best.d)) best = { k, d };
24980
+ }
24981
+ if (best) return best.k;
24982
+ return RESTRICTION_KEY.test(key) ? "" : void 0;
24983
+ }
24984
+ function typoOf(key, known) {
24985
+ const max = key.length >= 7 ? 2 : 1;
24986
+ let best;
24987
+ for (const k of known) {
24988
+ const d = editDistance(key.toLowerCase(), k.toLowerCase(), max);
24989
+ if (d <= max && (!best || d < best.d)) best = { k, d };
24990
+ }
24991
+ return best?.k;
24992
+ }
24896
24993
  function roleRange(defaults, a, at, issue2) {
24897
24994
  const spec = a.model_range ?? defaults?.model_range;
24898
24995
  if (!spec || !spec.floor && !spec.ceiling) return void 0;
@@ -25028,6 +25125,27 @@ function parseSwarmYaml(text3, file3, rel) {
25028
25125
  for (const role of Object.keys(agents))
25029
25126
  checkName(["swarms", name, "agents", role], role, "agent");
25030
25127
  }
25128
+ const ignoredKeys = [];
25129
+ const allKeys = schemaKeys();
25130
+ for (const u of unknownKeys(js)) {
25131
+ const near = typoOf(u.key, u.known);
25132
+ const found = { path: u.at.join("."), line: lineOf([...u.at, u.key]) };
25133
+ if (allKeys.has(u.key))
25134
+ issues.push({ ...found, message: `unknown key "${u.key}": not allowed here` });
25135
+ else if (near)
25136
+ issues.push({ ...found, message: `unknown key "${u.key}" (did you mean "${near}"?)` });
25137
+ else if (u.at.length === 4 && u.at[0] === "swarms" && u.at[2] === "agents" && restrictionLike(u.key, u.known) !== void 0) {
25138
+ const like = restrictionLike(u.key, u.known);
25139
+ issues.push({
25140
+ ...found,
25141
+ message: `unknown key "${u.key}" looks like a restriction${like ? ` (did you mean "${like}"?)` : ""}: ignoring it would silently drop a limit`
25142
+ });
25143
+ } else
25144
+ ignoredKeys.push({
25145
+ ...found,
25146
+ message: `unknown key "${u.key}" ignored: not a setting in this eminiar version`
25147
+ });
25148
+ }
25031
25149
  const parsed = RawFile.safeParse(js);
25032
25150
  if (!parsed.success) {
25033
25151
  return {
@@ -25045,15 +25163,9 @@ function parseSwarmYaml(text3, file3, rel) {
25045
25163
  ]
25046
25164
  };
25047
25165
  }
25048
- for (const k of Object.keys(js))
25049
- if (!TOP_KEYS.has(k) && !k.startsWith("x-") && k !== "<<")
25050
- issue2(
25051
- [k],
25052
- `unknown key "${k}" (top-level keys: ${[...TOP_KEYS].join(", ")}; x-* keys may hold YAML anchors)`
25053
- );
25054
25166
  const config2 = resolve3(parsed.data, file3, rel, issue2);
25055
25167
  if (issues.length) return { state: "invalid", file: file3, rel, enforce, issues };
25056
- return { state: "ok", config: config2 };
25168
+ return { state: "ok", config: { ...config2, ignoredKeys } };
25057
25169
  }
25058
25170
  function resolve3(raw, file3, rel, issue2) {
25059
25171
  const swarms = [];
@@ -25174,13 +25286,14 @@ function findRole(config2, agentType) {
25174
25286
  for (const role of swarm.roles) if (role.agentType === agentType) return { swarm, role };
25175
25287
  return void 0;
25176
25288
  }
25177
- var yamlLib, SWARM_FILES, AGENT_NAME_MAX, NAME_RE, NAME_MAX, NAME_MSG, noFence, FENCE_MSG, MODEL_RE, TOP_KEYS, DEFAULT_CONTEXT, AGENT_COLORS, ToolName, SkillName, Model, rank, RawModelRange, Glob, AgentName, RawContext, RawHookCommand, RawHookMatcher, RawHooks, RawAgent, RawSwarm, RawFile, uniq, MAX_FILE_CHARS, cache3, STARTER_YAML;
25289
+ var yamlLib, SWARM_FILES, AGENT_NAME_MAX, NAME_RE, NAME_MAX, NAME_MSG, noFence, FENCE_MSG, MODEL_RE, DEFAULT_CONTEXT, AGENT_COLORS, ToolName, SkillName, Model, rank, RawModelRange, Glob, AgentName, RawContext, RawHookCommand, RawHookMatcher, RawHooks, RawAgent, RawSwarm, RawFile, uniq, RESTRICTION_KEY, MAX_FILE_CHARS, cache3, STARTER_YAML;
25178
25290
  var init_config2 = __esm({
25179
25291
  "src/swarm/config.ts"() {
25180
25292
  "use strict";
25181
25293
  init_esm_shims();
25182
25294
  init_zod();
25183
25295
  init_types();
25296
+ init_typo();
25184
25297
  init_dispatch();
25185
25298
  init_glob();
25186
25299
  init_types2();
@@ -25192,15 +25305,6 @@ var init_config2 = __esm({
25192
25305
  noFence = (s) => !s.includes("---");
25193
25306
  FENCE_MSG = 'must not contain "---" (Claude Code would end the agent frontmatter there)';
25194
25307
  MODEL_RE = /^(?:inherit|opusplan|(?:sonnet|opus|haiku|fable)(?:\[1m\])?|(?:[a-z0-9-]+\.)*claude-[a-z0-9.:@-]+(?:\[1m\])?)$/;
25195
- TOP_KEYS = /* @__PURE__ */ new Set([
25196
- "version",
25197
- "enabled",
25198
- "sync",
25199
- "enforce",
25200
- "allowed_agents",
25201
- "defaults",
25202
- "swarms"
25203
- ]);
25204
25308
  DEFAULT_CONTEXT = {
25205
25309
  memories: 4,
25206
25310
  docs: 2,
@@ -25229,7 +25333,7 @@ var init_config2 = __esm({
25229
25333
  ).refine(noFence, FENCE_MSG);
25230
25334
  Model = external_exports.string().max(100).regex(MODEL_RE, "a model alias (inherit, sonnet, opus, haiku, fable) or a Claude model id").refine(noFence, FENCE_MSG);
25231
25335
  rank = (t) => TIERS.indexOf(t);
25232
- RawModelRange = external_exports.strictObject({ floor: external_exports.enum(TIERS).optional(), ceiling: external_exports.enum(TIERS).optional() }).refine(
25336
+ RawModelRange = external_exports.object({ floor: external_exports.enum(TIERS).optional(), ceiling: external_exports.enum(TIERS).optional() }).refine(
25233
25337
  (r) => !r.floor || !r.ceiling || rank(r.floor) <= rank(r.ceiling),
25234
25338
  `floor must not be above ceiling (${TIERS.join(" < ")})`
25235
25339
  );
@@ -25253,7 +25357,7 @@ var init_config2 = __esm({
25253
25357
  (n) => !n.startsWith("swarm-"),
25254
25358
  "swarm workers need no entry: they are allowed during a run of their swarm"
25255
25359
  );
25256
- RawContext = external_exports.strictObject({
25360
+ RawContext = external_exports.object({
25257
25361
  memories: external_exports.number().int().min(0).max(10).optional(),
25258
25362
  docs: external_exports.number().int().min(0).max(10).optional(),
25259
25363
  history: external_exports.boolean().optional(),
@@ -25262,12 +25366,12 @@ var init_config2 = __esm({
25262
25366
  // SubagentStart context over 10,000 characters is moved to a file Claude may never read.
25263
25367
  max_chars: external_exports.number().int().min(500).max(9e3).optional()
25264
25368
  });
25265
- RawHookCommand = external_exports.strictObject({
25369
+ RawHookCommand = external_exports.object({
25266
25370
  type: external_exports.literal("command"),
25267
25371
  command: external_exports.string().trim().min(1).max(2e3).refine(noFence, FENCE_MSG),
25268
25372
  timeout: external_exports.number().int().positive().max(600).optional()
25269
25373
  });
25270
- RawHookMatcher = external_exports.strictObject({
25374
+ RawHookMatcher = external_exports.object({
25271
25375
  matcher: external_exports.string().max(200).refine(noFence, FENCE_MSG).refine((m) => {
25272
25376
  try {
25273
25377
  new RegExp(m);
@@ -25278,12 +25382,12 @@ var init_config2 = __esm({
25278
25382
  }, "not a valid regular expression (Claude Code matches tool names with it)").optional(),
25279
25383
  hooks: external_exports.array(RawHookCommand).min(1).max(10)
25280
25384
  });
25281
- RawHooks = external_exports.strictObject({
25385
+ RawHooks = external_exports.object({
25282
25386
  PreToolUse: external_exports.array(RawHookMatcher).max(10).optional(),
25283
25387
  PostToolUse: external_exports.array(RawHookMatcher).max(10).optional(),
25284
25388
  Stop: external_exports.array(RawHookMatcher).max(10).optional()
25285
25389
  });
25286
- RawAgent = external_exports.strictObject({
25390
+ RawAgent = external_exports.object({
25287
25391
  description: external_exports.string().trim().min(1).max(500).refine(noFence, FENCE_MSG),
25288
25392
  prompt: external_exports.string().max(2e4).optional(),
25289
25393
  model: Model.optional(),
@@ -25301,7 +25405,7 @@ var init_config2 = __esm({
25301
25405
  color: external_exports.enum(AGENT_COLORS).optional(),
25302
25406
  context: RawContext.optional()
25303
25407
  });
25304
- RawSwarm = external_exports.strictObject({
25408
+ RawSwarm = external_exports.object({
25305
25409
  description: external_exports.string().trim().min(1).max(500),
25306
25410
  topology: external_exports.enum(TOPOLOGIES).optional(),
25307
25411
  max_agents: external_exports.number().int().min(1).max(16).optional(),
@@ -25317,7 +25421,7 @@ var init_config2 = __esm({
25317
25421
  sync: external_exports.enum(["auto", "manual"]).optional(),
25318
25422
  enforce: external_exports.boolean().optional(),
25319
25423
  allowed_agents: external_exports.array(AgentName).max(50).optional(),
25320
- defaults: external_exports.strictObject({
25424
+ defaults: external_exports.object({
25321
25425
  model: Model.optional(),
25322
25426
  model_range: RawModelRange.optional(),
25323
25427
  skills: external_exports.array(SkillName).max(20).optional(),
@@ -25326,6 +25430,7 @@ var init_config2 = __esm({
25326
25430
  swarms: external_exports.record(external_exports.string(), RawSwarm)
25327
25431
  });
25328
25432
  uniq = (xs) => [...new Set(xs)];
25433
+ RESTRICTION_KEY = /tool|scope|hook|allow|deny|permission|model|effort|count/i;
25329
25434
  MAX_FILE_CHARS = 256e3;
25330
25435
  cache3 = /* @__PURE__ */ new Map();
25331
25436
  STARTER_YAML = `# eminiar agent swarms (opt-in). Docs: https://github.com/rydn/eminiar/blob/main/docs/swarms.md
@@ -25838,9 +25943,9 @@ function consentedOrigins(a) {
25838
25943
  return out;
25839
25944
  }
25840
25945
  function withConsentedOrigin(a, origin) {
25841
- const list2 = consentedOrigins(a);
25842
- if (!list2.includes(origin)) list2.push(origin);
25843
- return list2;
25946
+ const list3 = consentedOrigins(a);
25947
+ if (!list3.includes(origin)) list3.push(origin);
25948
+ return list3;
25844
25949
  }
25845
25950
  function isLoopback(url2) {
25846
25951
  if (!url2) return false;
@@ -28012,11 +28117,11 @@ function createOpenAIProvider(r, cfg, deps = {}) {
28012
28117
  };
28013
28118
  }
28014
28119
  function mapAnswers(reqs, items2, raw, cat, askTool) {
28015
- const list2 = raw && typeof raw === "object" && Array.isArray(raw.items) ? raw.items : void 0;
28016
- if (!list2) throw new ProviderError("invalid", "the answer has no items array");
28120
+ const list3 = raw && typeof raw === "object" && Array.isArray(raw.items) ? raw.items : void 0;
28121
+ if (!list3) throw new ProviderError("invalid", "the answer has no items array");
28017
28122
  const Item = itemSchema(cat, askTool);
28018
28123
  const byId = /* @__PURE__ */ new Map();
28019
- for (const x of list2) {
28124
+ for (const x of list3) {
28020
28125
  const p2 = Item.safeParse(x);
28021
28126
  if (p2.success && !byId.has(p2.data.id)) byId.set(p2.data.id, p2.data);
28022
28127
  }
@@ -29437,8 +29542,8 @@ function pricedSavings(stats, calls, overrides, opts = {}) {
29437
29542
  };
29438
29543
  const bySession2 = /* @__PURE__ */ new Map();
29439
29544
  for (const c of calls) {
29440
- const list2 = bySession2.get(c.session_id);
29441
- if (list2) list2.push(c);
29545
+ const list3 = bySession2.get(c.session_id);
29546
+ if (list3) list3.push(c);
29442
29547
  else bySession2.set(c.session_id, [c]);
29443
29548
  }
29444
29549
  const sessionModel = /* @__PURE__ */ new Map();
@@ -29597,29 +29702,29 @@ function promptWindows(prompts, calls) {
29597
29702
  const bySession2 = /* @__PURE__ */ new Map();
29598
29703
  for (const p2 of prompts) {
29599
29704
  if (!p2.sessionId) continue;
29600
- const list2 = bySession2.get(p2.sessionId);
29601
- if (list2) list2.push(p2);
29705
+ const list3 = bySession2.get(p2.sessionId);
29706
+ if (list3) list3.push(p2);
29602
29707
  else bySession2.set(p2.sessionId, [p2]);
29603
29708
  }
29604
- for (const list2 of bySession2.values()) list2.sort((a, b) => a.ts - b.ts || a.id - b.id);
29709
+ for (const list3 of bySession2.values()) list3.sort((a, b) => a.ts - b.ts || a.id - b.id);
29605
29710
  const out = /* @__PURE__ */ new Map();
29606
29711
  for (const p2 of prompts) out.set(p2.id, []);
29607
29712
  for (const c of calls) {
29608
29713
  if (c.sidechain) continue;
29609
- const list2 = bySession2.get(c.session_id);
29610
- if (!list2) continue;
29714
+ const list3 = bySession2.get(c.session_id);
29715
+ if (!list3) continue;
29611
29716
  let lo = 0;
29612
- let hi = list2.length - 1;
29717
+ let hi = list3.length - 1;
29613
29718
  let at = -1;
29614
29719
  while (lo <= hi) {
29615
29720
  const mid = lo + hi >> 1;
29616
- if (list2[mid].ts <= c.ts) {
29721
+ if (list3[mid].ts <= c.ts) {
29617
29722
  at = mid;
29618
29723
  lo = mid + 1;
29619
29724
  } else hi = mid - 1;
29620
29725
  }
29621
29726
  if (at < 0) continue;
29622
- out.get(list2[at].id)?.push(c);
29727
+ out.get(list3[at].id)?.push(c);
29623
29728
  }
29624
29729
  return out;
29625
29730
  }
@@ -30223,8 +30328,8 @@ var init_learn = __esm({
30223
30328
  const m = /* @__PURE__ */ new Map();
30224
30329
  for (const p2 of allRows(this.db, { surface: "prompt", since })) {
30225
30330
  if (!p2.sessionId) continue;
30226
- const list2 = m.get(p2.sessionId);
30227
- if (list2) list2.push(p2);
30331
+ const list3 = m.get(p2.sessionId);
30332
+ if (list3) list3.push(p2);
30228
30333
  else m.set(p2.sessionId, [p2]);
30229
30334
  }
30230
30335
  this.promptsBySession = m;
@@ -30250,8 +30355,8 @@ var init_learn = __esm({
30250
30355
  const bySession2 = /* @__PURE__ */ new Map();
30251
30356
  for (const r of targets) {
30252
30357
  if (r.agentId || !r.sessionId) continue;
30253
- const list2 = bySession2.get(r.sessionId);
30254
- if (list2) list2.push(r);
30358
+ const list3 = bySession2.get(r.sessionId);
30359
+ if (list3) list3.push(r);
30255
30360
  else bySession2.set(r.sessionId, [r]);
30256
30361
  }
30257
30362
  if (!bySession2.size) return;
@@ -30269,8 +30374,8 @@ var init_learn = __esm({
30269
30374
  const callsBy = /* @__PURE__ */ new Map();
30270
30375
  for (const c of this.calls(sessionId)) {
30271
30376
  if (!c.sidechain || !c.agent_id || this.taken.has(c.agent_id)) continue;
30272
- const list2 = callsBy.get(c.agent_id);
30273
- if (list2) list2.push(c);
30377
+ const list3 = callsBy.get(c.agent_id);
30378
+ if (list3) list3.push(c);
30274
30379
  else callsBy.set(c.agent_id, [c]);
30275
30380
  }
30276
30381
  const agents = [...callsBy].map(([id, cs]) => ({
@@ -31235,6 +31340,68 @@ function existingGenerated(dir) {
31235
31340
  }
31236
31341
  return out;
31237
31342
  }
31343
+ function ignoredWhere(ignored, config2, agentType) {
31344
+ const hit = config2.swarms.flatMap(
31345
+ (swarm) => swarm.roles.filter((r) => r.agentType === agentType).map((r) => ({ swarm, role: r }))
31346
+ )[0];
31347
+ if (!hit) return [];
31348
+ const out = [];
31349
+ for (const i of ignored) {
31350
+ const seg = i.path === "" ? [] : i.path.split(".");
31351
+ const name = /"(.+?)"/.exec(i.message)?.[1] ?? "?";
31352
+ const mine = seg[0] !== "swarms" || seg.length < 2 || seg[1] === hit.swarm.name && (seg.length < 4 || seg[2] !== "agents" || seg[3] === hit.role.role);
31353
+ if (mine) out.push(name);
31354
+ }
31355
+ return out;
31356
+ }
31357
+ function frontmatterOf(raw) {
31358
+ const content = raw.replace(/\r\n/g, "\n");
31359
+ const end = content.indexOf("\n---\n", 3);
31360
+ if (!content.startsWith("---\n") || end === -1) return void 0;
31361
+ try {
31362
+ const v = yaml2().parse(content.slice(4, end));
31363
+ return v && typeof v === "object" ? v : void 0;
31364
+ } catch {
31365
+ return void 0;
31366
+ }
31367
+ }
31368
+ function tightens(oldRaw, newRaw) {
31369
+ const o = frontmatterOf(oldRaw);
31370
+ const n = frontmatterOf(newRaw);
31371
+ if (!o || !n) return false;
31372
+ let tighter = false;
31373
+ for (const k of Object.keys(o)) {
31374
+ if (NEUTRAL_KEYS.has(k)) continue;
31375
+ if (!(k in n)) return false;
31376
+ const a = o[k];
31377
+ const b = n[k];
31378
+ if (JSON.stringify(a) === JSON.stringify(b)) continue;
31379
+ if (k === "tools") {
31380
+ const ob = new Set(list(a));
31381
+ const nb = list(b);
31382
+ if (!nb.every((t) => ob.has(t))) return false;
31383
+ tighter = true;
31384
+ } else if (k === "disallowedTools") {
31385
+ const nb = new Set(list(b));
31386
+ if (!list(a).every((t) => nb.has(t))) return false;
31387
+ tighter = true;
31388
+ } else if (k === "hooks") {
31389
+ const oh = a ?? {};
31390
+ const nh = b ?? {};
31391
+ for (const [ev3, entries] of Object.entries(oh)) {
31392
+ const have = new Set((nh[ev3] ?? []).map((e) => JSON.stringify(e)));
31393
+ if (!Array.isArray(entries) || !entries.every((e) => have.has(JSON.stringify(e))))
31394
+ return false;
31395
+ }
31396
+ tighter = true;
31397
+ } else if (k === "maxTurns") {
31398
+ if (typeof a !== "number" || typeof b !== "number" || b > a) return false;
31399
+ tighter = true;
31400
+ } else return false;
31401
+ }
31402
+ for (const k of Object.keys(n)) if (!(k in o) && !NEUTRAL_KEYS.has(k)) tighter = true;
31403
+ return tighter;
31404
+ }
31238
31405
  function planAgentSync(root, config2, opts = {}) {
31239
31406
  const dir = agentsDir(root);
31240
31407
  const wantedRoles = config2?.enabled ? config2.swarms.flatMap((swarm) => swarm.roles.map((role) => ({ swarm, role }))) : [];
@@ -31302,6 +31469,24 @@ function planAgentSync(root, config2, opts = {}) {
31302
31469
  reason: config2?.enabled ? "no longer in the swarm file" : "swarms are disabled"
31303
31470
  }
31304
31471
  );
31472
+ const ignored = config2?.ignoredKeys ?? [];
31473
+ if (ignored.length && !opts.force) {
31474
+ const holds = (agentType) => ignoredWhere(ignored, config2, agentType);
31475
+ return actions.map((a) => {
31476
+ if (a.action !== "update") return a;
31477
+ const where = holds(a.agentType);
31478
+ if (!where.length) return a;
31479
+ const old = generated.get(a.agentType);
31480
+ if (old && tightens(old.content, a.content ?? "")) return a;
31481
+ return {
31482
+ agentType: a.agentType,
31483
+ path: a.path,
31484
+ action: "conflict",
31485
+ held: true,
31486
+ reason: `kept: ${config2.rel} has keys this eminiar version does not know (${where.slice(0, 3).join(", ")}${where.length > 3 ? ", ..." : ""}), and a newer one may have generated this file with them; update eminiar, or sync with --force`
31487
+ };
31488
+ });
31489
+ }
31305
31490
  return actions;
31306
31491
  }
31307
31492
  function syncAgents(root, config2, opts = {}) {
@@ -31343,7 +31528,7 @@ function syncAgents(root, config2, opts = {}) {
31343
31528
  }
31344
31529
  return { actions, changed, conflicts: actions.filter((a) => a.action === "conflict").length };
31345
31530
  }
31346
- var MARKER_PREFIX, HASH_RE, RANGE_RE, WORKER_EM_TOOLS, yamlLib2, EXEC_TOOLS, EM_MCP_PREFIXES, AGENTS_REL, TOPOLOGY_RULE, execToolNames, hashOf, SHARED_TREE_RULE;
31531
+ var MARKER_PREFIX, HASH_RE, RANGE_RE, WORKER_EM_TOOLS, yamlLib2, EXEC_TOOLS, EM_MCP_PREFIXES, AGENTS_REL, TOPOLOGY_RULE, execToolNames, hashOf, SHARED_TREE_RULE, list, NEUTRAL_KEYS;
31347
31532
  var init_agents = __esm({
31348
31533
  "src/swarm/agents.ts"() {
31349
31534
  "use strict";
@@ -31387,6 +31572,8 @@ ${fm}
31387
31572
  ${rest2}` : `${fm}
31388
31573
  ${rest2}`).digest("hex").slice(0, 12);
31389
31574
  SHARED_TREE_RULE = "Other workers may be editing this working tree at the same time, and their changes are not committed. Never run `git stash`, `git checkout`, `git switch`, `git reset`, `git restore` or `git clean`, not even on one path: they hide or wipe another worker's work. If you commit, add only the files you changed: `git add -A` or `git commit -a` takes their unfinished work with yours. To test without your change (a mutation check), copy the files into a scratch directory outside the tree and run the tests there.";
31575
+ list = (v) => typeof v === "string" ? v.split(",").map((x) => x.trim()).filter(Boolean) : [];
31576
+ NEUTRAL_KEYS = /* @__PURE__ */ new Set(["name", "description", "skills", "color", "model", "effort"]);
31390
31577
  }
31391
31578
  });
31392
31579
 
@@ -31579,8 +31766,8 @@ function manifest(dir) {
31579
31766
  }
31580
31767
  function agentPaths(dir) {
31581
31768
  const a = manifest(dir)?.agents;
31582
- const list2 = typeof a === "string" ? [a] : Array.isArray(a) ? a.filter((x) => typeof x === "string") : [];
31583
- return (list2.length ? list2 : ["./agents"]).map((p2) => resolve4(dir, p2));
31769
+ const list3 = typeof a === "string" ? [a] : Array.isArray(a) ? a.filter((x) => typeof x === "string") : [];
31770
+ return (list3.length ? list3 : ["./agents"]).map((p2) => resolve4(dir, p2));
31584
31771
  }
31585
31772
  function pluginDefs(segments, env, home) {
31586
31773
  const [plugin, ...rest2] = segments;
@@ -34881,9 +35068,9 @@ var require_micromatch = __commonJS({
34881
35068
  const index = v.indexOf("{");
34882
35069
  return index > -1 && v.indexOf("}", index) > -1;
34883
35070
  };
34884
- var micromatch2 = (list2, patterns, options) => {
35071
+ var micromatch2 = (list3, patterns, options) => {
34885
35072
  patterns = [].concat(patterns);
34886
- list2 = [].concat(list2);
35073
+ list3 = [].concat(list3);
34887
35074
  let omit2 = /* @__PURE__ */ new Set();
34888
35075
  let keep = /* @__PURE__ */ new Set();
34889
35076
  let items2 = /* @__PURE__ */ new Set();
@@ -34898,7 +35085,7 @@ var require_micromatch = __commonJS({
34898
35085
  let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true);
34899
35086
  let negated = isMatch.state.negated || isMatch.state.negatedExtglob;
34900
35087
  if (negated) negatives++;
34901
- for (let item of list2) {
35088
+ for (let item of list3) {
34902
35089
  let matched = isMatch(item, true);
34903
35090
  let match = negated ? !matched.isMatch : matched.isMatch;
34904
35091
  if (!match) continue;
@@ -34926,7 +35113,7 @@ var require_micromatch = __commonJS({
34926
35113
  micromatch2.matcher = (pattern2, options) => picomatch(pattern2, options);
34927
35114
  micromatch2.isMatch = (str3, patterns, options) => picomatch(patterns, options)(str3);
34928
35115
  micromatch2.any = micromatch2.isMatch;
34929
- micromatch2.not = (list2, patterns, options = {}) => {
35116
+ micromatch2.not = (list3, patterns, options = {}) => {
34930
35117
  patterns = [].concat(patterns).map(String);
34931
35118
  let result = /* @__PURE__ */ new Set();
34932
35119
  let items2 = [];
@@ -34934,7 +35121,7 @@ var require_micromatch = __commonJS({
34934
35121
  if (options.onResult) options.onResult(state);
34935
35122
  items2.push(state.output);
34936
35123
  };
34937
- let matches2 = new Set(micromatch2(list2, patterns, { ...options, onResult }));
35124
+ let matches2 = new Set(micromatch2(list3, patterns, { ...options, onResult }));
34938
35125
  for (let item of items2) {
34939
35126
  if (!matches2.has(item)) {
34940
35127
  result.add(item);
@@ -34968,8 +35155,8 @@ var require_micromatch = __commonJS({
34968
35155
  for (let key of keys) res[key] = obj[key];
34969
35156
  return res;
34970
35157
  };
34971
- micromatch2.some = (list2, patterns, options) => {
34972
- let items2 = [].concat(list2);
35158
+ micromatch2.some = (list3, patterns, options) => {
35159
+ let items2 = [].concat(list3);
34973
35160
  for (let pattern2 of [].concat(patterns)) {
34974
35161
  let isMatch = picomatch(String(pattern2), options);
34975
35162
  if (items2.some((item) => isMatch(item))) {
@@ -34978,8 +35165,8 @@ var require_micromatch = __commonJS({
34978
35165
  }
34979
35166
  return false;
34980
35167
  };
34981
- micromatch2.every = (list2, patterns, options) => {
34982
- let items2 = [].concat(list2);
35168
+ micromatch2.every = (list3, patterns, options) => {
35169
+ let items2 = [].concat(list3);
34983
35170
  for (let pattern2 of [].concat(patterns)) {
34984
35171
  let isMatch = picomatch(String(pattern2), options);
34985
35172
  if (!items2.every((item) => isMatch(item))) {
@@ -38860,7 +39047,7 @@ function read(ctx, db, name) {
38860
39047
  row: synced.row
38861
39048
  };
38862
39049
  }
38863
- function list(ctx, db, opts = {}) {
39050
+ function list2(ctx, db, opts = {}) {
38864
39051
  void ctx;
38865
39052
  const rows = db.memoryList({ ...opts, limit: opts.limit ?? 100 }).filter((r) => r.name);
38866
39053
  return rows.sort((a, b) => Number(b.kind === "onboarding") - Number(a.kind === "onboarding"));
@@ -39286,6 +39473,7 @@ function formatSwarmList(config2, plan, active, opts = {}) {
39286
39473
  const lines = [
39287
39474
  `eminiar swarms \xB7 ${config2.rel} \xB7 sync ${config2.sync}${enforceNote(config2)} \xB7 agent files: ${fileSummary || "none"}`
39288
39475
  ];
39476
+ if (config2.ignoredKeys.length) lines.push(formatIssues(config2.rel, config2.ignoredKeys));
39289
39477
  if (opts.swarm && !swarms.length)
39290
39478
  lines.push(
39291
39479
  `No swarm "${opts.swarm}"; ${config2.rel} defines: ${config2.swarms.map((s) => s.name).join(", ")}`
@@ -39344,6 +39532,11 @@ function formatSync(result, opts = {}) {
39344
39532
  ` ${SYNC_VERB[a.action].mark} ${word(a.action)} ${a.path}${a.reason ? `: ${a.reason}` : ""}`
39345
39533
  );
39346
39534
  }
39535
+ const held = result.actions.filter((a) => a.held).length;
39536
+ if (held)
39537
+ lines.push(
39538
+ `${held} update(s) held: the swarm file has keys this eminiar version does not know, so those agent files were not rewritten (an update that only tightens a file still applies). Update eminiar, or run \`eminiar swarm sync --force\`.`
39539
+ );
39347
39540
  if (!opts.dryRun && result.actions.some((a) => a.action === "create"))
39348
39541
  lines.push(
39349
39542
  "Claude Code reads agent files when a session starts: if a new worker type is not available yet, open /agents or restart the session."
@@ -39871,8 +40064,8 @@ function groupBy(calls, keyFn) {
39871
40064
  if (!isRealCall(c)) continue;
39872
40065
  const k = keyFn(c);
39873
40066
  if (k == null) continue;
39874
- const list2 = buckets.get(k);
39875
- if (list2) list2.push(c);
40067
+ const list3 = buckets.get(k);
40068
+ if (list3) list3.push(c);
39876
40069
  else buckets.set(k, [c]);
39877
40070
  }
39878
40071
  return [...buckets.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, rows]) => ({ key, totals: totals(rows) }));
@@ -40573,18 +40766,18 @@ function threads(calls) {
40573
40766
  const out = /* @__PURE__ */ new Map();
40574
40767
  for (const c of calls) {
40575
40768
  const key = `${c.session_id}\0${c.sidechain ? c.agent_id ?? "sidechain" : ""}`;
40576
- const list2 = out.get(key);
40577
- if (list2) list2.push(c);
40769
+ const list3 = out.get(key);
40770
+ if (list3) list3.push(c);
40578
40771
  else out.set(key, [c]);
40579
40772
  }
40580
- for (const list2 of out.values()) list2.sort((a, b) => a.ts - b.ts);
40773
+ for (const list3 of out.values()) list3.sort((a, b) => a.ts - b.ts);
40581
40774
  return out;
40582
40775
  }
40583
40776
  function groupBySession(rows) {
40584
40777
  const out = /* @__PURE__ */ new Map();
40585
40778
  for (const r of rows) {
40586
- const list2 = out.get(r.session_id);
40587
- if (list2) list2.push(r);
40779
+ const list3 = out.get(r.session_id);
40780
+ if (list3) list3.push(r);
40588
40781
  else out.set(r.session_id, [r]);
40589
40782
  }
40590
40783
  return out;
@@ -40615,9 +40808,9 @@ function withScope(base, sessionIds) {
40615
40808
  return out;
40616
40809
  }
40617
40810
  function hasCompactionBetween(ctx, sessionId, from, to) {
40618
- const list2 = ctx.compactionsBySession.get(sessionId);
40619
- if (!list2) return false;
40620
- return list2.some((t) => t > from && t <= to);
40811
+ const list3 = ctx.compactionsBySession.get(sessionId);
40812
+ if (!list3) return false;
40813
+ return list3.some((t) => t > from && t <= to);
40621
40814
  }
40622
40815
  function detectCacheThrash(ctx) {
40623
40816
  let runs = 0;
@@ -40625,7 +40818,7 @@ function detectCacheThrash(ctx) {
40625
40818
  let rewritten = 0;
40626
40819
  let savings = 0;
40627
40820
  const sessions = /* @__PURE__ */ new Set();
40628
- for (const list2 of ctx.threads.values()) {
40821
+ for (const list3 of ctx.threads.values()) {
40629
40822
  let run3 = [];
40630
40823
  const flush = () => {
40631
40824
  if (run3.length >= THRASH_RUN) {
@@ -40641,12 +40834,12 @@ function detectCacheThrash(ctx) {
40641
40834
  }
40642
40835
  run3 = [];
40643
40836
  };
40644
- for (let i = 1; i < list2.length; i++) {
40645
- const c = list2[i];
40646
- const prev = list2[i - 1];
40837
+ for (let i = 1; i < list3.length; i++) {
40838
+ const c = list3[i];
40839
+ const prev = list3[i - 1];
40647
40840
  const ctxTokens = contextOf(c);
40648
40841
  const heavy = ctxTokens > 0 && writesOf(c) / ctxTokens >= THRASH_WRITE_SHARE;
40649
- const broken = hasCompactionBetween(ctx, c.session_id, prev.ts, c.ts) || c.ts - prev.ts > ttlFor(list2);
40842
+ const broken = hasCompactionBetween(ctx, c.session_id, prev.ts, c.ts) || c.ts - prev.ts > ttlFor(list3);
40650
40843
  if (!heavy || broken) {
40651
40844
  flush();
40652
40845
  continue;
@@ -40669,10 +40862,10 @@ function detectCacheThrash(ctx) {
40669
40862
  sessions
40670
40863
  );
40671
40864
  }
40672
- function ttlFor(list2) {
40865
+ function ttlFor(list3) {
40673
40866
  let w5 = 0;
40674
40867
  let w1 = 0;
40675
- for (const c of list2) {
40868
+ for (const c of list3) {
40676
40869
  w5 += num3(c.cache_create_5m);
40677
40870
  w1 += num3(c.cache_create_1h);
40678
40871
  }
@@ -40684,11 +40877,11 @@ function detectCacheCold(ctx) {
40684
40877
  let savings = 0;
40685
40878
  let longestGap = 0;
40686
40879
  const sessions = /* @__PURE__ */ new Set();
40687
- for (const list2 of ctx.threads.values()) {
40688
- const ttl = ttlFor(list2);
40689
- for (let i = 1; i < list2.length; i++) {
40690
- const c = list2[i];
40691
- const prev = list2[i - 1];
40880
+ for (const list3 of ctx.threads.values()) {
40881
+ const ttl = ttlFor(list3);
40882
+ for (let i = 1; i < list3.length; i++) {
40883
+ const c = list3[i];
40884
+ const prev = list3[i - 1];
40692
40885
  const gap = c.ts - prev.ts;
40693
40886
  if (gap <= ttl) continue;
40694
40887
  if (hasCompactionBetween(ctx, c.session_id, prev.ts, c.ts)) continue;
@@ -40950,15 +41143,15 @@ function detectErrorLoop(ctx) {
40950
41143
  const byThread = /* @__PURE__ */ new Map();
40951
41144
  for (const u of ctx.toolUses) {
40952
41145
  const key = `${u.session_id}\0${u.agent_id ?? ""}`;
40953
- const list2 = byThread.get(key);
40954
- if (list2) list2.push(u);
41146
+ const list3 = byThread.get(key);
41147
+ if (list3) list3.push(u);
40955
41148
  else byThread.set(key, [u]);
40956
41149
  }
40957
- for (const list2 of byThread.values()) {
40958
- list2.sort((a, b) => a.ts - b.ts);
41150
+ for (const list3 of byThread.values()) {
41151
+ list3.sort((a, b) => a.ts - b.ts);
40959
41152
  let run3 = 0;
40960
41153
  let tool = "";
40961
- for (const u of list2) {
41154
+ for (const u of list3) {
40962
41155
  if (u.is_error && u.tool === tool) run3 += 1;
40963
41156
  else {
40964
41157
  run3 = u.is_error ? 1 : 0;
@@ -41192,11 +41385,11 @@ function detectInsights(input2) {
41192
41385
  const calls = input2.calls.filter(isRealCall);
41193
41386
  const compactionsBySession = /* @__PURE__ */ new Map();
41194
41387
  for (const e of input2.contextEvents) {
41195
- const list2 = compactionsBySession.get(e.session_id);
41196
- if (list2) list2.push(e.ts);
41388
+ const list3 = compactionsBySession.get(e.session_id);
41389
+ if (list3) list3.push(e.ts);
41197
41390
  else compactionsBySession.set(e.session_id, [e.ts]);
41198
41391
  }
41199
- for (const list2 of compactionsBySession.values()) list2.sort((a, b) => a - b);
41392
+ for (const list3 of compactionsBySession.values()) list3.sort((a, b) => a - b);
41200
41393
  const callTs = /* @__PURE__ */ new Map();
41201
41394
  for (const [sid, rows] of groupBySession(calls))
41202
41395
  callTs.set(
@@ -41450,8 +41643,8 @@ function periods(calls, keyFn) {
41450
41643
  const buckets = /* @__PURE__ */ new Map();
41451
41644
  for (const c of calls) {
41452
41645
  const k = keyFn(c.ts);
41453
- const list2 = buckets.get(k);
41454
- if (list2) list2.push(c);
41646
+ const list3 = buckets.get(k);
41647
+ if (list3) list3.push(c);
41455
41648
  else buckets.set(k, [c]);
41456
41649
  }
41457
41650
  return [...buckets.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, rows]) => ({ key, totals: totals(rows), models: modelSlices(rows) }));
@@ -41481,8 +41674,8 @@ function insightsFor(ctx, data) {
41481
41674
  const r = detectInsights(input2);
41482
41675
  return { insights: r.insights, scores: r.scores };
41483
41676
  }
41484
- function sortInsights(list2) {
41485
- return list2.slice().sort(
41677
+ function sortInsights(list3) {
41678
+ return list3.slice().sort(
41486
41679
  (a, b) => SEVERITY_RANK2[a.severity] - SEVERITY_RANK2[b.severity] || (b.estimatedSavingsUsd ?? 0) - (a.estimatedSavingsUsd ?? 0)
41487
41680
  );
41488
41681
  }
@@ -42576,11 +42769,11 @@ import { readFile } from "fs/promises";
42576
42769
  import { basename as basename5, extname as extname2, resolve as resolvePath } from "path";
42577
42770
  import { pathToFileURL } from "url";
42578
42771
  function parseFixture(raw, source = "fixture") {
42579
- const list2 = Array.isArray(raw) || !raw || typeof raw !== "object" ? raw : raw.items;
42580
- if (!Array.isArray(list2))
42772
+ const list3 = Array.isArray(raw) || !raw || typeof raw !== "object" ? raw : raw.items;
42773
+ if (!Array.isArray(list3))
42581
42774
  throw new EvalFixtureError(`${source}: expected an array of items or {"items": [...]}`);
42582
- if (!list2.length) throw new EvalFixtureError(`${source}: the fixture has no items`);
42583
- return list2.map((it, i) => {
42775
+ if (!list3.length) throw new EvalFixtureError(`${source}: the fixture has no items`);
42776
+ return list3.map((it, i) => {
42584
42777
  const r = ItemSchema.safeParse(it);
42585
42778
  if (!r.success) {
42586
42779
  const issue2 = r.error.issues[0];
@@ -43473,10 +43666,10 @@ function personalConsent() {
43473
43666
  try {
43474
43667
  const a = readRaw(paths().configFile).adjudicator;
43475
43668
  if (!isObj2(a)) return { remoteConsent: false };
43476
- const list2 = a.remoteConsentOrigins;
43669
+ const list3 = a.remoteConsentOrigins;
43477
43670
  return {
43478
43671
  remoteConsent: a.remoteConsent === true,
43479
- ...Array.isArray(list2) ? { remoteConsentOrigins: list2.filter((s) => typeof s === "string") } : {}
43672
+ ...Array.isArray(list3) ? { remoteConsentOrigins: list3.filter((s) => typeof s === "string") } : {}
43480
43673
  };
43481
43674
  } catch {
43482
43675
  return { remoteConsent: false };
@@ -43490,8 +43683,8 @@ function mustAsk(r, previous) {
43490
43683
  function consentPatch(r, asked) {
43491
43684
  if (!r.configuredRemote || !r.origin) return {};
43492
43685
  if (!asked && r.consentVia !== "legacy") return {};
43493
- const list2 = withConsentedOrigin(personalConsent(), r.origin);
43494
- return { remoteConsent: true, remoteConsentOrigins: list2 };
43686
+ const list3 = withConsentedOrigin(personalConsent(), r.origin);
43687
+ return { remoteConsent: true, remoteConsentOrigins: list3 };
43495
43688
  }
43496
43689
  function personalOrigin(root) {
43497
43690
  try {
@@ -45439,8 +45632,8 @@ function registerSettings(stable) {
45439
45632
  const hooks = settings.hooks ?? {};
45440
45633
  const hookCmd = `"${join21(stable, "bin", "em-hook")}"`;
45441
45634
  for (const ev3 of HOOK_EVENTS) {
45442
- const list2 = hooks[ev3] ?? [];
45443
- const filtered = list2.filter(
45635
+ const list3 = hooks[ev3] ?? [];
45636
+ const filtered = list3.filter(
45444
45637
  (entry2) => !(entry2.hooks ?? []).some((h) => isOurs(h.command, stable))
45445
45638
  );
45446
45639
  const entry = {
@@ -45480,9 +45673,9 @@ function unregisterSettings(stable, wrote) {
45480
45673
  const settings = readJson2(settingsPath());
45481
45674
  const hooks = settings.hooks ?? {};
45482
45675
  for (const ev3 of wrote.hookEvents) {
45483
- const list2 = hooks[ev3];
45484
- if (!list2) continue;
45485
- const kept = list2.filter(
45676
+ const list3 = hooks[ev3];
45677
+ if (!list3) continue;
45678
+ const kept = list3.filter(
45486
45679
  (entry) => !(entry.hooks ?? []).some((h) => isOurs(h.command, stable))
45487
45680
  );
45488
45681
  if (kept.length) hooks[ev3] = kept;
@@ -45574,13 +45767,13 @@ function registerCursor(stable) {
45574
45767
  const hooks = cfg.hooks ?? {};
45575
45768
  const command = cursorHookCommand(stable);
45576
45769
  for (const ev3 of CURSOR_HOOK_EVENTS) {
45577
- const list2 = (Array.isArray(hooks[ev3]) ? hooks[ev3] : []).filter(
45770
+ const list3 = (Array.isArray(hooks[ev3]) ? hooks[ev3] : []).filter(
45578
45771
  (h) => !isOurs(h.command, stable)
45579
45772
  );
45580
45773
  const entry = { command, timeout: TIMEOUTS[ev3] ?? 5 };
45581
45774
  if (ev3 === "preToolUse") entry.matcher = CURSOR_PRE_TOOL_MATCHER;
45582
- list2.push(entry);
45583
- hooks[ev3] = list2;
45775
+ list3.push(entry);
45776
+ hooks[ev3] = list3;
45584
45777
  }
45585
45778
  cfg.hooks = hooks;
45586
45779
  writeJsonWithBackup(cursorHooksPath(), cfg);
@@ -46439,8 +46632,8 @@ function findContextMode() {
46439
46632
  const settings = readJson2(settingsPath());
46440
46633
  const hooks = settings.hooks ?? {};
46441
46634
  const hookEntries = [];
46442
- for (const [event, list2] of Object.entries(hooks)) {
46443
- for (const entry of list2) {
46635
+ for (const [event, list3] of Object.entries(hooks)) {
46636
+ for (const entry of list3) {
46444
46637
  for (const h of entry.hooks ?? []) {
46445
46638
  if (typeof h.command === "string" && CM_HOOK.test(h.command))
46446
46639
  hookEntries.push({ event, command: h.command });
@@ -46485,8 +46678,8 @@ async function replaceContextMode(opts) {
46485
46678
  if (f.hookEntries.length) {
46486
46679
  const settings = readJson2(settingsPath());
46487
46680
  const hooks = settings.hooks ?? {};
46488
- for (const [event, list2] of Object.entries(hooks)) {
46489
- const kept = list2.map((entry) => ({
46681
+ for (const [event, list3] of Object.entries(hooks)) {
46682
+ const kept = list3.map((entry) => ({
46490
46683
  ...entry,
46491
46684
  hooks: (entry.hooks ?? []).filter(
46492
46685
  (h) => !(typeof h.command === "string" && CM_HOOK.test(h.command))
@@ -46752,10 +46945,10 @@ function loadPermissionRules(root, extraDeny = []) {
46752
46945
  const hit = cache4.get(key);
46753
46946
  if (hit?.stamps.every((s, i) => s === stamps[i])) return hit.rules;
46754
46947
  const out = { allow: [], deny: [], ask: [], root };
46755
- const push = (list2, raws) => {
46948
+ const push = (list3, raws) => {
46756
46949
  for (const raw of raws ?? []) {
46757
46950
  const r = parseRule(raw);
46758
- if (r) list2.push(r);
46951
+ if (r) list3.push(r);
46759
46952
  }
46760
46953
  };
46761
46954
  for (const f of files) {
@@ -47080,57 +47273,6 @@ var init_snippets = __esm({
47080
47273
  }
47081
47274
  });
47082
47275
 
47083
- // src/search/typo.ts
47084
- function editDistance(a, b, max = 3) {
47085
- if (Math.abs(a.length - b.length) > max) return max + 1;
47086
- const prev2 = [];
47087
- let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
47088
- let cur = new Array(b.length + 1).fill(0);
47089
- for (let i = 1; i <= a.length; i++) {
47090
- cur[0] = i;
47091
- let rowMin = cur[0];
47092
- for (let j = 1; j <= b.length; j++) {
47093
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
47094
- let v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
47095
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
47096
- v = Math.min(v, prev2[j - 2] + 1);
47097
- }
47098
- cur[j] = v;
47099
- if (v < rowMin) rowMin = v;
47100
- }
47101
- if (rowMin > max) return max + 1;
47102
- prev2.splice(0, prev2.length, ...prev);
47103
- [prev, cur] = [cur, prev];
47104
- }
47105
- return prev[b.length];
47106
- }
47107
- function correctTerms(db, terms) {
47108
- const corrections = [];
47109
- const out = terms.map((term) => {
47110
- if (term.length < 4 || /[^a-z0-9]/.test(term) || db.termExists(term)) return term;
47111
- const max = term.length >= 7 ? 2 : 1;
47112
- const candidates2 = db.vocabCandidates(term[0], 3e3);
47113
- let best;
47114
- for (const c of candidates2) {
47115
- if (c.term.length < 3) continue;
47116
- const d = editDistance(term, c.term, max);
47117
- if (d > max) continue;
47118
- if (!best || d < best.d || d === best.d && c.df > best.df)
47119
- best = { term: c.term, d, df: c.df };
47120
- }
47121
- if (!best) return term;
47122
- corrections.push({ from: term, to: best.term });
47123
- return `${best.term}*`;
47124
- });
47125
- return { terms: out, corrections };
47126
- }
47127
- var init_typo = __esm({
47128
- "src/search/typo.ts"() {
47129
- "use strict";
47130
- init_esm_shims();
47131
- }
47132
- });
47133
-
47134
47276
  // src/search/pipeline.ts
47135
47277
  var pipeline_exports = {};
47136
47278
  __export(pipeline_exports, {
@@ -47405,19 +47547,19 @@ function mergedCatalog(extra) {
47405
47547
  function catalogLookup(kind, key, catalog = CATALOG) {
47406
47548
  const k = key.trim();
47407
47549
  for (const e of catalog) {
47408
- const list2 = kind === "api" ? e.hosts : e[kind];
47409
- if (!list2) continue;
47550
+ const list3 = kind === "api" ? e.hosts : e[kind];
47551
+ if (!list3) continue;
47410
47552
  if (kind === "env") {
47411
- if (list2.some((p2) => envMatches(p2, k))) return e;
47553
+ if (list3.some((p2) => envMatches(p2, k))) return e;
47412
47554
  } else if (kind === "api") {
47413
47555
  const host = k.toLowerCase();
47414
- if (list2.some((h) => host === h || host.endsWith(`.${h}`))) return e;
47556
+ if (list3.some((h) => host === h || host.endsWith(`.${h}`))) return e;
47415
47557
  } else if (kind === "image") {
47416
47558
  const bare = k.split(":")[0].replace(/^docker\.io\/(library\/)?/, "");
47417
- if (list2.some((p2) => matches(p2, bare))) return e;
47559
+ if (list3.some((p2) => matches(p2, bare))) return e;
47418
47560
  } else if (kind === "go") {
47419
- if (list2.some((p2) => k === p2 || k.startsWith(p2))) return e;
47420
- } else if (list2.some((p2) => matches(p2, k))) return e;
47561
+ if (list3.some((p2) => k === p2 || k.startsWith(p2))) return e;
47562
+ } else if (list3.some((p2) => matches(p2, k))) return e;
47421
47563
  }
47422
47564
  return void 0;
47423
47565
  }
@@ -48827,9 +48969,9 @@ function schemaSummary(doc, schema, depth = 0) {
48827
48969
  if (Array.isArray(s.enum))
48828
48970
  return `enum(${s.enum.slice(0, 8).map(String).join(", ")}${s.enum.length > 8 ? ", \u2026" : ""})`;
48829
48971
  for (const k of ["oneOf", "anyOf", "allOf"]) {
48830
- const list2 = s[k];
48831
- if (Array.isArray(list2))
48832
- return `${k}<${list2.slice(0, 4).map((x) => schemaSummary(doc, x, depth + 1)).join(" | ")}>`;
48972
+ const list3 = s[k];
48973
+ if (Array.isArray(list3))
48974
+ return `${k}<${list3.slice(0, 4).map((x) => schemaSummary(doc, x, depth + 1)).join(" | ")}>`;
48833
48975
  }
48834
48976
  if (type === "array" || s.items) return `${schemaSummary(doc, s.items, depth + 1) || "any"}[]`;
48835
48977
  if (type === "object" || isObj3(s.properties)) {
@@ -48991,9 +49133,9 @@ function postmanBody(body) {
48991
49133
  const lang = isObj3(body.options) && isObj3(body.options.raw) ? String(body.options.raw.language ?? "json") : "json";
48992
49134
  return raw.length > 2e3 ? [`Body (${lang}): ${raw.slice(0, 2e3)}\u2026`] : ["Body:", "", `\`\`\`${lang}`, raw, "```"];
48993
49135
  }
48994
- const list2 = body[mode];
48995
- if (Array.isArray(list2)) {
48996
- const keys = list2.filter(isObj3).map(
49136
+ const list3 = body[mode];
49137
+ if (Array.isArray(list3)) {
49138
+ const keys = list3.filter(isObj3).map(
48997
49139
  (e) => `${String(e.key)}${e.type && e.type !== "text" ? ` (${String(e.type)})` : ""}${e.description ? ` \u2014 ${clip5(e.description, 100)}` : ""}`
48998
49140
  );
48999
49141
  return keys.length ? [`Body (${mode}): ${keys.join(", ")}`] : [];
@@ -49584,9 +49726,9 @@ function computeMetrics(db) {
49584
49726
  for (const s of symbols) {
49585
49727
  const f = s.path ? `file:${s.path}` : void 0;
49586
49728
  if (!f) continue;
49587
- const list2 = symbolsByFile.get(f) ?? [];
49588
- list2.push(s);
49589
- symbolsByFile.set(f, list2);
49729
+ const list3 = symbolsByFile.get(f) ?? [];
49730
+ list3.push(s);
49731
+ symbolsByFile.set(f, list3);
49590
49732
  }
49591
49733
  for (const f of files) {
49592
49734
  const m = meta3(f);
@@ -49639,9 +49781,9 @@ function computeMetrics(db) {
49639
49781
  const members2 = /* @__PURE__ */ new Map();
49640
49782
  for (const r of fileRows) {
49641
49783
  if (r.cluster === null) continue;
49642
- const list2 = members2.get(r.cluster) ?? [];
49643
- list2.push(r);
49644
- members2.set(r.cluster, list2);
49784
+ const list3 = members2.get(r.cluster) ?? [];
49785
+ list3.push(r);
49786
+ members2.set(r.cluster, list3);
49645
49787
  }
49646
49788
  const links = /* @__PURE__ */ new Map();
49647
49789
  for (const e of importEdges) {
@@ -49800,10 +49942,10 @@ function impact(db, ref, opts = {}) {
49800
49942
  add3(e.dst, e.weight, 1, `co-changed ${meta4.count ?? "?"}\xD7 (${Math.round(e.weight * 100)}%)`);
49801
49943
  }
49802
49944
  }
49803
- const list2 = [...hits.values()].sort((a, b) => b.score - a.score);
49804
- const nodes = new Map(db.graphGetNodes(list2.map((h) => h.id)).map((n) => [n.id, n]));
49805
- for (const h of list2) h.node = nodes.get(h.id);
49806
- return { root, hits: list2 };
49945
+ const list3 = [...hits.values()].sort((a, b) => b.score - a.score);
49946
+ const nodes = new Map(db.graphGetNodes(list3.map((h) => h.id)).map((n) => [n.id, n]));
49947
+ for (const h of list3) h.node = nodes.get(h.id);
49948
+ return { root, hits: list3 };
49807
49949
  }
49808
49950
  function dependencies(db, ref, depth = 1) {
49809
49951
  const root = resolveNode(db, ref);
@@ -49830,10 +49972,10 @@ function dependencies(db, ref, depth = 1) {
49830
49972
  frontier = next;
49831
49973
  if (!frontier.length) break;
49832
49974
  }
49833
- const list2 = [...hits.values()].sort((a, b) => b.score - a.score);
49834
- const nodes = new Map(db.graphGetNodes(list2.map((h) => h.id)).map((n) => [n.id, n]));
49835
- for (const h of list2) h.node = nodes.get(h.id);
49836
- return { root, hits: list2 };
49975
+ const list3 = [...hits.values()].sort((a, b) => b.score - a.score);
49976
+ const nodes = new Map(db.graphGetNodes(list3.map((h) => h.id)).map((n) => [n.id, n]));
49977
+ for (const h of list3) h.node = nodes.get(h.id);
49978
+ return { root, hits: list3 };
49837
49979
  }
49838
49980
  function neighbors(db, ref, depth = 1, kinds) {
49839
49981
  const root = resolveNode(db, ref);
@@ -50334,8 +50476,8 @@ function parseRouteAnnotations(doc) {
50334
50476
  const body = m[1] ?? "";
50335
50477
  const path3 = /^\s*"([^"]*)"/.exec(body)?.[1] ?? /\bpath\s*=\s*"([^"]*)"/.exec(body)?.[1];
50336
50478
  if (path3 === void 0) continue;
50337
- const list2 = /\bmethods\s*=\s*(\{[^}]*\}|"[^"]*")/.exec(body)?.[1] ?? "";
50338
- const methods = [...list2.matchAll(/"([^"]+)"/g)].map((x) => httpMethod(x[1])).filter((x) => !!x);
50479
+ const list3 = /\bmethods\s*=\s*(\{[^}]*\}|"[^"]*")/.exec(body)?.[1] ?? "";
50480
+ const methods = [...list3.matchAll(/"([^"]+)"/g)].map((x) => httpMethod(x[1])).filter((x) => !!x);
50339
50481
  for (const method of methods.length ? methods : ["ALL"]) out.push({ method, path: path3 });
50340
50482
  }
50341
50483
  return out;
@@ -51136,16 +51278,16 @@ function phpString(n) {
51136
51278
  return literalText(n)?.replace(/\\(\\|')/g, "$1");
51137
51279
  }
51138
51280
  function argsOf(call) {
51139
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51140
- return (list2?.namedChildren ?? []).filter((a) => a?.type === "argument").map((a) => a.namedChildren[a.namedChildren.length - 1]).filter((a) => !!a);
51281
+ const list3 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51282
+ return (list3?.namedChildren ?? []).filter((a) => a?.type === "argument").map((a) => a.namedChildren[a.namedChildren.length - 1]).filter((a) => !!a);
51141
51283
  }
51142
51284
  function positionalArgs(call) {
51143
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51144
- return (list2?.namedChildren ?? []).filter((a) => a?.type === "argument" && !a.childForFieldName("name")).map((a) => a.namedChildren[0]).filter((a) => !!a);
51285
+ const list3 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51286
+ return (list3?.namedChildren ?? []).filter((a) => a?.type === "argument" && !a.childForFieldName("name")).map((a) => a.namedChildren[0]).filter((a) => !!a);
51145
51287
  }
51146
51288
  function namedArg(call, name) {
51147
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51148
- for (const a of list2?.namedChildren ?? []) {
51289
+ const list3 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51290
+ for (const a of list3?.namedChildren ?? []) {
51149
51291
  if (a?.type === "argument" && a.childForFieldName("name")?.text === name)
51150
51292
  return a.namedChildren[a.namedChildren.length - 1] ?? void 0;
51151
51293
  }
@@ -54479,21 +54621,21 @@ function detectChanges(db, root, opts = {}) {
54479
54621
  }
54480
54622
  const byFile = /* @__PURE__ */ new Map();
54481
54623
  for (const h of hunks) {
54482
- const list2 = byFile.get(h.path) ?? [];
54483
- list2.push(h);
54484
- byFile.set(h.path, list2);
54624
+ const list3 = byFile.get(h.path) ?? [];
54625
+ list3.push(h);
54626
+ byFile.set(h.path, list3);
54485
54627
  }
54486
54628
  const symbols = /* @__PURE__ */ new Map();
54487
54629
  const files = [];
54488
54630
  const unindexed = [];
54489
- for (const [path3, list2] of byFile) {
54631
+ for (const [path3, list3] of byFile) {
54490
54632
  const indexed = !!db.graphGetNode(fileId(path3));
54491
- files.push({ path: path3, hunks: list2.length, indexed });
54633
+ files.push({ path: path3, hunks: list3.length, indexed });
54492
54634
  if (!indexed) {
54493
54635
  unindexed.push(path3);
54494
54636
  continue;
54495
54637
  }
54496
- for (const [id, s] of symbolsAt(db, path3, list2)) symbols.set(id, s);
54638
+ for (const [id, s] of symbolsAt(db, path3, list3)) symbols.set(id, s);
54497
54639
  }
54498
54640
  const ids = [...symbols.keys()];
54499
54641
  const metrics = new Map(db.metricsGet(ids).map((m) => [m.node_id, m]));
@@ -54733,7 +54875,7 @@ function architecture(ctx, db, aspects = ASPECTS) {
54733
54875
  hotspots: want.has("hotspots") ? hotspots(db, 12) : [],
54734
54876
  clusters: want.has("clusters") ? readClusters(db) : [],
54735
54877
  cycles: want.has("cycles") ? readCycles(db) : [],
54736
- decisions: want.has("decisions") ? list(ctx, db, { kind: "decision", limit: 50 }).filter((r) => (r.status ?? "accepted") === "accepted").map((r) => ({
54878
+ decisions: want.has("decisions") ? list2(ctx, db, { kind: "decision", limit: 50 }).filter((r) => (r.status ?? "accepted") === "accepted").map((r) => ({
54737
54879
  name: r.name ?? "",
54738
54880
  title: r.content.split("\n")[0]?.replace(/^#+\s*/, "").slice(0, 120) ?? "",
54739
54881
  status: r.status ?? "accepted",
@@ -55111,9 +55253,9 @@ function envSignals(dir, project, catalog) {
55111
55253
  }
55112
55254
  const token = name.split("_")[0];
55113
55255
  if (token.length < 3 || GENERIC_ENV.has(token)) continue;
55114
- const list2 = unknownPrefixes.get(token) ?? [];
55115
- if (!list2.includes(name)) list2.push(name);
55116
- unknownPrefixes.set(token, list2);
55256
+ const list3 = unknownPrefixes.get(token) ?? [];
55257
+ if (!list3.includes(name)) list3.push(name);
55258
+ unknownPrefixes.set(token, list3);
55117
55259
  }
55118
55260
  }
55119
55261
  return { signals, unknownPrefixes };
@@ -55438,15 +55580,15 @@ function discoverDocs(ctx, opts = {}) {
55438
55580
  );
55439
55581
  for (const hit of api.hits.values()) {
55440
55582
  if (inSubproject(hit.samples)) continue;
55441
- const list2 = apiHits.get(hit.host) ?? [];
55442
- list2.push(hit);
55443
- apiHits.set(hit.host, list2);
55583
+ const list3 = apiHits.get(hit.host) ?? [];
55584
+ list3.push(hit);
55585
+ apiHits.set(hit.host, list3);
55444
55586
  }
55445
55587
  for (const link of api.docLinks.values()) {
55446
55588
  if (inSubproject(link.samples)) continue;
55447
- const list2 = docLinks.get(link.host) ?? [];
55448
- list2.push(link);
55449
- docLinks.set(link.host, list2);
55589
+ const list3 = docLinks.get(link.host) ?? [];
55590
+ list3.push(link);
55591
+ docLinks.set(link.host, list3);
55450
55592
  }
55451
55593
  const env = envSignals(dir, project, catalog);
55452
55594
  signals.push(...env.signals);
@@ -55536,12 +55678,12 @@ function discoverDocs(ctx, opts = {}) {
55536
55678
  evidence: `${info.vars.slice(0, 4).join(", ")}${info.vars.length > 4 ? ", \u2026" : ""}`
55537
55679
  });
55538
55680
  }
55539
- for (const [host, list2] of apiHits) {
55540
- const calls = list2.reduce((n, h) => n + h.calls, 0);
55681
+ for (const [host, list3] of apiHits) {
55682
+ const calls = list3.reduce((n, h) => n + h.calls, 0);
55541
55683
  if (!calls) continue;
55542
55684
  const entry = catalogLookup("api", host, catalog);
55543
- const specUrls = [...new Set(list2.flatMap((h) => h.specUrls))];
55544
- for (const h of list2) {
55685
+ const specUrls = [...new Set(list3.flatMap((h) => h.specUrls))];
55686
+ for (const h of list3) {
55545
55687
  if (!h.calls) continue;
55546
55688
  const evidence = `api:${host} (${h.samples.slice(0, 2).join(", ")})${specUrls.length ? ` \xB7 spec ${specUrls[0]}` : ""}`;
55547
55689
  if (entry) {
@@ -55574,10 +55716,10 @@ function discoverDocs(ctx, opts = {}) {
55574
55716
  }
55575
55717
  }
55576
55718
  }
55577
- for (const [host, list2] of docLinks) {
55578
- const urls = [...new Set(list2.flatMap((l) => l.urls))].slice(0, 3);
55719
+ for (const [host, list3] of docLinks) {
55720
+ const urls = [...new Set(list3.flatMap((l) => l.urls))].slice(0, 3);
55579
55721
  const entry = catalogLookup("api", host, catalog);
55580
- for (const l of list2) {
55722
+ for (const l of list3) {
55581
55723
  const evidence = `link:${host} (${l.samples.slice(0, 2).join(", ")})`;
55582
55724
  if (entry) {
55583
55725
  add3({
@@ -56025,7 +56167,7 @@ function rootOf(host) {
56025
56167
  function docGuesses(host) {
56026
56168
  const h = host.toLowerCase();
56027
56169
  const root = rootOf(h);
56028
- const list2 = [
56170
+ const list3 = [
56029
56171
  `https://docs.${root}/`,
56030
56172
  `https://developer.${root}/`,
56031
56173
  `https://developers.${root}/`,
@@ -56043,7 +56185,7 @@ function docGuesses(host) {
56043
56185
  `https://${h}/openapi.json`,
56044
56186
  `https://${h}/swagger.json`
56045
56187
  ];
56046
- return [...new Set(list2)];
56188
+ return [...new Set(list3)];
56047
56189
  }
56048
56190
  async function probe2(url2, opts) {
56049
56191
  const f = opts.fetchImpl ?? fetch;
@@ -56470,16 +56612,16 @@ function formatDiscovery(d, max = 40) {
56470
56612
  ]
56471
56613
  ];
56472
56614
  for (const [conf, title, note, wants] of groups) {
56473
- const list2 = d.providers.filter(wants);
56474
- if (!list2.length) continue;
56475
- lines.push("", `${title} (${list2.length}; ${note}):`);
56476
- for (const p2 of list2.slice(0, max)) {
56615
+ const list3 = d.providers.filter(wants);
56616
+ if (!list3.length) continue;
56617
+ lines.push("", `${title} (${list3.length}; ${note}):`);
56618
+ for (const p2 of list3.slice(0, max)) {
56477
56619
  const used = p2.usedBy.length > 1 ? ` \xB7 used by ${p2.usedBy.length} projects` : p2.usedBy[0] && p2.usedBy[0] !== "." ? ` \xB7 ${p2.usedBy[0]}` : "";
56478
56620
  const where = p2.urls[0] ? ` \xB7 ${p2.urls[0]}` : "";
56479
56621
  const ev3 = conf === "probe" || conf === "unknown" ? ` \xB7 ${p2.evidence[0]}` : "";
56480
56622
  lines.push(`- ${p2.name} \u2190 ${p2.provider}${used}${where}${ev3}${reg(p2.registered)}`);
56481
56623
  }
56482
- if (list2.length > max) lines.push(` \u2026 ${list2.length - max} more`);
56624
+ if (list3.length > max) lines.push(` \u2026 ${list3.length - max} more`);
56483
56625
  }
56484
56626
  const rec = d.local.filter((c) => !c.registered).length + d.providers.filter(
56485
56627
  (p2) => !p2.registered && (p2.confidence === "probe" || p2.confidence === "catalog" && (p2.tier ?? "library") === "service")
@@ -58599,7 +58741,7 @@ var init_em_memory = __esm({
58599
58741
  return text(`${args.name} is now ${args.status}`);
58600
58742
  }
58601
58743
  case "list": {
58602
- const rows = list(ctx, db, {
58744
+ const rows = list2(ctx, db, {
58603
58745
  topic: args.topic,
58604
58746
  kind: args.kind,
58605
58747
  status: args.status,
@@ -58697,7 +58839,7 @@ var init_em_recall = __esm({
58697
58839
  const limit = args.limit ?? 8;
58698
58840
  const lines = [];
58699
58841
  if (!args.query) {
58700
- const rows = list(ctx, db, { kind: args.kind, topic: args.topic, limit });
58842
+ const rows = list2(ctx, db, { kind: args.kind, topic: args.topic, limit });
58701
58843
  if (!rows.length)
58702
58844
  return text(
58703
58845
  "no memories yet; use em_remember to record decisions and constraints (or /eminiar:em-onboard to write the onboarding set)"
@@ -60499,7 +60641,7 @@ async function searchPayload(ctx, q, mode, limit, source) {
60499
60641
  function memoriesPayload(ctx, opts = {}) {
60500
60642
  const db = getStorage(ctx);
60501
60643
  const summary = reconcile2(ctx, db);
60502
- const rows = list(ctx, db, {
60644
+ const rows = list2(ctx, db, {
60503
60645
  kind: opts.kind,
60504
60646
  topic: opts.topic,
60505
60647
  status: opts.status,
@@ -61300,9 +61442,9 @@ function clustersPayload(ctx) {
61300
61442
  for (const m of db.metricsTop({ kind: "file", limit: 5e3 })) {
61301
61443
  if (m.cluster === null || !m.path) continue;
61302
61444
  const key = String(m.cluster);
61303
- const list2 = members2[key] ?? [];
61304
- list2.push({ path: m.path, score: m.score, fanIn: m.fan_in });
61305
- members2[key] = list2;
61445
+ const list3 = members2[key] ?? [];
61446
+ list3.push({ path: m.path, score: m.score, fanIn: m.fan_in });
61447
+ members2[key] = list3;
61306
61448
  }
61307
61449
  return { clusters: readClusters(db), cycles: readCycles(db), members: members2 };
61308
61450
  }
@@ -61671,11 +61813,11 @@ function historyGraphPayload(ctx, limit) {
61671
61813
  function historyRiskPayload(ctx, paths2) {
61672
61814
  const m = model(ctx);
61673
61815
  if (!m) return NO_GIT;
61674
- const list2 = paths2?.length ? paths2 : workingTreeFiles(ctx.root);
61816
+ const list3 = paths2?.length ? paths2 : workingTreeFiles(ctx.root);
61675
61817
  return {
61676
61818
  git: true,
61677
61819
  source: paths2?.length ? "paths" : "working tree",
61678
- files: list2.map((p2) => {
61820
+ files: list3.map((p2) => {
61679
61821
  const clean3 = p2.replace(/^\.\//, "");
61680
61822
  const h = m.files.get(clean3);
61681
61823
  const commits = commitsForFile(m, clean3);
@@ -62477,7 +62619,16 @@ function readSwarmDoc(root) {
62477
62619
  const { file: file3, rel, exists } = swarmFile(root);
62478
62620
  const base = { file: file3, rel };
62479
62621
  if (!exists)
62480
- return { ...base, state: "absent", text: null, hash: null, doc: null, issues: [], locked: [] };
62622
+ return {
62623
+ ...base,
62624
+ state: "absent",
62625
+ text: null,
62626
+ hash: null,
62627
+ doc: null,
62628
+ issues: [],
62629
+ ignoredKeys: [],
62630
+ locked: []
62631
+ };
62481
62632
  let bytes;
62482
62633
  try {
62483
62634
  bytes = readFileSync30(file3);
@@ -62489,6 +62640,7 @@ function readSwarmDoc(root) {
62489
62640
  hash: null,
62490
62641
  doc: null,
62491
62642
  issues: [{ path: "", message: `cannot read ${rel}: ${err.message}` }],
62643
+ ignoredKeys: [],
62492
62644
  locked: []
62493
62645
  };
62494
62646
  }
@@ -62496,9 +62648,10 @@ function readSwarmDoc(root) {
62496
62648
  const hash2 = createHash13("sha256").update(bytes).digest("hex");
62497
62649
  const result = parseSwarmYaml(text3, file3, rel);
62498
62650
  const issues = result.state === "invalid" ? result.issues : [];
62651
+ const ignoredKeys = result.state === "ok" ? result.config.ignoredKeys : [];
62499
62652
  const state = result.state === "ok" ? "ok" : "invalid";
62500
62653
  if (text3.length > SWARM_FILE_MAX_CHARS)
62501
- return { ...base, state, text: text3, hash: hash2, doc: null, issues, locked: [] };
62654
+ return { ...base, state, text: text3, hash: hash2, doc: null, issues, ignoredKeys, locked: [] };
62502
62655
  const Y = yaml3();
62503
62656
  const parsed = Y.parseDocument(text3, { uniqueKeys: true, merge: true });
62504
62657
  let doc = null;
@@ -62513,7 +62666,7 @@ function readSwarmDoc(root) {
62513
62666
  } catch {
62514
62667
  }
62515
62668
  }
62516
- return { ...base, state, text: text3, hash: hash2, doc, issues, locked };
62669
+ return { ...base, state, text: text3, hash: hash2, doc, issues, ignoredKeys, locked };
62517
62670
  }
62518
62671
  function checkSwarmText(text3, opts = {}) {
62519
62672
  const rel = opts.rel ?? SWARM_FILES[0];
@@ -62896,6 +63049,9 @@ function applyDiff(ctx, path3, oldV, newV) {
62896
63049
  inherit(old, node2);
62897
63050
  setAt(ctx, path3, node2);
62898
63051
  }
63052
+ function ignoredKeyWarnings(ignoredKeys) {
63053
+ return ignoredKeys.map((i) => ({ path: i.path, kind: "ignored-key", message: i.message }));
63054
+ }
62899
63055
  function docWarnings(doc, activeRuns = [], prev) {
62900
63056
  const out = [];
62901
63057
  const swarms = isPlain(doc.swarms) ? doc.swarms : {};
@@ -63631,9 +63787,9 @@ function runDetail(ctx, run3, opts = {}) {
63631
63787
  const byAgent2 = /* @__PURE__ */ new Map();
63632
63788
  for (const e of all) {
63633
63789
  if (!e.agent_id) continue;
63634
- const list2 = byAgent2.get(e.agent_id) ?? [];
63635
- list2.push(e);
63636
- byAgent2.set(e.agent_id, list2);
63790
+ const list3 = byAgent2.get(e.agent_id) ?? [];
63791
+ list3.push(e);
63792
+ byAgent2.set(e.agent_id, list3);
63637
63793
  }
63638
63794
  const loaded = loadSwarmConfig(ctx.root);
63639
63795
  const spec = loaded.state === "ok" ? loaded.config.swarms.find((s) => s.name === run3.swarm) : void 0;
@@ -63779,7 +63935,10 @@ function swarmConfigDoc(ctx) {
63779
63935
  hash: read2.hash,
63780
63936
  doc: read2.doc,
63781
63937
  issues: read2.issues,
63782
- warnings: read2.doc ? docWarnings(read2.doc, activeRuns, read2.doc) : [],
63938
+ warnings: [
63939
+ ...ignoredKeyWarnings(read2.ignoredKeys),
63940
+ ...read2.doc ? docWarnings(read2.doc, activeRuns, read2.doc) : []
63941
+ ],
63783
63942
  locked: read2.locked,
63784
63943
  starter: read2.state === "absent" ? starterDoc() : void 0,
63785
63944
  activeRuns,
@@ -63829,6 +63988,7 @@ async function prepareConfig(ctx, body) {
63829
63988
  const meta4 = { file: read2.file, rel: read2.rel };
63830
63989
  let text3;
63831
63990
  let issues = [];
63991
+ let ignoredKeys = [];
63832
63992
  let draft = null;
63833
63993
  if (b.doc !== void 0) {
63834
63994
  draft = b.doc;
@@ -63836,10 +63996,12 @@ async function prepareConfig(ctx, body) {
63836
63996
  if (!r.ok) return { reply: fail2(422, r.error, { locked: r.locked ?? read2.locked }) };
63837
63997
  text3 = r.text;
63838
63998
  if (r.result.state === "invalid") issues = r.result.issues;
63999
+ else if (r.result.state === "ok") ignoredKeys = r.result.config.ignoredKeys;
63839
64000
  } else {
63840
64001
  text3 = b.text;
63841
64002
  const { result, enforceOk } = checkSwarmText(text3, meta4);
63842
64003
  if (result.state === "invalid") issues = result.issues;
64004
+ else if (result.state === "ok") ignoredKeys = result.config.ignoredKeys;
63843
64005
  if (!enforceOk)
63844
64006
  issues = [
63845
64007
  ...issues,
@@ -63856,7 +64018,10 @@ async function prepareConfig(ctx, body) {
63856
64018
  }
63857
64019
  }
63858
64020
  const diff2 = lineDiff(read2.text ?? "", text3);
63859
- const warnings = draft && typeof draft === "object" ? docWarnings(draft, activeRunsOf(ctx), read2.doc) : [];
64021
+ const warnings = [
64022
+ ...ignoredKeyWarnings(ignoredKeys),
64023
+ ...draft && typeof draft === "object" ? docWarnings(draft, activeRunsOf(ctx), read2.doc) : []
64024
+ ];
63860
64025
  return {
63861
64026
  parsed: b,
63862
64027
  p: {
@@ -64178,9 +64343,9 @@ function listedProjects() {
64178
64343
  const now = Date.now();
64179
64344
  if (projectList && projectList.mtime === mtime && now - projectList.at < PROJECT_LIST_TTL_MS)
64180
64345
  return projectList.list;
64181
- const list2 = listProjects();
64182
- projectList = { at: now, mtime, list: list2 };
64183
- return list2;
64346
+ const list3 = listProjects();
64347
+ projectList = { at: now, mtime, list: list3 };
64348
+ return list3;
64184
64349
  }
64185
64350
  function resetProjectListCache() {
64186
64351
  projectList = void 0;
@@ -64859,7 +65024,8 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64859
65024
  enabled: loaded.config.enabled,
64860
65025
  enforce: loaded.config.enforce,
64861
65026
  allowed_agents: loaded.config.allowedAgents,
64862
- swarms: loaded.config.swarms.map((s) => s.name)
65027
+ swarms: loaded.config.swarms.map((s) => s.name),
65028
+ ignored_keys: loaded.config.ignoredKeys
64863
65029
  } : loaded.state === "invalid" ? {
64864
65030
  state: "invalid",
64865
65031
  file: loaded.rel,
@@ -64881,6 +65047,7 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64881
65047
  io.out(
64882
65048
  `ok: ${c.rel} \xB7 ${c.swarms.length} swarm(s), ${c.swarms.reduce((n, s) => n + s.roles.length, 0)} role(s)${c.enabled ? "" : " \xB7 disabled (enabled: false)"}${enforceNote(c)}`
64883
65049
  );
65050
+ if (c.ignoredKeys.length) io.err(formatIssues(c.rel, c.ignoredKeys));
64884
65051
  return 0;
64885
65052
  }
64886
65053
  case "sync": {
@@ -64963,9 +65130,9 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64963
65130
  return 2;
64964
65131
  }
64965
65132
  const db = await storage2(ctx);
64966
- const list2 = items(db, db.swarm.runs({ limit: Math.min(limit, 500) }));
64967
- if (json3) emit(list2);
64968
- else io.out(formatRunList(list2));
65133
+ const list3 = items(db, db.swarm.runs({ limit: Math.min(limit, 500) }));
65134
+ if (json3) emit(list3);
65135
+ else io.out(formatRunList(list3));
64969
65136
  return 0;
64970
65137
  }
64971
65138
  case "status": {