eminiar 0.7.0 → 0.8.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/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -1
- package/dist/cli.js +471 -11
- package/dist/hook.js +147 -48
- package/dist/server.js +35 -8
- package/dist/ui/app.global.js +48 -48
- package/dist/ui/styles.css +4 -0
- package/package.json +1 -1
package/dist/hook.js
CHANGED
|
@@ -3941,11 +3941,11 @@ var require_out = __commonJS({
|
|
|
3941
3941
|
async.read(path2, getSettings(optionsOrSettingsOrCallback), callback);
|
|
3942
3942
|
}
|
|
3943
3943
|
exports.stat = stat;
|
|
3944
|
-
function
|
|
3944
|
+
function statSync6(path2, optionsOrSettings) {
|
|
3945
3945
|
const settings = getSettings(optionsOrSettings);
|
|
3946
3946
|
return sync.read(path2, settings);
|
|
3947
3947
|
}
|
|
3948
|
-
exports.statSync =
|
|
3948
|
+
exports.statSync = statSync6;
|
|
3949
3949
|
function getSettings(settingsOrOptions = {}) {
|
|
3950
3950
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
3951
3951
|
return settingsOrOptions;
|
|
@@ -4403,7 +4403,7 @@ var require_queue = __commonJS({
|
|
|
4403
4403
|
if (!(_concurrency >= 1)) {
|
|
4404
4404
|
throw new Error("fastqueue concurrency must be equal to or greater than 1");
|
|
4405
4405
|
}
|
|
4406
|
-
var
|
|
4406
|
+
var cache3 = reusify(Task);
|
|
4407
4407
|
var queueHead = null;
|
|
4408
4408
|
var queueTail = null;
|
|
4409
4409
|
var _running = 0;
|
|
@@ -4482,7 +4482,7 @@ var require_queue = __commonJS({
|
|
|
4482
4482
|
return _running === 0 && self.length() === 0;
|
|
4483
4483
|
}
|
|
4484
4484
|
function push(value, done) {
|
|
4485
|
-
var current =
|
|
4485
|
+
var current = cache3.get();
|
|
4486
4486
|
current.context = context;
|
|
4487
4487
|
current.release = release;
|
|
4488
4488
|
current.value = value;
|
|
@@ -4503,7 +4503,7 @@ var require_queue = __commonJS({
|
|
|
4503
4503
|
}
|
|
4504
4504
|
}
|
|
4505
4505
|
function unshift(value, done) {
|
|
4506
|
-
var current =
|
|
4506
|
+
var current = cache3.get();
|
|
4507
4507
|
current.context = context;
|
|
4508
4508
|
current.release = release;
|
|
4509
4509
|
current.value = value;
|
|
@@ -4525,7 +4525,7 @@ var require_queue = __commonJS({
|
|
|
4525
4525
|
}
|
|
4526
4526
|
function release(holder) {
|
|
4527
4527
|
if (holder) {
|
|
4528
|
-
|
|
4528
|
+
cache3.release(holder);
|
|
4529
4529
|
}
|
|
4530
4530
|
var next = queueHead;
|
|
4531
4531
|
if (next && _running <= _concurrency) {
|
|
@@ -4575,7 +4575,7 @@ var require_queue = __commonJS({
|
|
|
4575
4575
|
errorHandler2(new Error("abort"), val);
|
|
4576
4576
|
}
|
|
4577
4577
|
callback.call(context2, new Error("abort"));
|
|
4578
|
-
|
|
4578
|
+
cache3.release(current);
|
|
4579
4579
|
current = next;
|
|
4580
4580
|
}
|
|
4581
4581
|
self.drain = noop;
|
|
@@ -25733,21 +25733,21 @@ function visit(schema, fnOrHandlers) {
|
|
|
25733
25733
|
const h = fnOrHandlers[node2._zod.def.type];
|
|
25734
25734
|
return h ? h(node2, rewritten) : node2;
|
|
25735
25735
|
};
|
|
25736
|
-
const
|
|
25736
|
+
const cache3 = /* @__PURE__ */ new Map();
|
|
25737
25737
|
function run(s) {
|
|
25738
|
-
const cached3 =
|
|
25738
|
+
const cached3 = cache3.get(s);
|
|
25739
25739
|
if (cached3 === RESOLVING) {
|
|
25740
25740
|
return new $ZodLazy({
|
|
25741
25741
|
type: "lazy",
|
|
25742
|
-
getter: () =>
|
|
25742
|
+
getter: () => cache3.get(s)
|
|
25743
25743
|
});
|
|
25744
25744
|
}
|
|
25745
25745
|
if (cached3 !== void 0)
|
|
25746
25746
|
return cached3;
|
|
25747
|
-
|
|
25747
|
+
cache3.set(s, RESOLVING);
|
|
25748
25748
|
const inner = mapInner(s);
|
|
25749
25749
|
const mapped = fn(inner, inner !== s);
|
|
25750
|
-
|
|
25750
|
+
cache3.set(s, mapped);
|
|
25751
25751
|
return mapped;
|
|
25752
25752
|
}
|
|
25753
25753
|
function mapInner(s) {
|
|
@@ -28947,8 +28947,8 @@ var preCompact = (input2) => {
|
|
|
28947
28947
|
|
|
28948
28948
|
// src/hooks/routing.ts
|
|
28949
28949
|
init_esm_shims();
|
|
28950
|
-
import { realpathSync as
|
|
28951
|
-
import { extname as extname2, join as
|
|
28950
|
+
import { realpathSync as realpathSync4, statSync as statSync4 } from "fs";
|
|
28951
|
+
import { extname as extname2, join as join11, relative as relative4, resolve as resolve3 } from "path";
|
|
28952
28952
|
|
|
28953
28953
|
// src/docs/manifest.ts
|
|
28954
28954
|
init_esm_shims();
|
|
@@ -28998,10 +28998,107 @@ function readManifest(ctx) {
|
|
|
28998
28998
|
return readManifestAt(manifestPath(ctx));
|
|
28999
28999
|
}
|
|
29000
29000
|
|
|
29001
|
+
// src/permissions/settings.ts
|
|
29002
|
+
init_esm_shims();
|
|
29003
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync2 } from "fs";
|
|
29004
|
+
import { homedir as homedir2 } from "os";
|
|
29005
|
+
import { join as join5 } from "path";
|
|
29006
|
+
|
|
29007
|
+
// src/permissions/rules.ts
|
|
29008
|
+
init_esm_shims();
|
|
29009
|
+
function parseRule(raw) {
|
|
29010
|
+
const m = /^([A-Za-z][\w-]*)(?:\((.*)\))?$/s.exec(raw.trim());
|
|
29011
|
+
if (!m) return void 0;
|
|
29012
|
+
return { raw, tool: m[1], pattern: m[2] };
|
|
29013
|
+
}
|
|
29014
|
+
function escapeRe(s) {
|
|
29015
|
+
return s.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
29016
|
+
}
|
|
29017
|
+
var readRegexCache = /* @__PURE__ */ new Map();
|
|
29018
|
+
function readRegex(pattern) {
|
|
29019
|
+
let re = readRegexCache.get(pattern);
|
|
29020
|
+
if (!re) {
|
|
29021
|
+
if (readRegexCache.size >= 1024) readRegexCache.clear();
|
|
29022
|
+
re = new RegExp(
|
|
29023
|
+
`^${pattern.split("**").map((seg) => seg.split("*").map(escapeRe).join("[^/]*")).join(".*")}$`
|
|
29024
|
+
);
|
|
29025
|
+
readRegexCache.set(pattern, re);
|
|
29026
|
+
}
|
|
29027
|
+
return re;
|
|
29028
|
+
}
|
|
29029
|
+
function matchRead(rule, absPath) {
|
|
29030
|
+
if (rule.tool !== "Read") return false;
|
|
29031
|
+
if (rule.pattern === void 0) return true;
|
|
29032
|
+
let p = rule.pattern;
|
|
29033
|
+
if (p.startsWith("~")) p = (process.env.HOME ?? "") + p.slice(1);
|
|
29034
|
+
return readRegex(p).test(absPath);
|
|
29035
|
+
}
|
|
29036
|
+
|
|
29037
|
+
// src/permissions/split.ts
|
|
29038
|
+
init_esm_shims();
|
|
29039
|
+
|
|
29040
|
+
// src/permissions/settings.ts
|
|
29041
|
+
function readRules(file3) {
|
|
29042
|
+
if (!existsSync4(file3)) return {};
|
|
29043
|
+
try {
|
|
29044
|
+
const s = JSON.parse(readFileSync4(file3, "utf8"));
|
|
29045
|
+
return s.permissions ?? {};
|
|
29046
|
+
} catch {
|
|
29047
|
+
return {};
|
|
29048
|
+
}
|
|
29049
|
+
}
|
|
29050
|
+
function stamp(file3) {
|
|
29051
|
+
try {
|
|
29052
|
+
return statSync2(file3).mtimeMs;
|
|
29053
|
+
} catch {
|
|
29054
|
+
return -1;
|
|
29055
|
+
}
|
|
29056
|
+
}
|
|
29057
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
29058
|
+
function loadPermissionRules(root, extraDeny = []) {
|
|
29059
|
+
const files = [
|
|
29060
|
+
join5(homedir2(), ".claude", "settings.json"),
|
|
29061
|
+
join5(root, ".claude", "settings.json"),
|
|
29062
|
+
join5(root, ".claude", "settings.local.json")
|
|
29063
|
+
];
|
|
29064
|
+
const key = `${root}\0${extraDeny.join("\0")}`;
|
|
29065
|
+
const stamps = files.map(stamp);
|
|
29066
|
+
const hit = cache2.get(key);
|
|
29067
|
+
if (hit?.stamps.every((s, i) => s === stamps[i])) return hit.rules;
|
|
29068
|
+
const out = { allow: [], deny: [], ask: [] };
|
|
29069
|
+
const push = (list, raws) => {
|
|
29070
|
+
for (const raw of raws ?? []) {
|
|
29071
|
+
const r = parseRule(raw);
|
|
29072
|
+
if (r) list.push(r);
|
|
29073
|
+
}
|
|
29074
|
+
};
|
|
29075
|
+
for (const f of files) {
|
|
29076
|
+
const p = readRules(f);
|
|
29077
|
+
push(out.allow, p.allow);
|
|
29078
|
+
push(out.deny, p.deny);
|
|
29079
|
+
push(out.ask, p.ask);
|
|
29080
|
+
}
|
|
29081
|
+
push(out.deny, extraDeny);
|
|
29082
|
+
if (cache2.size >= 16) cache2.clear();
|
|
29083
|
+
cache2.set(key, { stamps, rules: out });
|
|
29084
|
+
return out;
|
|
29085
|
+
}
|
|
29086
|
+
function checkRead(rules, absPaths) {
|
|
29087
|
+
for (const kind of ["deny", "ask"]) {
|
|
29088
|
+
for (const r of rules[kind]) {
|
|
29089
|
+
if (absPaths.some((p) => matchRead(r, p))) return { allowed: false, rule: r.raw, kind };
|
|
29090
|
+
}
|
|
29091
|
+
}
|
|
29092
|
+
return { allowed: true };
|
|
29093
|
+
}
|
|
29094
|
+
function checkReadPath(rules, abs) {
|
|
29095
|
+
return checkRead(rules, [.../* @__PURE__ */ new Set([abs, realpathSync3(abs), realpathSync3.native(abs)])]);
|
|
29096
|
+
}
|
|
29097
|
+
|
|
29001
29098
|
// src/session/brief.ts
|
|
29002
29099
|
init_esm_shims();
|
|
29003
|
-
import { existsSync as
|
|
29004
|
-
import { join as
|
|
29100
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
29101
|
+
import { join as join7 } from "path";
|
|
29005
29102
|
|
|
29006
29103
|
// src/memory/frontmatter.ts
|
|
29007
29104
|
init_esm_shims();
|
|
@@ -29035,15 +29132,15 @@ function parseMemoryFile(text) {
|
|
|
29035
29132
|
init_esm_shims();
|
|
29036
29133
|
var import_fast_glob2 = __toESM(require_out4(), 1);
|
|
29037
29134
|
import {
|
|
29038
|
-
existsSync as
|
|
29135
|
+
existsSync as existsSync5,
|
|
29039
29136
|
mkdirSync as mkdirSync3,
|
|
29040
|
-
readFileSync as
|
|
29137
|
+
readFileSync as readFileSync5,
|
|
29041
29138
|
renameSync,
|
|
29042
|
-
statSync as
|
|
29139
|
+
statSync as statSync3,
|
|
29043
29140
|
unlinkSync,
|
|
29044
29141
|
writeFileSync as writeFileSync2
|
|
29045
29142
|
} from "fs";
|
|
29046
|
-
import { dirname as dirname3, join as
|
|
29143
|
+
import { dirname as dirname3, join as join6, relative as relative3, sep } from "path";
|
|
29047
29144
|
|
|
29048
29145
|
// src/storage/types.ts
|
|
29049
29146
|
init_esm_shims();
|
|
@@ -29055,7 +29152,7 @@ function memoriesRel(ctx) {
|
|
|
29055
29152
|
return ctx.config.memories.dir.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
29056
29153
|
}
|
|
29057
29154
|
function memoriesDir(ctx) {
|
|
29058
|
-
return
|
|
29155
|
+
return join6(ctx.root, memoriesRel(ctx));
|
|
29059
29156
|
}
|
|
29060
29157
|
|
|
29061
29158
|
// src/session/brief.ts
|
|
@@ -29098,10 +29195,10 @@ function historyLine(db) {
|
|
|
29098
29195
|
return `${parts.join("; ")}. em_history {action:"file", path} before editing, {action:"risk"} before committing.`;
|
|
29099
29196
|
}
|
|
29100
29197
|
function overviewParagraph(ctx) {
|
|
29101
|
-
const file3 =
|
|
29102
|
-
if (!
|
|
29198
|
+
const file3 = join7(memoriesDir(ctx), "onboarding", "overview.md");
|
|
29199
|
+
if (!existsSync6(file3)) return void 0;
|
|
29103
29200
|
try {
|
|
29104
|
-
const body = parseMemoryFile(
|
|
29201
|
+
const body = parseMemoryFile(readFileSync6(file3, "utf8")).body.trim();
|
|
29105
29202
|
const para = body.split(/\n\s*\n/).map(
|
|
29106
29203
|
(p) => p.replace(/^#+\s.*$/m, "").replace(/\s+/g, " ").trim()
|
|
29107
29204
|
).find((p) => p.length > 20);
|
|
@@ -29150,10 +29247,10 @@ function fitBudget(lines, budget) {
|
|
|
29150
29247
|
|
|
29151
29248
|
// src/session/server-alive.ts
|
|
29152
29249
|
init_esm_shims();
|
|
29153
|
-
import { existsSync as
|
|
29154
|
-
import { join as
|
|
29250
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
29251
|
+
import { join as join8 } from "path";
|
|
29155
29252
|
function markersDir(ctx) {
|
|
29156
|
-
return
|
|
29253
|
+
return join8(projectDir(ctx.id), "servers");
|
|
29157
29254
|
}
|
|
29158
29255
|
function processAlive(pid) {
|
|
29159
29256
|
try {
|
|
@@ -29165,13 +29262,13 @@ function processAlive(pid) {
|
|
|
29165
29262
|
}
|
|
29166
29263
|
function liveServers(ctx) {
|
|
29167
29264
|
const dir = markersDir(ctx);
|
|
29168
|
-
if (!
|
|
29265
|
+
if (!existsSync7(dir)) return [];
|
|
29169
29266
|
const live2 = [];
|
|
29170
29267
|
for (const name of readdirSync(dir)) {
|
|
29171
29268
|
const pid = Number(name);
|
|
29172
29269
|
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
29173
29270
|
if (processAlive(pid)) live2.push(pid);
|
|
29174
|
-
else rmSync(
|
|
29271
|
+
else rmSync(join8(dir, name), { force: true });
|
|
29175
29272
|
}
|
|
29176
29273
|
return live2;
|
|
29177
29274
|
}
|
|
@@ -29181,30 +29278,30 @@ function serverAlive(ctx) {
|
|
|
29181
29278
|
|
|
29182
29279
|
// src/hooks/coexist.ts
|
|
29183
29280
|
init_esm_shims();
|
|
29184
|
-
import { readFileSync as
|
|
29185
|
-
import { join as
|
|
29281
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
29282
|
+
import { join as join10 } from "path";
|
|
29186
29283
|
|
|
29187
29284
|
// src/install/claude-config.ts
|
|
29188
29285
|
init_esm_shims();
|
|
29189
29286
|
import {
|
|
29190
29287
|
copyFileSync,
|
|
29191
|
-
existsSync as
|
|
29288
|
+
existsSync as existsSync8,
|
|
29192
29289
|
mkdirSync as mkdirSync5,
|
|
29193
29290
|
readdirSync as readdirSync2,
|
|
29194
|
-
readFileSync as
|
|
29291
|
+
readFileSync as readFileSync7,
|
|
29195
29292
|
writeFileSync as writeFileSync4
|
|
29196
29293
|
} from "fs";
|
|
29197
|
-
import { homedir as
|
|
29198
|
-
import { dirname as dirname4, join as
|
|
29199
|
-
var claudeDir = () => process.env.CLAUDE_CONFIG_DIR ||
|
|
29200
|
-
var pluginsDir = () =>
|
|
29294
|
+
import { homedir as homedir3 } from "os";
|
|
29295
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
29296
|
+
var claudeDir = () => process.env.CLAUDE_CONFIG_DIR || join9(homedir3(), ".claude");
|
|
29297
|
+
var pluginsDir = () => join9(claudeDir(), "plugins");
|
|
29201
29298
|
|
|
29202
29299
|
// src/hooks/coexist.ts
|
|
29203
29300
|
var cached2;
|
|
29204
29301
|
function contextModeInstalled() {
|
|
29205
29302
|
if (cached2 !== void 0) return cached2;
|
|
29206
29303
|
try {
|
|
29207
|
-
const reg = JSON.parse(
|
|
29304
|
+
const reg = JSON.parse(readFileSync8(join10(pluginsDir(), "installed_plugins.json"), "utf8"));
|
|
29208
29305
|
cached2 = Object.keys(reg.plugins ?? {}).some((id) => id.startsWith("context-mode@"));
|
|
29209
29306
|
} catch {
|
|
29210
29307
|
cached2 = false;
|
|
@@ -29259,7 +29356,7 @@ function coverageHint(db, rel) {
|
|
|
29259
29356
|
}
|
|
29260
29357
|
function docsSources(root) {
|
|
29261
29358
|
try {
|
|
29262
|
-
return readManifestAt(
|
|
29359
|
+
return readManifestAt(join11(root, ".eminiar", "docs.json")).sources;
|
|
29263
29360
|
} catch {
|
|
29264
29361
|
return [];
|
|
29265
29362
|
}
|
|
@@ -29318,9 +29415,11 @@ function suggest(toolName, input2, root) {
|
|
|
29318
29415
|
const fp = String(input2.file_path ?? "");
|
|
29319
29416
|
if (!fp) return void 0;
|
|
29320
29417
|
try {
|
|
29321
|
-
const
|
|
29418
|
+
const abs = resolve3(root, fp);
|
|
29419
|
+
const st = statSync4(abs);
|
|
29322
29420
|
const ext = extname2(fp).toLowerCase();
|
|
29323
29421
|
if (st.size > 200 * 1024 || BIG_TEXT_EXT.has(ext) && st.size > 20 * 1024) {
|
|
29422
|
+
if (!checkReadPath(loadPermissionRules(root), abs).allowed) return void 0;
|
|
29324
29423
|
return {
|
|
29325
29424
|
tool: "em_execute_file",
|
|
29326
29425
|
reason: `${fp} is ${Math.round(st.size / 1024)} KB; em_execute_file {path, code} processes it in the sandbox so only what you print enters context`
|
|
@@ -29372,7 +29471,7 @@ function projectRel(ctx, fp) {
|
|
|
29372
29471
|
if (!fp) return void 0;
|
|
29373
29472
|
let abs = resolve3(ctx.root, fp);
|
|
29374
29473
|
try {
|
|
29375
|
-
abs =
|
|
29474
|
+
abs = realpathSync4(abs);
|
|
29376
29475
|
} catch {
|
|
29377
29476
|
}
|
|
29378
29477
|
const rel = relative4(ctx.root, abs).split("\\").join("/");
|
|
@@ -29573,15 +29672,15 @@ function annotate(s, note = "") {
|
|
|
29573
29672
|
|
|
29574
29673
|
// src/hooks/session-start.ts
|
|
29575
29674
|
init_esm_shims();
|
|
29576
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
29577
|
-
import { join as
|
|
29675
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
|
|
29676
|
+
import { join as join13 } from "path";
|
|
29578
29677
|
|
|
29579
29678
|
// src/session/current.ts
|
|
29580
29679
|
init_esm_shims();
|
|
29581
|
-
import { readFileSync as
|
|
29582
|
-
import { join as
|
|
29680
|
+
import { readFileSync as readFileSync9, statSync as statSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
29681
|
+
import { join as join12 } from "path";
|
|
29583
29682
|
function file2(ctx) {
|
|
29584
|
-
return
|
|
29683
|
+
return join12(projectDir(ctx.id), "current-session");
|
|
29585
29684
|
}
|
|
29586
29685
|
function setCurrentSession(ctx, sessionId) {
|
|
29587
29686
|
writeFileSync5(file2(ctx), sessionId);
|
|
@@ -29664,8 +29763,8 @@ ${guide}`);
|
|
|
29664
29763
|
} catch {
|
|
29665
29764
|
}
|
|
29666
29765
|
try {
|
|
29667
|
-
const onboarding =
|
|
29668
|
-
const onboarded =
|
|
29766
|
+
const onboarding = join13(memoriesDir(ctx), "onboarding");
|
|
29767
|
+
const onboarded = existsSync9(onboarding) && readdirSync3(onboarding).some((f) => f.endsWith(".md"));
|
|
29669
29768
|
if (!onboarded)
|
|
29670
29769
|
parts.push(
|
|
29671
29770
|
"No onboarding memories yet: run /eminiar:em-onboard once so future sessions start with the project's structure, build and test commands."
|
package/dist/server.js
CHANGED
|
@@ -18023,6 +18023,7 @@ __export(store_exports, {
|
|
|
18023
18023
|
isValidName: () => isValidName,
|
|
18024
18024
|
list: () => list,
|
|
18025
18025
|
memoriesDir: () => memoriesDir,
|
|
18026
|
+
memoriesRel: () => memoriesRel,
|
|
18026
18027
|
memoryLinks: () => memoryLinks,
|
|
18027
18028
|
normalizeRelated: () => normalizeRelated,
|
|
18028
18029
|
read: () => read,
|
|
@@ -51936,7 +51937,7 @@ import { join as join17 } from "path";
|
|
|
51936
51937
|
|
|
51937
51938
|
// src/permissions/settings.ts
|
|
51938
51939
|
init_esm_shims();
|
|
51939
|
-
import { existsSync as existsSync10, readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
51940
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, realpathSync as realpathSync2, statSync as statSync8 } from "fs";
|
|
51940
51941
|
import { homedir as homedir2 } from "os";
|
|
51941
51942
|
import { join as join15 } from "path";
|
|
51942
51943
|
|
|
@@ -51977,15 +51978,24 @@ function matchBash(rule, command) {
|
|
|
51977
51978
|
if (rule.pattern === void 0) return true;
|
|
51978
51979
|
return bashRegex(rule.pattern).test(command);
|
|
51979
51980
|
}
|
|
51981
|
+
var readRegexCache = /* @__PURE__ */ new Map();
|
|
51982
|
+
function readRegex(pattern2) {
|
|
51983
|
+
let re = readRegexCache.get(pattern2);
|
|
51984
|
+
if (!re) {
|
|
51985
|
+
if (readRegexCache.size >= 1024) readRegexCache.clear();
|
|
51986
|
+
re = new RegExp(
|
|
51987
|
+
`^${pattern2.split("**").map((seg) => seg.split("*").map(escapeRe2).join("[^/]*")).join(".*")}$`
|
|
51988
|
+
);
|
|
51989
|
+
readRegexCache.set(pattern2, re);
|
|
51990
|
+
}
|
|
51991
|
+
return re;
|
|
51992
|
+
}
|
|
51980
51993
|
function matchRead(rule, absPath) {
|
|
51981
51994
|
if (rule.tool !== "Read") return false;
|
|
51982
51995
|
if (rule.pattern === void 0) return true;
|
|
51983
51996
|
let p = rule.pattern;
|
|
51984
51997
|
if (p.startsWith("~")) p = (process.env.HOME ?? "") + p.slice(1);
|
|
51985
|
-
|
|
51986
|
-
`^${p.split("**").map((seg) => seg.split("*").map(escapeRe2).join("[^/]*")).join(".*")}$`
|
|
51987
|
-
);
|
|
51988
|
-
return re.test(absPath);
|
|
51998
|
+
return readRegex(p).test(absPath);
|
|
51989
51999
|
}
|
|
51990
52000
|
|
|
51991
52001
|
// src/permissions/split.ts
|
|
@@ -52147,6 +52157,17 @@ function checkCommand(rules, command) {
|
|
|
52147
52157
|
}
|
|
52148
52158
|
return { allowed: true };
|
|
52149
52159
|
}
|
|
52160
|
+
function checkRead(rules, absPaths) {
|
|
52161
|
+
for (const kind of ["deny", "ask"]) {
|
|
52162
|
+
for (const r of rules[kind]) {
|
|
52163
|
+
if (absPaths.some((p) => matchRead(r, p))) return { allowed: false, rule: r.raw, kind };
|
|
52164
|
+
}
|
|
52165
|
+
}
|
|
52166
|
+
return { allowed: true };
|
|
52167
|
+
}
|
|
52168
|
+
function checkReadPath(rules, abs) {
|
|
52169
|
+
return checkRead(rules, [.../* @__PURE__ */ new Set([abs, realpathSync2(abs), realpathSync2.native(abs)])]);
|
|
52170
|
+
}
|
|
52150
52171
|
|
|
52151
52172
|
// src/sandbox/env.ts
|
|
52152
52173
|
init_esm_shims();
|
|
@@ -57096,16 +57117,18 @@ init_esm_shims();
|
|
|
57096
57117
|
|
|
57097
57118
|
// src/sandbox/file.ts
|
|
57098
57119
|
init_esm_shims();
|
|
57099
|
-
import { realpathSync as
|
|
57120
|
+
import { realpathSync as realpathSync3 } from "fs";
|
|
57100
57121
|
import { isAbsolute, relative as relative9, resolve as resolve7 } from "path";
|
|
57101
57122
|
function confinePath(root, target, rules) {
|
|
57102
57123
|
const abs = resolve7(root, target);
|
|
57124
|
+
refuse(checkRead(rules, [abs]), target);
|
|
57103
57125
|
let real;
|
|
57104
57126
|
try {
|
|
57105
|
-
real =
|
|
57127
|
+
real = realpathSync3(abs);
|
|
57106
57128
|
} catch {
|
|
57107
57129
|
throw new Error(`file not found: ${target}`);
|
|
57108
57130
|
}
|
|
57131
|
+
refuse(checkReadPath(rules, abs), target);
|
|
57109
57132
|
const rel = relative9(root, real);
|
|
57110
57133
|
const inside = rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
57111
57134
|
if (inside) return real;
|
|
@@ -57114,11 +57137,15 @@ function confinePath(root, target, rules) {
|
|
|
57114
57137
|
`${target} is outside the project root; add a Read(${real}) rule to permissions.allow to opt it in`
|
|
57115
57138
|
);
|
|
57116
57139
|
}
|
|
57140
|
+
function refuse(check3, target) {
|
|
57141
|
+
if (!check3.allowed)
|
|
57142
|
+
throw new Error(`refused by permission rule ${check3.rule} (${check3.kind}) on path: ${target}`);
|
|
57143
|
+
}
|
|
57117
57144
|
|
|
57118
57145
|
// src/tools/em_execute_file.ts
|
|
57119
57146
|
var emExecuteFile = defineTool({
|
|
57120
57147
|
name: "em_execute_file",
|
|
57121
|
-
description: "Process a file in the sandbox without reading it into context. Your code receives the absolute path as $EM_FILE (shell) / process.env.EM_FILE (node) / os.environ['EM_FILE'] (python); print only what you need. The file must be inside the project root unless a Read(<path>) allow rule opts it in. Omit `code` to get a quick summary (size, lines, head).",
|
|
57148
|
+
description: "Process a file in the sandbox without reading it into context. Your code receives the absolute path as $EM_FILE (shell) / process.env.EM_FILE (node) / os.environ['EM_FILE'] (python); print only what you need. The file must be inside the project root unless a Read(<path>) allow rule opts it in; a matching Read deny or ask rule refuses the path, inside the root or out. Omit `code` to get a quick summary (size, lines, head).",
|
|
57122
57149
|
schema: {
|
|
57123
57150
|
path: external_exports.string().describe("File to process, relative to the project root or absolute"),
|
|
57124
57151
|
language: LANG_ENUM.optional(),
|