eminiar 0.13.3 → 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)
@@ -20796,6 +20796,18 @@ function adjudicatorDefaults() {
20796
20796
  privacy: { maxChars: 2e3, storeHead: true, captureExchanges: false }
20797
20797
  };
20798
20798
  }
20799
+ function graphGlobProblem(g) {
20800
+ if (g.length > 200) return "longer than 200 characters";
20801
+ if ((g.match(/\{/g)?.length ?? 0) > 4) return "more than 4 braces";
20802
+ if ((g.match(/\(/g)?.length ?? 0) > 2) return "more than 2 extglob groups";
20803
+ let total = 0;
20804
+ for (const seg of g.split(/[\\/]/)) {
20805
+ const groups = seg.match(/\*+|\?/g)?.length ?? 0;
20806
+ if (groups > 3) return "more than 3 wildcards in one path segment";
20807
+ total += groups;
20808
+ }
20809
+ return total > 8 ? "more than 8 wildcards" : void 0;
20810
+ }
20799
20811
  function ownJson(v) {
20800
20812
  if (Array.isArray(v)) return v.map(ownJson);
20801
20813
  if (typeof v !== "object" || v === null) return v;
@@ -21052,7 +21064,7 @@ function parseConfig(merged) {
21052
21064
  if (!base.success) return base;
21053
21065
  return { success: true, data: { ...base.data, adjudicator: adjudicatorDefaults() } };
21054
21066
  }
21055
- var RoutingMode, PROJECT_RELATIVE_PATH_RE, SECRET_FIELD, buildAdjudicatorObject, buildAdjudicatorSchema, adjudicatorSchema, AdjudicatorConfigSchema, BaseConfigSchema, ConfigSchema, UNSAFE_KEYS, PROJECT_ADJUDICATOR_KEYS, CASE_INSENSITIVE_FS, MAX_GIT_DEPTH, MAX_WORKTREES, PROJECT_PATH_KEYS;
21067
+ var RoutingMode, PROJECT_RELATIVE_PATH_RE, SECRET_FIELD, buildAdjudicatorObject, buildAdjudicatorSchema, adjudicatorSchema, AdjudicatorConfigSchema, GraphGlob, BaseConfigSchema, ConfigSchema, UNSAFE_KEYS, PROJECT_ADJUDICATOR_KEYS, CASE_INSENSITIVE_FS, MAX_GIT_DEPTH, MAX_WORKTREES, PROJECT_PATH_KEYS;
21056
21068
  var init_config = __esm({
21057
21069
  "src/config.ts"() {
21058
21070
  "use strict";
@@ -21190,6 +21202,14 @@ var init_config = __esm({
21190
21202
  AdjudicatorConfigSchema = external_exports.lazy(
21191
21203
  () => adjudicatorSchema ??= buildAdjudicatorSchema()
21192
21204
  );
21205
+ GraphGlob = external_exports.string().superRefine((g, ctx) => {
21206
+ const why = graphGlobProblem(g);
21207
+ if (why)
21208
+ ctx.addIssue({
21209
+ code: "custom",
21210
+ message: `graph glob ${JSON.stringify(g.slice(0, 40))} is ${why}`
21211
+ });
21212
+ });
21193
21213
  BaseConfigSchema = external_exports.object({
21194
21214
  routing: external_exports.object({
21195
21215
  /** auto = annotate while context-mode is installed, enforce once it is gone. */
@@ -21216,18 +21236,21 @@ var init_config = __esm({
21216
21236
  dims: external_exports.number().int().positive().default(384)
21217
21237
  }).prefault({}),
21218
21238
  graph: external_exports.object({
21219
- include: external_exports.array(external_exports.string()).default([
21239
+ include: external_exports.array(GraphGlob).default([
21220
21240
  "**/*.ts",
21221
21241
  "**/*.tsx",
21222
21242
  "**/*.js",
21223
21243
  "**/*.jsx",
21224
21244
  "**/*.mjs",
21225
21245
  "**/*.cjs",
21246
+ "**/*.mts",
21247
+ "**/*.cts",
21226
21248
  "**/*.py",
21249
+ "**/*.pyi",
21227
21250
  "**/*.go",
21228
21251
  "**/*.php"
21229
21252
  ]),
21230
- exclude: external_exports.array(external_exports.string()).default([
21253
+ exclude: external_exports.array(GraphGlob).default([
21231
21254
  "**/node_modules/**",
21232
21255
  "**/dist/**",
21233
21256
  "**/build/**",
@@ -24735,6 +24758,57 @@ var init_storage = __esm({
24735
24758
  }
24736
24759
  });
24737
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
+
24738
24812
  // src/swarm/glob.ts
24739
24813
  function normalize(g) {
24740
24814
  let s = g.trim().replace(/\\/g, "/");
@@ -24870,6 +24944,52 @@ function mergeContext(...layers) {
24870
24944
  }
24871
24945
  return out;
24872
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
+ }
24873
24993
  function roleRange(defaults, a, at, issue2) {
24874
24994
  const spec = a.model_range ?? defaults?.model_range;
24875
24995
  if (!spec || !spec.floor && !spec.ceiling) return void 0;
@@ -25005,6 +25125,27 @@ function parseSwarmYaml(text3, file3, rel) {
25005
25125
  for (const role of Object.keys(agents))
25006
25126
  checkName(["swarms", name, "agents", role], role, "agent");
25007
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
+ }
25008
25149
  const parsed = RawFile.safeParse(js);
25009
25150
  if (!parsed.success) {
25010
25151
  return {
@@ -25022,15 +25163,9 @@ function parseSwarmYaml(text3, file3, rel) {
25022
25163
  ]
25023
25164
  };
25024
25165
  }
25025
- for (const k of Object.keys(js))
25026
- if (!TOP_KEYS.has(k) && !k.startsWith("x-") && k !== "<<")
25027
- issue2(
25028
- [k],
25029
- `unknown key "${k}" (top-level keys: ${[...TOP_KEYS].join(", ")}; x-* keys may hold YAML anchors)`
25030
- );
25031
25166
  const config2 = resolve3(parsed.data, file3, rel, issue2);
25032
25167
  if (issues.length) return { state: "invalid", file: file3, rel, enforce, issues };
25033
- return { state: "ok", config: config2 };
25168
+ return { state: "ok", config: { ...config2, ignoredKeys } };
25034
25169
  }
25035
25170
  function resolve3(raw, file3, rel, issue2) {
25036
25171
  const swarms = [];
@@ -25151,13 +25286,14 @@ function findRole(config2, agentType) {
25151
25286
  for (const role of swarm.roles) if (role.agentType === agentType) return { swarm, role };
25152
25287
  return void 0;
25153
25288
  }
25154
- 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;
25155
25290
  var init_config2 = __esm({
25156
25291
  "src/swarm/config.ts"() {
25157
25292
  "use strict";
25158
25293
  init_esm_shims();
25159
25294
  init_zod();
25160
25295
  init_types();
25296
+ init_typo();
25161
25297
  init_dispatch();
25162
25298
  init_glob();
25163
25299
  init_types2();
@@ -25169,15 +25305,6 @@ var init_config2 = __esm({
25169
25305
  noFence = (s) => !s.includes("---");
25170
25306
  FENCE_MSG = 'must not contain "---" (Claude Code would end the agent frontmatter there)';
25171
25307
  MODEL_RE = /^(?:inherit|opusplan|(?:sonnet|opus|haiku|fable)(?:\[1m\])?|(?:[a-z0-9-]+\.)*claude-[a-z0-9.:@-]+(?:\[1m\])?)$/;
25172
- TOP_KEYS = /* @__PURE__ */ new Set([
25173
- "version",
25174
- "enabled",
25175
- "sync",
25176
- "enforce",
25177
- "allowed_agents",
25178
- "defaults",
25179
- "swarms"
25180
- ]);
25181
25308
  DEFAULT_CONTEXT = {
25182
25309
  memories: 4,
25183
25310
  docs: 2,
@@ -25206,7 +25333,7 @@ var init_config2 = __esm({
25206
25333
  ).refine(noFence, FENCE_MSG);
25207
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);
25208
25335
  rank = (t) => TIERS.indexOf(t);
25209
- 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(
25210
25337
  (r) => !r.floor || !r.ceiling || rank(r.floor) <= rank(r.ceiling),
25211
25338
  `floor must not be above ceiling (${TIERS.join(" < ")})`
25212
25339
  );
@@ -25230,7 +25357,7 @@ var init_config2 = __esm({
25230
25357
  (n) => !n.startsWith("swarm-"),
25231
25358
  "swarm workers need no entry: they are allowed during a run of their swarm"
25232
25359
  );
25233
- RawContext = external_exports.strictObject({
25360
+ RawContext = external_exports.object({
25234
25361
  memories: external_exports.number().int().min(0).max(10).optional(),
25235
25362
  docs: external_exports.number().int().min(0).max(10).optional(),
25236
25363
  history: external_exports.boolean().optional(),
@@ -25239,12 +25366,12 @@ var init_config2 = __esm({
25239
25366
  // SubagentStart context over 10,000 characters is moved to a file Claude may never read.
25240
25367
  max_chars: external_exports.number().int().min(500).max(9e3).optional()
25241
25368
  });
25242
- RawHookCommand = external_exports.strictObject({
25369
+ RawHookCommand = external_exports.object({
25243
25370
  type: external_exports.literal("command"),
25244
25371
  command: external_exports.string().trim().min(1).max(2e3).refine(noFence, FENCE_MSG),
25245
25372
  timeout: external_exports.number().int().positive().max(600).optional()
25246
25373
  });
25247
- RawHookMatcher = external_exports.strictObject({
25374
+ RawHookMatcher = external_exports.object({
25248
25375
  matcher: external_exports.string().max(200).refine(noFence, FENCE_MSG).refine((m) => {
25249
25376
  try {
25250
25377
  new RegExp(m);
@@ -25255,12 +25382,12 @@ var init_config2 = __esm({
25255
25382
  }, "not a valid regular expression (Claude Code matches tool names with it)").optional(),
25256
25383
  hooks: external_exports.array(RawHookCommand).min(1).max(10)
25257
25384
  });
25258
- RawHooks = external_exports.strictObject({
25385
+ RawHooks = external_exports.object({
25259
25386
  PreToolUse: external_exports.array(RawHookMatcher).max(10).optional(),
25260
25387
  PostToolUse: external_exports.array(RawHookMatcher).max(10).optional(),
25261
25388
  Stop: external_exports.array(RawHookMatcher).max(10).optional()
25262
25389
  });
25263
- RawAgent = external_exports.strictObject({
25390
+ RawAgent = external_exports.object({
25264
25391
  description: external_exports.string().trim().min(1).max(500).refine(noFence, FENCE_MSG),
25265
25392
  prompt: external_exports.string().max(2e4).optional(),
25266
25393
  model: Model.optional(),
@@ -25278,7 +25405,7 @@ var init_config2 = __esm({
25278
25405
  color: external_exports.enum(AGENT_COLORS).optional(),
25279
25406
  context: RawContext.optional()
25280
25407
  });
25281
- RawSwarm = external_exports.strictObject({
25408
+ RawSwarm = external_exports.object({
25282
25409
  description: external_exports.string().trim().min(1).max(500),
25283
25410
  topology: external_exports.enum(TOPOLOGIES).optional(),
25284
25411
  max_agents: external_exports.number().int().min(1).max(16).optional(),
@@ -25294,7 +25421,7 @@ var init_config2 = __esm({
25294
25421
  sync: external_exports.enum(["auto", "manual"]).optional(),
25295
25422
  enforce: external_exports.boolean().optional(),
25296
25423
  allowed_agents: external_exports.array(AgentName).max(50).optional(),
25297
- defaults: external_exports.strictObject({
25424
+ defaults: external_exports.object({
25298
25425
  model: Model.optional(),
25299
25426
  model_range: RawModelRange.optional(),
25300
25427
  skills: external_exports.array(SkillName).max(20).optional(),
@@ -25303,6 +25430,7 @@ var init_config2 = __esm({
25303
25430
  swarms: external_exports.record(external_exports.string(), RawSwarm)
25304
25431
  });
25305
25432
  uniq = (xs) => [...new Set(xs)];
25433
+ RESTRICTION_KEY = /tool|scope|hook|allow|deny|permission|model|effort|count/i;
25306
25434
  MAX_FILE_CHARS = 256e3;
25307
25435
  cache3 = /* @__PURE__ */ new Map();
25308
25436
  STARTER_YAML = `# eminiar agent swarms (opt-in). Docs: https://github.com/rydn/eminiar/blob/main/docs/swarms.md
@@ -25815,9 +25943,9 @@ function consentedOrigins(a) {
25815
25943
  return out;
25816
25944
  }
25817
25945
  function withConsentedOrigin(a, origin) {
25818
- const list2 = consentedOrigins(a);
25819
- if (!list2.includes(origin)) list2.push(origin);
25820
- return list2;
25946
+ const list3 = consentedOrigins(a);
25947
+ if (!list3.includes(origin)) list3.push(origin);
25948
+ return list3;
25821
25949
  }
25822
25950
  function isLoopback(url2) {
25823
25951
  if (!url2) return false;
@@ -27989,11 +28117,11 @@ function createOpenAIProvider(r, cfg, deps = {}) {
27989
28117
  };
27990
28118
  }
27991
28119
  function mapAnswers(reqs, items2, raw, cat, askTool) {
27992
- const list2 = raw && typeof raw === "object" && Array.isArray(raw.items) ? raw.items : void 0;
27993
- 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");
27994
28122
  const Item = itemSchema(cat, askTool);
27995
28123
  const byId = /* @__PURE__ */ new Map();
27996
- for (const x of list2) {
28124
+ for (const x of list3) {
27997
28125
  const p2 = Item.safeParse(x);
27998
28126
  if (p2.success && !byId.has(p2.data.id)) byId.set(p2.data.id, p2.data);
27999
28127
  }
@@ -29414,8 +29542,8 @@ function pricedSavings(stats, calls, overrides, opts = {}) {
29414
29542
  };
29415
29543
  const bySession2 = /* @__PURE__ */ new Map();
29416
29544
  for (const c of calls) {
29417
- const list2 = bySession2.get(c.session_id);
29418
- if (list2) list2.push(c);
29545
+ const list3 = bySession2.get(c.session_id);
29546
+ if (list3) list3.push(c);
29419
29547
  else bySession2.set(c.session_id, [c]);
29420
29548
  }
29421
29549
  const sessionModel = /* @__PURE__ */ new Map();
@@ -29574,29 +29702,29 @@ function promptWindows(prompts, calls) {
29574
29702
  const bySession2 = /* @__PURE__ */ new Map();
29575
29703
  for (const p2 of prompts) {
29576
29704
  if (!p2.sessionId) continue;
29577
- const list2 = bySession2.get(p2.sessionId);
29578
- if (list2) list2.push(p2);
29705
+ const list3 = bySession2.get(p2.sessionId);
29706
+ if (list3) list3.push(p2);
29579
29707
  else bySession2.set(p2.sessionId, [p2]);
29580
29708
  }
29581
- 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);
29582
29710
  const out = /* @__PURE__ */ new Map();
29583
29711
  for (const p2 of prompts) out.set(p2.id, []);
29584
29712
  for (const c of calls) {
29585
29713
  if (c.sidechain) continue;
29586
- const list2 = bySession2.get(c.session_id);
29587
- if (!list2) continue;
29714
+ const list3 = bySession2.get(c.session_id);
29715
+ if (!list3) continue;
29588
29716
  let lo = 0;
29589
- let hi = list2.length - 1;
29717
+ let hi = list3.length - 1;
29590
29718
  let at = -1;
29591
29719
  while (lo <= hi) {
29592
29720
  const mid = lo + hi >> 1;
29593
- if (list2[mid].ts <= c.ts) {
29721
+ if (list3[mid].ts <= c.ts) {
29594
29722
  at = mid;
29595
29723
  lo = mid + 1;
29596
29724
  } else hi = mid - 1;
29597
29725
  }
29598
29726
  if (at < 0) continue;
29599
- out.get(list2[at].id)?.push(c);
29727
+ out.get(list3[at].id)?.push(c);
29600
29728
  }
29601
29729
  return out;
29602
29730
  }
@@ -30200,8 +30328,8 @@ var init_learn = __esm({
30200
30328
  const m = /* @__PURE__ */ new Map();
30201
30329
  for (const p2 of allRows(this.db, { surface: "prompt", since })) {
30202
30330
  if (!p2.sessionId) continue;
30203
- const list2 = m.get(p2.sessionId);
30204
- if (list2) list2.push(p2);
30331
+ const list3 = m.get(p2.sessionId);
30332
+ if (list3) list3.push(p2);
30205
30333
  else m.set(p2.sessionId, [p2]);
30206
30334
  }
30207
30335
  this.promptsBySession = m;
@@ -30227,8 +30355,8 @@ var init_learn = __esm({
30227
30355
  const bySession2 = /* @__PURE__ */ new Map();
30228
30356
  for (const r of targets) {
30229
30357
  if (r.agentId || !r.sessionId) continue;
30230
- const list2 = bySession2.get(r.sessionId);
30231
- if (list2) list2.push(r);
30358
+ const list3 = bySession2.get(r.sessionId);
30359
+ if (list3) list3.push(r);
30232
30360
  else bySession2.set(r.sessionId, [r]);
30233
30361
  }
30234
30362
  if (!bySession2.size) return;
@@ -30246,8 +30374,8 @@ var init_learn = __esm({
30246
30374
  const callsBy = /* @__PURE__ */ new Map();
30247
30375
  for (const c of this.calls(sessionId)) {
30248
30376
  if (!c.sidechain || !c.agent_id || this.taken.has(c.agent_id)) continue;
30249
- const list2 = callsBy.get(c.agent_id);
30250
- if (list2) list2.push(c);
30377
+ const list3 = callsBy.get(c.agent_id);
30378
+ if (list3) list3.push(c);
30251
30379
  else callsBy.set(c.agent_id, [c]);
30252
30380
  }
30253
30381
  const agents = [...callsBy].map(([id, cs]) => ({
@@ -31212,6 +31340,68 @@ function existingGenerated(dir) {
31212
31340
  }
31213
31341
  return out;
31214
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
+ }
31215
31405
  function planAgentSync(root, config2, opts = {}) {
31216
31406
  const dir = agentsDir(root);
31217
31407
  const wantedRoles = config2?.enabled ? config2.swarms.flatMap((swarm) => swarm.roles.map((role) => ({ swarm, role }))) : [];
@@ -31279,6 +31469,24 @@ function planAgentSync(root, config2, opts = {}) {
31279
31469
  reason: config2?.enabled ? "no longer in the swarm file" : "swarms are disabled"
31280
31470
  }
31281
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
+ }
31282
31490
  return actions;
31283
31491
  }
31284
31492
  function syncAgents(root, config2, opts = {}) {
@@ -31320,7 +31528,7 @@ function syncAgents(root, config2, opts = {}) {
31320
31528
  }
31321
31529
  return { actions, changed, conflicts: actions.filter((a) => a.action === "conflict").length };
31322
31530
  }
31323
- 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;
31324
31532
  var init_agents = __esm({
31325
31533
  "src/swarm/agents.ts"() {
31326
31534
  "use strict";
@@ -31364,6 +31572,8 @@ ${fm}
31364
31572
  ${rest2}` : `${fm}
31365
31573
  ${rest2}`).digest("hex").slice(0, 12);
31366
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"]);
31367
31577
  }
31368
31578
  });
31369
31579
 
@@ -31556,8 +31766,8 @@ function manifest(dir) {
31556
31766
  }
31557
31767
  function agentPaths(dir) {
31558
31768
  const a = manifest(dir)?.agents;
31559
- const list2 = typeof a === "string" ? [a] : Array.isArray(a) ? a.filter((x) => typeof x === "string") : [];
31560
- 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));
31561
31771
  }
31562
31772
  function pluginDefs(segments, env, home) {
31563
31773
  const [plugin, ...rest2] = segments;
@@ -34858,9 +35068,9 @@ var require_micromatch = __commonJS({
34858
35068
  const index = v.indexOf("{");
34859
35069
  return index > -1 && v.indexOf("}", index) > -1;
34860
35070
  };
34861
- var micromatch = (list2, patterns, options) => {
35071
+ var micromatch2 = (list3, patterns, options) => {
34862
35072
  patterns = [].concat(patterns);
34863
- list2 = [].concat(list2);
35073
+ list3 = [].concat(list3);
34864
35074
  let omit2 = /* @__PURE__ */ new Set();
34865
35075
  let keep = /* @__PURE__ */ new Set();
34866
35076
  let items2 = /* @__PURE__ */ new Set();
@@ -34875,7 +35085,7 @@ var require_micromatch = __commonJS({
34875
35085
  let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true);
34876
35086
  let negated = isMatch.state.negated || isMatch.state.negatedExtglob;
34877
35087
  if (negated) negatives++;
34878
- for (let item of list2) {
35088
+ for (let item of list3) {
34879
35089
  let matched = isMatch(item, true);
34880
35090
  let match = negated ? !matched.isMatch : matched.isMatch;
34881
35091
  if (!match) continue;
@@ -34899,11 +35109,11 @@ var require_micromatch = __commonJS({
34899
35109
  }
34900
35110
  return matches2;
34901
35111
  };
34902
- micromatch.match = micromatch;
34903
- micromatch.matcher = (pattern2, options) => picomatch(pattern2, options);
34904
- micromatch.isMatch = (str3, patterns, options) => picomatch(patterns, options)(str3);
34905
- micromatch.any = micromatch.isMatch;
34906
- micromatch.not = (list2, patterns, options = {}) => {
35112
+ micromatch2.match = micromatch2;
35113
+ micromatch2.matcher = (pattern2, options) => picomatch(pattern2, options);
35114
+ micromatch2.isMatch = (str3, patterns, options) => picomatch(patterns, options)(str3);
35115
+ micromatch2.any = micromatch2.isMatch;
35116
+ micromatch2.not = (list3, patterns, options = {}) => {
34907
35117
  patterns = [].concat(patterns).map(String);
34908
35118
  let result = /* @__PURE__ */ new Set();
34909
35119
  let items2 = [];
@@ -34911,7 +35121,7 @@ var require_micromatch = __commonJS({
34911
35121
  if (options.onResult) options.onResult(state);
34912
35122
  items2.push(state.output);
34913
35123
  };
34914
- let matches2 = new Set(micromatch(list2, patterns, { ...options, onResult }));
35124
+ let matches2 = new Set(micromatch2(list3, patterns, { ...options, onResult }));
34915
35125
  for (let item of items2) {
34916
35126
  if (!matches2.has(item)) {
34917
35127
  result.add(item);
@@ -34919,12 +35129,12 @@ var require_micromatch = __commonJS({
34919
35129
  }
34920
35130
  return [...result];
34921
35131
  };
34922
- micromatch.contains = (str3, pattern2, options) => {
35132
+ micromatch2.contains = (str3, pattern2, options) => {
34923
35133
  if (typeof str3 !== "string") {
34924
35134
  throw new TypeError(`Expected a string: "${util.inspect(str3)}"`);
34925
35135
  }
34926
35136
  if (Array.isArray(pattern2)) {
34927
- return pattern2.some((p2) => micromatch.contains(str3, p2, options));
35137
+ return pattern2.some((p2) => micromatch2.contains(str3, p2, options));
34928
35138
  }
34929
35139
  if (typeof pattern2 === "string") {
34930
35140
  if (isEmptyString(str3) || isEmptyString(pattern2)) {
@@ -34934,19 +35144,19 @@ var require_micromatch = __commonJS({
34934
35144
  return true;
34935
35145
  }
34936
35146
  }
34937
- return micromatch.isMatch(str3, pattern2, { ...options, contains: true });
35147
+ return micromatch2.isMatch(str3, pattern2, { ...options, contains: true });
34938
35148
  };
34939
- micromatch.matchKeys = (obj, patterns, options) => {
35149
+ micromatch2.matchKeys = (obj, patterns, options) => {
34940
35150
  if (!utils.isObject(obj)) {
34941
35151
  throw new TypeError("Expected the first argument to be an object");
34942
35152
  }
34943
- let keys = micromatch(Object.keys(obj), patterns, options);
35153
+ let keys = micromatch2(Object.keys(obj), patterns, options);
34944
35154
  let res = {};
34945
35155
  for (let key of keys) res[key] = obj[key];
34946
35156
  return res;
34947
35157
  };
34948
- micromatch.some = (list2, patterns, options) => {
34949
- let items2 = [].concat(list2);
35158
+ micromatch2.some = (list3, patterns, options) => {
35159
+ let items2 = [].concat(list3);
34950
35160
  for (let pattern2 of [].concat(patterns)) {
34951
35161
  let isMatch = picomatch(String(pattern2), options);
34952
35162
  if (items2.some((item) => isMatch(item))) {
@@ -34955,8 +35165,8 @@ var require_micromatch = __commonJS({
34955
35165
  }
34956
35166
  return false;
34957
35167
  };
34958
- micromatch.every = (list2, patterns, options) => {
34959
- let items2 = [].concat(list2);
35168
+ micromatch2.every = (list3, patterns, options) => {
35169
+ let items2 = [].concat(list3);
34960
35170
  for (let pattern2 of [].concat(patterns)) {
34961
35171
  let isMatch = picomatch(String(pattern2), options);
34962
35172
  if (!items2.every((item) => isMatch(item))) {
@@ -34965,13 +35175,13 @@ var require_micromatch = __commonJS({
34965
35175
  }
34966
35176
  return true;
34967
35177
  };
34968
- micromatch.all = (str3, patterns, options) => {
35178
+ micromatch2.all = (str3, patterns, options) => {
34969
35179
  if (typeof str3 !== "string") {
34970
35180
  throw new TypeError(`Expected a string: "${util.inspect(str3)}"`);
34971
35181
  }
34972
35182
  return [].concat(patterns).every((p2) => picomatch(p2, options)(str3));
34973
35183
  };
34974
- micromatch.capture = (glob2, input2, options) => {
35184
+ micromatch2.capture = (glob2, input2, options) => {
34975
35185
  let posix3 = utils.isWindows(options);
34976
35186
  let regex = picomatch.makeRe(String(glob2), { ...options, capture: true });
34977
35187
  let match = regex.exec(posix3 ? utils.toPosixSlashes(input2) : input2);
@@ -34979,9 +35189,9 @@ var require_micromatch = __commonJS({
34979
35189
  return match.slice(1).map((v) => v === void 0 ? "" : v);
34980
35190
  }
34981
35191
  };
34982
- micromatch.makeRe = (...args) => picomatch.makeRe(...args);
34983
- micromatch.scan = (...args) => picomatch.scan(...args);
34984
- micromatch.parse = (patterns, options) => {
35192
+ micromatch2.makeRe = (...args) => picomatch.makeRe(...args);
35193
+ micromatch2.scan = (...args) => picomatch.scan(...args);
35194
+ micromatch2.parse = (patterns, options) => {
34985
35195
  let res = [];
34986
35196
  for (let pattern2 of [].concat(patterns || [])) {
34987
35197
  for (let str3 of braces(String(pattern2), options)) {
@@ -34990,19 +35200,19 @@ var require_micromatch = __commonJS({
34990
35200
  }
34991
35201
  return res;
34992
35202
  };
34993
- micromatch.braces = (pattern2, options) => {
35203
+ micromatch2.braces = (pattern2, options) => {
34994
35204
  if (typeof pattern2 !== "string") throw new TypeError("Expected a string");
34995
35205
  if (options && options.nobrace === true || !hasBraces(pattern2)) {
34996
35206
  return [pattern2];
34997
35207
  }
34998
35208
  return braces(pattern2, options);
34999
35209
  };
35000
- micromatch.braceExpand = (pattern2, options) => {
35210
+ micromatch2.braceExpand = (pattern2, options) => {
35001
35211
  if (typeof pattern2 !== "string") throw new TypeError("Expected a string");
35002
- return micromatch.braces(pattern2, { ...options, expand: true });
35212
+ return micromatch2.braces(pattern2, { ...options, expand: true });
35003
35213
  };
35004
- micromatch.hasBraces = hasBraces;
35005
- module.exports = micromatch;
35214
+ micromatch2.hasBraces = hasBraces;
35215
+ module.exports = micromatch2;
35006
35216
  }
35007
35217
  });
35008
35218
 
@@ -35015,7 +35225,7 @@ var require_pattern = __commonJS({
35015
35225
  exports.isAbsolute = exports.partitionAbsoluteAndRelative = exports.removeDuplicateSlashes = exports.matchAny = exports.convertPatternsToRe = exports.makeRe = exports.getPatternParts = exports.expandBraceExpansion = exports.expandPatternsWithBraceExpansion = exports.isAffectDepthOfReadingPattern = exports.endsWithSlashGlobStar = exports.hasGlobStar = exports.getBaseDirectory = exports.isPatternRelatedToParentDirectory = exports.getPatternsOutsideCurrentDirectory = exports.getPatternsInsideCurrentDirectory = exports.getPositivePatterns = exports.getNegativePatterns = exports.isPositivePattern = exports.isNegativePattern = exports.convertToNegativePattern = exports.convertToPositivePattern = exports.isDynamicPattern = exports.isStaticPattern = void 0;
35016
35226
  var path3 = __require("path");
35017
35227
  var globParent = require_glob_parent();
35018
- var micromatch = require_micromatch();
35228
+ var micromatch2 = require_micromatch();
35019
35229
  var GLOBSTAR = "**";
35020
35230
  var ESCAPE_SYMBOL = "\\";
35021
35231
  var COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/;
@@ -35108,8 +35318,8 @@ var require_pattern = __commonJS({
35108
35318
  }
35109
35319
  exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
35110
35320
  function isAffectDepthOfReadingPattern(pattern2) {
35111
- const basename10 = path3.basename(pattern2);
35112
- return endsWithSlashGlobStar(pattern2) || isStaticPattern(basename10);
35321
+ const basename11 = path3.basename(pattern2);
35322
+ return endsWithSlashGlobStar(pattern2) || isStaticPattern(basename11);
35113
35323
  }
35114
35324
  exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
35115
35325
  function expandPatternsWithBraceExpansion(patterns) {
@@ -35119,13 +35329,13 @@ var require_pattern = __commonJS({
35119
35329
  }
35120
35330
  exports.expandPatternsWithBraceExpansion = expandPatternsWithBraceExpansion;
35121
35331
  function expandBraceExpansion(pattern2) {
35122
- const patterns = micromatch.braces(pattern2, { expand: true, nodupes: true, keepEscaping: true });
35332
+ const patterns = micromatch2.braces(pattern2, { expand: true, nodupes: true, keepEscaping: true });
35123
35333
  patterns.sort((a, b) => a.length - b.length);
35124
35334
  return patterns.filter((pattern3) => pattern3 !== "");
35125
35335
  }
35126
35336
  exports.expandBraceExpansion = expandBraceExpansion;
35127
35337
  function getPatternParts(pattern2, options) {
35128
- let { parts } = micromatch.scan(pattern2, Object.assign(Object.assign({}, options), { parts: true }));
35338
+ let { parts } = micromatch2.scan(pattern2, Object.assign(Object.assign({}, options), { parts: true }));
35129
35339
  if (parts.length === 0) {
35130
35340
  parts = [pattern2];
35131
35341
  }
@@ -35137,7 +35347,7 @@ var require_pattern = __commonJS({
35137
35347
  }
35138
35348
  exports.getPatternParts = getPatternParts;
35139
35349
  function makeRe(pattern2, options) {
35140
- return micromatch.makeRe(pattern2, options);
35350
+ return micromatch2.makeRe(pattern2, options);
35141
35351
  }
35142
35352
  exports.makeRe = makeRe;
35143
35353
  function convertPatternsToRe(patterns, options) {
@@ -35156,7 +35366,7 @@ var require_pattern = __commonJS({
35156
35366
  const absolute = [];
35157
35367
  const relative18 = [];
35158
35368
  for (const pattern2 of patterns) {
35159
- if (isAbsolute8(pattern2)) {
35369
+ if (isAbsolute9(pattern2)) {
35160
35370
  absolute.push(pattern2);
35161
35371
  } else {
35162
35372
  relative18.push(pattern2);
@@ -35165,10 +35375,10 @@ var require_pattern = __commonJS({
35165
35375
  return [absolute, relative18];
35166
35376
  }
35167
35377
  exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
35168
- function isAbsolute8(pattern2) {
35378
+ function isAbsolute9(pattern2) {
35169
35379
  return path3.isAbsolute(pattern2);
35170
35380
  }
35171
- exports.isAbsolute = isAbsolute8;
35381
+ exports.isAbsolute = isAbsolute9;
35172
35382
  }
35173
35383
  });
35174
35384
 
@@ -38837,7 +39047,7 @@ function read(ctx, db, name) {
38837
39047
  row: synced.row
38838
39048
  };
38839
39049
  }
38840
- function list(ctx, db, opts = {}) {
39050
+ function list2(ctx, db, opts = {}) {
38841
39051
  void ctx;
38842
39052
  const rows = db.memoryList({ ...opts, limit: opts.limit ?? 100 }).filter((r) => r.name);
38843
39053
  return rows.sort((a, b) => Number(b.kind === "onboarding") - Number(a.kind === "onboarding"));
@@ -39263,6 +39473,7 @@ function formatSwarmList(config2, plan, active, opts = {}) {
39263
39473
  const lines = [
39264
39474
  `eminiar swarms \xB7 ${config2.rel} \xB7 sync ${config2.sync}${enforceNote(config2)} \xB7 agent files: ${fileSummary || "none"}`
39265
39475
  ];
39476
+ if (config2.ignoredKeys.length) lines.push(formatIssues(config2.rel, config2.ignoredKeys));
39266
39477
  if (opts.swarm && !swarms.length)
39267
39478
  lines.push(
39268
39479
  `No swarm "${opts.swarm}"; ${config2.rel} defines: ${config2.swarms.map((s) => s.name).join(", ")}`
@@ -39321,6 +39532,11 @@ function formatSync(result, opts = {}) {
39321
39532
  ` ${SYNC_VERB[a.action].mark} ${word(a.action)} ${a.path}${a.reason ? `: ${a.reason}` : ""}`
39322
39533
  );
39323
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
+ );
39324
39540
  if (!opts.dryRun && result.actions.some((a) => a.action === "create"))
39325
39541
  lines.push(
39326
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."
@@ -39848,8 +40064,8 @@ function groupBy(calls, keyFn) {
39848
40064
  if (!isRealCall(c)) continue;
39849
40065
  const k = keyFn(c);
39850
40066
  if (k == null) continue;
39851
- const list2 = buckets.get(k);
39852
- if (list2) list2.push(c);
40067
+ const list3 = buckets.get(k);
40068
+ if (list3) list3.push(c);
39853
40069
  else buckets.set(k, [c]);
39854
40070
  }
39855
40071
  return [...buckets.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, rows]) => ({ key, totals: totals(rows) }));
@@ -40550,18 +40766,18 @@ function threads(calls) {
40550
40766
  const out = /* @__PURE__ */ new Map();
40551
40767
  for (const c of calls) {
40552
40768
  const key = `${c.session_id}\0${c.sidechain ? c.agent_id ?? "sidechain" : ""}`;
40553
- const list2 = out.get(key);
40554
- if (list2) list2.push(c);
40769
+ const list3 = out.get(key);
40770
+ if (list3) list3.push(c);
40555
40771
  else out.set(key, [c]);
40556
40772
  }
40557
- 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);
40558
40774
  return out;
40559
40775
  }
40560
40776
  function groupBySession(rows) {
40561
40777
  const out = /* @__PURE__ */ new Map();
40562
40778
  for (const r of rows) {
40563
- const list2 = out.get(r.session_id);
40564
- if (list2) list2.push(r);
40779
+ const list3 = out.get(r.session_id);
40780
+ if (list3) list3.push(r);
40565
40781
  else out.set(r.session_id, [r]);
40566
40782
  }
40567
40783
  return out;
@@ -40592,9 +40808,9 @@ function withScope(base, sessionIds) {
40592
40808
  return out;
40593
40809
  }
40594
40810
  function hasCompactionBetween(ctx, sessionId, from, to) {
40595
- const list2 = ctx.compactionsBySession.get(sessionId);
40596
- if (!list2) return false;
40597
- 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);
40598
40814
  }
40599
40815
  function detectCacheThrash(ctx) {
40600
40816
  let runs = 0;
@@ -40602,7 +40818,7 @@ function detectCacheThrash(ctx) {
40602
40818
  let rewritten = 0;
40603
40819
  let savings = 0;
40604
40820
  const sessions = /* @__PURE__ */ new Set();
40605
- for (const list2 of ctx.threads.values()) {
40821
+ for (const list3 of ctx.threads.values()) {
40606
40822
  let run3 = [];
40607
40823
  const flush = () => {
40608
40824
  if (run3.length >= THRASH_RUN) {
@@ -40618,12 +40834,12 @@ function detectCacheThrash(ctx) {
40618
40834
  }
40619
40835
  run3 = [];
40620
40836
  };
40621
- for (let i = 1; i < list2.length; i++) {
40622
- const c = list2[i];
40623
- 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];
40624
40840
  const ctxTokens = contextOf(c);
40625
40841
  const heavy = ctxTokens > 0 && writesOf(c) / ctxTokens >= THRASH_WRITE_SHARE;
40626
- 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);
40627
40843
  if (!heavy || broken) {
40628
40844
  flush();
40629
40845
  continue;
@@ -40646,10 +40862,10 @@ function detectCacheThrash(ctx) {
40646
40862
  sessions
40647
40863
  );
40648
40864
  }
40649
- function ttlFor(list2) {
40865
+ function ttlFor(list3) {
40650
40866
  let w5 = 0;
40651
40867
  let w1 = 0;
40652
- for (const c of list2) {
40868
+ for (const c of list3) {
40653
40869
  w5 += num3(c.cache_create_5m);
40654
40870
  w1 += num3(c.cache_create_1h);
40655
40871
  }
@@ -40661,11 +40877,11 @@ function detectCacheCold(ctx) {
40661
40877
  let savings = 0;
40662
40878
  let longestGap = 0;
40663
40879
  const sessions = /* @__PURE__ */ new Set();
40664
- for (const list2 of ctx.threads.values()) {
40665
- const ttl = ttlFor(list2);
40666
- for (let i = 1; i < list2.length; i++) {
40667
- const c = list2[i];
40668
- 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];
40669
40885
  const gap = c.ts - prev.ts;
40670
40886
  if (gap <= ttl) continue;
40671
40887
  if (hasCompactionBetween(ctx, c.session_id, prev.ts, c.ts)) continue;
@@ -40927,15 +41143,15 @@ function detectErrorLoop(ctx) {
40927
41143
  const byThread = /* @__PURE__ */ new Map();
40928
41144
  for (const u of ctx.toolUses) {
40929
41145
  const key = `${u.session_id}\0${u.agent_id ?? ""}`;
40930
- const list2 = byThread.get(key);
40931
- if (list2) list2.push(u);
41146
+ const list3 = byThread.get(key);
41147
+ if (list3) list3.push(u);
40932
41148
  else byThread.set(key, [u]);
40933
41149
  }
40934
- for (const list2 of byThread.values()) {
40935
- list2.sort((a, b) => a.ts - b.ts);
41150
+ for (const list3 of byThread.values()) {
41151
+ list3.sort((a, b) => a.ts - b.ts);
40936
41152
  let run3 = 0;
40937
41153
  let tool = "";
40938
- for (const u of list2) {
41154
+ for (const u of list3) {
40939
41155
  if (u.is_error && u.tool === tool) run3 += 1;
40940
41156
  else {
40941
41157
  run3 = u.is_error ? 1 : 0;
@@ -41169,11 +41385,11 @@ function detectInsights(input2) {
41169
41385
  const calls = input2.calls.filter(isRealCall);
41170
41386
  const compactionsBySession = /* @__PURE__ */ new Map();
41171
41387
  for (const e of input2.contextEvents) {
41172
- const list2 = compactionsBySession.get(e.session_id);
41173
- if (list2) list2.push(e.ts);
41388
+ const list3 = compactionsBySession.get(e.session_id);
41389
+ if (list3) list3.push(e.ts);
41174
41390
  else compactionsBySession.set(e.session_id, [e.ts]);
41175
41391
  }
41176
- 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);
41177
41393
  const callTs = /* @__PURE__ */ new Map();
41178
41394
  for (const [sid, rows] of groupBySession(calls))
41179
41395
  callTs.set(
@@ -41427,8 +41643,8 @@ function periods(calls, keyFn) {
41427
41643
  const buckets = /* @__PURE__ */ new Map();
41428
41644
  for (const c of calls) {
41429
41645
  const k = keyFn(c.ts);
41430
- const list2 = buckets.get(k);
41431
- if (list2) list2.push(c);
41646
+ const list3 = buckets.get(k);
41647
+ if (list3) list3.push(c);
41432
41648
  else buckets.set(k, [c]);
41433
41649
  }
41434
41650
  return [...buckets.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, rows]) => ({ key, totals: totals(rows), models: modelSlices(rows) }));
@@ -41458,8 +41674,8 @@ function insightsFor(ctx, data) {
41458
41674
  const r = detectInsights(input2);
41459
41675
  return { insights: r.insights, scores: r.scores };
41460
41676
  }
41461
- function sortInsights(list2) {
41462
- return list2.slice().sort(
41677
+ function sortInsights(list3) {
41678
+ return list3.slice().sort(
41463
41679
  (a, b) => SEVERITY_RANK2[a.severity] - SEVERITY_RANK2[b.severity] || (b.estimatedSavingsUsd ?? 0) - (a.estimatedSavingsUsd ?? 0)
41464
41680
  );
41465
41681
  }
@@ -42553,11 +42769,11 @@ import { readFile } from "fs/promises";
42553
42769
  import { basename as basename5, extname as extname2, resolve as resolvePath } from "path";
42554
42770
  import { pathToFileURL } from "url";
42555
42771
  function parseFixture(raw, source = "fixture") {
42556
- const list2 = Array.isArray(raw) || !raw || typeof raw !== "object" ? raw : raw.items;
42557
- if (!Array.isArray(list2))
42772
+ const list3 = Array.isArray(raw) || !raw || typeof raw !== "object" ? raw : raw.items;
42773
+ if (!Array.isArray(list3))
42558
42774
  throw new EvalFixtureError(`${source}: expected an array of items or {"items": [...]}`);
42559
- if (!list2.length) throw new EvalFixtureError(`${source}: the fixture has no items`);
42560
- return list2.map((it, i) => {
42775
+ if (!list3.length) throw new EvalFixtureError(`${source}: the fixture has no items`);
42776
+ return list3.map((it, i) => {
42561
42777
  const r = ItemSchema.safeParse(it);
42562
42778
  if (!r.success) {
42563
42779
  const issue2 = r.error.issues[0];
@@ -43450,10 +43666,10 @@ function personalConsent() {
43450
43666
  try {
43451
43667
  const a = readRaw(paths().configFile).adjudicator;
43452
43668
  if (!isObj2(a)) return { remoteConsent: false };
43453
- const list2 = a.remoteConsentOrigins;
43669
+ const list3 = a.remoteConsentOrigins;
43454
43670
  return {
43455
43671
  remoteConsent: a.remoteConsent === true,
43456
- ...Array.isArray(list2) ? { remoteConsentOrigins: list2.filter((s) => typeof s === "string") } : {}
43672
+ ...Array.isArray(list3) ? { remoteConsentOrigins: list3.filter((s) => typeof s === "string") } : {}
43457
43673
  };
43458
43674
  } catch {
43459
43675
  return { remoteConsent: false };
@@ -43467,8 +43683,8 @@ function mustAsk(r, previous) {
43467
43683
  function consentPatch(r, asked) {
43468
43684
  if (!r.configuredRemote || !r.origin) return {};
43469
43685
  if (!asked && r.consentVia !== "legacy") return {};
43470
- const list2 = withConsentedOrigin(personalConsent(), r.origin);
43471
- return { remoteConsent: true, remoteConsentOrigins: list2 };
43686
+ const list3 = withConsentedOrigin(personalConsent(), r.origin);
43687
+ return { remoteConsent: true, remoteConsentOrigins: list3 };
43472
43688
  }
43473
43689
  function personalOrigin(root) {
43474
43690
  try {
@@ -45416,8 +45632,8 @@ function registerSettings(stable) {
45416
45632
  const hooks = settings.hooks ?? {};
45417
45633
  const hookCmd = `"${join21(stable, "bin", "em-hook")}"`;
45418
45634
  for (const ev3 of HOOK_EVENTS) {
45419
- const list2 = hooks[ev3] ?? [];
45420
- const filtered = list2.filter(
45635
+ const list3 = hooks[ev3] ?? [];
45636
+ const filtered = list3.filter(
45421
45637
  (entry2) => !(entry2.hooks ?? []).some((h) => isOurs(h.command, stable))
45422
45638
  );
45423
45639
  const entry = {
@@ -45457,9 +45673,9 @@ function unregisterSettings(stable, wrote) {
45457
45673
  const settings = readJson2(settingsPath());
45458
45674
  const hooks = settings.hooks ?? {};
45459
45675
  for (const ev3 of wrote.hookEvents) {
45460
- const list2 = hooks[ev3];
45461
- if (!list2) continue;
45462
- const kept = list2.filter(
45676
+ const list3 = hooks[ev3];
45677
+ if (!list3) continue;
45678
+ const kept = list3.filter(
45463
45679
  (entry) => !(entry.hooks ?? []).some((h) => isOurs(h.command, stable))
45464
45680
  );
45465
45681
  if (kept.length) hooks[ev3] = kept;
@@ -45551,13 +45767,13 @@ function registerCursor(stable) {
45551
45767
  const hooks = cfg.hooks ?? {};
45552
45768
  const command = cursorHookCommand(stable);
45553
45769
  for (const ev3 of CURSOR_HOOK_EVENTS) {
45554
- const list2 = (Array.isArray(hooks[ev3]) ? hooks[ev3] : []).filter(
45770
+ const list3 = (Array.isArray(hooks[ev3]) ? hooks[ev3] : []).filter(
45555
45771
  (h) => !isOurs(h.command, stable)
45556
45772
  );
45557
45773
  const entry = { command, timeout: TIMEOUTS[ev3] ?? 5 };
45558
45774
  if (ev3 === "preToolUse") entry.matcher = CURSOR_PRE_TOOL_MATCHER;
45559
- list2.push(entry);
45560
- hooks[ev3] = list2;
45775
+ list3.push(entry);
45776
+ hooks[ev3] = list3;
45561
45777
  }
45562
45778
  cfg.hooks = hooks;
45563
45779
  writeJsonWithBackup(cursorHooksPath(), cfg);
@@ -46416,8 +46632,8 @@ function findContextMode() {
46416
46632
  const settings = readJson2(settingsPath());
46417
46633
  const hooks = settings.hooks ?? {};
46418
46634
  const hookEntries = [];
46419
- for (const [event, list2] of Object.entries(hooks)) {
46420
- for (const entry of list2) {
46635
+ for (const [event, list3] of Object.entries(hooks)) {
46636
+ for (const entry of list3) {
46421
46637
  for (const h of entry.hooks ?? []) {
46422
46638
  if (typeof h.command === "string" && CM_HOOK.test(h.command))
46423
46639
  hookEntries.push({ event, command: h.command });
@@ -46462,8 +46678,8 @@ async function replaceContextMode(opts) {
46462
46678
  if (f.hookEntries.length) {
46463
46679
  const settings = readJson2(settingsPath());
46464
46680
  const hooks = settings.hooks ?? {};
46465
- for (const [event, list2] of Object.entries(hooks)) {
46466
- const kept = list2.map((entry) => ({
46681
+ for (const [event, list3] of Object.entries(hooks)) {
46682
+ const kept = list3.map((entry) => ({
46467
46683
  ...entry,
46468
46684
  hooks: (entry.hooks ?? []).filter(
46469
46685
  (h) => !(typeof h.command === "string" && CM_HOOK.test(h.command))
@@ -46729,10 +46945,10 @@ function loadPermissionRules(root, extraDeny = []) {
46729
46945
  const hit = cache4.get(key);
46730
46946
  if (hit?.stamps.every((s, i) => s === stamps[i])) return hit.rules;
46731
46947
  const out = { allow: [], deny: [], ask: [], root };
46732
- const push = (list2, raws) => {
46948
+ const push = (list3, raws) => {
46733
46949
  for (const raw of raws ?? []) {
46734
46950
  const r = parseRule(raw);
46735
- if (r) list2.push(r);
46951
+ if (r) list3.push(r);
46736
46952
  }
46737
46953
  };
46738
46954
  for (const f of files) {
@@ -47057,57 +47273,6 @@ var init_snippets = __esm({
47057
47273
  }
47058
47274
  });
47059
47275
 
47060
- // src/search/typo.ts
47061
- function editDistance(a, b, max = 3) {
47062
- if (Math.abs(a.length - b.length) > max) return max + 1;
47063
- const prev2 = [];
47064
- let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
47065
- let cur = new Array(b.length + 1).fill(0);
47066
- for (let i = 1; i <= a.length; i++) {
47067
- cur[0] = i;
47068
- let rowMin = cur[0];
47069
- for (let j = 1; j <= b.length; j++) {
47070
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
47071
- let v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
47072
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
47073
- v = Math.min(v, prev2[j - 2] + 1);
47074
- }
47075
- cur[j] = v;
47076
- if (v < rowMin) rowMin = v;
47077
- }
47078
- if (rowMin > max) return max + 1;
47079
- prev2.splice(0, prev2.length, ...prev);
47080
- [prev, cur] = [cur, prev];
47081
- }
47082
- return prev[b.length];
47083
- }
47084
- function correctTerms(db, terms) {
47085
- const corrections = [];
47086
- const out = terms.map((term) => {
47087
- if (term.length < 4 || /[^a-z0-9]/.test(term) || db.termExists(term)) return term;
47088
- const max = term.length >= 7 ? 2 : 1;
47089
- const candidates2 = db.vocabCandidates(term[0], 3e3);
47090
- let best;
47091
- for (const c of candidates2) {
47092
- if (c.term.length < 3) continue;
47093
- const d = editDistance(term, c.term, max);
47094
- if (d > max) continue;
47095
- if (!best || d < best.d || d === best.d && c.df > best.df)
47096
- best = { term: c.term, d, df: c.df };
47097
- }
47098
- if (!best) return term;
47099
- corrections.push({ from: term, to: best.term });
47100
- return `${best.term}*`;
47101
- });
47102
- return { terms: out, corrections };
47103
- }
47104
- var init_typo = __esm({
47105
- "src/search/typo.ts"() {
47106
- "use strict";
47107
- init_esm_shims();
47108
- }
47109
- });
47110
-
47111
47276
  // src/search/pipeline.ts
47112
47277
  var pipeline_exports = {};
47113
47278
  __export(pipeline_exports, {
@@ -47382,19 +47547,19 @@ function mergedCatalog(extra) {
47382
47547
  function catalogLookup(kind, key, catalog = CATALOG) {
47383
47548
  const k = key.trim();
47384
47549
  for (const e of catalog) {
47385
- const list2 = kind === "api" ? e.hosts : e[kind];
47386
- if (!list2) continue;
47550
+ const list3 = kind === "api" ? e.hosts : e[kind];
47551
+ if (!list3) continue;
47387
47552
  if (kind === "env") {
47388
- if (list2.some((p2) => envMatches(p2, k))) return e;
47553
+ if (list3.some((p2) => envMatches(p2, k))) return e;
47389
47554
  } else if (kind === "api") {
47390
47555
  const host = k.toLowerCase();
47391
- if (list2.some((h) => host === h || host.endsWith(`.${h}`))) return e;
47556
+ if (list3.some((h) => host === h || host.endsWith(`.${h}`))) return e;
47392
47557
  } else if (kind === "image") {
47393
47558
  const bare = k.split(":")[0].replace(/^docker\.io\/(library\/)?/, "");
47394
- if (list2.some((p2) => matches(p2, bare))) return e;
47559
+ if (list3.some((p2) => matches(p2, bare))) return e;
47395
47560
  } else if (kind === "go") {
47396
- if (list2.some((p2) => k === p2 || k.startsWith(p2))) return e;
47397
- } 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;
47398
47563
  }
47399
47564
  return void 0;
47400
47565
  }
@@ -48804,9 +48969,9 @@ function schemaSummary(doc, schema, depth = 0) {
48804
48969
  if (Array.isArray(s.enum))
48805
48970
  return `enum(${s.enum.slice(0, 8).map(String).join(", ")}${s.enum.length > 8 ? ", \u2026" : ""})`;
48806
48971
  for (const k of ["oneOf", "anyOf", "allOf"]) {
48807
- const list2 = s[k];
48808
- if (Array.isArray(list2))
48809
- 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(" | ")}>`;
48810
48975
  }
48811
48976
  if (type === "array" || s.items) return `${schemaSummary(doc, s.items, depth + 1) || "any"}[]`;
48812
48977
  if (type === "object" || isObj3(s.properties)) {
@@ -48968,9 +49133,9 @@ function postmanBody(body) {
48968
49133
  const lang = isObj3(body.options) && isObj3(body.options.raw) ? String(body.options.raw.language ?? "json") : "json";
48969
49134
  return raw.length > 2e3 ? [`Body (${lang}): ${raw.slice(0, 2e3)}\u2026`] : ["Body:", "", `\`\`\`${lang}`, raw, "```"];
48970
49135
  }
48971
- const list2 = body[mode];
48972
- if (Array.isArray(list2)) {
48973
- const keys = list2.filter(isObj3).map(
49136
+ const list3 = body[mode];
49137
+ if (Array.isArray(list3)) {
49138
+ const keys = list3.filter(isObj3).map(
48974
49139
  (e) => `${String(e.key)}${e.type && e.type !== "text" ? ` (${String(e.type)})` : ""}${e.description ? ` \u2014 ${clip5(e.description, 100)}` : ""}`
48975
49140
  );
48976
49141
  return keys.length ? [`Body (${mode}): ${keys.join(", ")}`] : [];
@@ -49561,9 +49726,9 @@ function computeMetrics(db) {
49561
49726
  for (const s of symbols) {
49562
49727
  const f = s.path ? `file:${s.path}` : void 0;
49563
49728
  if (!f) continue;
49564
- const list2 = symbolsByFile.get(f) ?? [];
49565
- list2.push(s);
49566
- symbolsByFile.set(f, list2);
49729
+ const list3 = symbolsByFile.get(f) ?? [];
49730
+ list3.push(s);
49731
+ symbolsByFile.set(f, list3);
49567
49732
  }
49568
49733
  for (const f of files) {
49569
49734
  const m = meta3(f);
@@ -49616,9 +49781,9 @@ function computeMetrics(db) {
49616
49781
  const members2 = /* @__PURE__ */ new Map();
49617
49782
  for (const r of fileRows) {
49618
49783
  if (r.cluster === null) continue;
49619
- const list2 = members2.get(r.cluster) ?? [];
49620
- list2.push(r);
49621
- members2.set(r.cluster, list2);
49784
+ const list3 = members2.get(r.cluster) ?? [];
49785
+ list3.push(r);
49786
+ members2.set(r.cluster, list3);
49622
49787
  }
49623
49788
  const links = /* @__PURE__ */ new Map();
49624
49789
  for (const e of importEdges) {
@@ -49777,10 +49942,10 @@ function impact(db, ref, opts = {}) {
49777
49942
  add3(e.dst, e.weight, 1, `co-changed ${meta4.count ?? "?"}\xD7 (${Math.round(e.weight * 100)}%)`);
49778
49943
  }
49779
49944
  }
49780
- const list2 = [...hits.values()].sort((a, b) => b.score - a.score);
49781
- const nodes = new Map(db.graphGetNodes(list2.map((h) => h.id)).map((n) => [n.id, n]));
49782
- for (const h of list2) h.node = nodes.get(h.id);
49783
- 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 };
49784
49949
  }
49785
49950
  function dependencies(db, ref, depth = 1) {
49786
49951
  const root = resolveNode(db, ref);
@@ -49807,10 +49972,10 @@ function dependencies(db, ref, depth = 1) {
49807
49972
  frontier = next;
49808
49973
  if (!frontier.length) break;
49809
49974
  }
49810
- const list2 = [...hits.values()].sort((a, b) => b.score - a.score);
49811
- const nodes = new Map(db.graphGetNodes(list2.map((h) => h.id)).map((n) => [n.id, n]));
49812
- for (const h of list2) h.node = nodes.get(h.id);
49813
- 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 };
49814
49979
  }
49815
49980
  function neighbors(db, ref, depth = 1, kinds) {
49816
49981
  const root = resolveNode(db, ref);
@@ -50311,8 +50476,8 @@ function parseRouteAnnotations(doc) {
50311
50476
  const body = m[1] ?? "";
50312
50477
  const path3 = /^\s*"([^"]*)"/.exec(body)?.[1] ?? /\bpath\s*=\s*"([^"]*)"/.exec(body)?.[1];
50313
50478
  if (path3 === void 0) continue;
50314
- const list2 = /\bmethods\s*=\s*(\{[^}]*\}|"[^"]*")/.exec(body)?.[1] ?? "";
50315
- 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);
50316
50481
  for (const method of methods.length ? methods : ["ALL"]) out.push({ method, path: path3 });
50317
50482
  }
50318
50483
  return out;
@@ -51113,16 +51278,16 @@ function phpString(n) {
51113
51278
  return literalText(n)?.replace(/\\(\\|')/g, "$1");
51114
51279
  }
51115
51280
  function argsOf(call) {
51116
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51117
- 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);
51118
51283
  }
51119
51284
  function positionalArgs(call) {
51120
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51121
- 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);
51122
51287
  }
51123
51288
  function namedArg(call, name) {
51124
- const list2 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51125
- for (const a of list2?.namedChildren ?? []) {
51289
+ const list3 = call.childForFieldName("arguments") ?? call.childForFieldName("parameters");
51290
+ for (const a of list3?.namedChildren ?? []) {
51126
51291
  if (a?.type === "argument" && a.childForFieldName("name")?.text === name)
51127
51292
  return a.namedChildren[a.namedChildren.length - 1] ?? void 0;
51128
51293
  }
@@ -53676,16 +53841,42 @@ var init_link = __esm({
53676
53841
 
53677
53842
  // src/graph/reindex.ts
53678
53843
  import { readFileSync as readFileSync25, statSync as statSync16 } from "fs";
53679
- import { join as join33 } from "path";
53844
+ import { basename as basename7, isAbsolute as isAbsolute7, join as join33 } from "path";
53680
53845
  function listCodeFiles(ctx) {
53681
53846
  return import_fast_glob3.default.sync(ctx.config.graph.include, {
53847
+ ...CODE_GLOB,
53682
53848
  cwd: ctx.root,
53683
- ignore: ctx.config.graph.exclude,
53684
- onlyFiles: true,
53685
- dot: false,
53686
- followSymbolicLinks: false
53849
+ ignore: ctx.config.graph.exclude
53687
53850
  });
53688
53851
  }
53852
+ function codeFileFilter(graph) {
53853
+ const cached6 = FILTERS.get(graph);
53854
+ if (cached6) return cached6;
53855
+ const f = compileCodeFilter(graph);
53856
+ FILTERS.set(graph, f);
53857
+ return f;
53858
+ }
53859
+ function compileCodeFilter(graph) {
53860
+ const tasks = import_fast_glob3.default.generateTasks(graph.include, { ignore: graph.exclude });
53861
+ const re = (patterns, opts) => patterns.map((p2) => import_micromatch.default.makeRe(p2, opts));
53862
+ const any2 = (res, s) => res.some((r) => r.test(s));
53863
+ const positive = re(
53864
+ tasks.flatMap((t) => t.positive),
53865
+ MATCH
53866
+ );
53867
+ const ignore = tasks[0]?.negative ?? [];
53868
+ const ignored = re(ignore, { ...MATCH, dot: true });
53869
+ const pruned = re(
53870
+ ignore.filter((p2) => p2.endsWith("/**") || !import_fast_glob3.default.isDynamicPattern(basename7(p2))),
53871
+ MATCH
53872
+ );
53873
+ return (rel) => {
53874
+ if (isAbsolute7(rel) || rel.startsWith("../") || !any2(positive, rel) || any2(ignored, rel))
53875
+ return false;
53876
+ const dirs = rel.split("/").slice(0, -1);
53877
+ return !dirs.some((_, i) => any2(pruned, dirs.slice(0, i + 1).join("/")));
53878
+ };
53879
+ }
53689
53880
  async function indexOne(ctx, db, rel, force) {
53690
53881
  const abs = join33(ctx.root, rel);
53691
53882
  const st = statSync16(abs);
@@ -53886,7 +54077,7 @@ function statSafe(p2) {
53886
54077
  }
53887
54078
  async function drainReindexQueue(ctx, db) {
53888
54079
  if (draining) return 0;
53889
- const paths2 = db.reindexQueueDrain();
54080
+ const paths2 = db.reindexQueueDrain().filter(codeFileFilter(ctx.config.graph));
53890
54081
  if (!paths2.length) return 0;
53891
54082
  draining = true;
53892
54083
  try {
@@ -53936,12 +54127,13 @@ function indexFreshness(ctx, db) {
53936
54127
  lastRun: db.indexRunsRecent(1)[0]?.finished_at ?? null
53937
54128
  };
53938
54129
  }
53939
- var import_fast_glob3, MAX_CODE_BYTES, CODE_INDEX_VERSION, draining;
54130
+ var import_fast_glob3, import_micromatch, MAX_CODE_BYTES, CODE_INDEX_VERSION, CODE_GLOB, MATCH, FILTERS, draining;
53940
54131
  var init_reindex = __esm({
53941
54132
  "src/graph/reindex.ts"() {
53942
54133
  "use strict";
53943
54134
  init_esm_shims();
53944
54135
  import_fast_glob3 = __toESM(require_out4(), 1);
54136
+ import_micromatch = __toESM(require_micromatch(), 1);
53945
54137
  init_chunker();
53946
54138
  init_symbols();
53947
54139
  init_backend();
@@ -53951,6 +54143,9 @@ var init_reindex = __esm({
53951
54143
  init_metrics();
53952
54144
  MAX_CODE_BYTES = 15e5;
53953
54145
  CODE_INDEX_VERSION = "3";
54146
+ CODE_GLOB = { onlyFiles: true, dot: false, followSymbolicLinks: false };
54147
+ MATCH = { dot: false, posix: true, strictSlashes: false };
54148
+ FILTERS = /* @__PURE__ */ new WeakMap();
53954
54149
  draining = false;
53955
54150
  }
53956
54151
  });
@@ -54426,21 +54621,21 @@ function detectChanges(db, root, opts = {}) {
54426
54621
  }
54427
54622
  const byFile = /* @__PURE__ */ new Map();
54428
54623
  for (const h of hunks) {
54429
- const list2 = byFile.get(h.path) ?? [];
54430
- list2.push(h);
54431
- byFile.set(h.path, list2);
54624
+ const list3 = byFile.get(h.path) ?? [];
54625
+ list3.push(h);
54626
+ byFile.set(h.path, list3);
54432
54627
  }
54433
54628
  const symbols = /* @__PURE__ */ new Map();
54434
54629
  const files = [];
54435
54630
  const unindexed = [];
54436
- for (const [path3, list2] of byFile) {
54631
+ for (const [path3, list3] of byFile) {
54437
54632
  const indexed = !!db.graphGetNode(fileId(path3));
54438
- files.push({ path: path3, hunks: list2.length, indexed });
54633
+ files.push({ path: path3, hunks: list3.length, indexed });
54439
54634
  if (!indexed) {
54440
54635
  unindexed.push(path3);
54441
54636
  continue;
54442
54637
  }
54443
- 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);
54444
54639
  }
54445
54640
  const ids = [...symbols.keys()];
54446
54641
  const metrics = new Map(db.metricsGet(ids).map((m) => [m.node_id, m]));
@@ -54680,7 +54875,7 @@ function architecture(ctx, db, aspects = ASPECTS) {
54680
54875
  hotspots: want.has("hotspots") ? hotspots(db, 12) : [],
54681
54876
  clusters: want.has("clusters") ? readClusters(db) : [],
54682
54877
  cycles: want.has("cycles") ? readCycles(db) : [],
54683
- 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) => ({
54684
54879
  name: r.name ?? "",
54685
54880
  title: r.content.split("\n")[0]?.replace(/^#+\s*/, "").slice(0, 120) ?? "",
54686
54881
  status: r.status ?? "accepted",
@@ -54898,7 +55093,7 @@ var init_em_index_status = __esm({
54898
55093
 
54899
55094
  // src/docs/discover.ts
54900
55095
  import { existsSync as existsSync30, readFileSync as readFileSync27, statSync as statSync17 } from "fs";
54901
- import { basename as basename7, join as join35, relative as relative15 } from "path";
55096
+ import { basename as basename8, join as join35, relative as relative15 } from "path";
54902
55097
  function readText(file3) {
54903
55098
  try {
54904
55099
  return readFileSync27(file3, "utf8");
@@ -55058,9 +55253,9 @@ function envSignals(dir, project, catalog) {
55058
55253
  }
55059
55254
  const token = name.split("_")[0];
55060
55255
  if (token.length < 3 || GENERIC_ENV.has(token)) continue;
55061
- const list2 = unknownPrefixes.get(token) ?? [];
55062
- if (!list2.includes(name)) list2.push(name);
55063
- unknownPrefixes.set(token, list2);
55256
+ const list3 = unknownPrefixes.get(token) ?? [];
55257
+ if (!list3.includes(name)) list3.push(name);
55258
+ unknownPrefixes.set(token, list3);
55064
55259
  }
55065
55260
  }
55066
55261
  return { signals, unknownPrefixes };
@@ -55094,7 +55289,7 @@ function apiSignals(dir, project) {
55094
55289
  const text3 = readText(file3);
55095
55290
  if (!text3 || text3.includes("\0")) continue;
55096
55291
  const rel = relative15(dir, file3).split("\\").join("/");
55097
- const isEnv = basename7(file3).startsWith(".env");
55292
+ const isEnv = basename8(file3).startsWith(".env");
55098
55293
  const lines = text3.split("\n");
55099
55294
  const found = [];
55100
55295
  for (let i = 0; i < lines.length; i++) {
@@ -55182,7 +55377,7 @@ function fileSignals(dir, project) {
55182
55377
  }
55183
55378
  function localCandidates(root, dir, project, isRegistered) {
55184
55379
  const out = [];
55185
- const prefix = project ? `${slugify2(basename7(dir))}-` : "";
55380
+ const prefix = project ? `${slugify2(basename8(dir))}-` : "";
55186
55381
  const rel = (abs) => relative15(root, abs).split("\\").join("/");
55187
55382
  const push = (c) => {
55188
55383
  if (!c.files) return;
@@ -55206,7 +55401,7 @@ function localCandidates(root, dir, project, isRegistered) {
55206
55401
  push({
55207
55402
  name: `${prefix}readme`,
55208
55403
  path: rel(dir) || ".",
55209
- glob: guides.map((g) => basename7(g)),
55404
+ glob: guides.map((g) => basename8(g)),
55210
55405
  recursive: false,
55211
55406
  files: guides.length,
55212
55407
  bytes: sizeOf(guides),
@@ -55307,7 +55502,7 @@ function localCandidates(root, dir, project, isRegistered) {
55307
55502
  push({
55308
55503
  name: `${prefix}env-example`,
55309
55504
  path: rel(dir) || ".",
55310
- glob: env.map((f) => basename7(f)),
55505
+ glob: env.map((f) => basename8(f)),
55311
55506
  recursive: false,
55312
55507
  files: env.length,
55313
55508
  bytes: sizeOf(env),
@@ -55385,15 +55580,15 @@ function discoverDocs(ctx, opts = {}) {
55385
55580
  );
55386
55581
  for (const hit of api.hits.values()) {
55387
55582
  if (inSubproject(hit.samples)) continue;
55388
- const list2 = apiHits.get(hit.host) ?? [];
55389
- list2.push(hit);
55390
- apiHits.set(hit.host, list2);
55583
+ const list3 = apiHits.get(hit.host) ?? [];
55584
+ list3.push(hit);
55585
+ apiHits.set(hit.host, list3);
55391
55586
  }
55392
55587
  for (const link of api.docLinks.values()) {
55393
55588
  if (inSubproject(link.samples)) continue;
55394
- const list2 = docLinks.get(link.host) ?? [];
55395
- list2.push(link);
55396
- docLinks.set(link.host, list2);
55589
+ const list3 = docLinks.get(link.host) ?? [];
55590
+ list3.push(link);
55591
+ docLinks.set(link.host, list3);
55397
55592
  }
55398
55593
  const env = envSignals(dir, project, catalog);
55399
55594
  signals.push(...env.signals);
@@ -55483,12 +55678,12 @@ function discoverDocs(ctx, opts = {}) {
55483
55678
  evidence: `${info.vars.slice(0, 4).join(", ")}${info.vars.length > 4 ? ", \u2026" : ""}`
55484
55679
  });
55485
55680
  }
55486
- for (const [host, list2] of apiHits) {
55487
- 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);
55488
55683
  if (!calls) continue;
55489
55684
  const entry = catalogLookup("api", host, catalog);
55490
- const specUrls = [...new Set(list2.flatMap((h) => h.specUrls))];
55491
- for (const h of list2) {
55685
+ const specUrls = [...new Set(list3.flatMap((h) => h.specUrls))];
55686
+ for (const h of list3) {
55492
55687
  if (!h.calls) continue;
55493
55688
  const evidence = `api:${host} (${h.samples.slice(0, 2).join(", ")})${specUrls.length ? ` \xB7 spec ${specUrls[0]}` : ""}`;
55494
55689
  if (entry) {
@@ -55521,10 +55716,10 @@ function discoverDocs(ctx, opts = {}) {
55521
55716
  }
55522
55717
  }
55523
55718
  }
55524
- for (const [host, list2] of docLinks) {
55525
- 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);
55526
55721
  const entry = catalogLookup("api", host, catalog);
55527
- for (const l of list2) {
55722
+ for (const l of list3) {
55528
55723
  const evidence = `link:${host} (${l.samples.slice(0, 2).join(", ")})`;
55529
55724
  if (entry) {
55530
55725
  add3({
@@ -55972,7 +56167,7 @@ function rootOf(host) {
55972
56167
  function docGuesses(host) {
55973
56168
  const h = host.toLowerCase();
55974
56169
  const root = rootOf(h);
55975
- const list2 = [
56170
+ const list3 = [
55976
56171
  `https://docs.${root}/`,
55977
56172
  `https://developer.${root}/`,
55978
56173
  `https://developers.${root}/`,
@@ -55990,7 +56185,7 @@ function docGuesses(host) {
55990
56185
  `https://${h}/openapi.json`,
55991
56186
  `https://${h}/swagger.json`
55992
56187
  ];
55993
- return [...new Set(list2)];
56188
+ return [...new Set(list3)];
55994
56189
  }
55995
56190
  async function probe2(url2, opts) {
55996
56191
  const f = opts.fetchImpl ?? fetch;
@@ -56417,16 +56612,16 @@ function formatDiscovery(d, max = 40) {
56417
56612
  ]
56418
56613
  ];
56419
56614
  for (const [conf, title, note, wants] of groups) {
56420
- const list2 = d.providers.filter(wants);
56421
- if (!list2.length) continue;
56422
- lines.push("", `${title} (${list2.length}; ${note}):`);
56423
- 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)) {
56424
56619
  const used = p2.usedBy.length > 1 ? ` \xB7 used by ${p2.usedBy.length} projects` : p2.usedBy[0] && p2.usedBy[0] !== "." ? ` \xB7 ${p2.usedBy[0]}` : "";
56425
56620
  const where = p2.urls[0] ? ` \xB7 ${p2.urls[0]}` : "";
56426
56621
  const ev3 = conf === "probe" || conf === "unknown" ? ` \xB7 ${p2.evidence[0]}` : "";
56427
56622
  lines.push(`- ${p2.name} \u2190 ${p2.provider}${used}${where}${ev3}${reg(p2.registered)}`);
56428
56623
  }
56429
- if (list2.length > max) lines.push(` \u2026 ${list2.length - max} more`);
56624
+ if (list3.length > max) lines.push(` \u2026 ${list3.length - max} more`);
56430
56625
  }
56431
56626
  const rec = d.local.filter((c) => !c.registered).length + d.providers.filter(
56432
56627
  (p2) => !p2.registered && (p2.confidence === "probe" || p2.confidence === "catalog" && (p2.tier ?? "library") === "service")
@@ -58546,7 +58741,7 @@ var init_em_memory = __esm({
58546
58741
  return text(`${args.name} is now ${args.status}`);
58547
58742
  }
58548
58743
  case "list": {
58549
- const rows = list(ctx, db, {
58744
+ const rows = list2(ctx, db, {
58550
58745
  topic: args.topic,
58551
58746
  kind: args.kind,
58552
58747
  status: args.status,
@@ -58644,7 +58839,7 @@ var init_em_recall = __esm({
58644
58839
  const limit = args.limit ?? 8;
58645
58840
  const lines = [];
58646
58841
  if (!args.query) {
58647
- 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 });
58648
58843
  if (!rows.length)
58649
58844
  return text(
58650
58845
  "no memories yet; use em_remember to record decisions and constraints (or /eminiar:em-onboard to write the onboarding set)"
@@ -60446,7 +60641,7 @@ async function searchPayload(ctx, q, mode, limit, source) {
60446
60641
  function memoriesPayload(ctx, opts = {}) {
60447
60642
  const db = getStorage(ctx);
60448
60643
  const summary = reconcile2(ctx, db);
60449
- const rows = list(ctx, db, {
60644
+ const rows = list2(ctx, db, {
60450
60645
  kind: opts.kind,
60451
60646
  topic: opts.topic,
60452
60647
  status: opts.status,
@@ -61247,9 +61442,9 @@ function clustersPayload(ctx) {
61247
61442
  for (const m of db.metricsTop({ kind: "file", limit: 5e3 })) {
61248
61443
  if (m.cluster === null || !m.path) continue;
61249
61444
  const key = String(m.cluster);
61250
- const list2 = members2[key] ?? [];
61251
- list2.push({ path: m.path, score: m.score, fanIn: m.fan_in });
61252
- 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;
61253
61448
  }
61254
61449
  return { clusters: readClusters(db), cycles: readCycles(db), members: members2 };
61255
61450
  }
@@ -61618,11 +61813,11 @@ function historyGraphPayload(ctx, limit) {
61618
61813
  function historyRiskPayload(ctx, paths2) {
61619
61814
  const m = model(ctx);
61620
61815
  if (!m) return NO_GIT;
61621
- const list2 = paths2?.length ? paths2 : workingTreeFiles(ctx.root);
61816
+ const list3 = paths2?.length ? paths2 : workingTreeFiles(ctx.root);
61622
61817
  return {
61623
61818
  git: true,
61624
61819
  source: paths2?.length ? "paths" : "working tree",
61625
- files: list2.map((p2) => {
61820
+ files: list3.map((p2) => {
61626
61821
  const clean3 = p2.replace(/^\.\//, "");
61627
61822
  const h = m.files.get(clean3);
61628
61823
  const commits = commitsForFile(m, clean3);
@@ -62424,7 +62619,16 @@ function readSwarmDoc(root) {
62424
62619
  const { file: file3, rel, exists } = swarmFile(root);
62425
62620
  const base = { file: file3, rel };
62426
62621
  if (!exists)
62427
- 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
+ };
62428
62632
  let bytes;
62429
62633
  try {
62430
62634
  bytes = readFileSync30(file3);
@@ -62436,6 +62640,7 @@ function readSwarmDoc(root) {
62436
62640
  hash: null,
62437
62641
  doc: null,
62438
62642
  issues: [{ path: "", message: `cannot read ${rel}: ${err.message}` }],
62643
+ ignoredKeys: [],
62439
62644
  locked: []
62440
62645
  };
62441
62646
  }
@@ -62443,9 +62648,10 @@ function readSwarmDoc(root) {
62443
62648
  const hash2 = createHash13("sha256").update(bytes).digest("hex");
62444
62649
  const result = parseSwarmYaml(text3, file3, rel);
62445
62650
  const issues = result.state === "invalid" ? result.issues : [];
62651
+ const ignoredKeys = result.state === "ok" ? result.config.ignoredKeys : [];
62446
62652
  const state = result.state === "ok" ? "ok" : "invalid";
62447
62653
  if (text3.length > SWARM_FILE_MAX_CHARS)
62448
- return { ...base, state, text: text3, hash: hash2, doc: null, issues, locked: [] };
62654
+ return { ...base, state, text: text3, hash: hash2, doc: null, issues, ignoredKeys, locked: [] };
62449
62655
  const Y = yaml3();
62450
62656
  const parsed = Y.parseDocument(text3, { uniqueKeys: true, merge: true });
62451
62657
  let doc = null;
@@ -62460,7 +62666,7 @@ function readSwarmDoc(root) {
62460
62666
  } catch {
62461
62667
  }
62462
62668
  }
62463
- return { ...base, state, text: text3, hash: hash2, doc, issues, locked };
62669
+ return { ...base, state, text: text3, hash: hash2, doc, issues, ignoredKeys, locked };
62464
62670
  }
62465
62671
  function checkSwarmText(text3, opts = {}) {
62466
62672
  const rel = opts.rel ?? SWARM_FILES[0];
@@ -62843,6 +63049,9 @@ function applyDiff(ctx, path3, oldV, newV) {
62843
63049
  inherit(old, node2);
62844
63050
  setAt(ctx, path3, node2);
62845
63051
  }
63052
+ function ignoredKeyWarnings(ignoredKeys) {
63053
+ return ignoredKeys.map((i) => ({ path: i.path, kind: "ignored-key", message: i.message }));
63054
+ }
62846
63055
  function docWarnings(doc, activeRuns = [], prev) {
62847
63056
  const out = [];
62848
63057
  const swarms = isPlain(doc.swarms) ? doc.swarms : {};
@@ -63041,10 +63250,10 @@ import {
63041
63250
  statSync as statSync19,
63042
63251
  writeSync
63043
63252
  } from "fs";
63044
- import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute7, relative as relative17, resolve as resolve16, sep as sep6 } from "path";
63253
+ import { basename as basename9, dirname as dirname16, isAbsolute as isAbsolute8, relative as relative17, resolve as resolve16, sep as sep6 } from "path";
63045
63254
  function within2(child, parent) {
63046
63255
  const rel = relative17(parent, child);
63047
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep6}`) && !isAbsolute7(rel);
63256
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep6}`) && !isAbsolute8(rel);
63048
63257
  }
63049
63258
  function locationProblem2(file3, root) {
63050
63259
  if (file3 === root || !within2(file3, root)) return "it is outside the project";
@@ -63119,7 +63328,7 @@ function saveSwarmFile(root, text3, baseHash) {
63119
63328
  const mode = current ? statSync19(file3).mode & 511 : 420;
63120
63329
  const tmp = resolve16(
63121
63330
  dirname16(file3),
63122
- `.${basename8(file3)}.${process.pid}.${randomBytes4(4).toString("hex")}.tmp`
63331
+ `.${basename9(file3)}.${process.pid}.${randomBytes4(4).toString("hex")}.tmp`
63123
63332
  );
63124
63333
  try {
63125
63334
  const fd = openSync3(tmp, "wx", mode);
@@ -63578,9 +63787,9 @@ function runDetail(ctx, run3, opts = {}) {
63578
63787
  const byAgent2 = /* @__PURE__ */ new Map();
63579
63788
  for (const e of all) {
63580
63789
  if (!e.agent_id) continue;
63581
- const list2 = byAgent2.get(e.agent_id) ?? [];
63582
- list2.push(e);
63583
- 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);
63584
63793
  }
63585
63794
  const loaded = loadSwarmConfig(ctx.root);
63586
63795
  const spec = loaded.state === "ok" ? loaded.config.swarms.find((s) => s.name === run3.swarm) : void 0;
@@ -63726,7 +63935,10 @@ function swarmConfigDoc(ctx) {
63726
63935
  hash: read2.hash,
63727
63936
  doc: read2.doc,
63728
63937
  issues: read2.issues,
63729
- 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
+ ],
63730
63942
  locked: read2.locked,
63731
63943
  starter: read2.state === "absent" ? starterDoc() : void 0,
63732
63944
  activeRuns,
@@ -63776,6 +63988,7 @@ async function prepareConfig(ctx, body) {
63776
63988
  const meta4 = { file: read2.file, rel: read2.rel };
63777
63989
  let text3;
63778
63990
  let issues = [];
63991
+ let ignoredKeys = [];
63779
63992
  let draft = null;
63780
63993
  if (b.doc !== void 0) {
63781
63994
  draft = b.doc;
@@ -63783,10 +63996,12 @@ async function prepareConfig(ctx, body) {
63783
63996
  if (!r.ok) return { reply: fail2(422, r.error, { locked: r.locked ?? read2.locked }) };
63784
63997
  text3 = r.text;
63785
63998
  if (r.result.state === "invalid") issues = r.result.issues;
63999
+ else if (r.result.state === "ok") ignoredKeys = r.result.config.ignoredKeys;
63786
64000
  } else {
63787
64001
  text3 = b.text;
63788
64002
  const { result, enforceOk } = checkSwarmText(text3, meta4);
63789
64003
  if (result.state === "invalid") issues = result.issues;
64004
+ else if (result.state === "ok") ignoredKeys = result.config.ignoredKeys;
63790
64005
  if (!enforceOk)
63791
64006
  issues = [
63792
64007
  ...issues,
@@ -63803,7 +64018,10 @@ async function prepareConfig(ctx, body) {
63803
64018
  }
63804
64019
  }
63805
64020
  const diff2 = lineDiff(read2.text ?? "", text3);
63806
- 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
+ ];
63807
64025
  return {
63808
64026
  parsed: b,
63809
64027
  p: {
@@ -64125,9 +64343,9 @@ function listedProjects() {
64125
64343
  const now = Date.now();
64126
64344
  if (projectList && projectList.mtime === mtime && now - projectList.at < PROJECT_LIST_TTL_MS)
64127
64345
  return projectList.list;
64128
- const list2 = listProjects();
64129
- projectList = { at: now, mtime, list: list2 };
64130
- return list2;
64346
+ const list3 = listProjects();
64347
+ projectList = { at: now, mtime, list: list3 };
64348
+ return list3;
64131
64349
  }
64132
64350
  function resetProjectListCache() {
64133
64351
  projectList = void 0;
@@ -64647,7 +64865,7 @@ var init_identity = __esm({
64647
64865
  // src/swarm/hooks.ts
64648
64866
  import { execFileSync } from "child_process";
64649
64867
  import { readFileSync as readFileSync35, realpathSync as realpathSync13, statSync as statSync21 } from "fs";
64650
- import { basename as basename9, dirname as dirname17, join as join42, resolve as resolve18 } from "path";
64868
+ import { basename as basename10, dirname as dirname17, join as join42, resolve as resolve18 } from "path";
64651
64869
  function coordinationRoot(root) {
64652
64870
  try {
64653
64871
  const dotGit = join42(root, ".git");
@@ -64661,7 +64879,7 @@ function coordinationRoot(root) {
64661
64879
  } catch {
64662
64880
  return root;
64663
64881
  }
64664
- if (basename9(common) === ".git") return realpathSync13(dirname17(common));
64882
+ if (basename10(common) === ".git") return realpathSync13(dirname17(common));
64665
64883
  const out = execFileSync("git", ["worktree", "list", "--porcelain"], {
64666
64884
  cwd: root,
64667
64885
  encoding: "utf8",
@@ -64806,7 +65024,8 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64806
65024
  enabled: loaded.config.enabled,
64807
65025
  enforce: loaded.config.enforce,
64808
65026
  allowed_agents: loaded.config.allowedAgents,
64809
- swarms: loaded.config.swarms.map((s) => s.name)
65027
+ swarms: loaded.config.swarms.map((s) => s.name),
65028
+ ignored_keys: loaded.config.ignoredKeys
64810
65029
  } : loaded.state === "invalid" ? {
64811
65030
  state: "invalid",
64812
65031
  file: loaded.rel,
@@ -64828,6 +65047,7 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64828
65047
  io.out(
64829
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)}`
64830
65049
  );
65050
+ if (c.ignoredKeys.length) io.err(formatIssues(c.rel, c.ignoredKeys));
64831
65051
  return 0;
64832
65052
  }
64833
65053
  case "sync": {
@@ -64910,9 +65130,9 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
64910
65130
  return 2;
64911
65131
  }
64912
65132
  const db = await storage2(ctx);
64913
- const list2 = items(db, db.swarm.runs({ limit: Math.min(limit, 500) }));
64914
- if (json3) emit(list2);
64915
- 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));
64916
65136
  return 0;
64917
65137
  }
64918
65138
  case "status": {
@@ -65149,7 +65369,9 @@ function renderStatusline(raw) {
65149
65369
  }
65150
65370
  let line;
65151
65371
  try {
65152
- const ctx = getContext(input2.cwd ?? input2.workspace?.current_dir);
65372
+ const ctx = getContext(
65373
+ input2.workspace?.project_dir ?? input2.cwd ?? input2.workspace?.current_dir
65374
+ );
65153
65375
  const db = getStorage(ctx, { vectors: false });
65154
65376
  const session = summarize(db.statsBySession(input2.session_id ?? ""));
65155
65377
  const life = summarize(globalDb().lifetime());