eminiar 0.13.0 → 0.13.2

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.
@@ -4,12 +4,12 @@ import {
4
4
  parseJob,
5
5
  runAsyncJob,
6
6
  spawnAsyncJob
7
- } from "./hook-chunk-77I6QQ43.js";
8
- import "./hook-chunk-IYHVLMJ4.js";
7
+ } from "./hook-chunk-MVSMFCKL.js";
8
+ import "./hook-chunk-ETYHCPPH.js";
9
9
  export {
10
10
  ASYNC_JOB_MAX_MS,
11
11
  parseJob,
12
12
  runAsyncJob,
13
13
  spawnAsyncJob
14
14
  };
15
- //# sourceMappingURL=hook-async-4MIP3VHX.js.map
15
+ //# sourceMappingURL=hook-async-3TLK23ZY.js.map
@@ -19929,6 +19929,12 @@ import { join } from "path";
19929
19929
  function eminiarHome() {
19930
19930
  return process.env.EMINIAR_HOME || join(homedir(), ".eminiar");
19931
19931
  }
19932
+ function claudeConfigDir(env = process.env, home = homedir()) {
19933
+ return env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
19934
+ }
19935
+ function claudePluginsDir(env = process.env, home = homedir()) {
19936
+ return env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim() || join(claudeConfigDir(env, home), "plugins");
19937
+ }
19932
19938
  function paths() {
19933
19939
  const home = eminiarHome();
19934
19940
  return {
@@ -20032,9 +20038,9 @@ var buildAdjudicatorObject = () => external_exports.object({
20032
20038
  }).prefault({}),
20033
20039
  minPromptChars: external_exports.number().int().min(0).default(12),
20034
20040
  /**
20035
- * Ordered ladder, smallest first; "fable" may be inserted by the user. Every provider request
20036
- * carries the whole ladder and a committed project file may set it, so it is bounded: each
20037
- * tier at most once (task #56).
20041
+ * Ordered ladder, smallest first; "fable" may be inserted by the user. Personal config only
20042
+ * (a committed project file cannot set it). Every provider request carries the whole ladder,
20043
+ * so it is bounded: each tier at most once (task #56).
20038
20044
  */
20039
20045
  tiers: external_exports.array(external_exports.enum(TIERS)).min(1).max(TIERS.length).refine((t) => new Set(t).size === t.length, "adjudicator.tiers must not repeat a tier").meta({ uniqueItems: true }).default(["haiku", "sonnet", "opus"]),
20040
20046
  weights: external_exports.object({
@@ -20211,8 +20217,11 @@ var BaseConfigSchema = external_exports.object({
20211
20217
  backend: external_exports.enum(["tree-sitter"]).default("tree-sitter")
20212
20218
  }).prefault({}),
20213
20219
  memories: external_exports.object({
20214
- /** Project-relative directory of markdown memory files (`<topic>/<name>.md`); commit it. */
20215
- dir: external_exports.string().default(".eminiar/memories")
20220
+ /**
20221
+ * Project-relative directory of markdown memory files (`<topic>/<name>.md`); commit it.
20222
+ * Absolute paths and `..` segments are refused: reconcile repairs the headers of files there.
20223
+ */
20224
+ dir: external_exports.string().regex(PROJECT_RELATIVE_PATH_RE, "must be a path inside the project (no leading / or ..)").default(".eminiar/memories")
20216
20225
  }).prefault({}),
20217
20226
  recall: external_exports.object({
20218
20227
  /** Inject the memories and doc pages that match each prompt (UserPromptSubmit). */
@@ -20384,22 +20393,22 @@ function envOverrides() {
20384
20393
  }
20385
20394
  var PROJECT_ADJUDICATOR_KEYS = [
20386
20395
  "enabled",
20387
- "mode",
20388
20396
  "surfaces",
20389
20397
  "promptMode",
20390
20398
  "minPromptChars",
20391
- "tiers",
20392
20399
  "weights",
20393
- "apply",
20394
20400
  "advice",
20395
20401
  "embedding",
20396
20402
  "learning",
20397
20403
  "cache"
20398
20404
  ];
20405
+ function projectKeeps(adj, k) {
20406
+ return PROJECT_ADJUDICATOR_KEYS.includes(k) || k === "mode" && adj.mode === "advise";
20407
+ }
20399
20408
  function droppedProjectAdjudicatorKeys(raw) {
20400
20409
  const adj = raw.adjudicator;
20401
20410
  if (!isPlainObject2(adj)) return [];
20402
- return Object.keys(adj).filter((k) => !PROJECT_ADJUDICATOR_KEYS.includes(k)).sort();
20411
+ return Object.keys(adj).filter((k) => !projectKeeps(adj, k)).sort();
20403
20412
  }
20404
20413
  var CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
20405
20414
  function realPath(p) {
@@ -20516,32 +20525,40 @@ function projectLayer(raw) {
20516
20525
  if (!isPlainObject2(adj)) return raw;
20517
20526
  if (findSecretFields(adj).length) return raw;
20518
20527
  const kept = {};
20519
- for (const k of PROJECT_ADJUDICATOR_KEYS) if (Object.hasOwn(adj, k)) kept[k] = adj[k];
20528
+ for (const k of Object.keys(adj)) if (projectKeeps(adj, k)) kept[k] = adj[k];
20520
20529
  return { ...ownJson(raw), adjudicator: kept };
20521
20530
  }
20522
- function withoutUnsafeDocsManifest(raw, source) {
20523
- const docs = raw.docs;
20524
- if (!isPlainObject2(docs) || !Object.hasOwn(docs, "manifest")) return raw;
20525
- const m = docs.manifest;
20526
- if (typeof m === "string" && PROJECT_RELATIVE_PATH_RE.test(m)) return raw;
20527
- process.stderr.write(
20528
- `eminiar: ignoring docs.manifest ${JSON.stringify(m)} in ${source}: it must be a path inside the project
20531
+ var PROJECT_PATH_KEYS = [
20532
+ ["docs", "manifest"],
20533
+ ["memories", "dir"]
20534
+ ];
20535
+ function withoutUnsafePaths(raw, source) {
20536
+ let out = raw;
20537
+ for (const [section, key] of PROJECT_PATH_KEYS) {
20538
+ const sec = out[section];
20539
+ if (!isPlainObject2(sec) || !Object.hasOwn(sec, key)) continue;
20540
+ const v = sec[key];
20541
+ if (typeof v === "string" && PROJECT_RELATIVE_PATH_RE.test(v)) continue;
20542
+ process.stderr.write(
20543
+ `eminiar: ignoring ${section}.${key} ${JSON.stringify(v)} in ${source}: it must be a path inside the project
20529
20544
  `
20530
- );
20531
- const { manifest: _dropped, ...rest } = ownJson(docs);
20532
- return { ...ownJson(raw), docs: rest };
20545
+ );
20546
+ const { [key]: _dropped, ...rest } = ownJson(sec);
20547
+ out = { ...ownJson(out), [section]: rest };
20548
+ }
20549
+ return out;
20533
20550
  }
20534
20551
  function personalLayer(projectRoot) {
20535
20552
  const file2 = paths().configFile;
20536
20553
  const raw = readJson(file2);
20537
20554
  const layer = !droppedProjectAdjudicatorKeys(raw).length || personalConfigTrusted(projectRoot, file2) ? raw : projectLayer(raw);
20538
- return withoutUnsafeDocsManifest(layer, file2);
20555
+ return withoutUnsafePaths(layer, file2);
20539
20556
  }
20540
20557
  function loadConfig(projectRoot) {
20541
20558
  const merged = deepMerge(
20542
20559
  deepMerge(
20543
20560
  personalLayer(projectRoot),
20544
- withoutUnsafeDocsManifest(
20561
+ withoutUnsafePaths(
20545
20562
  projectLayer(readJson(join2(projectRoot, "eminiar.config.json"))),
20546
20563
  "eminiar.config.json"
20547
20564
  )
@@ -22603,7 +22620,7 @@ function usageWhere(f, opts = {}) {
22603
22620
  var SqliteAdapter = class _SqliteAdapter {
22604
22621
  constructor(path2, opts = {}) {
22605
22622
  this.path = path2;
22606
- this.db = new Database(path2, { timeout: 2e3 });
22623
+ this.db = new Database(path2, { timeout: opts.busyTimeoutMs ?? 2e3 });
22607
22624
  this.swarm = new SqliteSwarmStore(this.db);
22608
22625
  this.adjudicator = new SqliteAdjudicatorStore(this.db);
22609
22626
  this.db.pragma("journal_mode = WAL");
@@ -23817,13 +23834,18 @@ var SqliteAdapter = class _SqliteAdapter {
23817
23834
 
23818
23835
  // src/storage/index.ts
23819
23836
  var open2 = /* @__PURE__ */ new Map();
23837
+ var busyTimeoutMs;
23838
+ function setStorageBusyTimeout(ms) {
23839
+ busyTimeoutMs = ms;
23840
+ }
23820
23841
  function getStorage(ctx, opts = {}) {
23821
23842
  const key = `${ctx.dbPath}|${opts.vectors === false ? "novec" : "vec"}`;
23822
23843
  let adapter = open2.get(key);
23823
23844
  if (!adapter) {
23824
23845
  adapter = new SqliteAdapter(ctx.dbPath, {
23825
23846
  dims: ctx.config.embeddings.dims,
23826
- vectors: opts.vectors ?? true
23847
+ vectors: opts.vectors ?? true,
23848
+ ...busyTimeoutMs === void 0 ? {} : { busyTimeoutMs }
23827
23849
  });
23828
23850
  open2.set(key, adapter);
23829
23851
  }
@@ -24077,16 +24099,21 @@ export {
24077
24099
  AGENT_EFFORT_SINCE,
24078
24100
  TOOL_IDS,
24079
24101
  DEFAULT_ROLES,
24102
+ claudeConfigDir,
24103
+ claudePluginsDir,
24080
24104
  paths,
24081
24105
  ensureDirs,
24082
24106
  projectDir,
24107
+ PROJECT_RELATIVE_PATH_RE,
24083
24108
  AdjudicatorConfigSchema,
24084
24109
  loadConfig,
24085
24110
  findProjectRoot,
24111
+ resolveProjectRoot,
24086
24112
  getContext,
24087
24113
  tierOf,
24088
24114
  KEPT_MODEL_FLAG,
24089
24115
  keptModel,
24116
+ setStorageBusyTimeout,
24090
24117
  getStorage,
24091
24118
  GUIDE_ORDER,
24092
24119
  ev,
@@ -24096,4 +24123,4 @@ export {
24096
24123
  classifyToolCall,
24097
24124
  classifyAssistant
24098
24125
  };
24099
- //# sourceMappingURL=hook-chunk-IYHVLMJ4.js.map
24126
+ //# sourceMappingURL=hook-chunk-ETYHCPPH.js.map
@@ -13,7 +13,7 @@ import {
13
13
  init_esm_shims,
14
14
  loadConfig,
15
15
  paths
16
- } from "./hook-chunk-IYHVLMJ4.js";
16
+ } from "./hook-chunk-ETYHCPPH.js";
17
17
 
18
18
  // src/adjudicator/async.ts
19
19
  init_esm_shims();
@@ -3777,4 +3777,4 @@ export {
3777
3777
  parseJob,
3778
3778
  runAsyncJob
3779
3779
  };
3780
- //# sourceMappingURL=hook-chunk-77I6QQ43.js.map
3780
+ //# sourceMappingURL=hook-chunk-MVSMFCKL.js.map
@@ -1,5 +1,6 @@
1
1
  import { createRequire as __emCreateRequire } from "node:module"; const require = __emCreateRequire(import.meta.url);
2
2
  import {
3
+ PROJECT_RELATIVE_PATH_RE,
3
4
  TIERS,
4
5
  __commonJS,
5
6
  __require,
@@ -11,8 +12,9 @@ import {
11
12
  getStorage,
12
13
  init_esm_shims,
13
14
  paths,
15
+ resolveProjectRoot,
14
16
  tierOf
15
- } from "./hook-chunk-IYHVLMJ4.js";
17
+ } from "./hook-chunk-ETYHCPPH.js";
16
18
 
17
19
  // node_modules/fast-glob/out/utils/array.js
18
20
  var require_array = __commonJS({
@@ -5883,9 +5885,10 @@ function empty() {
5883
5885
  return { version: 1, sources: [] };
5884
5886
  }
5885
5887
  function normalize(raw) {
5886
- if (!raw || typeof raw !== "object") return { manifest: empty(), dropped: 0 };
5888
+ if (!raw || typeof raw !== "object") return { manifest: empty(), dropped: 0, outside: [] };
5887
5889
  const sources = Array.isArray(raw.sources) ? raw.sources : [];
5888
5890
  const out = [];
5891
+ const outside = [];
5889
5892
  const seen = /* @__PURE__ */ new Set();
5890
5893
  for (const s of sources) {
5891
5894
  if (!s || typeof s !== "object" || typeof s.name !== "string") continue;
@@ -5893,22 +5896,37 @@ function normalize(raw) {
5893
5896
  if (s.kind !== "url" && s.kind !== "path") continue;
5894
5897
  if (s.kind === "url" && !(Array.isArray(s.urls) && s.urls.length)) continue;
5895
5898
  if (s.kind === "path" && typeof s.path !== "string") continue;
5899
+ if (s.kind === "path" && !PROJECT_RELATIVE_PATH_RE.test(s.path)) {
5900
+ process.stderr.write(
5901
+ `eminiar: ignoring docs source ${JSON.stringify(s.name)}: its path ${JSON.stringify(s.path)} must be inside the project
5902
+ `
5903
+ );
5904
+ outside.push(s.name);
5905
+ continue;
5906
+ }
5896
5907
  seen.add(s.name);
5897
5908
  out.push({
5898
5909
  ...s,
5899
5910
  addedAt: typeof s.addedAt === "string" ? s.addedAt : (/* @__PURE__ */ new Date(0)).toISOString()
5900
5911
  });
5901
5912
  }
5902
- return { manifest: { version: 1, sources: out }, dropped: sources.length - out.length };
5913
+ return {
5914
+ manifest: { version: 1, sources: out },
5915
+ dropped: sources.length - out.length,
5916
+ outside
5917
+ };
5903
5918
  }
5904
- function lossyReason(raw, dropped) {
5919
+ function lossyReason(raw, dropped, outside, removing) {
5905
5920
  if (raw.version !== 1)
5906
5921
  return raw.version === void 0 ? "it has no version (this eminiar writes version 1)" : `it has version ${JSON.stringify(raw.version)}, and this eminiar only writes version 1`;
5907
5922
  const extra = Object.keys(raw).filter((k) => k !== "version" && k !== "sources");
5908
5923
  if (extra.length) return `it has keys this eminiar does not know (${extra.sort().join(", ")})`;
5909
5924
  if (Object.hasOwn(raw, "sources") && !Array.isArray(raw.sources))
5910
5925
  return "its sources is not an array";
5911
- if (dropped) return `${dropped} of its sources ${dropped === 1 ? "is" : "are"} not valid entries`;
5926
+ const rest = outside.filter((n) => n !== removing);
5927
+ const lost = dropped - (outside.length - rest.length);
5928
+ if (lost)
5929
+ return `${lost} of its sources ${lost === 1 ? "is" : "are"} not valid entries${rest.length ? ` (${rest.join(", ")}: path outside the project)` : ""}`;
5912
5930
  return void 0;
5913
5931
  }
5914
5932
  var MANIFEST_MAX_BYTES = 1024 * 1024;
@@ -5985,12 +6003,12 @@ function probeManifestAt(file, opts = {}) {
5985
6003
  }
5986
6004
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
5987
6005
  return { state: "refused", reason: "it is not a JSON object" };
5988
- const { manifest, dropped } = normalize(raw);
6006
+ const { manifest, dropped, outside } = normalize(raw);
5989
6007
  if (opts.write) {
5990
- const lossy = lossyReason(raw, dropped);
6008
+ const lossy = lossyReason(raw, dropped, outside, opts.removing);
5991
6009
  if (lossy) return { state: "refused", reason: lossy };
5992
6010
  }
5993
- return { state: "ok", manifest };
6011
+ return { state: "ok", manifest, ...outside.length ? { outside } : {} };
5994
6012
  } catch (err) {
5995
6013
  const code = err.code;
5996
6014
  if (code === "ENOENT") return { state: "missing" };
@@ -6018,7 +6036,7 @@ function readManifest(ctx) {
6018
6036
  // src/swarm/hooks.ts
6019
6037
  init_esm_shims();
6020
6038
  import { execFileSync } from "child_process";
6021
- import { readFileSync as readFileSync7, realpathSync as realpathSync3, statSync as statSync5 } from "fs";
6039
+ import { readFileSync as readFileSync7, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
6022
6040
  import { basename as basename2, dirname as dirname3, join as join8, resolve as resolve3 } from "path";
6023
6041
 
6024
6042
  // src/swarm/agents.ts
@@ -6065,6 +6083,14 @@ function yaml() {
6065
6083
  yamlLib ??= createRequire(import.meta.url)("yaml");
6066
6084
  return yamlLib;
6067
6085
  }
6086
+ var EXEC_TOOLS = /* @__PURE__ */ new Set([
6087
+ "em_execute",
6088
+ "em_execute_file",
6089
+ "em_batch_execute"
6090
+ ]);
6091
+ function roleHasShell(role) {
6092
+ return (role.tools?.includes("Bash") ?? true) && !role.disallowedTools?.includes("Bash");
6093
+ }
6068
6094
  var EM_MCP_PREFIXES = ["mcp__plugin_eminiar_eminiar__", "mcp__eminiar__"];
6069
6095
  var AGENTS_REL = ".claude/agents";
6070
6096
  function agentsDir(root) {
@@ -6078,21 +6104,26 @@ var TOPOLOGY_RULE = {
6078
6104
  mesh: "peers share one task board. Claim any open task (your role's first), and read the blackboard for what the other workers found.",
6079
6105
  pipeline: "work moves in stages. You can claim a task only once every task of the earlier stages is done."
6080
6106
  };
6081
- function workerTools(tools) {
6107
+ function workerTools(tools, shell = tools.includes("Bash")) {
6082
6108
  const out = tools.includes("ToolSearch") ? [...tools] : [...tools, "ToolSearch"];
6083
6109
  for (const prefix of EM_MCP_PREFIXES)
6084
- for (const t of WORKER_EM_TOOLS) if (!out.includes(prefix + t)) out.push(prefix + t);
6110
+ for (const t of WORKER_EM_TOOLS)
6111
+ if ((shell || !EXEC_TOOLS.has(t)) && !out.includes(prefix + t)) out.push(prefix + t);
6085
6112
  return out;
6086
6113
  }
6114
+ var execToolNames = () => EM_MCP_PREFIXES.flatMap((prefix) => [...EXEC_TOOLS].map((t) => prefix + t));
6087
6115
  function frontmatter(swarm, role) {
6088
6116
  const fm = {
6089
6117
  name: role.agentType,
6090
6118
  description: `Worker "${role.role}" of the eminiar swarm "${swarm.name}": ${role.description} Spawn it for a task of this swarm and name the task as "task #N" in the prompt; the em-swarm skill coordinates runs.`
6091
6119
  };
6092
6120
  if (role.model) fm.model = role.model;
6093
- if (role.tools) fm.tools = workerTools(role.tools).join(", ");
6121
+ if (role.tools) fm.tools = workerTools(role.tools, roleHasShell(role)).join(", ");
6094
6122
  const spawns = role.tools?.some((t) => t === "Agent" || t === "Task");
6095
- const disallowed = [.../* @__PURE__ */ new Set([...role.disallowedTools ?? [], ...spawns ? [] : ["Agent"]])];
6123
+ const noShell = role.disallowedTools?.includes("Bash") ? execToolNames() : [];
6124
+ const disallowed = [
6125
+ .../* @__PURE__ */ new Set([...role.disallowedTools ?? [], ...spawns ? [] : ["Agent"], ...noShell])
6126
+ ];
6096
6127
  if (disallowed.length) fm.disallowedTools = disallowed.join(", ");
6097
6128
  if (role.skills.length) fm.skills = role.skills;
6098
6129
  if (role.hooks) {
@@ -6111,6 +6142,7 @@ var hashOf = (fm, rest, range) => createHash("sha1").update(range ? `range=${ran
6111
6142
  ${fm}
6112
6143
  ${rest}` : `${fm}
6113
6144
  ${rest}`).digest("hex").slice(0, 12);
6145
+ var 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.";
6114
6146
  function renderAgentFile(config, swarm, role) {
6115
6147
  const fm = yaml().stringify(frontmatter(swarm, role), { lineWidth: 0 }).trimEnd();
6116
6148
  if (fm.includes("---"))
@@ -6124,12 +6156,15 @@ function renderAgentFile(config, swarm, role) {
6124
6156
  ...role.prompt ? [role.prompt, ""] : [],
6125
6157
  "## Swarm protocol",
6126
6158
  "",
6127
- '1. eminiar starts you with a swarm brief: the run goal, the open tasks, the shared notes and what the project knows (memories, history, structure). First claim the task your prompt names with `em_swarm {action:"claim", task:N}` (or the next open one with `em_swarm {action:"claim"}`); if the brief says you already hold a task, continue it.',
6128
- '2. Ask eminiar before acting: `em_recall {query}` for decisions and constraints, `em_history {action:"file", path}` before editing a file, `em_graph_impact {node}` before changing a symbol, `em_symbols` / `em_search` instead of grepping.',
6129
- '3. Share what other workers need with `em_swarm {action:"post", key, value}` and read theirs with `em_swarm {action:"read"}`.',
6130
- '4. Close every task with `em_swarm {action:"update", task, status, result}`: status `done`, `failed` or `blocked`; the result says what changed and how you verified it.',
6131
- "5. Record durable decisions with `em_remember` so later sessions know them.",
6132
- "6. Your final message goes back to the coordinator: lead with the outcome, then the files you changed and anything left open.",
6159
+ ...[
6160
+ 'eminiar starts you with a swarm brief: the run goal, the open tasks, the shared notes and what the project knows (memories, history, structure). First claim the task your prompt names with `em_swarm {action:"claim", task:N}` (or the next open one with `em_swarm {action:"claim"}`); if the brief says you already hold a task, continue it.',
6161
+ 'Ask eminiar before acting: `em_recall {query}` for decisions and constraints, `em_history {action:"file", path}` before editing a file, `em_graph_impact {node}` before changing a symbol, `em_symbols` / `em_search` instead of grepping.',
6162
+ ...!role.isolation && roleHasShell(role) ? [SHARED_TREE_RULE] : [],
6163
+ 'Share what other workers need with `em_swarm {action:"post", key, value}` and read theirs with `em_swarm {action:"read"}`.',
6164
+ 'Close every task with `em_swarm {action:"update", task, status, result}`: status `done`, `failed` or `blocked`; the result says what changed and how you verified it.',
6165
+ "Record durable decisions with `em_remember` so later sessions know them.",
6166
+ "Your final message goes back to the coordinator: lead with the outcome, then the files you changed and anything left open."
6167
+ ].map((step, i) => `${i + 1}. ${step}`),
6133
6168
  ""
6134
6169
  ].join("\n");
6135
6170
  const range = role.range ? modelRangeText(role.range) : void 0;
@@ -6336,7 +6371,7 @@ init_esm_shims();
6336
6371
  // src/index/indexer.ts
6337
6372
  init_esm_shims();
6338
6373
  var import_fast_glob = __toESM(require_out4(), 1);
6339
- import { readFileSync as readFileSync2, statSync as statSync2 } from "fs";
6374
+ import { existsSync, readFileSync as readFileSync2, realpathSync as realpathSync3, statSync as statSync2 } from "fs";
6340
6375
  import { relative as relative3, resolve } from "path";
6341
6376
 
6342
6377
  // src/chunker/index.ts
@@ -6717,7 +6752,7 @@ function readFileRisk(db) {
6717
6752
 
6718
6753
  // src/session/brief.ts
6719
6754
  init_esm_shims();
6720
- import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
6755
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
6721
6756
  import { join as join4 } from "path";
6722
6757
 
6723
6758
  // src/memory/frontmatter.ts
@@ -6752,9 +6787,12 @@ function parseMemoryFile(text) {
6752
6787
  init_esm_shims();
6753
6788
  var import_fast_glob2 = __toESM(require_out4(), 1);
6754
6789
  import {
6755
- existsSync,
6790
+ existsSync as existsSync2,
6791
+ lstatSync as lstatSync3,
6756
6792
  mkdirSync as mkdirSync3,
6793
+ readdirSync as readdirSync2,
6757
6794
  readFileSync as readFileSync3,
6795
+ realpathSync as realpathSync4,
6758
6796
  renameSync as renameSync3,
6759
6797
  statSync as statSync3,
6760
6798
  unlinkSync as unlinkSync2,
@@ -6830,7 +6868,7 @@ function historyLine(db) {
6830
6868
  }
6831
6869
  function overviewParagraph(ctx) {
6832
6870
  const file = join4(memoriesDir(ctx), "onboarding", "overview.md");
6833
- if (!existsSync2(file)) return void 0;
6871
+ if (!existsSync3(file)) return void 0;
6834
6872
  try {
6835
6873
  const body = parseMemoryFile(readFileSync4(file, "utf8")).body.trim();
6836
6874
  const para = body.split(/\n\s*\n/).map(
@@ -7704,13 +7742,13 @@ init_esm_shims();
7704
7742
  // src/swarm/runtime.ts
7705
7743
  init_esm_shims();
7706
7744
  import { randomBytes as randomBytes2 } from "crypto";
7707
- import { existsSync as existsSync4, statSync as statSync4 } from "fs";
7745
+ import { existsSync as existsSync5, statSync as statSync4 } from "fs";
7708
7746
  import { isAbsolute as isAbsolute2, join as join6, relative as relative5 } from "path";
7709
7747
 
7710
7748
  // src/swarm/config.ts
7711
7749
  init_esm_shims();
7712
7750
  import { createHash as createHash3 } from "crypto";
7713
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
7751
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
7714
7752
  import { createRequire as createRequire2 } from "module";
7715
7753
  import { join as join5 } from "path";
7716
7754
 
@@ -8088,7 +8126,7 @@ function roleRange(defaults, a, at, issue) {
8088
8126
  function swarmFile(root) {
8089
8127
  for (const rel of SWARM_FILES) {
8090
8128
  const file = join5(root, rel);
8091
- if (existsSync3(file)) return { file, rel, exists: true };
8129
+ if (existsSync4(file)) return { file, rel, exists: true };
8092
8130
  }
8093
8131
  return { file: join5(root, SWARM_FILES[0]), rel: SWARM_FILES[0], exists: false };
8094
8132
  }
@@ -9082,7 +9120,7 @@ function coordinationRoot(root) {
9082
9120
  } catch {
9083
9121
  return root;
9084
9122
  }
9085
- if (basename2(common) === ".git") return realpathSync3(dirname3(common));
9123
+ if (basename2(common) === ".git") return realpathSync5(dirname3(common));
9086
9124
  const out = execFileSync("git", ["worktree", "list", "--porcelain"], {
9087
9125
  cwd: root,
9088
9126
  encoding: "utf8",
@@ -9091,8 +9129,8 @@ function coordinationRoot(root) {
9091
9129
  });
9092
9130
  const first = /^worktree (.+)$/m.exec(out)?.[1];
9093
9131
  if (!first || /^bare$/m.test(out.split("\n\n")[0] ?? "")) return root;
9094
- const main = realpathSync3(first);
9095
- return main !== realpathSync3(common) && statSync5(join8(main, ".git"), { throwIfNoEntry: false }) ? main : root;
9132
+ const main = realpathSync5(first);
9133
+ return main !== realpathSync5(common) && statSync5(join8(main, ".git"), { throwIfNoEntry: false }) ? main : root;
9096
9134
  } catch {
9097
9135
  return root;
9098
9136
  }
@@ -9109,7 +9147,7 @@ function sessionRoot() {
9109
9147
  process.env.CLAUDE_PROJECT_DIR || process.env.EMINIAR_PROJECT_ROOT || process.cwd()
9110
9148
  );
9111
9149
  try {
9112
- return realpathSync3(root);
9150
+ return realpathSync5(root);
9113
9151
  } catch {
9114
9152
  return root;
9115
9153
  }
@@ -9123,6 +9161,18 @@ function orderedRoots(hookRoot) {
9123
9161
  if (hookRoot && !out.includes(hookRoot)) out.push(hookRoot);
9124
9162
  return out;
9125
9163
  }
9164
+ function swarmRoots(input) {
9165
+ let hook;
9166
+ try {
9167
+ hook = resolveProjectRoot(input.cwd || void 0);
9168
+ } catch {
9169
+ }
9170
+ const out = [];
9171
+ for (const r of orderedRoots(hook)) {
9172
+ for (const d of [r, coordinationRoot(r)]) if (!out.includes(d)) out.push(d);
9173
+ }
9174
+ return out;
9175
+ }
9126
9176
  function enforcementRoots() {
9127
9177
  try {
9128
9178
  const r = sessionRoot();
@@ -9383,6 +9433,19 @@ function swarmTouch(ctx, input) {
9383
9433
  fail("touch", err);
9384
9434
  }
9385
9435
  }
9436
+ function workerLacksTool(input, agentType, tool) {
9437
+ if (!EXEC_TOOLS.has(tool) || !isSwarmAgentType(agentType)) return false;
9438
+ try {
9439
+ for (const dir of swarmRoots(input)) {
9440
+ const config = activeSwarmConfig(dir);
9441
+ const found = config && findRole(config, agentType);
9442
+ if (found) return !roleHasShell(found.role);
9443
+ }
9444
+ } catch (err) {
9445
+ fail("shell", err);
9446
+ }
9447
+ return false;
9448
+ }
9386
9449
  function allowWith(updatedInput) {
9387
9450
  return {
9388
9451
  hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "allow", updatedInput }
@@ -9757,12 +9820,12 @@ var FALLBACK_MODEL = "claude-sonnet-5-5";
9757
9820
  export {
9758
9821
  hookLog,
9759
9822
  agentFileRange,
9760
- indexContent,
9761
- git,
9762
9823
  DOCS_PREFIX,
9763
9824
  manifestPath,
9764
9825
  readManifestAt,
9765
9826
  readManifest,
9827
+ indexContent,
9828
+ git,
9766
9829
  memoriesDir,
9767
9830
  renderProjectBrief,
9768
9831
  recordShown,
@@ -9773,12 +9836,14 @@ export {
9773
9836
  commitContext,
9774
9837
  recallForError,
9775
9838
  isSwarmTool,
9839
+ spawnType,
9776
9840
  coordinationRoot,
9777
9841
  swarmPreAgent,
9778
9842
  failedText,
9779
9843
  rawEnforced,
9780
9844
  swarmGate,
9781
9845
  swarmTouch,
9846
+ workerLacksTool,
9782
9847
  swarmStampCaller,
9783
9848
  swarmAgentReturned,
9784
9849
  swarmSessionEnd,
@@ -9840,4 +9905,4 @@ queue-microtask/index.js:
9840
9905
  run-parallel/index.js:
9841
9906
  (*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)
9842
9907
  */
9843
- //# sourceMappingURL=hook-chunk-MVOBVFQL.js.map
9908
+ //# sourceMappingURL=hook-chunk-ZLRLOPLR.js.map
@@ -8,7 +8,7 @@ import {
8
8
  manifestPath,
9
9
  readManifestAt,
10
10
  resolvePrice
11
- } from "./hook-chunk-MVOBVFQL.js";
11
+ } from "./hook-chunk-ZLRLOPLR.js";
12
12
  import {
13
13
  adjudicateOne,
14
14
  briefUnitsOf,
@@ -18,17 +18,19 @@ import {
18
18
  resolveAdjudicator,
19
19
  spawnAsyncJob,
20
20
  topIntent
21
- } from "./hook-chunk-77I6QQ43.js";
21
+ } from "./hook-chunk-MVSMFCKL.js";
22
22
  import {
23
23
  AGENT_EFFORT_SINCE,
24
24
  KEPT_MODEL_FLAG,
25
25
  TIERS,
26
+ claudeConfigDir,
27
+ claudePluginsDir,
26
28
  getContext,
27
29
  getStorage,
28
30
  init_esm_shims,
29
31
  keptModel,
30
32
  tierOf
31
- } from "./hook-chunk-IYHVLMJ4.js";
33
+ } from "./hook-chunk-ETYHCPPH.js";
32
34
 
33
35
  // src/adjudicator/hooks.ts
34
36
  init_esm_shims();
@@ -349,7 +351,7 @@ function projectDirs(root, cwd) {
349
351
  }
350
352
  function pluginDirs(plugin, env, home) {
351
353
  const out = /* @__PURE__ */ new Set();
352
- const pluginsRoot = env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim() || join(home, ".claude", "plugins");
354
+ const pluginsRoot = claudePluginsDir(env, home);
353
355
  try {
354
356
  const j = JSON.parse(readFileSync(join(pluginsRoot, "installed_plugins.json"), "utf8"));
355
357
  for (const [key, val] of Object.entries(j?.plugins ?? {})) {
@@ -450,7 +452,7 @@ function resolveAgentPin(agentType, q) {
450
452
  const scopes = [];
451
453
  if (managed) scopes.push(["managed", join(managed, ".claude", "agents")]);
452
454
  for (const d of projectDirs(q.root, q.cwd)) scopes.push(["project", d]);
453
- scopes.push(["user", join(home, ".claude", "agents")]);
455
+ scopes.push(["user", join(claudeConfigDir(env, home), "agents")]);
454
456
  let truncated = false;
455
457
  for (const [source, dir] of scopes) {
456
458
  const found = byName(dir, agentType);
@@ -1824,4 +1826,4 @@ export {
1824
1826
  withModel,
1825
1827
  withNote
1826
1828
  };
1827
- //# sourceMappingURL=hook-hooks-U6GDOQSY.js.map
1829
+ //# sourceMappingURL=hook-hooks-5U2AI6W7.js.map