eminiar 0.13.0 → 0.13.1

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/server.js CHANGED
@@ -10691,8 +10691,8 @@ var require_pattern2 = __commonJS({
10691
10691
  }
10692
10692
  exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
10693
10693
  function isAffectDepthOfReadingPattern(pattern2) {
10694
- const basename8 = path3.basename(pattern2);
10695
- return endsWithSlashGlobStar(pattern2) || isStaticPattern(basename8);
10694
+ const basename9 = path3.basename(pattern2);
10695
+ return endsWithSlashGlobStar(pattern2) || isStaticPattern(basename9);
10696
10696
  }
10697
10697
  exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
10698
10698
  function expandPatternsWithBraceExpansion(patterns) {
@@ -11176,11 +11176,11 @@ var require_out = __commonJS({
11176
11176
  async.read(path3, getSettings(optionsOrSettingsOrCallback), callback);
11177
11177
  }
11178
11178
  exports.stat = stat;
11179
- function statSync18(path3, optionsOrSettings) {
11179
+ function statSync19(path3, optionsOrSettings) {
11180
11180
  const settings = getSettings(optionsOrSettings);
11181
11181
  return sync.read(path3, settings);
11182
11182
  }
11183
- exports.statSync = statSync18;
11183
+ exports.statSync = statSync19;
11184
11184
  function getSettings(settingsOrOptions = {}) {
11185
11185
  if (settingsOrOptions instanceof settings_1.default) {
11186
11186
  return settingsOrOptions;
@@ -42768,6 +42768,12 @@ import { join } from "path";
42768
42768
  function eminiarHome() {
42769
42769
  return process.env.EMINIAR_HOME || join(homedir(), ".eminiar");
42770
42770
  }
42771
+ function claudeConfigDir(env = process.env, home = homedir()) {
42772
+ return env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
42773
+ }
42774
+ function claudePluginsDir(env = process.env, home = homedir()) {
42775
+ return env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim() || join(claudeConfigDir(env, home), "plugins");
42776
+ }
42771
42777
  function paths() {
42772
42778
  const home = eminiarHome();
42773
42779
  return {
@@ -42871,9 +42877,9 @@ var buildAdjudicatorObject = () => external_exports.object({
42871
42877
  }).prefault({}),
42872
42878
  minPromptChars: external_exports.number().int().min(0).default(12),
42873
42879
  /**
42874
- * Ordered ladder, smallest first; "fable" may be inserted by the user. Every provider request
42875
- * carries the whole ladder and a committed project file may set it, so it is bounded: each
42876
- * tier at most once (task #56).
42880
+ * Ordered ladder, smallest first; "fable" may be inserted by the user. Personal config only
42881
+ * (a committed project file cannot set it). Every provider request carries the whole ladder,
42882
+ * so it is bounded: each tier at most once (task #56).
42877
42883
  */
42878
42884
  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"]),
42879
42885
  weights: external_exports.object({
@@ -43223,22 +43229,22 @@ function envOverrides() {
43223
43229
  }
43224
43230
  var PROJECT_ADJUDICATOR_KEYS = [
43225
43231
  "enabled",
43226
- "mode",
43227
43232
  "surfaces",
43228
43233
  "promptMode",
43229
43234
  "minPromptChars",
43230
- "tiers",
43231
43235
  "weights",
43232
- "apply",
43233
43236
  "advice",
43234
43237
  "embedding",
43235
43238
  "learning",
43236
43239
  "cache"
43237
43240
  ];
43241
+ function projectKeeps(adj, k) {
43242
+ return PROJECT_ADJUDICATOR_KEYS.includes(k) || k === "mode" && adj.mode === "advise";
43243
+ }
43238
43244
  function droppedProjectAdjudicatorKeys(raw) {
43239
43245
  const adj = raw.adjudicator;
43240
43246
  if (!isPlainObject3(adj)) return [];
43241
- return Object.keys(adj).filter((k) => !PROJECT_ADJUDICATOR_KEYS.includes(k)).sort();
43247
+ return Object.keys(adj).filter((k) => !projectKeeps(adj, k)).sort();
43242
43248
  }
43243
43249
  function projectAdjudicatorWarning(projectRoot) {
43244
43250
  const lines = [];
@@ -43385,7 +43391,7 @@ function projectLayer(raw) {
43385
43391
  if (!isPlainObject3(adj)) return raw;
43386
43392
  if (findSecretFields(adj).length) return raw;
43387
43393
  const kept = {};
43388
- for (const k of PROJECT_ADJUDICATOR_KEYS) if (Object.hasOwn(adj, k)) kept[k] = adj[k];
43394
+ for (const k of Object.keys(adj)) if (projectKeeps(adj, k)) kept[k] = adj[k];
43389
43395
  return { ...ownJson(raw), adjudicator: kept };
43390
43396
  }
43391
43397
  function withoutUnsafeDocsManifest(raw, source) {
@@ -51595,7 +51601,7 @@ function usageWhere(f, opts = {}) {
51595
51601
  var SqliteAdapter = class _SqliteAdapter {
51596
51602
  constructor(path3, opts = {}) {
51597
51603
  this.path = path3;
51598
- this.db = new Database(path3, { timeout: 2e3 });
51604
+ this.db = new Database(path3, { timeout: opts.busyTimeoutMs ?? 2e3 });
51599
51605
  this.swarm = new SqliteSwarmStore(this.db);
51600
51606
  this.adjudicator = new SqliteAdjudicatorStore(this.db);
51601
51607
  this.db.pragma("journal_mode = WAL");
@@ -52809,13 +52815,15 @@ var SqliteAdapter = class _SqliteAdapter {
52809
52815
 
52810
52816
  // src/storage/index.ts
52811
52817
  var open2 = /* @__PURE__ */ new Map();
52818
+ var busyTimeoutMs;
52812
52819
  function getStorage(ctx, opts = {}) {
52813
52820
  const key = `${ctx.dbPath}|${opts.vectors === false ? "novec" : "vec"}`;
52814
52821
  let adapter = open2.get(key);
52815
52822
  if (!adapter) {
52816
52823
  adapter = new SqliteAdapter(ctx.dbPath, {
52817
52824
  dims: ctx.config.embeddings.dims,
52818
- vectors: opts.vectors ?? true
52825
+ vectors: opts.vectors ?? true,
52826
+ ...busyTimeoutMs === void 0 ? {} : { busyTimeoutMs }
52819
52827
  });
52820
52828
  open2.set(key, adapter);
52821
52829
  }
@@ -58186,6 +58194,14 @@ function yaml() {
58186
58194
  yamlLib ??= createRequire(import.meta.url)("yaml");
58187
58195
  return yamlLib;
58188
58196
  }
58197
+ var EXEC_TOOLS = /* @__PURE__ */ new Set([
58198
+ "em_execute",
58199
+ "em_execute_file",
58200
+ "em_batch_execute"
58201
+ ]);
58202
+ function roleHasShell(role) {
58203
+ return (role.tools?.includes("Bash") ?? true) && !role.disallowedTools?.includes("Bash");
58204
+ }
58189
58205
  var EM_MCP_PREFIXES = ["mcp__plugin_eminiar_eminiar__", "mcp__eminiar__"];
58190
58206
  var AGENTS_REL = ".claude/agents";
58191
58207
  function agentsDir(root) {
@@ -58199,21 +58215,26 @@ var TOPOLOGY_RULE = {
58199
58215
  mesh: "peers share one task board. Claim any open task (your role's first), and read the blackboard for what the other workers found.",
58200
58216
  pipeline: "work moves in stages. You can claim a task only once every task of the earlier stages is done."
58201
58217
  };
58202
- function workerTools(tools2) {
58218
+ function workerTools(tools2, shell = tools2.includes("Bash")) {
58203
58219
  const out = tools2.includes("ToolSearch") ? [...tools2] : [...tools2, "ToolSearch"];
58204
58220
  for (const prefix of EM_MCP_PREFIXES)
58205
- for (const t of WORKER_EM_TOOLS) if (!out.includes(prefix + t)) out.push(prefix + t);
58221
+ for (const t of WORKER_EM_TOOLS)
58222
+ if ((shell || !EXEC_TOOLS.has(t)) && !out.includes(prefix + t)) out.push(prefix + t);
58206
58223
  return out;
58207
58224
  }
58225
+ var execToolNames = () => EM_MCP_PREFIXES.flatMap((prefix) => [...EXEC_TOOLS].map((t) => prefix + t));
58208
58226
  function frontmatter(swarm, role) {
58209
58227
  const fm = {
58210
58228
  name: role.agentType,
58211
58229
  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.`
58212
58230
  };
58213
58231
  if (role.model) fm.model = role.model;
58214
- if (role.tools) fm.tools = workerTools(role.tools).join(", ");
58232
+ if (role.tools) fm.tools = workerTools(role.tools, roleHasShell(role)).join(", ");
58215
58233
  const spawns = role.tools?.some((t) => t === "Agent" || t === "Task");
58216
- const disallowed = [.../* @__PURE__ */ new Set([...role.disallowedTools ?? [], ...spawns ? [] : ["Agent"]])];
58234
+ const noShell = role.disallowedTools?.includes("Bash") ? execToolNames() : [];
58235
+ const disallowed = [
58236
+ .../* @__PURE__ */ new Set([...role.disallowedTools ?? [], ...spawns ? [] : ["Agent"], ...noShell])
58237
+ ];
58217
58238
  if (disallowed.length) fm.disallowedTools = disallowed.join(", ");
58218
58239
  if (role.skills.length) fm.skills = role.skills;
58219
58240
  if (role.hooks) {
@@ -58232,6 +58253,7 @@ var hashOf = (fm, rest, range) => createHash8("sha1").update(range ? `range=${ra
58232
58253
  ${fm}
58233
58254
  ${rest}` : `${fm}
58234
58255
  ${rest}`).digest("hex").slice(0, 12);
58256
+ 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.";
58235
58257
  function renderAgentFile(config2, swarm, role) {
58236
58258
  const fm = yaml().stringify(frontmatter(swarm, role), { lineWidth: 0 }).trimEnd();
58237
58259
  if (fm.includes("---"))
@@ -58245,12 +58267,15 @@ function renderAgentFile(config2, swarm, role) {
58245
58267
  ...role.prompt ? [role.prompt, ""] : [],
58246
58268
  "## Swarm protocol",
58247
58269
  "",
58248
- '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.',
58249
- '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.',
58250
- '3. Share what other workers need with `em_swarm {action:"post", key, value}` and read theirs with `em_swarm {action:"read"}`.',
58251
- '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.',
58252
- "5. Record durable decisions with `em_remember` so later sessions know them.",
58253
- "6. Your final message goes back to the coordinator: lead with the outcome, then the files you changed and anything left open.",
58270
+ ...[
58271
+ '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.',
58272
+ '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.',
58273
+ ...!role.isolation && roleHasShell(role) ? [SHARED_TREE_RULE] : [],
58274
+ 'Share what other workers need with `em_swarm {action:"post", key, value}` and read theirs with `em_swarm {action:"read"}`.',
58275
+ '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.',
58276
+ "Record durable decisions with `em_remember` so later sessions know them.",
58277
+ "Your final message goes back to the coordinator: lead with the outcome, then the files you changed and anything left open."
58278
+ ].map((step, i) => `${i + 1}. ${step}`),
58254
58279
  ""
58255
58280
  ].join("\n");
58256
58281
  const range = role.range ? modelRangeText(role.range) : void 0;
@@ -58615,7 +58640,7 @@ function projectDirs(root, cwd) {
58615
58640
  }
58616
58641
  function pluginDirs(plugin, env, home) {
58617
58642
  const out = /* @__PURE__ */ new Set();
58618
- const pluginsRoot = env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim() || join15(home, ".claude", "plugins");
58643
+ const pluginsRoot = claudePluginsDir(env, home);
58619
58644
  try {
58620
58645
  const j = JSON.parse(readFileSync12(join15(pluginsRoot, "installed_plugins.json"), "utf8"));
58621
58646
  for (const [key, val] of Object.entries(j?.plugins ?? {})) {
@@ -58716,7 +58741,7 @@ function resolveAgentPin(agentType, q) {
58716
58741
  const scopes = [];
58717
58742
  if (managed) scopes.push(["managed", join15(managed, ".claude", "agents")]);
58718
58743
  for (const d of projectDirs(q.root, q.cwd)) scopes.push(["project", d]);
58719
- scopes.push(["user", join15(home, ".claude", "agents")]);
58744
+ scopes.push(["user", join15(claudeConfigDir(env, home), "agents")]);
58720
58745
  let truncated = false;
58721
58746
  for (const [source, dir] of scopes) {
58722
58747
  const found = byName(dir, agentType);
@@ -60915,7 +60940,6 @@ function topToolConsumers(toolUses, limit = 10) {
60915
60940
  init_esm_shims();
60916
60941
  import { createHash as createHash10 } from "crypto";
60917
60942
  import { closeSync, existsSync as existsSync12, openSync, readdirSync as readdirSync8, readSync, statSync as statSync12 } from "fs";
60918
- import { homedir as homedir3 } from "os";
60919
60943
  import { basename as basename3, dirname as dirname11, join as join19, resolve as resolve10, sep as sep3 } from "path";
60920
60944
 
60921
60945
  // src/usage/transcript.ts
@@ -61144,7 +61168,7 @@ function isValidSessionId(id) {
61144
61168
  return SESSION_ID_RE.test(id);
61145
61169
  }
61146
61170
  function claudeDir() {
61147
- return process.env.EMINIAR_CLAUDE_DIR || join19(homedir3(), ".claude");
61171
+ return process.env.EMINIAR_CLAUDE_DIR || claudeConfigDir();
61148
61172
  }
61149
61173
  function insideDir(path3, dir) {
61150
61174
  const d = resolve10(dir);
@@ -63981,7 +64005,6 @@ import { join as join23 } from "path";
63981
64005
  // src/permissions/settings.ts
63982
64006
  init_esm_shims();
63983
64007
  import { existsSync as existsSync14, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync13 } from "fs";
63984
- import { homedir as homedir4 } from "os";
63985
64008
  import { join as join21 } from "path";
63986
64009
 
63987
64010
  // src/permissions/rules.ts
@@ -64163,11 +64186,11 @@ function stamp(file3) {
64163
64186
  var cache5 = /* @__PURE__ */ new Map();
64164
64187
  function loadPermissionRules(root, extraDeny = []) {
64165
64188
  const files = [
64166
- join21(homedir4(), ".claude", "settings.json"),
64189
+ join21(claudeConfigDir(), "settings.json"),
64167
64190
  join21(root, ".claude", "settings.json"),
64168
64191
  join21(root, ".claude", "settings.local.json")
64169
64192
  ];
64170
- const key = `${root}\0${extraDeny.join("\0")}`;
64193
+ const key = [...files, ...extraDeny].join("\0");
64171
64194
  const stamps = files.map(stamp);
64172
64195
  const hit = cache5.get(key);
64173
64196
  if (hit?.stamps.every((s, i) => s === stamps[i])) return hit.rules;
@@ -69135,12 +69158,13 @@ import {
69135
69158
  readdirSync as readdirSync9,
69136
69159
  readFileSync as readFileSync18,
69137
69160
  renameSync as renameSync6,
69161
+ statSync as statSync17,
69138
69162
  unlinkSync as unlinkSync6,
69139
69163
  writeFileSync as writeFileSync9
69140
69164
  } from "fs";
69141
69165
  import { connect } from "net";
69142
- import { homedir as homedir5 } from "os";
69143
- import { dirname as dirname14, join as join26 } from "path";
69166
+ import { homedir as homedir3 } from "os";
69167
+ import { basename as basename7, dirname as dirname14, join as join26 } from "path";
69144
69168
  import { parseArgs } from "util";
69145
69169
 
69146
69170
  // src/adjudicator/eval.ts
@@ -69534,10 +69558,9 @@ import {
69534
69558
  readFileSync as readFileSync20,
69535
69559
  writeFileSync as writeFileSync10
69536
69560
  } from "fs";
69537
- import { homedir as homedir6 } from "os";
69538
69561
  import { dirname as dirname15, join as join28 } from "path";
69539
- var claudeDir2 = () => process.env.CLAUDE_CONFIG_DIR || join28(homedir6(), ".claude");
69540
- var pluginsDir = () => join28(claudeDir2(), "plugins");
69562
+ var claudeDir2 = () => claudeConfigDir();
69563
+ var pluginsDir = () => claudePluginsDir();
69541
69564
  function readJson3(file3) {
69542
69565
  if (!existsSync20(file3)) return {};
69543
69566
  try {
@@ -69905,9 +69928,23 @@ function symbolsAt(db, path3, hunks) {
69905
69928
  }
69906
69929
  return out;
69907
69930
  }
69931
+ function isDiffRef(ref) {
69932
+ return ref.length > 0 && ref.length <= 256 && !ref.startsWith("-") && !new RegExp("\\p{Cc}", "u").test(ref);
69933
+ }
69908
69934
  function detectChanges(db, root, opts = {}) {
69909
- const args = ["diff", "--unified=0", "--no-color", "--relative", "--no-ext-diff"];
69910
- if (opts.ref) args.push(opts.ref);
69935
+ const args = [
69936
+ "diff",
69937
+ "--unified=0",
69938
+ "--no-color",
69939
+ "--relative",
69940
+ "--no-ext-diff",
69941
+ "--no-textconv"
69942
+ ];
69943
+ if (opts.ref) {
69944
+ if (!isDiffRef(opts.ref))
69945
+ throw new Error(`not a ref, sha or range: ${JSON.stringify(opts.ref)}`);
69946
+ args.push("--end-of-options", opts.ref);
69947
+ }
69911
69948
  const hunks = parseUnifiedDiff(git2(root, args));
69912
69949
  if (!opts.ref) {
69913
69950
  for (const p2 of git2(root, ["ls-files", "--others", "--exclude-standard"]).split("\n")) {
@@ -71919,8 +71956,8 @@ ${swarm.instructions}`] : []
71919
71956
  // src/swarm/hooks.ts
71920
71957
  init_esm_shims();
71921
71958
  import { execFileSync } from "child_process";
71922
- import { readFileSync as readFileSync25, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
71923
- import { basename as basename7, dirname as dirname16, join as join33, resolve as resolve12 } from "path";
71959
+ import { readFileSync as readFileSync25, realpathSync as realpathSync8, statSync as statSync18 } from "fs";
71960
+ import { basename as basename8, dirname as dirname16, join as join33, resolve as resolve12 } from "path";
71924
71961
 
71925
71962
  // src/hooks/log.ts
71926
71963
  init_esm_shims();
@@ -71986,7 +72023,7 @@ function verifyCaller(input2) {
71986
72023
  function coordinationRoot(root) {
71987
72024
  try {
71988
72025
  const dotGit = join33(root, ".git");
71989
- if (!statSync17(dotGit).isFile()) return root;
72026
+ if (!statSync18(dotGit).isFile()) return root;
71990
72027
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync25(dotGit, "utf8"));
71991
72028
  if (!m) return root;
71992
72029
  const gitdir = resolve12(root, m[1]);
@@ -71996,7 +72033,7 @@ function coordinationRoot(root) {
71996
72033
  } catch {
71997
72034
  return root;
71998
72035
  }
71999
- if (basename7(common) === ".git") return realpathSync8(dirname16(common));
72036
+ if (basename8(common) === ".git") return realpathSync8(dirname16(common));
72000
72037
  const out = execFileSync("git", ["worktree", "list", "--porcelain"], {
72001
72038
  cwd: root,
72002
72039
  encoding: "utf8",
@@ -72006,7 +72043,7 @@ function coordinationRoot(root) {
72006
72043
  const first = /^worktree (.+)$/m.exec(out)?.[1];
72007
72044
  if (!first || /^bare$/m.test(out.split("\n\n")[0] ?? "")) return root;
72008
72045
  const main = realpathSync8(first);
72009
- return main !== realpathSync8(common) && statSync17(join33(main, ".git"), { throwIfNoEntry: false }) ? main : root;
72046
+ return main !== realpathSync8(common) && statSync18(join33(main, ".git"), { throwIfNoEntry: false }) ? main : root;
72010
72047
  } catch {
72011
72048
  return root;
72012
72049
  }