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/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +43 -15
- package/bin/_resolve.sh +7 -4
- package/bin/em-hook +2 -1
- package/bin/em-server +2 -1
- package/bin/eminiar +2 -1
- package/dist/cli.js +1502 -224
- package/dist/{hook-async-4MIP3VHX.js → hook-async-J3UKDO62.js} +3 -3
- package/dist/{hook-chunk-IYHVLMJ4.js → hook-chunk-BECSRJFD.js} +26 -11
- package/dist/{hook-chunk-MVOBVFQL.js → hook-chunk-DSLVDGOB.js} +57 -12
- package/dist/{hook-chunk-77I6QQ43.js → hook-chunk-RYZAFUTT.js} +2 -2
- package/dist/{hook-hooks-U6GDOQSY.js → hook-hooks-IDTGXCFD.js} +8 -6
- package/dist/hook.js +234 -57
- package/dist/server.js +80 -43
- package/dist/ui/app.global.js +78 -72
- package/dist/ui/styles.css +4724 -1508
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4602,7 +4602,7 @@ function isRef(value) {
|
|
|
4602
4602
|
function cloneIssues(issues) {
|
|
4603
4603
|
return issues.map((iss) => iss.path ? { ...iss, path: iss.path.slice() } : { ...iss });
|
|
4604
4604
|
}
|
|
4605
|
-
function isRecursive(inst, stack,
|
|
4605
|
+
function isRecursive(inst, stack, resolve16) {
|
|
4606
4606
|
const cached6 = recursive.get(inst);
|
|
4607
4607
|
if (cached6 !== void 0)
|
|
4608
4608
|
return cached6 ? PROVEN : NONE;
|
|
@@ -4612,7 +4612,7 @@ function isRecursive(inst, stack, resolve14) {
|
|
|
4612
4612
|
let result = NONE;
|
|
4613
4613
|
const check3 = (child) => {
|
|
4614
4614
|
if (result !== PROVEN && child?._zod) {
|
|
4615
|
-
const answer = isRecursive(child, stack,
|
|
4615
|
+
const answer = isRecursive(child, stack, resolve16);
|
|
4616
4616
|
if (answer > result)
|
|
4617
4617
|
result = answer;
|
|
4618
4618
|
}
|
|
@@ -4623,7 +4623,7 @@ function isRecursive(inst, stack, resolve14) {
|
|
|
4623
4623
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
4624
4624
|
if (spread && !desc.enumerable)
|
|
4625
4625
|
continue;
|
|
4626
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
4626
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve16) : NONE;
|
|
4627
4627
|
if (child > answer)
|
|
4628
4628
|
answer = child;
|
|
4629
4629
|
}
|
|
@@ -4687,7 +4687,7 @@ function isRecursive(inst, stack, resolve14) {
|
|
|
4687
4687
|
break;
|
|
4688
4688
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
4689
4689
|
case "lazy": {
|
|
4690
|
-
const inner = def._cachedInner ?? (
|
|
4690
|
+
const inner = def._cachedInner ?? (resolve16 ? inst._zod.innerType : void 0);
|
|
4691
4691
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
4692
4692
|
break;
|
|
4693
4693
|
}
|
|
@@ -20695,6 +20695,16 @@ import { join } from "path";
|
|
|
20695
20695
|
function eminiarHome() {
|
|
20696
20696
|
return process.env.EMINIAR_HOME || join(homedir(), ".eminiar");
|
|
20697
20697
|
}
|
|
20698
|
+
function claudeConfigDir(env = process.env, home = homedir()) {
|
|
20699
|
+
return env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
|
|
20700
|
+
}
|
|
20701
|
+
function claudeJsonFile(env = process.env, home = homedir()) {
|
|
20702
|
+
const dir = env.CLAUDE_CONFIG_DIR?.trim();
|
|
20703
|
+
return dir ? join(dir, ".claude.json") : join(home, ".claude.json");
|
|
20704
|
+
}
|
|
20705
|
+
function claudePluginsDir(env = process.env, home = homedir()) {
|
|
20706
|
+
return env.CLAUDE_CODE_PLUGIN_CACHE_DIR?.trim() || join(claudeConfigDir(env, home), "plugins");
|
|
20707
|
+
}
|
|
20698
20708
|
function paths() {
|
|
20699
20709
|
const home = eminiarHome();
|
|
20700
20710
|
return {
|
|
@@ -20842,10 +20852,13 @@ function envOverrides() {
|
|
|
20842
20852
|
if (Object.keys(adj).length) o.adjudicator = adj;
|
|
20843
20853
|
return o;
|
|
20844
20854
|
}
|
|
20855
|
+
function projectKeeps(adj, k) {
|
|
20856
|
+
return PROJECT_ADJUDICATOR_KEYS.includes(k) || k === "mode" && adj.mode === "advise";
|
|
20857
|
+
}
|
|
20845
20858
|
function droppedProjectAdjudicatorKeys(raw) {
|
|
20846
20859
|
const adj = raw.adjudicator;
|
|
20847
20860
|
if (!isPlainObject2(adj)) return [];
|
|
20848
|
-
return Object.keys(adj).filter((k) => !
|
|
20861
|
+
return Object.keys(adj).filter((k) => !projectKeeps(adj, k)).sort();
|
|
20849
20862
|
}
|
|
20850
20863
|
function projectAdjudicatorWarning(projectRoot) {
|
|
20851
20864
|
const lines = [];
|
|
@@ -20989,7 +21002,7 @@ function projectLayer(raw) {
|
|
|
20989
21002
|
if (!isPlainObject2(adj)) return raw;
|
|
20990
21003
|
if (findSecretFields(adj).length) return raw;
|
|
20991
21004
|
const kept = {};
|
|
20992
|
-
for (const k of
|
|
21005
|
+
for (const k of Object.keys(adj)) if (projectKeeps(adj, k)) kept[k] = adj[k];
|
|
20993
21006
|
return { ...ownJson(raw), adjudicator: kept };
|
|
20994
21007
|
}
|
|
20995
21008
|
function withoutUnsafeDocsManifest(raw, source) {
|
|
@@ -21101,9 +21114,9 @@ var init_config = __esm({
|
|
|
21101
21114
|
}).prefault({}),
|
|
21102
21115
|
minPromptChars: external_exports.number().int().min(0).default(12),
|
|
21103
21116
|
/**
|
|
21104
|
-
* Ordered ladder, smallest first; "fable" may be inserted by the user.
|
|
21105
|
-
*
|
|
21106
|
-
* tier at most once (task #56).
|
|
21117
|
+
* Ordered ladder, smallest first; "fable" may be inserted by the user. Personal config only
|
|
21118
|
+
* (a committed project file cannot set it). Every provider request carries the whole ladder,
|
|
21119
|
+
* so it is bounded: each tier at most once (task #56).
|
|
21107
21120
|
*/
|
|
21108
21121
|
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"]),
|
|
21109
21122
|
weights: external_exports.object({
|
|
@@ -21359,13 +21372,10 @@ var init_config = __esm({
|
|
|
21359
21372
|
UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
21360
21373
|
PROJECT_ADJUDICATOR_KEYS = [
|
|
21361
21374
|
"enabled",
|
|
21362
|
-
"mode",
|
|
21363
21375
|
"surfaces",
|
|
21364
21376
|
"promptMode",
|
|
21365
21377
|
"minPromptChars",
|
|
21366
|
-
"tiers",
|
|
21367
21378
|
"weights",
|
|
21368
|
-
"apply",
|
|
21369
21379
|
"advice",
|
|
21370
21380
|
"embedding",
|
|
21371
21381
|
"learning",
|
|
@@ -23463,7 +23473,7 @@ var init_adapter = __esm({
|
|
|
23463
23473
|
SqliteAdapter = class _SqliteAdapter {
|
|
23464
23474
|
constructor(path3, opts = {}) {
|
|
23465
23475
|
this.path = path3;
|
|
23466
|
-
this.db = new Database(path3, { timeout: 2e3 });
|
|
23476
|
+
this.db = new Database(path3, { timeout: opts.busyTimeoutMs ?? 2e3 });
|
|
23467
23477
|
this.swarm = new SqliteSwarmStore(this.db);
|
|
23468
23478
|
this.adjudicator = new SqliteAdjudicatorStore(this.db);
|
|
23469
23479
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -24681,15 +24691,20 @@ var init_adapter = __esm({
|
|
|
24681
24691
|
var storage_exports = {};
|
|
24682
24692
|
__export(storage_exports, {
|
|
24683
24693
|
closeAllStorage: () => closeAllStorage,
|
|
24684
|
-
getStorage: () => getStorage
|
|
24694
|
+
getStorage: () => getStorage,
|
|
24695
|
+
setStorageBusyTimeout: () => setStorageBusyTimeout
|
|
24685
24696
|
});
|
|
24697
|
+
function setStorageBusyTimeout(ms4) {
|
|
24698
|
+
busyTimeoutMs = ms4;
|
|
24699
|
+
}
|
|
24686
24700
|
function getStorage(ctx, opts = {}) {
|
|
24687
24701
|
const key = `${ctx.dbPath}|${opts.vectors === false ? "novec" : "vec"}`;
|
|
24688
24702
|
let adapter = open2.get(key);
|
|
24689
24703
|
if (!adapter) {
|
|
24690
24704
|
adapter = new SqliteAdapter(ctx.dbPath, {
|
|
24691
24705
|
dims: ctx.config.embeddings.dims,
|
|
24692
|
-
vectors: opts.vectors ?? true
|
|
24706
|
+
vectors: opts.vectors ?? true,
|
|
24707
|
+
...busyTimeoutMs === void 0 ? {} : { busyTimeoutMs }
|
|
24693
24708
|
});
|
|
24694
24709
|
open2.set(key, adapter);
|
|
24695
24710
|
}
|
|
@@ -24699,7 +24714,7 @@ function closeAllStorage() {
|
|
|
24699
24714
|
for (const a of open2.values()) a.close();
|
|
24700
24715
|
open2.clear();
|
|
24701
24716
|
}
|
|
24702
|
-
var open2;
|
|
24717
|
+
var open2, busyTimeoutMs;
|
|
24703
24718
|
var init_storage = __esm({
|
|
24704
24719
|
"src/storage/index.ts"() {
|
|
24705
24720
|
"use strict";
|
|
@@ -27103,7 +27118,7 @@ function maskYamlBlocks(text3) {
|
|
|
27103
27118
|
function maskCookiePairs(pairs) {
|
|
27104
27119
|
return pairs.replace(
|
|
27105
27120
|
/(^|;[ \t]*)([^=;]+)=([^;]*)/g,
|
|
27106
|
-
(m,
|
|
27121
|
+
(m, sep7, name, value) => !value || value === "***" || COOKIE_ATTRIBUTES.has(name.trim().toLowerCase()) ? m : `${sep7}${name}=***`
|
|
27107
27122
|
);
|
|
27108
27123
|
}
|
|
27109
27124
|
function clean(text3) {
|
|
@@ -27753,15 +27768,15 @@ function retryWait(header) {
|
|
|
27753
27768
|
return Number.isFinite(at) ? Math.max(0, at - Date.now()) : RETRY_BACKOFF_MS;
|
|
27754
27769
|
}
|
|
27755
27770
|
function sleep(ms4, signal) {
|
|
27756
|
-
return new Promise((
|
|
27757
|
-
if (signal?.aborted) return
|
|
27771
|
+
return new Promise((resolve16) => {
|
|
27772
|
+
if (signal?.aborted) return resolve16(false);
|
|
27758
27773
|
const t = setTimeout(() => {
|
|
27759
27774
|
signal?.removeEventListener("abort", onAbort);
|
|
27760
|
-
|
|
27775
|
+
resolve16(true);
|
|
27761
27776
|
}, ms4);
|
|
27762
27777
|
const onAbort = () => {
|
|
27763
27778
|
clearTimeout(t);
|
|
27764
|
-
|
|
27779
|
+
resolve16(false);
|
|
27765
27780
|
};
|
|
27766
27781
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
27767
27782
|
});
|
|
@@ -28520,8 +28535,8 @@ var init_units = __esm({
|
|
|
28520
28535
|
PASSES = "(?:pass(?:es)?|be green|stay green|succeed|exits? 0|exit cleanly|(?:is|are) clean)";
|
|
28521
28536
|
IS_GREEN = "(?:is|are) (?:all )?(?:clean|green)";
|
|
28522
28537
|
LIST_SEP2 = String.raw`\s*(?:,|\+|&&?|/|\band\b|\bor\b)\s*`;
|
|
28523
|
-
checkList = (item, verdict,
|
|
28524
|
-
String.raw`^${item}(?:${
|
|
28538
|
+
checkList = (item, verdict, sep7 = LIST_SEP2) => new RegExp(
|
|
28539
|
+
String.raw`^${item}(?:${sep7}${item}){0,8}(?:\s+(?:must |should |all |still |both )*${verdict})?(?:\s+if [\w\s'-]{1,30})?\s*[.!]?$`
|
|
28525
28540
|
);
|
|
28526
28541
|
CHECKS_ONLY = checkList(CHECK_ITEM, PASSES);
|
|
28527
28542
|
ROUTINE_CHECKS = checkList(
|
|
@@ -28997,10 +29012,10 @@ function finish(items2, opts, start, now, persist, locks) {
|
|
|
28997
29012
|
async function callWithin(provider, reqs, ms4, capture) {
|
|
28998
29013
|
const ac = new AbortController();
|
|
28999
29014
|
let timer;
|
|
29000
|
-
const timeout = new Promise((
|
|
29015
|
+
const timeout = new Promise((resolve16) => {
|
|
29001
29016
|
timer = setTimeout(() => {
|
|
29002
29017
|
ac.abort();
|
|
29003
|
-
|
|
29018
|
+
resolve16({ ok: false, kind: "timeout" });
|
|
29004
29019
|
}, ms4);
|
|
29005
29020
|
timer.unref?.();
|
|
29006
29021
|
});
|
|
@@ -30870,7 +30885,7 @@ function classify(q, exemplars, vectors, o) {
|
|
|
30870
30885
|
};
|
|
30871
30886
|
}
|
|
30872
30887
|
function withDeadline(p2, ms4, signal) {
|
|
30873
|
-
return new Promise((
|
|
30888
|
+
return new Promise((resolve16, reject) => {
|
|
30874
30889
|
const fail3 = () => reject(new ProviderError("timeout", "embedding deadline exceeded"));
|
|
30875
30890
|
if (signal?.aborted) return fail3();
|
|
30876
30891
|
const timer = setTimeout(fail3, Math.max(0, ms4));
|
|
@@ -30883,7 +30898,7 @@ function withDeadline(p2, ms4, signal) {
|
|
|
30883
30898
|
(v) => {
|
|
30884
30899
|
clearTimeout(timer);
|
|
30885
30900
|
signal?.removeEventListener("abort", onAbort);
|
|
30886
|
-
|
|
30901
|
+
resolve16(v);
|
|
30887
30902
|
},
|
|
30888
30903
|
(err) => {
|
|
30889
30904
|
clearTimeout(timer);
|
|
@@ -31034,16 +31049,20 @@ function yaml2() {
|
|
|
31034
31049
|
yamlLib2 ??= createRequire2(import.meta.url)("yaml");
|
|
31035
31050
|
return yamlLib2;
|
|
31036
31051
|
}
|
|
31052
|
+
function roleHasShell(role) {
|
|
31053
|
+
return (role.tools?.includes("Bash") ?? true) && !role.disallowedTools?.includes("Bash");
|
|
31054
|
+
}
|
|
31037
31055
|
function agentsDir(root) {
|
|
31038
31056
|
return join6(root, ".claude", "agents");
|
|
31039
31057
|
}
|
|
31040
31058
|
function agentRel(agentType) {
|
|
31041
31059
|
return `${AGENTS_REL}/${agentType}.md`;
|
|
31042
31060
|
}
|
|
31043
|
-
function workerTools(tools) {
|
|
31061
|
+
function workerTools(tools, shell = tools.includes("Bash")) {
|
|
31044
31062
|
const out = tools.includes("ToolSearch") ? [...tools] : [...tools, "ToolSearch"];
|
|
31045
31063
|
for (const prefix of EM_MCP_PREFIXES)
|
|
31046
|
-
for (const t of WORKER_EM_TOOLS)
|
|
31064
|
+
for (const t of WORKER_EM_TOOLS)
|
|
31065
|
+
if ((shell || !EXEC_TOOLS.has(t)) && !out.includes(prefix + t)) out.push(prefix + t);
|
|
31047
31066
|
return out;
|
|
31048
31067
|
}
|
|
31049
31068
|
function frontmatter(swarm, role) {
|
|
@@ -31052,9 +31071,12 @@ function frontmatter(swarm, role) {
|
|
|
31052
31071
|
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.`
|
|
31053
31072
|
};
|
|
31054
31073
|
if (role.model) fm.model = role.model;
|
|
31055
|
-
if (role.tools) fm.tools = workerTools(role.tools).join(", ");
|
|
31074
|
+
if (role.tools) fm.tools = workerTools(role.tools, roleHasShell(role)).join(", ");
|
|
31056
31075
|
const spawns = role.tools?.some((t) => t === "Agent" || t === "Task");
|
|
31057
|
-
const
|
|
31076
|
+
const noShell = role.disallowedTools?.includes("Bash") ? execToolNames() : [];
|
|
31077
|
+
const disallowed = [
|
|
31078
|
+
.../* @__PURE__ */ new Set([...role.disallowedTools ?? [], ...spawns ? [] : ["Agent"], ...noShell])
|
|
31079
|
+
];
|
|
31058
31080
|
if (disallowed.length) fm.disallowedTools = disallowed.join(", ");
|
|
31059
31081
|
if (role.skills.length) fm.skills = role.skills;
|
|
31060
31082
|
if (role.hooks) {
|
|
@@ -31082,12 +31104,15 @@ function renderAgentFile(config2, swarm, role) {
|
|
|
31082
31104
|
...role.prompt ? [role.prompt, ""] : [],
|
|
31083
31105
|
"## Swarm protocol",
|
|
31084
31106
|
"",
|
|
31085
|
-
|
|
31086
|
-
|
|
31087
|
-
|
|
31088
|
-
|
|
31089
|
-
|
|
31090
|
-
|
|
31107
|
+
...[
|
|
31108
|
+
'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.',
|
|
31109
|
+
'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.',
|
|
31110
|
+
...!role.isolation && roleHasShell(role) ? [SHARED_TREE_RULE] : [],
|
|
31111
|
+
'Share what other workers need with `em_swarm {action:"post", key, value}` and read theirs with `em_swarm {action:"read"}`.',
|
|
31112
|
+
'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.',
|
|
31113
|
+
"Record durable decisions with `em_remember` so later sessions know them.",
|
|
31114
|
+
"Your final message goes back to the coordinator: lead with the outcome, then the files you changed and anything left open."
|
|
31115
|
+
].map((step, i) => `${i + 1}. ${step}`),
|
|
31091
31116
|
""
|
|
31092
31117
|
].join("\n");
|
|
31093
31118
|
const range = role.range ? modelRangeText(role.range) : void 0;
|
|
@@ -31284,7 +31309,7 @@ function syncAgents(root, config2, opts = {}) {
|
|
|
31284
31309
|
}
|
|
31285
31310
|
return { actions, changed, conflicts: actions.filter((a) => a.action === "conflict").length };
|
|
31286
31311
|
}
|
|
31287
|
-
var MARKER_PREFIX, HASH_RE, RANGE_RE, WORKER_EM_TOOLS, yamlLib2, EM_MCP_PREFIXES, AGENTS_REL, TOPOLOGY_RULE, hashOf;
|
|
31312
|
+
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;
|
|
31288
31313
|
var init_agents = __esm({
|
|
31289
31314
|
"src/swarm/agents.ts"() {
|
|
31290
31315
|
"use strict";
|
|
@@ -31310,6 +31335,11 @@ var init_agents = __esm({
|
|
|
31310
31335
|
"em_docs",
|
|
31311
31336
|
"em_fetch_and_index"
|
|
31312
31337
|
];
|
|
31338
|
+
EXEC_TOOLS = /* @__PURE__ */ new Set([
|
|
31339
|
+
"em_execute",
|
|
31340
|
+
"em_execute_file",
|
|
31341
|
+
"em_batch_execute"
|
|
31342
|
+
]);
|
|
31313
31343
|
EM_MCP_PREFIXES = ["mcp__plugin_eminiar_eminiar__", "mcp__eminiar__"];
|
|
31314
31344
|
AGENTS_REL = ".claude/agents";
|
|
31315
31345
|
TOPOLOGY_RULE = {
|
|
@@ -31317,10 +31347,12 @@ var init_agents = __esm({
|
|
|
31317
31347
|
mesh: "peers share one task board. Claim any open task (your role's first), and read the blackboard for what the other workers found.",
|
|
31318
31348
|
pipeline: "work moves in stages. You can claim a task only once every task of the earlier stages is done."
|
|
31319
31349
|
};
|
|
31350
|
+
execToolNames = () => EM_MCP_PREFIXES.flatMap((prefix) => [...EXEC_TOOLS].map((t) => prefix + t));
|
|
31320
31351
|
hashOf = (fm, rest2, range) => createHash8("sha1").update(range ? `range=${range}
|
|
31321
31352
|
${fm}
|
|
31322
31353
|
${rest2}` : `${fm}
|
|
31323
31354
|
${rest2}`).digest("hex").slice(0, 12);
|
|
31355
|
+
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.";
|
|
31324
31356
|
}
|
|
31325
31357
|
});
|
|
31326
31358
|
|
|
@@ -31481,7 +31513,7 @@ function projectDirs(root, cwd) {
|
|
|
31481
31513
|
}
|
|
31482
31514
|
function pluginDirs(plugin, env, home) {
|
|
31483
31515
|
const out = /* @__PURE__ */ new Set();
|
|
31484
|
-
const pluginsRoot = env
|
|
31516
|
+
const pluginsRoot = claudePluginsDir(env, home);
|
|
31485
31517
|
try {
|
|
31486
31518
|
const j = JSON.parse(readFileSync6(join7(pluginsRoot, "installed_plugins.json"), "utf8"));
|
|
31487
31519
|
for (const [key, val] of Object.entries(j?.plugins ?? {})) {
|
|
@@ -31494,8 +31526,8 @@ function pluginDirs(plugin, env, home) {
|
|
|
31494
31526
|
}
|
|
31495
31527
|
} catch {
|
|
31496
31528
|
}
|
|
31497
|
-
const
|
|
31498
|
-
for (const raw of (env.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(
|
|
31529
|
+
const sep7 = process.platform === "win32" ? ";" : ":";
|
|
31530
|
+
for (const raw of (env.CLAUDE_CODE_PLUGIN_DIRS ?? "").split(sep7)) {
|
|
31499
31531
|
const p2 = raw.trim().replace(/^~(?=$|[/\\])/, home);
|
|
31500
31532
|
if (!p2 || !isAbsolute3(p2)) continue;
|
|
31501
31533
|
const name = manifest(p2)?.name;
|
|
@@ -31582,7 +31614,7 @@ function resolveAgentPin(agentType, q) {
|
|
|
31582
31614
|
const scopes = [];
|
|
31583
31615
|
if (managed) scopes.push(["managed", join7(managed, ".claude", "agents")]);
|
|
31584
31616
|
for (const d of projectDirs(q.root, q.cwd)) scopes.push(["project", d]);
|
|
31585
|
-
scopes.push(["user", join7(
|
|
31617
|
+
scopes.push(["user", join7(claudeConfigDir(env, home), "agents")]);
|
|
31586
31618
|
let truncated = false;
|
|
31587
31619
|
for (const [source, dir] of scopes) {
|
|
31588
31620
|
const found = byName(dir, agentType);
|
|
@@ -31608,6 +31640,7 @@ var init_agent_pin = __esm({
|
|
|
31608
31640
|
"src/adjudicator/agent-pin.ts"() {
|
|
31609
31641
|
"use strict";
|
|
31610
31642
|
init_esm_shims();
|
|
31643
|
+
init_paths();
|
|
31611
31644
|
init_agents();
|
|
31612
31645
|
init_savings2();
|
|
31613
31646
|
FORK_AGENT = "fork";
|
|
@@ -35064,8 +35097,8 @@ var require_pattern = __commonJS({
|
|
|
35064
35097
|
}
|
|
35065
35098
|
exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
|
|
35066
35099
|
function isAffectDepthOfReadingPattern(pattern2) {
|
|
35067
|
-
const
|
|
35068
|
-
return endsWithSlashGlobStar(pattern2) || isStaticPattern(
|
|
35100
|
+
const basename10 = path3.basename(pattern2);
|
|
35101
|
+
return endsWithSlashGlobStar(pattern2) || isStaticPattern(basename10);
|
|
35069
35102
|
}
|
|
35070
35103
|
exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
|
|
35071
35104
|
function expandPatternsWithBraceExpansion(patterns) {
|
|
@@ -35110,21 +35143,21 @@ var require_pattern = __commonJS({
|
|
|
35110
35143
|
exports.removeDuplicateSlashes = removeDuplicateSlashes;
|
|
35111
35144
|
function partitionAbsoluteAndRelative(patterns) {
|
|
35112
35145
|
const absolute = [];
|
|
35113
|
-
const
|
|
35146
|
+
const relative18 = [];
|
|
35114
35147
|
for (const pattern2 of patterns) {
|
|
35115
|
-
if (
|
|
35148
|
+
if (isAbsolute7(pattern2)) {
|
|
35116
35149
|
absolute.push(pattern2);
|
|
35117
35150
|
} else {
|
|
35118
|
-
|
|
35151
|
+
relative18.push(pattern2);
|
|
35119
35152
|
}
|
|
35120
35153
|
}
|
|
35121
|
-
return [absolute,
|
|
35154
|
+
return [absolute, relative18];
|
|
35122
35155
|
}
|
|
35123
35156
|
exports.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
|
|
35124
|
-
function
|
|
35157
|
+
function isAbsolute7(pattern2) {
|
|
35125
35158
|
return path3.isAbsolute(pattern2);
|
|
35126
35159
|
}
|
|
35127
|
-
exports.isAbsolute =
|
|
35160
|
+
exports.isAbsolute = isAbsolute7;
|
|
35128
35161
|
}
|
|
35129
35162
|
});
|
|
35130
35163
|
|
|
@@ -35549,11 +35582,11 @@ var require_out = __commonJS({
|
|
|
35549
35582
|
async.read(path3, getSettings(optionsOrSettingsOrCallback), callback);
|
|
35550
35583
|
}
|
|
35551
35584
|
exports.stat = stat;
|
|
35552
|
-
function
|
|
35585
|
+
function statSync21(path3, optionsOrSettings) {
|
|
35553
35586
|
const settings = getSettings(optionsOrSettings);
|
|
35554
35587
|
return sync.read(path3, settings);
|
|
35555
35588
|
}
|
|
35556
|
-
exports.statSync =
|
|
35589
|
+
exports.statSync = statSync21;
|
|
35557
35590
|
function getSettings(settingsOrOptions = {}) {
|
|
35558
35591
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
35559
35592
|
return settingsOrOptions;
|
|
@@ -36234,41 +36267,41 @@ var require_queue = __commonJS({
|
|
|
36234
36267
|
queue.drained = drained;
|
|
36235
36268
|
return queue;
|
|
36236
36269
|
function push(value) {
|
|
36237
|
-
var p2 = new Promise(function(
|
|
36270
|
+
var p2 = new Promise(function(resolve16, reject) {
|
|
36238
36271
|
pushCb(value, function(err, result) {
|
|
36239
36272
|
if (err) {
|
|
36240
36273
|
reject(err);
|
|
36241
36274
|
return;
|
|
36242
36275
|
}
|
|
36243
|
-
|
|
36276
|
+
resolve16(result);
|
|
36244
36277
|
});
|
|
36245
36278
|
});
|
|
36246
36279
|
p2.catch(noop);
|
|
36247
36280
|
return p2;
|
|
36248
36281
|
}
|
|
36249
36282
|
function unshift(value) {
|
|
36250
|
-
var p2 = new Promise(function(
|
|
36283
|
+
var p2 = new Promise(function(resolve16, reject) {
|
|
36251
36284
|
unshiftCb(value, function(err, result) {
|
|
36252
36285
|
if (err) {
|
|
36253
36286
|
reject(err);
|
|
36254
36287
|
return;
|
|
36255
36288
|
}
|
|
36256
|
-
|
|
36289
|
+
resolve16(result);
|
|
36257
36290
|
});
|
|
36258
36291
|
});
|
|
36259
36292
|
p2.catch(noop);
|
|
36260
36293
|
return p2;
|
|
36261
36294
|
}
|
|
36262
36295
|
function drained() {
|
|
36263
|
-
var p2 = new Promise(function(
|
|
36296
|
+
var p2 = new Promise(function(resolve16) {
|
|
36264
36297
|
process.nextTick(function() {
|
|
36265
36298
|
if (queue.idle()) {
|
|
36266
|
-
|
|
36299
|
+
resolve16();
|
|
36267
36300
|
} else {
|
|
36268
36301
|
var previousDrain = queue.drain;
|
|
36269
36302
|
queue.drain = function() {
|
|
36270
36303
|
if (typeof previousDrain === "function") previousDrain();
|
|
36271
|
-
|
|
36304
|
+
resolve16();
|
|
36272
36305
|
queue.drain = previousDrain;
|
|
36273
36306
|
};
|
|
36274
36307
|
}
|
|
@@ -36765,9 +36798,9 @@ var require_stream3 = __commonJS({
|
|
|
36765
36798
|
});
|
|
36766
36799
|
}
|
|
36767
36800
|
_getStat(filepath) {
|
|
36768
|
-
return new Promise((
|
|
36801
|
+
return new Promise((resolve16, reject) => {
|
|
36769
36802
|
this._stat(filepath, this._fsStatSettings, (error62, stats) => {
|
|
36770
|
-
return error62 === null ?
|
|
36803
|
+
return error62 === null ? resolve16(stats) : reject(error62);
|
|
36771
36804
|
});
|
|
36772
36805
|
});
|
|
36773
36806
|
}
|
|
@@ -36792,10 +36825,10 @@ var require_async5 = __commonJS({
|
|
|
36792
36825
|
this._readerStream = new stream_1.default(this._settings);
|
|
36793
36826
|
}
|
|
36794
36827
|
dynamic(root, options) {
|
|
36795
|
-
return new Promise((
|
|
36828
|
+
return new Promise((resolve16, reject) => {
|
|
36796
36829
|
this._walkAsync(root, options, (error62, entries) => {
|
|
36797
36830
|
if (error62 === null) {
|
|
36798
|
-
|
|
36831
|
+
resolve16(entries);
|
|
36799
36832
|
} else {
|
|
36800
36833
|
reject(error62);
|
|
36801
36834
|
}
|
|
@@ -36805,10 +36838,10 @@ var require_async5 = __commonJS({
|
|
|
36805
36838
|
async static(patterns, options) {
|
|
36806
36839
|
const entries = [];
|
|
36807
36840
|
const stream = this._readerStream.static(patterns, options);
|
|
36808
|
-
return new Promise((
|
|
36841
|
+
return new Promise((resolve16, reject) => {
|
|
36809
36842
|
stream.once("error", reject);
|
|
36810
36843
|
stream.on("data", (entry) => entries.push(entry));
|
|
36811
|
-
stream.once("end", () =>
|
|
36844
|
+
stream.once("end", () => resolve16(entries));
|
|
36812
36845
|
});
|
|
36813
36846
|
}
|
|
36814
36847
|
};
|
|
@@ -39737,13 +39770,12 @@ __export(ingest_exports, {
|
|
|
39737
39770
|
});
|
|
39738
39771
|
import { createHash as createHash10 } from "crypto";
|
|
39739
39772
|
import { closeSync, existsSync as existsSync7, openSync, readdirSync as readdirSync4, readSync, statSync as statSync8 } from "fs";
|
|
39740
|
-
import { homedir as homedir3 } from "os";
|
|
39741
39773
|
import { basename as basename3, dirname as dirname6, join as join11, resolve as resolve6, sep as sep3 } from "path";
|
|
39742
39774
|
function isValidSessionId(id) {
|
|
39743
39775
|
return SESSION_ID_RE.test(id);
|
|
39744
39776
|
}
|
|
39745
39777
|
function claudeDir() {
|
|
39746
|
-
return process.env.EMINIAR_CLAUDE_DIR ||
|
|
39778
|
+
return process.env.EMINIAR_CLAUDE_DIR || claudeConfigDir();
|
|
39747
39779
|
}
|
|
39748
39780
|
function insideDir(path3, dir) {
|
|
39749
39781
|
const d = resolve6(dir);
|
|
@@ -40032,6 +40064,7 @@ var init_ingest = __esm({
|
|
|
40032
40064
|
"src/usage/ingest.ts"() {
|
|
40033
40065
|
"use strict";
|
|
40034
40066
|
init_esm_shims();
|
|
40067
|
+
init_paths();
|
|
40035
40068
|
init_pricing();
|
|
40036
40069
|
init_transcript();
|
|
40037
40070
|
ZERO = { calls: 0, toolUses: 0, contextEvents: 0 };
|
|
@@ -40875,11 +40908,11 @@ function parseLimit(value) {
|
|
|
40875
40908
|
return n;
|
|
40876
40909
|
}
|
|
40877
40910
|
function recentlyIngested(root, sessionId, now = Date.now()) {
|
|
40878
|
-
const
|
|
40911
|
+
const within3 = (key) => {
|
|
40879
40912
|
const t = lastIngest.get(key);
|
|
40880
40913
|
return t !== void 0 && now - t < INGEST_GUARD_MS;
|
|
40881
40914
|
};
|
|
40882
|
-
return
|
|
40915
|
+
return within3(root) || sessionId !== void 0 && within3(sessionIngestKey(root, sessionId));
|
|
40883
40916
|
}
|
|
40884
40917
|
function ingestFor(db, ctx, scope, sessionId, now) {
|
|
40885
40918
|
const overrides = ctx.config.usage.pricing;
|
|
@@ -42691,12 +42724,13 @@ import {
|
|
|
42691
42724
|
readdirSync as readdirSync5,
|
|
42692
42725
|
readFileSync as readFileSync10,
|
|
42693
42726
|
renameSync as renameSync5,
|
|
42727
|
+
statSync as statSync9,
|
|
42694
42728
|
unlinkSync as unlinkSync5,
|
|
42695
42729
|
writeFileSync as writeFileSync6
|
|
42696
42730
|
} from "fs";
|
|
42697
42731
|
import { connect } from "net";
|
|
42698
|
-
import { homedir as
|
|
42699
|
-
import { dirname as dirname7, join as join12 } from "path";
|
|
42732
|
+
import { homedir as homedir3 } from "os";
|
|
42733
|
+
import { basename as basename5, dirname as dirname7, join as join12 } from "path";
|
|
42700
42734
|
import { parseArgs } from "util";
|
|
42701
42735
|
function defaultIo() {
|
|
42702
42736
|
return {
|
|
@@ -42725,7 +42759,7 @@ async function askLine(question) {
|
|
|
42725
42759
|
}
|
|
42726
42760
|
function readHidden(question) {
|
|
42727
42761
|
const stdin = process.stdin;
|
|
42728
|
-
return new Promise((
|
|
42762
|
+
return new Promise((resolve16, reject) => {
|
|
42729
42763
|
let buf = "";
|
|
42730
42764
|
const wasRaw = stdin.isRaw;
|
|
42731
42765
|
stdin.setRawMode(true);
|
|
@@ -42738,7 +42772,7 @@ function readHidden(question) {
|
|
|
42738
42772
|
stdin.pause();
|
|
42739
42773
|
process.stdout.write("\n");
|
|
42740
42774
|
if (err) reject(err);
|
|
42741
|
-
else
|
|
42775
|
+
else resolve16(buf);
|
|
42742
42776
|
};
|
|
42743
42777
|
const onData = (chunk2) => {
|
|
42744
42778
|
for (const ch of chunk2) {
|
|
@@ -42851,6 +42885,15 @@ function valueLooksLikeKey(value) {
|
|
|
42851
42885
|
if (KEY_PREFIX.test(v)) return true;
|
|
42852
42886
|
return v.split(/[\s\-_/.:@+=,;&?#%~]+/).some((seg) => seg.length >= 20 && /\d/.test(seg));
|
|
42853
42887
|
}
|
|
42888
|
+
function pathLooksLikeKey(value) {
|
|
42889
|
+
const v = value.trim();
|
|
42890
|
+
let isFile3 = false;
|
|
42891
|
+
try {
|
|
42892
|
+
isFile3 = statSync9(v).isFile();
|
|
42893
|
+
} catch {
|
|
42894
|
+
}
|
|
42895
|
+
return valueLooksLikeKey(isFile3 ? basename5(v) : v);
|
|
42896
|
+
}
|
|
42854
42897
|
function baseUrlProblem(raw) {
|
|
42855
42898
|
let u;
|
|
42856
42899
|
try {
|
|
@@ -42869,7 +42912,8 @@ function baseUrlProblem(raw) {
|
|
|
42869
42912
|
function argvKeyProblem(values) {
|
|
42870
42913
|
for (const flag of ["model", "since", "fixture", "repeat", "providers"]) {
|
|
42871
42914
|
const v = values[flag];
|
|
42872
|
-
if (typeof v
|
|
42915
|
+
if (typeof v !== "string") continue;
|
|
42916
|
+
if (flag === "fixture" ? pathLooksLikeKey(v) : valueLooksLikeKey(v)) return KEY_NOT_FROM_ARGV;
|
|
42873
42917
|
}
|
|
42874
42918
|
const url2 = values["base-url"];
|
|
42875
42919
|
if (typeof url2 === "string" && url2) return baseUrlProblem(url2);
|
|
@@ -43114,12 +43158,12 @@ async function pickProvider(io) {
|
|
|
43114
43158
|
return direct && a !== "1" ? direct : { provider: "heuristic" };
|
|
43115
43159
|
}
|
|
43116
43160
|
function portOpen(port, ms4) {
|
|
43117
|
-
return new Promise((
|
|
43161
|
+
return new Promise((resolve16) => {
|
|
43118
43162
|
const s = connect({ host: "127.0.0.1", port });
|
|
43119
43163
|
const end = (v) => {
|
|
43120
43164
|
clearTimeout(t);
|
|
43121
43165
|
s.destroy();
|
|
43122
|
-
|
|
43166
|
+
resolve16(v);
|
|
43123
43167
|
};
|
|
43124
43168
|
const t = setTimeout(() => end(false), ms4);
|
|
43125
43169
|
s.once("connect", () => end(true));
|
|
@@ -44228,7 +44272,7 @@ var init_cli = __esm({
|
|
|
44228
44272
|
isObj2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
44229
44273
|
projectFile = (root) => join12(root, "eminiar.config.json");
|
|
44230
44274
|
tilde = (p2) => {
|
|
44231
|
-
const h =
|
|
44275
|
+
const h = homedir3();
|
|
44232
44276
|
return h && p2.startsWith(h) ? `~${p2.slice(h.length)}` : p2;
|
|
44233
44277
|
};
|
|
44234
44278
|
CHOICES = [
|
|
@@ -44457,7 +44501,6 @@ import {
|
|
|
44457
44501
|
readFileSync as readFileSync13,
|
|
44458
44502
|
writeFileSync as writeFileSync7
|
|
44459
44503
|
} from "fs";
|
|
44460
|
-
import { homedir as homedir5 } from "os";
|
|
44461
44504
|
import { dirname as dirname9, join as join15 } from "path";
|
|
44462
44505
|
function readJson2(file3) {
|
|
44463
44506
|
if (!existsSync10(file3)) return {};
|
|
@@ -44540,10 +44583,10 @@ var init_claude_config = __esm({
|
|
|
44540
44583
|
"use strict";
|
|
44541
44584
|
init_esm_shims();
|
|
44542
44585
|
init_paths();
|
|
44543
|
-
claudeDir2 = () =>
|
|
44586
|
+
claudeDir2 = () => claudeConfigDir();
|
|
44544
44587
|
settingsPath = () => join15(claudeDir2(), "settings.json");
|
|
44545
|
-
claudeJsonPath = () =>
|
|
44546
|
-
pluginsDir = () =>
|
|
44588
|
+
claudeJsonPath = () => claudeJsonFile();
|
|
44589
|
+
pluginsDir = () => claudePluginsDir();
|
|
44547
44590
|
PLUGIN_SERVER_ID = "plugin:eminiar:eminiar";
|
|
44548
44591
|
mcpNeedsAuthPath = () => join15(claudeDir2(), "mcp-needs-auth-cache.json");
|
|
44549
44592
|
}
|
|
@@ -44753,10 +44796,10 @@ var init_server_alive = __esm({
|
|
|
44753
44796
|
|
|
44754
44797
|
// src/hooks/cursor.ts
|
|
44755
44798
|
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync15, rmSync as rmSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
44756
|
-
import { homedir as
|
|
44799
|
+
import { homedir as homedir4 } from "os";
|
|
44757
44800
|
import { join as join19 } from "path";
|
|
44758
44801
|
function cursorDir() {
|
|
44759
|
-
return process.env.CURSOR_CONFIG_DIR || join19(
|
|
44802
|
+
return process.env.CURSOR_CONFIG_DIR || join19(homedir4(), ".cursor");
|
|
44760
44803
|
}
|
|
44761
44804
|
var PENDING_TTL_MS2;
|
|
44762
44805
|
var init_cursor = __esm({
|
|
@@ -45325,12 +45368,12 @@ import { join as join24 } from "path";
|
|
|
45325
45368
|
function mcpHandshake(bin, ms4 = 15e3, opts = {}) {
|
|
45326
45369
|
const exitMs = opts.exitMs ?? 2e3;
|
|
45327
45370
|
const start = opts.spawn ?? ((b) => spawn(b, [], { stdio: ["pipe", "pipe", "pipe"] }));
|
|
45328
|
-
return new Promise((
|
|
45371
|
+
return new Promise((resolve16) => {
|
|
45329
45372
|
let child;
|
|
45330
45373
|
try {
|
|
45331
45374
|
child = start(bin);
|
|
45332
45375
|
} catch (e) {
|
|
45333
|
-
|
|
45376
|
+
resolve16(`spawn failed: ${e.message}`);
|
|
45334
45377
|
return;
|
|
45335
45378
|
}
|
|
45336
45379
|
let buf = "";
|
|
@@ -45340,7 +45383,7 @@ function mcpHandshake(bin, ms4 = 15e3, opts = {}) {
|
|
|
45340
45383
|
const timers = [];
|
|
45341
45384
|
const done = () => {
|
|
45342
45385
|
for (const t of timers) clearTimeout(t);
|
|
45343
|
-
if (result !== void 0)
|
|
45386
|
+
if (result !== void 0) resolve16(result);
|
|
45344
45387
|
};
|
|
45345
45388
|
const finish2 = (r) => {
|
|
45346
45389
|
if (result !== void 0) return;
|
|
@@ -45476,7 +45519,7 @@ async function fullDoctor(opts = {}) {
|
|
|
45476
45519
|
});
|
|
45477
45520
|
}
|
|
45478
45521
|
} else if (rec.method === "settings") {
|
|
45479
|
-
const s = existsSync18(
|
|
45522
|
+
const s = existsSync18(settingsPath()) ? readFileSync20(settingsPath(), "utf8") : "";
|
|
45480
45523
|
checks.push({
|
|
45481
45524
|
name: "hooks in settings.json",
|
|
45482
45525
|
ok: s.includes("em-hook"),
|
|
@@ -45682,7 +45725,7 @@ async function install(opts) {
|
|
|
45682
45725
|
if (usedMethod === "settings") {
|
|
45683
45726
|
wrote = registerSettings(stable);
|
|
45684
45727
|
log.ok(
|
|
45685
|
-
|
|
45728
|
+
`hooks written to ${settingsPath()}, MCP server to ${claudeJsonPath()}, skills to ${join25(claudeDir2(), "skills")}`
|
|
45686
45729
|
);
|
|
45687
45730
|
}
|
|
45688
45731
|
if (wantClaude) {
|
|
@@ -45754,19 +45797,7 @@ function writeTeamFiles(root, marketplace, extra = {}) {
|
|
|
45754
45797
|
`${JSON.stringify(
|
|
45755
45798
|
{
|
|
45756
45799
|
$schema: "https://raw.githubusercontent.com/rydn/eminiar/main/eminiar.config.schema.json",
|
|
45757
|
-
routing: { mode: "auto", deferToContextMode: true }
|
|
45758
|
-
graph: {
|
|
45759
|
-
exclude: [
|
|
45760
|
-
"**/node_modules/**",
|
|
45761
|
-
"**/dist/**",
|
|
45762
|
-
"**/build/**",
|
|
45763
|
-
"**/.git/**",
|
|
45764
|
-
"**/coverage/**",
|
|
45765
|
-
"**/*.d.ts"
|
|
45766
|
-
]
|
|
45767
|
-
},
|
|
45768
|
-
index: { docs: ["**/*.md", "docs/**"] },
|
|
45769
|
-
permissions: { extraDeny: [] }
|
|
45800
|
+
routing: { mode: "auto", deferToContextMode: true }
|
|
45770
45801
|
},
|
|
45771
45802
|
null,
|
|
45772
45803
|
2
|
|
@@ -45872,7 +45903,7 @@ async function uninstall(opts) {
|
|
|
45872
45903
|
const p2 = paths();
|
|
45873
45904
|
const plan = [
|
|
45874
45905
|
rec?.method === "plugin" || !rec ? "claude plugin uninstall eminiar@eminiar + marketplace remove" : "",
|
|
45875
|
-
rec?.method === "settings" ?
|
|
45906
|
+
rec?.method === "settings" ? `remove eminiar hook entries from ${settingsPath()}, mcpServers.eminiar from ${claudeJsonPath()}, em-* skills` : "",
|
|
45876
45907
|
rec?.wrote.cursor ? "remove eminiar hook entries from ~/.cursor/hooks.json, mcpServers.eminiar from ~/.cursor/mcp.json, em-* skills from ~/.cursor/skills" : "",
|
|
45877
45908
|
rec?.wrote.statusline ? "clear the eminiar statusLine" : "",
|
|
45878
45909
|
`delete ${p2.plugin}`,
|
|
@@ -46892,16 +46923,16 @@ var init_metrics = __esm({
|
|
|
46892
46923
|
function resolveNode(db, ref) {
|
|
46893
46924
|
const direct = db.graphGetNode(ref);
|
|
46894
46925
|
if (direct) return direct;
|
|
46895
|
-
const
|
|
46896
|
-
const asFile = db.graphGetNode(fileId(
|
|
46926
|
+
const clean3 = ref.replace(/^\.\//, "");
|
|
46927
|
+
const asFile = db.graphGetNode(fileId(clean3));
|
|
46897
46928
|
if (asFile) return asFile;
|
|
46898
|
-
if (
|
|
46899
|
-
const [p2, n] =
|
|
46929
|
+
if (clean3.includes("#")) {
|
|
46930
|
+
const [p2, n] = clean3.split("#");
|
|
46900
46931
|
const s = db.graphGetNode(symId(p2, n));
|
|
46901
46932
|
if (s) return s;
|
|
46902
46933
|
}
|
|
46903
|
-
const found = db.graphFindNodes({ query:
|
|
46904
|
-
return found.find((n) => n.name ===
|
|
46934
|
+
const found = db.graphFindNodes({ query: clean3, limit: 5 });
|
|
46935
|
+
return found.find((n) => n.name === clean3) ?? found[0];
|
|
46905
46936
|
}
|
|
46906
46937
|
function expand2(db, node2) {
|
|
46907
46938
|
if (node2.kind !== "file") return [node2.id];
|
|
@@ -48158,7 +48189,7 @@ var init_go = __esm({
|
|
|
48158
48189
|
});
|
|
48159
48190
|
|
|
48160
48191
|
// src/graph/languages/php.ts
|
|
48161
|
-
import { readdirSync as readdirSync12, readFileSync as readFileSync22, statSync as
|
|
48192
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync22, statSync as statSync10 } from "fs";
|
|
48162
48193
|
import { dirname as dirname11, join as join28, normalize as normalize4, relative as relative9, resolve as resolve8 } from "path";
|
|
48163
48194
|
function readComposer(dir) {
|
|
48164
48195
|
const file3 = join28(dir, "composer.json");
|
|
@@ -49207,7 +49238,7 @@ var init_php = __esm({
|
|
|
49207
49238
|
SPATIE_ATTRIBUTES = "Spatie\\RouteAttributes\\Attributes\\";
|
|
49208
49239
|
isFile = (p2) => {
|
|
49209
49240
|
try {
|
|
49210
|
-
return
|
|
49241
|
+
return statSync10(p2).isFile();
|
|
49211
49242
|
} catch {
|
|
49212
49243
|
return false;
|
|
49213
49244
|
}
|
|
@@ -49225,7 +49256,7 @@ var init_php = __esm({
|
|
|
49225
49256
|
});
|
|
49226
49257
|
|
|
49227
49258
|
// src/graph/languages/python.ts
|
|
49228
|
-
import { existsSync as existsSync23, statSync as
|
|
49259
|
+
import { existsSync as existsSync23, statSync as statSync11 } from "fs";
|
|
49229
49260
|
import { dirname as dirname12, join as join29, normalize as normalize5, relative as relative10, resolve as resolve9 } from "path";
|
|
49230
49261
|
function resolvePython(root, fromRel, module, level) {
|
|
49231
49262
|
const parts = module ? module.split(".") : [];
|
|
@@ -49600,7 +49631,7 @@ var init_python = __esm({
|
|
|
49600
49631
|
BOOL_OPS3 = /* @__PURE__ */ new Set(["and", "or"]);
|
|
49601
49632
|
isFile2 = (p2) => {
|
|
49602
49633
|
try {
|
|
49603
|
-
return
|
|
49634
|
+
return statSync11(p2).isFile();
|
|
49604
49635
|
} catch {
|
|
49605
49636
|
return false;
|
|
49606
49637
|
}
|
|
@@ -49629,7 +49660,7 @@ var init_python = __esm({
|
|
|
49629
49660
|
});
|
|
49630
49661
|
|
|
49631
49662
|
// src/graph/resolve.ts
|
|
49632
|
-
import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as
|
|
49663
|
+
import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync12 } from "fs";
|
|
49633
49664
|
import { dirname as dirname13, join as join30, normalize as normalize6, relative as relative11, resolve as resolve10 } from "path";
|
|
49634
49665
|
function loadTsPaths(root) {
|
|
49635
49666
|
const hit = tsPathsCache.get(root);
|
|
@@ -49660,7 +49691,7 @@ function loadTsPaths(root) {
|
|
|
49660
49691
|
function probe(abs) {
|
|
49661
49692
|
const tryFile = (p2) => {
|
|
49662
49693
|
try {
|
|
49663
|
-
return
|
|
49694
|
+
return statSync12(p2).isFile() ? p2 : void 0;
|
|
49664
49695
|
} catch {
|
|
49665
49696
|
return void 0;
|
|
49666
49697
|
}
|
|
@@ -49701,9 +49732,9 @@ function loadWorkspaces(root) {
|
|
|
49701
49732
|
if (Array.isArray(ws)) globs.push(...ws);
|
|
49702
49733
|
else if (ws?.packages) globs.push(...ws.packages);
|
|
49703
49734
|
try {
|
|
49704
|
-
const
|
|
49705
|
-
if (existsSync24(
|
|
49706
|
-
for (const m of readFileSync23(
|
|
49735
|
+
const yaml4 = join30(root, "pnpm-workspace.yaml");
|
|
49736
|
+
if (existsSync24(yaml4)) {
|
|
49737
|
+
for (const m of readFileSync23(yaml4, "utf8").matchAll(/^\s*-\s*['"]?([^'"\n#]+?)['"]?\s*$/gm))
|
|
49707
49738
|
globs.push(m[1].trim());
|
|
49708
49739
|
}
|
|
49709
49740
|
} catch {
|
|
@@ -50860,7 +50891,7 @@ var init_link = __esm({
|
|
|
50860
50891
|
});
|
|
50861
50892
|
|
|
50862
50893
|
// src/graph/reindex.ts
|
|
50863
|
-
import { readFileSync as readFileSync24, statSync as
|
|
50894
|
+
import { readFileSync as readFileSync24, statSync as statSync13 } from "fs";
|
|
50864
50895
|
import { join as join31 } from "path";
|
|
50865
50896
|
function listCodeFiles(ctx) {
|
|
50866
50897
|
return import_fast_glob3.default.sync(ctx.config.graph.include, {
|
|
@@ -50873,7 +50904,7 @@ function listCodeFiles(ctx) {
|
|
|
50873
50904
|
}
|
|
50874
50905
|
async function indexOne(ctx, db, rel, force) {
|
|
50875
50906
|
const abs = join31(ctx.root, rel);
|
|
50876
|
-
const st =
|
|
50907
|
+
const st = statSync13(abs);
|
|
50877
50908
|
const backend = getCodeBackend(ctx);
|
|
50878
50909
|
const language = backend.languageOf(rel) ?? null;
|
|
50879
50910
|
if (st.size > MAX_CODE_BYTES) {
|
|
@@ -50973,7 +51004,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
50973
51004
|
summary.unsupported++;
|
|
50974
51005
|
if (db.fileIndexGet(rel)?.status === "unsupported") continue;
|
|
50975
51006
|
try {
|
|
50976
|
-
const st =
|
|
51007
|
+
const st = statSync13(join31(ctx.root, rel));
|
|
50977
51008
|
db.fileIndexSet({
|
|
50978
51009
|
path: rel,
|
|
50979
51010
|
hash: "",
|
|
@@ -51001,7 +51032,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
51001
51032
|
const error62 = err.message;
|
|
51002
51033
|
summary.errors.push({ path: rel, error: error62 });
|
|
51003
51034
|
try {
|
|
51004
|
-
const st =
|
|
51035
|
+
const st = statSync13(join31(ctx.root, rel));
|
|
51005
51036
|
db.fileIndexSet({
|
|
51006
51037
|
path: rel,
|
|
51007
51038
|
hash: "",
|
|
@@ -51064,7 +51095,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
51064
51095
|
}
|
|
51065
51096
|
function statSafe(p2) {
|
|
51066
51097
|
try {
|
|
51067
|
-
return
|
|
51098
|
+
return statSync13(p2).isFile();
|
|
51068
51099
|
} catch {
|
|
51069
51100
|
return false;
|
|
51070
51101
|
}
|
|
@@ -51105,7 +51136,7 @@ function indexFreshness(ctx, db) {
|
|
|
51105
51136
|
for (const r of rows.slice(0, 400)) {
|
|
51106
51137
|
try {
|
|
51107
51138
|
const abs = join31(ctx.root, r.path);
|
|
51108
|
-
const st =
|
|
51139
|
+
const st = statSync13(abs);
|
|
51109
51140
|
if (r.mtime !== null && Math.abs(st.mtimeMs - r.mtime) < 1 && st.size === r.size) continue;
|
|
51110
51141
|
if (hashText(readFileSync24(abs, "utf8")) !== r.hash) dirty.push(r.path);
|
|
51111
51142
|
} catch {
|
|
@@ -51572,9 +51603,23 @@ function symbolsAt(db, path3, hunks) {
|
|
|
51572
51603
|
}
|
|
51573
51604
|
return out;
|
|
51574
51605
|
}
|
|
51606
|
+
function isDiffRef(ref) {
|
|
51607
|
+
return ref.length > 0 && ref.length <= 256 && !ref.startsWith("-") && !new RegExp("\\p{Cc}", "u").test(ref);
|
|
51608
|
+
}
|
|
51575
51609
|
function detectChanges(db, root, opts = {}) {
|
|
51576
|
-
const args = [
|
|
51577
|
-
|
|
51610
|
+
const args = [
|
|
51611
|
+
"diff",
|
|
51612
|
+
"--unified=0",
|
|
51613
|
+
"--no-color",
|
|
51614
|
+
"--relative",
|
|
51615
|
+
"--no-ext-diff",
|
|
51616
|
+
"--no-textconv"
|
|
51617
|
+
];
|
|
51618
|
+
if (opts.ref) {
|
|
51619
|
+
if (!isDiffRef(opts.ref))
|
|
51620
|
+
throw new Error(`not a ref, sha or range: ${JSON.stringify(opts.ref)}`);
|
|
51621
|
+
args.push("--end-of-options", opts.ref);
|
|
51622
|
+
}
|
|
51578
51623
|
const hunks = parseUnifiedDiff(git(root, args));
|
|
51579
51624
|
if (!opts.ref) {
|
|
51580
51625
|
for (const p2 of git(root, ["ls-files", "--others", "--exclude-standard"]).split("\n")) {
|
|
@@ -51784,8 +51829,8 @@ function entryPoints(root, db) {
|
|
|
51784
51829
|
const out = [];
|
|
51785
51830
|
const push = (kind, name, path3) => {
|
|
51786
51831
|
if (typeof path3 !== "string") return;
|
|
51787
|
-
const
|
|
51788
|
-
if (!out.some((e) => e.kind === kind && e.name === name)) out.push({ kind, name, path:
|
|
51832
|
+
const clean3 = path3.replace(/^\.\//, "");
|
|
51833
|
+
if (!out.some((e) => e.kind === kind && e.name === name)) out.push({ kind, name, path: clean3 });
|
|
51789
51834
|
};
|
|
51790
51835
|
const bin = pkg.bin;
|
|
51791
51836
|
if (typeof bin === "string") push("bin", String(pkg.name ?? "bin"), bin);
|
|
@@ -53109,10 +53154,10 @@ import {
|
|
|
53109
53154
|
realpathSync as realpathSync5,
|
|
53110
53155
|
renameSync as renameSync6,
|
|
53111
53156
|
rmSync as rmSync7,
|
|
53112
|
-
statSync as
|
|
53157
|
+
statSync as statSync14,
|
|
53113
53158
|
writeFileSync as writeFileSync13
|
|
53114
53159
|
} from "fs";
|
|
53115
|
-
import { basename as
|
|
53160
|
+
import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute5, join as join33, relative as relative12, sep as sep4 } from "path";
|
|
53116
53161
|
function docsTag(name) {
|
|
53117
53162
|
return `${DOCS_PREFIX}${name}`;
|
|
53118
53163
|
}
|
|
@@ -53187,7 +53232,7 @@ function locationProblem(file3, root, write2) {
|
|
|
53187
53232
|
if (write2) {
|
|
53188
53233
|
let dangling = false;
|
|
53189
53234
|
try {
|
|
53190
|
-
dangling = !
|
|
53235
|
+
dangling = !statSync14(file3, { throwIfNoEntry: false });
|
|
53191
53236
|
} catch {
|
|
53192
53237
|
}
|
|
53193
53238
|
return dangling ? "it is a symlink to a missing file" : "it is a symlink, and writes replace only a regular file";
|
|
@@ -53212,7 +53257,7 @@ function probeManifestAt(file3, opts = {}) {
|
|
|
53212
53257
|
}
|
|
53213
53258
|
let fd;
|
|
53214
53259
|
try {
|
|
53215
|
-
const st =
|
|
53260
|
+
const st = statSync14(file3, { throwIfNoEntry: false });
|
|
53216
53261
|
if (!st) {
|
|
53217
53262
|
return lstatSync2(file3, { throwIfNoEntry: false }) ? { state: "refused", reason: "it is a symlink to a missing file" } : { state: "missing" };
|
|
53218
53263
|
}
|
|
@@ -53285,8 +53330,8 @@ function writeManifest(ctx, m) {
|
|
|
53285
53330
|
version: 1,
|
|
53286
53331
|
sources: [...m.sources].sort((a, b) => a.name.localeCompare(b.name))
|
|
53287
53332
|
};
|
|
53288
|
-
const mode = p2.state === "ok" ?
|
|
53289
|
-
const tmp = join33(dir, `.${
|
|
53333
|
+
const mode = p2.state === "ok" ? statSync14(file3, { throwIfNoEntry: false })?.mode : void 0;
|
|
53334
|
+
const tmp = join33(dir, `.${basename6(file3)}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`);
|
|
53290
53335
|
try {
|
|
53291
53336
|
writeFileSync13(tmp, `${JSON.stringify(sorted, null, 2)}
|
|
53292
53337
|
`, { flag: "wx" });
|
|
@@ -53403,8 +53448,8 @@ var init_manifest = __esm({
|
|
|
53403
53448
|
});
|
|
53404
53449
|
|
|
53405
53450
|
// src/docs/discover.ts
|
|
53406
|
-
import { existsSync as existsSync26, readFileSync as readFileSync26, statSync as
|
|
53407
|
-
import { basename as
|
|
53451
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26, statSync as statSync15 } from "fs";
|
|
53452
|
+
import { basename as basename7, join as join34, relative as relative13 } from "path";
|
|
53408
53453
|
function readText(file3) {
|
|
53409
53454
|
try {
|
|
53410
53455
|
return readFileSync26(file3, "utf8");
|
|
@@ -53425,7 +53470,7 @@ function sizeOf(files) {
|
|
|
53425
53470
|
let n = 0;
|
|
53426
53471
|
for (const f of files) {
|
|
53427
53472
|
try {
|
|
53428
|
-
n +=
|
|
53473
|
+
n += statSync15(f).size;
|
|
53429
53474
|
} catch {
|
|
53430
53475
|
}
|
|
53431
53476
|
}
|
|
@@ -53592,7 +53637,7 @@ function apiSignals(dir, project) {
|
|
|
53592
53637
|
for (const file3 of files) {
|
|
53593
53638
|
let size = 0;
|
|
53594
53639
|
try {
|
|
53595
|
-
size =
|
|
53640
|
+
size = statSync15(file3).size;
|
|
53596
53641
|
} catch {
|
|
53597
53642
|
continue;
|
|
53598
53643
|
}
|
|
@@ -53600,7 +53645,7 @@ function apiSignals(dir, project) {
|
|
|
53600
53645
|
const text3 = readText(file3);
|
|
53601
53646
|
if (!text3 || text3.includes("\0")) continue;
|
|
53602
53647
|
const rel = relative13(dir, file3).split("\\").join("/");
|
|
53603
|
-
const isEnv =
|
|
53648
|
+
const isEnv = basename7(file3).startsWith(".env");
|
|
53604
53649
|
const lines = text3.split("\n");
|
|
53605
53650
|
const found = [];
|
|
53606
53651
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -53688,7 +53733,7 @@ function fileSignals(dir, project) {
|
|
|
53688
53733
|
}
|
|
53689
53734
|
function localCandidates(root, dir, project, isRegistered) {
|
|
53690
53735
|
const out = [];
|
|
53691
|
-
const prefix = project ? `${slugify3(
|
|
53736
|
+
const prefix = project ? `${slugify3(basename7(dir))}-` : "";
|
|
53692
53737
|
const rel = (abs) => relative13(root, abs).split("\\").join("/");
|
|
53693
53738
|
const push = (c) => {
|
|
53694
53739
|
if (!c.files) return;
|
|
@@ -53712,7 +53757,7 @@ function localCandidates(root, dir, project, isRegistered) {
|
|
|
53712
53757
|
push({
|
|
53713
53758
|
name: `${prefix}readme`,
|
|
53714
53759
|
path: rel(dir) || ".",
|
|
53715
|
-
glob: guides.map((g) =>
|
|
53760
|
+
glob: guides.map((g) => basename7(g)),
|
|
53716
53761
|
recursive: false,
|
|
53717
53762
|
files: guides.length,
|
|
53718
53763
|
bytes: sizeOf(guides),
|
|
@@ -53813,7 +53858,7 @@ function localCandidates(root, dir, project, isRegistered) {
|
|
|
53813
53858
|
push({
|
|
53814
53859
|
name: `${prefix}env-example`,
|
|
53815
53860
|
path: rel(dir) || ".",
|
|
53816
|
-
glob: env.map((f) =>
|
|
53861
|
+
glob: env.map((f) => basename7(f)),
|
|
53817
53862
|
recursive: false,
|
|
53818
53863
|
files: env.length,
|
|
53819
53864
|
bytes: sizeOf(env),
|
|
@@ -54541,7 +54586,7 @@ var init_category = __esm({
|
|
|
54541
54586
|
});
|
|
54542
54587
|
|
|
54543
54588
|
// src/docs/graph.ts
|
|
54544
|
-
import { existsSync as existsSync27, statSync as
|
|
54589
|
+
import { existsSync as existsSync27, statSync as statSync16 } from "fs";
|
|
54545
54590
|
import { dirname as dirname15, posix, relative as relative14, sep as sep5 } from "path";
|
|
54546
54591
|
function manifestRel(ctx) {
|
|
54547
54592
|
return relative14(ctx.root, manifestPath(ctx)).split(sep5).join("/");
|
|
@@ -54639,7 +54684,7 @@ function localDocPages(ctx, db) {
|
|
|
54639
54684
|
}
|
|
54640
54685
|
function stampOf(ctx, db) {
|
|
54641
54686
|
const file3 = manifestPath(ctx);
|
|
54642
|
-
const st = existsSync27(file3) ?
|
|
54687
|
+
const st = existsSync27(file3) ? statSync16(file3) : void 0;
|
|
54643
54688
|
const counts3 = db.graphNodeCounts();
|
|
54644
54689
|
const syncs = readManifest(ctx).sources.map((s) => syncState(db, s.name)?.at ?? 0).join(",");
|
|
54645
54690
|
return `${st ? `${Math.floor(st.mtimeMs)}:${st.size}` : "none"}|${counts3.file ?? 0}|${counts3.package ?? 0}|${syncs}`;
|
|
@@ -56681,14 +56726,14 @@ function buildHistory(ctx, db, opts = {}) {
|
|
|
56681
56726
|
};
|
|
56682
56727
|
});
|
|
56683
56728
|
const bySha = new Map(commits.map((c) => [c.sha, c]));
|
|
56684
|
-
const
|
|
56729
|
+
const resolve16 = (prefix) => {
|
|
56685
56730
|
if (bySha.has(prefix)) return bySha.get(prefix);
|
|
56686
56731
|
for (const c of commits) if (c.sha.startsWith(prefix)) return c;
|
|
56687
56732
|
return void 0;
|
|
56688
56733
|
};
|
|
56689
56734
|
for (const c of commits) {
|
|
56690
56735
|
if (c.kind !== "revert" || !c.revertOf) continue;
|
|
56691
|
-
const target2 =
|
|
56736
|
+
const target2 = resolve16(c.revertOf);
|
|
56692
56737
|
if (target2) {
|
|
56693
56738
|
target2.revertedBy = c.sha;
|
|
56694
56739
|
c.origins.push(target2.sha);
|
|
@@ -57143,15 +57188,15 @@ function safeRegex(q) {
|
|
|
57143
57188
|
}
|
|
57144
57189
|
}
|
|
57145
57190
|
function commitsForFile(m, path3) {
|
|
57146
|
-
const
|
|
57147
|
-
const from = m.files.get(
|
|
57191
|
+
const clean3 = path3.replace(/^\.\//, "");
|
|
57192
|
+
const from = m.files.get(clean3)?.renamedFrom;
|
|
57148
57193
|
return m.commits.filter(
|
|
57149
|
-
(c) => c.files.some((f) => f.path ===
|
|
57194
|
+
(c) => c.files.some((f) => f.path === clean3 || from && f.path === from)
|
|
57150
57195
|
);
|
|
57151
57196
|
}
|
|
57152
57197
|
function originsForFile(m, path3) {
|
|
57153
|
-
const
|
|
57154
|
-
const shas = new Set(m.links.filter((l) => l.path ===
|
|
57198
|
+
const clean3 = path3.replace(/^\.\//, "");
|
|
57199
|
+
const shas = new Set(m.links.filter((l) => l.path === clean3).map((l) => l.origin));
|
|
57155
57200
|
return m.commits.filter((c) => shas.has(c.sha));
|
|
57156
57201
|
}
|
|
57157
57202
|
function resolveCommit(m, ref) {
|
|
@@ -60522,7 +60567,7 @@ var init_symbols2 = __esm({
|
|
|
60522
60567
|
});
|
|
60523
60568
|
|
|
60524
60569
|
// src/ui/graph-api.ts
|
|
60525
|
-
import { readFileSync as readFileSync28, realpathSync as realpathSync6, statSync as
|
|
60570
|
+
import { readFileSync as readFileSync28, realpathSync as realpathSync6, statSync as statSync17 } from "fs";
|
|
60526
60571
|
import { relative as relative16, resolve as resolve12 } from "path";
|
|
60527
60572
|
function metaOf2(row) {
|
|
60528
60573
|
if (!row?.meta) return {};
|
|
@@ -60583,22 +60628,22 @@ function treePayload(ctx) {
|
|
|
60583
60628
|
return { root: ctx.root, files };
|
|
60584
60629
|
}
|
|
60585
60630
|
function filePayload(ctx, rel) {
|
|
60586
|
-
const
|
|
60587
|
-
const abs = resolve12(ctx.root,
|
|
60631
|
+
const clean3 = rel.replace(/^\.\//, "");
|
|
60632
|
+
const abs = resolve12(ctx.root, clean3);
|
|
60588
60633
|
if (relative16(ctx.root, abs).startsWith("..")) throw new Error("path outside the project");
|
|
60589
60634
|
let real = abs;
|
|
60590
60635
|
try {
|
|
60591
60636
|
real = realpathSync6(abs);
|
|
60592
60637
|
} catch {
|
|
60593
|
-
return { error: "not found", path:
|
|
60638
|
+
return { error: "not found", path: clean3 };
|
|
60594
60639
|
}
|
|
60595
60640
|
if (relative16(realpathSync6(ctx.root), real).startsWith(".."))
|
|
60596
60641
|
throw new Error("path outside the project");
|
|
60597
|
-
const st =
|
|
60598
|
-
if (!st.isFile()) return { error: "not a file", path:
|
|
60642
|
+
const st = statSync17(real);
|
|
60643
|
+
if (!st.isFile()) return { error: "not a file", path: clean3 };
|
|
60599
60644
|
const db = getStorage(ctx);
|
|
60600
|
-
const row = db.fileIndexGet(
|
|
60601
|
-
const symbols = overview(db,
|
|
60645
|
+
const row = db.fileIndexGet(clean3);
|
|
60646
|
+
const symbols = overview(db, clean3).map((n) => ({
|
|
60602
60647
|
id: n.id,
|
|
60603
60648
|
name: n.name,
|
|
60604
60649
|
kind: n.kind,
|
|
@@ -60607,10 +60652,10 @@ function filePayload(ctx, rel) {
|
|
|
60607
60652
|
exported: isExported2(n)
|
|
60608
60653
|
}));
|
|
60609
60654
|
if (st.size > MAX_CODE_BYTES)
|
|
60610
|
-
return { path:
|
|
60655
|
+
return { path: clean3, tooLarge: true, size: st.size, status: row?.status ?? null, symbols };
|
|
60611
60656
|
const content = readFileSync28(real, "utf8");
|
|
60612
60657
|
return {
|
|
60613
|
-
path:
|
|
60658
|
+
path: clean3,
|
|
60614
60659
|
size: st.size,
|
|
60615
60660
|
language: row?.language ?? null,
|
|
60616
60661
|
status: row?.status ?? null,
|
|
@@ -60650,25 +60695,25 @@ function symbolPayload(ctx, ref) {
|
|
|
60650
60695
|
}
|
|
60651
60696
|
function fileImpactPayload(ctx, rel) {
|
|
60652
60697
|
const db = getStorage(ctx);
|
|
60653
|
-
const
|
|
60654
|
-
const r = impact(db, fileId(
|
|
60655
|
-
if (!r) return { error: "not in the graph", path:
|
|
60698
|
+
const clean3 = rel.replace(/^\.\//, "");
|
|
60699
|
+
const r = impact(db, fileId(clean3), { depth: 2, includeGit: true });
|
|
60700
|
+
if (!r) return { error: "not in the graph", path: clean3 };
|
|
60656
60701
|
const direct = r.hits.filter(
|
|
60657
60702
|
(h) => h.hops === 1 && h.id.startsWith("file:") && !h.reasons.every((x) => /^co-changed|^memory/.test(x))
|
|
60658
60703
|
);
|
|
60659
60704
|
const tests = r.hits.filter((h) => h.node?.path && TEST_PATH4.test(h.node.path));
|
|
60660
60705
|
const coChanged = r.hits.filter((h) => h.reasons.some((x) => x.startsWith("co-changed")));
|
|
60661
60706
|
const memories = r.hits.filter((h) => h.id.startsWith("memory:"));
|
|
60662
|
-
const n = neighbors(db, fileId(
|
|
60707
|
+
const n = neighbors(db, fileId(clean3), 1, ["imports", "reexports"]);
|
|
60663
60708
|
const nodeMap = new Map((n?.nodes ?? []).map((x) => [x.id, x]));
|
|
60664
60709
|
const edges = (n?.edges ?? []).slice(0, 80);
|
|
60665
|
-
const keep = /* @__PURE__ */ new Set([fileId(
|
|
60710
|
+
const keep = /* @__PURE__ */ new Set([fileId(clean3)]);
|
|
60666
60711
|
for (const e of edges) {
|
|
60667
60712
|
keep.add(e.src);
|
|
60668
60713
|
keep.add(e.dst);
|
|
60669
60714
|
}
|
|
60670
60715
|
return {
|
|
60671
|
-
path:
|
|
60716
|
+
path: clean3,
|
|
60672
60717
|
directDependents: direct.length,
|
|
60673
60718
|
affected: r.hits.filter((h) => h.id.startsWith("file:")).length,
|
|
60674
60719
|
tests: tests.length,
|
|
@@ -60685,7 +60730,7 @@ function fileImpactPayload(ctx, rel) {
|
|
|
60685
60730
|
})),
|
|
60686
60731
|
graph: {
|
|
60687
60732
|
nodes: [...keep].map(
|
|
60688
|
-
(id) => vis(nodeMap.get(id) ?? db.graphGetNode(id), id, id === fileId(
|
|
60733
|
+
(id) => vis(nodeMap.get(id) ?? db.graphGetNode(id), id, id === fileId(clean3))
|
|
60689
60734
|
),
|
|
60690
60735
|
edges: edges.map(visEdge)
|
|
60691
60736
|
}
|
|
@@ -61052,16 +61097,16 @@ function historyDiffPayload(ctx, sha, path3) {
|
|
|
61052
61097
|
function historyFilePayload(ctx, path3) {
|
|
61053
61098
|
const m = model(ctx);
|
|
61054
61099
|
if (!m) return NO_GIT;
|
|
61055
|
-
const
|
|
61056
|
-
const h = m.files.get(
|
|
61057
|
-
const commits = commitsForFile(m,
|
|
61058
|
-
const origins = originsForFile(m,
|
|
61100
|
+
const clean3 = path3.replace(/^\.\//, "");
|
|
61101
|
+
const h = m.files.get(clean3);
|
|
61102
|
+
const commits = commitsForFile(m, clean3);
|
|
61103
|
+
const origins = originsForFile(m, clean3).map((c) => ({
|
|
61059
61104
|
...commitRow(c),
|
|
61060
61105
|
fixes: c.blamedBy.map((s) => m.bySha.get(s)).filter((x) => !!x).map((x) => ({ ...commitRow(x), daysLater: Math.round((x.at - c.at) / 864e5) }))
|
|
61061
61106
|
}));
|
|
61062
61107
|
return {
|
|
61063
61108
|
git: true,
|
|
61064
|
-
path:
|
|
61109
|
+
path: clean3,
|
|
61065
61110
|
file: h ? fileRow(h) : null,
|
|
61066
61111
|
commits: commits.map(commitRow),
|
|
61067
61112
|
origins
|
|
@@ -61136,14 +61181,14 @@ function historyRiskPayload(ctx, paths2) {
|
|
|
61136
61181
|
git: true,
|
|
61137
61182
|
source: paths2?.length ? "paths" : "working tree",
|
|
61138
61183
|
files: list2.map((p2) => {
|
|
61139
|
-
const
|
|
61140
|
-
const h = m.files.get(
|
|
61141
|
-
const commits = commitsForFile(m,
|
|
61184
|
+
const clean3 = p2.replace(/^\.\//, "");
|
|
61185
|
+
const h = m.files.get(clean3);
|
|
61186
|
+
const commits = commitsForFile(m, clean3);
|
|
61142
61187
|
return {
|
|
61143
|
-
path:
|
|
61188
|
+
path: clean3,
|
|
61144
61189
|
file: h ? fileRow(h) : null,
|
|
61145
61190
|
lastFix: commits.find((c) => c.kind === "fix")?.subject ?? null,
|
|
61146
|
-
origins: originsForFile(m,
|
|
61191
|
+
origins: originsForFile(m, clean3).slice(0, 3).map(commitRow)
|
|
61147
61192
|
};
|
|
61148
61193
|
})
|
|
61149
61194
|
};
|
|
@@ -61886,9 +61931,996 @@ var init_knowledge_api = __esm({
|
|
|
61886
61931
|
}
|
|
61887
61932
|
});
|
|
61888
61933
|
|
|
61934
|
+
// src/swarm/edit.ts
|
|
61935
|
+
import { createHash as createHash13 } from "crypto";
|
|
61936
|
+
import { readFileSync as readFileSync29 } from "fs";
|
|
61937
|
+
import { createRequire as createRequire6 } from "module";
|
|
61938
|
+
function yaml3() {
|
|
61939
|
+
yamlLib3 ??= createRequire6(import.meta.url)("yaml");
|
|
61940
|
+
return yamlLib3;
|
|
61941
|
+
}
|
|
61942
|
+
function hashText2(text3) {
|
|
61943
|
+
return createHash13("sha256").update(text3, "utf8").digest("hex");
|
|
61944
|
+
}
|
|
61945
|
+
function deepEqual(a, b) {
|
|
61946
|
+
if (a === b || typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b))
|
|
61947
|
+
return true;
|
|
61948
|
+
if (Array.isArray(a))
|
|
61949
|
+
return Array.isArray(b) && a.length === b.length && a.every((x, i) => deepEqual(x, b[i]));
|
|
61950
|
+
if (isPlain(a) && isPlain(b)) {
|
|
61951
|
+
const ka = Object.keys(a);
|
|
61952
|
+
return ka.length === Object.keys(b).length && ka.every((k) => Object.hasOwn(b, k) && deepEqual(a[k], b[k]));
|
|
61953
|
+
}
|
|
61954
|
+
return false;
|
|
61955
|
+
}
|
|
61956
|
+
function clean2(value, depth = 0) {
|
|
61957
|
+
if (depth > 64) throw new Error("the draft is nested too deeply");
|
|
61958
|
+
if (Array.isArray(value)) return value.map((v) => clean2(v, depth + 1));
|
|
61959
|
+
if (isPlain(value)) {
|
|
61960
|
+
const out = {};
|
|
61961
|
+
for (const [k, v] of Object.entries(value)) {
|
|
61962
|
+
if (v === void 0) continue;
|
|
61963
|
+
Object.defineProperty(out, k, {
|
|
61964
|
+
value: clean2(v, depth + 1),
|
|
61965
|
+
enumerable: true,
|
|
61966
|
+
writable: true,
|
|
61967
|
+
configurable: true
|
|
61968
|
+
});
|
|
61969
|
+
}
|
|
61970
|
+
return out;
|
|
61971
|
+
}
|
|
61972
|
+
if (typeof value === "number" && !Number.isFinite(value)) throw new Error("not a finite number");
|
|
61973
|
+
if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint")
|
|
61974
|
+
throw new Error(`a ${typeof value} cannot be written to YAML`);
|
|
61975
|
+
return value;
|
|
61976
|
+
}
|
|
61977
|
+
function starterDoc() {
|
|
61978
|
+
const doc = yaml3().parseDocument(STARTER_YAML, { uniqueKeys: true, merge: true });
|
|
61979
|
+
return doc.toJS({ maxAliasCount: 200 });
|
|
61980
|
+
}
|
|
61981
|
+
function readSwarmDoc(root) {
|
|
61982
|
+
const { file: file3, rel, exists } = swarmFile(root);
|
|
61983
|
+
const base = { file: file3, rel };
|
|
61984
|
+
if (!exists)
|
|
61985
|
+
return { ...base, state: "absent", text: null, hash: null, doc: null, issues: [], locked: [] };
|
|
61986
|
+
let bytes;
|
|
61987
|
+
try {
|
|
61988
|
+
bytes = readFileSync29(file3);
|
|
61989
|
+
} catch (err) {
|
|
61990
|
+
return {
|
|
61991
|
+
...base,
|
|
61992
|
+
state: "invalid",
|
|
61993
|
+
text: null,
|
|
61994
|
+
hash: null,
|
|
61995
|
+
doc: null,
|
|
61996
|
+
issues: [{ path: "", message: `cannot read ${rel}: ${err.message}` }],
|
|
61997
|
+
locked: []
|
|
61998
|
+
};
|
|
61999
|
+
}
|
|
62000
|
+
const text3 = bytes.toString("utf8");
|
|
62001
|
+
const hash2 = createHash13("sha256").update(bytes).digest("hex");
|
|
62002
|
+
const result = parseSwarmYaml(text3, file3, rel);
|
|
62003
|
+
const issues = result.state === "invalid" ? result.issues : [];
|
|
62004
|
+
const state = result.state === "ok" ? "ok" : "invalid";
|
|
62005
|
+
if (text3.length > SWARM_FILE_MAX_CHARS)
|
|
62006
|
+
return { ...base, state, text: text3, hash: hash2, doc: null, issues, locked: [] };
|
|
62007
|
+
const Y = yaml3();
|
|
62008
|
+
const parsed = Y.parseDocument(text3, { uniqueKeys: true, merge: true });
|
|
62009
|
+
let doc = null;
|
|
62010
|
+
let locked = [];
|
|
62011
|
+
if (!parsed.errors.length) {
|
|
62012
|
+
try {
|
|
62013
|
+
const js = parsed.toJS({ maxAliasCount: 200 });
|
|
62014
|
+
if (isPlain(js)) {
|
|
62015
|
+
doc = js;
|
|
62016
|
+
locked = collectLocked(Y, parsed).map((p2) => p2.join("."));
|
|
62017
|
+
}
|
|
62018
|
+
} catch {
|
|
62019
|
+
}
|
|
62020
|
+
}
|
|
62021
|
+
return { ...base, state, text: text3, hash: hash2, doc, issues, locked };
|
|
62022
|
+
}
|
|
62023
|
+
function checkSwarmText(text3, opts = {}) {
|
|
62024
|
+
const rel = opts.rel ?? SWARM_FILES[0];
|
|
62025
|
+
const result = parseSwarmYaml(text3, opts.file ?? rel, rel);
|
|
62026
|
+
const parsed = result.state === "ok" ? result.config.enforce && result.config.enabled : result.state === "invalid" ? result.enforce : void 0;
|
|
62027
|
+
return { result, enforceOk: parsed === void 0 || parsed === enforceIntent(text3) };
|
|
62028
|
+
}
|
|
62029
|
+
function mergedKeys(Y, doc, value) {
|
|
62030
|
+
const sources = Y.isSeq(value) ? value.items : [value];
|
|
62031
|
+
const keys = [];
|
|
62032
|
+
for (const src of sources) {
|
|
62033
|
+
const m = Y.isAlias(src) ? src.resolve(doc) : src;
|
|
62034
|
+
if (Y.isMap(m)) {
|
|
62035
|
+
for (const p2 of m.items) if (!isMergePair(p2)) keys.push(keyText(p2));
|
|
62036
|
+
}
|
|
62037
|
+
}
|
|
62038
|
+
return keys;
|
|
62039
|
+
}
|
|
62040
|
+
function collectLocked(Y, doc) {
|
|
62041
|
+
const out = [];
|
|
62042
|
+
const walk4 = (node2, path3) => {
|
|
62043
|
+
if (Y.isAlias(node2)) {
|
|
62044
|
+
out.push(path3);
|
|
62045
|
+
return;
|
|
62046
|
+
}
|
|
62047
|
+
if (!Y.isNode(node2)) return;
|
|
62048
|
+
if (node2.anchor) out.push(path3);
|
|
62049
|
+
if (Y.isMap(node2)) {
|
|
62050
|
+
const explicit = new Set(node2.items.filter((p2) => !isMergePair(p2)).map(keyText));
|
|
62051
|
+
for (const p2 of node2.items) {
|
|
62052
|
+
if (isMergePair(p2)) {
|
|
62053
|
+
out.push([...path3, "<<"]);
|
|
62054
|
+
for (const k2 of mergedKeys(Y, doc, p2.value)) if (!explicit.has(k2)) out.push([...path3, k2]);
|
|
62055
|
+
continue;
|
|
62056
|
+
}
|
|
62057
|
+
const k = keyText(p2);
|
|
62058
|
+
const child = [...path3, k];
|
|
62059
|
+
const hooks = path3.length === 4 && path3[0] === "swarms" && path3[2] === "agents";
|
|
62060
|
+
if (path3.length === 0 && k.startsWith("x-") || hooks && k === "hooks") {
|
|
62061
|
+
out.push(child);
|
|
62062
|
+
continue;
|
|
62063
|
+
}
|
|
62064
|
+
walk4(p2.value, child);
|
|
62065
|
+
}
|
|
62066
|
+
} else if (Y.isSeq(node2)) {
|
|
62067
|
+
node2.items.forEach((it, i) => {
|
|
62068
|
+
walk4(it, [...path3, String(i)]);
|
|
62069
|
+
});
|
|
62070
|
+
}
|
|
62071
|
+
};
|
|
62072
|
+
walk4(doc.contents, []);
|
|
62073
|
+
return out;
|
|
62074
|
+
}
|
|
62075
|
+
function orderOf(path3) {
|
|
62076
|
+
const last = path3[path3.length - 1];
|
|
62077
|
+
if (path3.length === 0) return TOP_ORDER;
|
|
62078
|
+
if (last === "context") return CONTEXT_ORDER;
|
|
62079
|
+
if (last === "model_range") return RANGE_ORDER;
|
|
62080
|
+
if (path3.length === 1 && path3[0] === "defaults") return DEFAULTS_ORDER;
|
|
62081
|
+
if (path3.length === 2 && path3[0] === "swarms") return SWARM_ORDER;
|
|
62082
|
+
if (path3.length === 4 && path3[0] === "swarms" && path3[2] === "agents") return ROLE_ORDER;
|
|
62083
|
+
return void 0;
|
|
62084
|
+
}
|
|
62085
|
+
function prefersFlow(items2) {
|
|
62086
|
+
return items2.length <= 6 && items2.every(
|
|
62087
|
+
(v) => typeof v === "number" || typeof v === "boolean" || typeof v === "string" && v.length <= 40 && !v.includes("\n")
|
|
62088
|
+
);
|
|
62089
|
+
}
|
|
62090
|
+
function renderText(baseText, draft, renames) {
|
|
62091
|
+
const Y = yaml3();
|
|
62092
|
+
const base = baseText ?? STARTER_YAML;
|
|
62093
|
+
const bom = base.startsWith("\uFEFF");
|
|
62094
|
+
const body = bom ? base.slice(1) : base;
|
|
62095
|
+
const crlfCount = (body.match(/\r\n/g) ?? []).length;
|
|
62096
|
+
const crlf = crlfCount > 0 && crlfCount * 2 >= (body.match(/\n/g) ?? []).length;
|
|
62097
|
+
const doc = Y.parseDocument(body, { uniqueKeys: true, merge: true });
|
|
62098
|
+
if (doc.errors.length)
|
|
62099
|
+
throw new RenderFail(
|
|
62100
|
+
"yaml",
|
|
62101
|
+
`the file is not valid YAML (${doc.errors[0]?.message.split("\n")[0] ?? "parse error"}); edit it in raw mode`
|
|
62102
|
+
);
|
|
62103
|
+
if (!Y.isMap(doc.contents))
|
|
62104
|
+
throw new RenderFail("yaml", "the file is not a mapping; edit it in raw mode");
|
|
62105
|
+
let target2;
|
|
62106
|
+
try {
|
|
62107
|
+
target2 = clean2(draft);
|
|
62108
|
+
} catch (err) {
|
|
62109
|
+
throw new RenderFail("mismatch", err.message);
|
|
62110
|
+
}
|
|
62111
|
+
if (!isPlain(target2)) throw new RenderFail("mismatch", "the draft is not a mapping");
|
|
62112
|
+
for (const r of renames) applyRename(Y, doc, r);
|
|
62113
|
+
let before;
|
|
62114
|
+
try {
|
|
62115
|
+
before = doc.toJS({ maxAliasCount: 200 });
|
|
62116
|
+
} catch (err) {
|
|
62117
|
+
throw new RenderFail("yaml", `the file cannot be read: ${err.message}`);
|
|
62118
|
+
}
|
|
62119
|
+
restoreNonFinite(before, target2);
|
|
62120
|
+
if (!renames.length && deepEqual(before, target2))
|
|
62121
|
+
return { text: base, changed: baseText === null };
|
|
62122
|
+
const locked = collectLocked(Y, doc);
|
|
62123
|
+
const ctx = { Y, doc, locked };
|
|
62124
|
+
let text3 = renames.length ? null : spliceScalars(ctx, body, before, target2);
|
|
62125
|
+
if (text3 === null) {
|
|
62126
|
+
applyDiff(ctx, [], before, target2);
|
|
62127
|
+
text3 = doc.toString({ lineWidth: 0, flowCollectionPadding: false });
|
|
62128
|
+
if (!text3.endsWith("\n")) text3 += "\n";
|
|
62129
|
+
if (crlf) text3 = text3.replace(/\r?\n/g, "\r\n");
|
|
62130
|
+
}
|
|
62131
|
+
if (bom) text3 = `\uFEFF${text3}`;
|
|
62132
|
+
const again = Y.parseDocument(bom ? text3.slice(1) : text3, { uniqueKeys: true, merge: true });
|
|
62133
|
+
let after;
|
|
62134
|
+
try {
|
|
62135
|
+
after = again.errors.length ? void 0 : again.toJS({ maxAliasCount: 200 });
|
|
62136
|
+
} catch {
|
|
62137
|
+
after = void 0;
|
|
62138
|
+
}
|
|
62139
|
+
if (!deepEqual(after, target2))
|
|
62140
|
+
throw new RenderFail(
|
|
62141
|
+
"mismatch",
|
|
62142
|
+
"the edit could not be written without changing something else (an alias or merge key in the file?); edit it in raw mode",
|
|
62143
|
+
locked.map((p2) => p2.join("."))
|
|
62144
|
+
);
|
|
62145
|
+
return { text: text3, changed: text3 !== baseText };
|
|
62146
|
+
}
|
|
62147
|
+
function renderSwarmDoc(baseText, draft, renames = [], opts = {}) {
|
|
62148
|
+
let rendered;
|
|
62149
|
+
try {
|
|
62150
|
+
rendered = renderText(baseText, draft, renames);
|
|
62151
|
+
} catch (err) {
|
|
62152
|
+
if (err instanceof RenderFail)
|
|
62153
|
+
return {
|
|
62154
|
+
ok: false,
|
|
62155
|
+
code: err.code,
|
|
62156
|
+
error: err.message,
|
|
62157
|
+
...err.locked ? { locked: err.locked } : {}
|
|
62158
|
+
};
|
|
62159
|
+
throw err;
|
|
62160
|
+
}
|
|
62161
|
+
const { result, enforceOk } = checkSwarmText(rendered.text, opts);
|
|
62162
|
+
if (!enforceOk)
|
|
62163
|
+
return {
|
|
62164
|
+
ok: false,
|
|
62165
|
+
code: "enforce",
|
|
62166
|
+
error: "the enforce setting is not on a plain top-level `enforce:` line, so the shell hook would read it differently; edit it in raw mode"
|
|
62167
|
+
};
|
|
62168
|
+
return { ok: true, text: rendered.text, result, changed: rendered.changed };
|
|
62169
|
+
}
|
|
62170
|
+
function spliceScalars(ctx, body, oldV, newV) {
|
|
62171
|
+
const { Y, doc } = ctx;
|
|
62172
|
+
const edits = [];
|
|
62173
|
+
const walk4 = (path3, a, b) => {
|
|
62174
|
+
if (deepEqual(a, b)) return true;
|
|
62175
|
+
if (isPlain(a) && isPlain(b)) {
|
|
62176
|
+
const ka = Object.keys(a);
|
|
62177
|
+
if (ka.length !== Object.keys(b).length) return false;
|
|
62178
|
+
return ka.every((k) => Object.hasOwn(b, k) && walk4([...path3, k], a[k], b[k]));
|
|
62179
|
+
}
|
|
62180
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
62181
|
+
if (a.length !== b.length) return false;
|
|
62182
|
+
return a.every((x, i) => {
|
|
62183
|
+
const y = b[i];
|
|
62184
|
+
if (!deepEqual(x, y) && isScalarValue(x) && isScalarValue(y)) {
|
|
62185
|
+
if (b.some((v) => deepEqual(v, x)) || a.some((v) => deepEqual(v, y))) return false;
|
|
62186
|
+
}
|
|
62187
|
+
return walk4([...path3, String(i)], x, y);
|
|
62188
|
+
});
|
|
62189
|
+
}
|
|
62190
|
+
if (!isScalarValue(a) || !isScalarValue(b) || a === null || b === null) return false;
|
|
62191
|
+
if (lockedAt(ctx, path3)) return false;
|
|
62192
|
+
const node2 = nodeAt(Y, doc, path3);
|
|
62193
|
+
if (!Y.isScalar(node2) || !node2.range || node2.anchor) return false;
|
|
62194
|
+
if (node2.type === "BLOCK_LITERAL" || node2.type === "BLOCK_FOLDED") return false;
|
|
62195
|
+
if (typeof b === "string" && (b.includes("\n") || b.includes("\r"))) return false;
|
|
62196
|
+
if (typeof b === "string" && node2.type === "PLAIN" && /[,[\]{}]/.test(b)) return false;
|
|
62197
|
+
const [start, end] = node2.range;
|
|
62198
|
+
if (end <= start) return false;
|
|
62199
|
+
const fresh = new Y.Scalar(b);
|
|
62200
|
+
if (typeof b === "string" && node2.type && node2.type !== "PLAIN") fresh.type = node2.type;
|
|
62201
|
+
const text3 = new Y.Document(fresh).toString({ lineWidth: 0 }).replace(/\r?\n$/, "");
|
|
62202
|
+
if (text3.includes("\n")) return false;
|
|
62203
|
+
edits.push({ start, end, text: text3 });
|
|
62204
|
+
return true;
|
|
62205
|
+
};
|
|
62206
|
+
if (!walk4([], oldV, newV) || !edits.length) return null;
|
|
62207
|
+
let out = body;
|
|
62208
|
+
for (const e of edits.sort((x, y) => y.start - x.start))
|
|
62209
|
+
out = out.slice(0, e.start) + e.text + out.slice(e.end);
|
|
62210
|
+
return out;
|
|
62211
|
+
}
|
|
62212
|
+
function lockedFail(ctx, path3) {
|
|
62213
|
+
return new RenderFail(
|
|
62214
|
+
"locked",
|
|
62215
|
+
`${path3.join(".") || "the file"} is read-only here (an alias, anchor, merge key, x-* key or hooks); edit it in raw mode`,
|
|
62216
|
+
ctx.locked.map((p2) => p2.join("."))
|
|
62217
|
+
);
|
|
62218
|
+
}
|
|
62219
|
+
function findPair(Y, map2, name) {
|
|
62220
|
+
for (let i = map2.items.length - 1; i >= 0; i--) {
|
|
62221
|
+
const p2 = map2.items[i];
|
|
62222
|
+
if (Y.isScalar(p2.key) && String(p2.key.value) === name) return p2;
|
|
62223
|
+
}
|
|
62224
|
+
return void 0;
|
|
62225
|
+
}
|
|
62226
|
+
function nodeAt(Y, doc, path3) {
|
|
62227
|
+
let node2 = doc.contents;
|
|
62228
|
+
for (const seg of path3) {
|
|
62229
|
+
if (Y.isMap(node2)) {
|
|
62230
|
+
const pair = findPair(Y, node2, seg);
|
|
62231
|
+
if (!pair) return void 0;
|
|
62232
|
+
node2 = pair.value;
|
|
62233
|
+
} else if (Y.isSeq(node2)) {
|
|
62234
|
+
node2 = node2.items[Number(seg)];
|
|
62235
|
+
} else return void 0;
|
|
62236
|
+
}
|
|
62237
|
+
return node2;
|
|
62238
|
+
}
|
|
62239
|
+
function deleteAt(ctx, path3) {
|
|
62240
|
+
const { Y, doc } = ctx;
|
|
62241
|
+
const parent = nodeAt(Y, doc, path3.slice(0, -1));
|
|
62242
|
+
const last = path3[path3.length - 1];
|
|
62243
|
+
if (Y.isMap(parent)) {
|
|
62244
|
+
const pair = findPair(Y, parent, last);
|
|
62245
|
+
if (pair) parent.items.splice(parent.items.indexOf(pair), 1);
|
|
62246
|
+
} else if (Y.isSeq(parent)) parent.items.splice(Number(last), 1);
|
|
62247
|
+
}
|
|
62248
|
+
function setAt(ctx, path3, value) {
|
|
62249
|
+
const { Y, doc } = ctx;
|
|
62250
|
+
const parent = nodeAt(Y, doc, path3.slice(0, -1));
|
|
62251
|
+
const last = path3[path3.length - 1];
|
|
62252
|
+
if (Y.isMap(parent)) {
|
|
62253
|
+
const pair = findPair(Y, parent, last);
|
|
62254
|
+
if (pair) pair.value = value;
|
|
62255
|
+
else parent.items.push(new Y.Pair(new Y.Scalar(last), value));
|
|
62256
|
+
} else if (Y.isSeq(parent)) parent.items[Number(last)] = value;
|
|
62257
|
+
else throw new RenderFail("mismatch", `${path3.join(".")} is not inside a mapping or list`);
|
|
62258
|
+
}
|
|
62259
|
+
function restoreNonFinite(before, target2) {
|
|
62260
|
+
if (Array.isArray(before) && Array.isArray(target2)) {
|
|
62261
|
+
before.forEach((b, i) => {
|
|
62262
|
+
if (typeof b === "number" && !Number.isFinite(b) && target2[i] === null) target2[i] = b;
|
|
62263
|
+
else restoreNonFinite(b, target2[i]);
|
|
62264
|
+
});
|
|
62265
|
+
} else if (isPlain(before) && isPlain(target2)) {
|
|
62266
|
+
for (const [k, b] of Object.entries(before)) {
|
|
62267
|
+
if (!Object.hasOwn(target2, k)) continue;
|
|
62268
|
+
if (typeof b === "number" && !Number.isFinite(b) && target2[k] === null) target2[k] = b;
|
|
62269
|
+
else restoreNonFinite(b, target2[k]);
|
|
62270
|
+
}
|
|
62271
|
+
}
|
|
62272
|
+
}
|
|
62273
|
+
function applyRename(Y, doc, r) {
|
|
62274
|
+
const fail3 = (msg) => new RenderFail("rename", msg);
|
|
62275
|
+
const swarms = doc.get("swarms", true);
|
|
62276
|
+
if (!Y.isMap(swarms)) throw fail3("the file has no swarms to rename");
|
|
62277
|
+
const rename2 = (map2, from, to, what) => {
|
|
62278
|
+
if (!to) throw fail3(`the new ${what} name is empty`);
|
|
62279
|
+
const pair = findPair(Y, map2, from);
|
|
62280
|
+
if (!pair || !Y.isScalar(pair.key)) throw fail3(`there is no ${what} "${from}" to rename`);
|
|
62281
|
+
if (from === to) return;
|
|
62282
|
+
if (findPair(Y, map2, to)) throw fail3(`a ${what} named "${to}" already exists`);
|
|
62283
|
+
pair.key.value = to;
|
|
62284
|
+
};
|
|
62285
|
+
if (r.role === void 0) {
|
|
62286
|
+
rename2(swarms, r.swarm, r.to, "swarm");
|
|
62287
|
+
return;
|
|
62288
|
+
}
|
|
62289
|
+
const swarm = findPair(Y, swarms, r.swarm)?.value;
|
|
62290
|
+
const agents = Y.isMap(swarm) ? findPair(Y, swarm, "agents")?.value : void 0;
|
|
62291
|
+
if (!Y.isMap(swarm) || !Y.isMap(agents)) throw fail3(`there is no swarm "${r.swarm}" with agents`);
|
|
62292
|
+
rename2(agents, r.role, r.to, "agent");
|
|
62293
|
+
const stages = findPair(Y, swarm, "stages")?.value;
|
|
62294
|
+
if (Y.isSeq(stages)) {
|
|
62295
|
+
for (const it of stages.items)
|
|
62296
|
+
if (Y.isScalar(it) && it.value === r.role) it.value = r.to;
|
|
62297
|
+
}
|
|
62298
|
+
}
|
|
62299
|
+
function build(ctx, value, path3) {
|
|
62300
|
+
const { Y } = ctx;
|
|
62301
|
+
if (Array.isArray(value)) {
|
|
62302
|
+
const seq = new Y.YAMLSeq();
|
|
62303
|
+
seq.items = value.map((v, i) => build(ctx, v, [...path3, String(i)]));
|
|
62304
|
+
if (prefersFlow(value)) seq.flow = true;
|
|
62305
|
+
return seq;
|
|
62306
|
+
}
|
|
62307
|
+
if (isPlain(value)) {
|
|
62308
|
+
const map2 = new Y.YAMLMap();
|
|
62309
|
+
const order = orderOf(path3) ?? [];
|
|
62310
|
+
const keys = Object.keys(value);
|
|
62311
|
+
const rank2 = (k) => {
|
|
62312
|
+
const i = order.indexOf(k);
|
|
62313
|
+
return i < 0 ? order.length : i;
|
|
62314
|
+
};
|
|
62315
|
+
keys.sort((a, b) => rank2(a) - rank2(b));
|
|
62316
|
+
for (const k of keys)
|
|
62317
|
+
map2.items.push(new Y.Pair(new Y.Scalar(k), build(ctx, value[k], [...path3, k])));
|
|
62318
|
+
return map2;
|
|
62319
|
+
}
|
|
62320
|
+
const s = new Y.Scalar(value);
|
|
62321
|
+
if (typeof value === "string" && value.includes("\n")) s.type = "BLOCK_LITERAL";
|
|
62322
|
+
return s;
|
|
62323
|
+
}
|
|
62324
|
+
function inherit(from, to) {
|
|
62325
|
+
if (!from || !to || typeof from !== "object" || typeof to !== "object") return;
|
|
62326
|
+
const f = from;
|
|
62327
|
+
const t = to;
|
|
62328
|
+
if (f.comment !== void 0) t.comment = f.comment;
|
|
62329
|
+
if (f.commentBefore !== void 0) t.commentBefore = f.commentBefore;
|
|
62330
|
+
if (f.spaceBefore !== void 0) t.spaceBefore = f.spaceBefore;
|
|
62331
|
+
}
|
|
62332
|
+
function insertPair(ctx, map2, path3, pair) {
|
|
62333
|
+
const order = orderOf(path3);
|
|
62334
|
+
const rank2 = (k) => order?.indexOf(k) ?? -1;
|
|
62335
|
+
const at = rank2(keyText(pair));
|
|
62336
|
+
let index = map2.items.length;
|
|
62337
|
+
if (order && at >= 0) {
|
|
62338
|
+
const i = map2.items.findIndex((p2) => !isMergePair(p2) && rank2(keyText(p2)) > at);
|
|
62339
|
+
if (i >= 0) index = i;
|
|
62340
|
+
}
|
|
62341
|
+
if (path3.length === 1 && path3[0] === "swarms" && map2.items.length)
|
|
62342
|
+
pair.key.spaceBefore = true;
|
|
62343
|
+
map2.items.splice(index, 0, pair);
|
|
62344
|
+
void ctx;
|
|
62345
|
+
}
|
|
62346
|
+
function applyDiff(ctx, path3, oldV, newV) {
|
|
62347
|
+
const { Y, doc } = ctx;
|
|
62348
|
+
if (deepEqual(oldV, newV)) return;
|
|
62349
|
+
if (lockedAt(ctx, path3)) throw lockedFail(ctx, path3);
|
|
62350
|
+
if (isPlain(oldV) && isPlain(newV)) {
|
|
62351
|
+
const node3 = path3.length ? nodeAt(Y, doc, path3) : doc.contents;
|
|
62352
|
+
if (!Y.isMap(node3))
|
|
62353
|
+
throw new RenderFail("mismatch", `${path3.join(".") || "the file"} is not a plain mapping`);
|
|
62354
|
+
for (const k of Object.keys(oldV)) {
|
|
62355
|
+
if (Object.hasOwn(newV, k)) continue;
|
|
62356
|
+
const child = [...path3, k];
|
|
62357
|
+
if (lockedAt(ctx, child) || lockedBelow(ctx, child)) throw lockedFail(ctx, child);
|
|
62358
|
+
deleteAt(ctx, child);
|
|
62359
|
+
}
|
|
62360
|
+
for (const k of Object.keys(newV)) {
|
|
62361
|
+
const child = [...path3, k];
|
|
62362
|
+
if (Object.hasOwn(oldV, k)) {
|
|
62363
|
+
applyDiff(ctx, child, oldV[k], newV[k]);
|
|
62364
|
+
continue;
|
|
62365
|
+
}
|
|
62366
|
+
if (k === "<<" || path3.length === 0 && k.startsWith("x-")) throw lockedFail(ctx, child);
|
|
62367
|
+
if (!node3.items.length && node3.flow && !["context", "model_range"].includes(k))
|
|
62368
|
+
node3.flow = false;
|
|
62369
|
+
const pair = new Y.Pair(new Y.Scalar(k), build(ctx, newV[k], child));
|
|
62370
|
+
insertPair(ctx, node3, path3, pair);
|
|
62371
|
+
}
|
|
62372
|
+
return;
|
|
62373
|
+
}
|
|
62374
|
+
if (lockedBelow(ctx, path3)) throw lockedFail(ctx, path3);
|
|
62375
|
+
const old = nodeAt(Y, doc, path3);
|
|
62376
|
+
if (Array.isArray(newV)) {
|
|
62377
|
+
const oldSeq = Y.isSeq(old) ? old : void 0;
|
|
62378
|
+
const pool = oldSeq ? [...oldSeq.items] : [];
|
|
62379
|
+
const seq = new Y.YAMLSeq();
|
|
62380
|
+
seq.items = newV.map((v, i) => {
|
|
62381
|
+
if (isScalarValue(v)) {
|
|
62382
|
+
const j = pool.findIndex((it) => Y.isScalar(it) && it.value === v);
|
|
62383
|
+
if (j >= 0) return pool.splice(j, 1)[0];
|
|
62384
|
+
}
|
|
62385
|
+
return build(ctx, v, [...path3, String(i)]);
|
|
62386
|
+
});
|
|
62387
|
+
seq.flow = oldSeq ? oldSeq.flow === true : prefersFlow(newV);
|
|
62388
|
+
inherit(oldSeq, seq);
|
|
62389
|
+
setAt(ctx, path3, seq);
|
|
62390
|
+
return;
|
|
62391
|
+
}
|
|
62392
|
+
if (isScalarValue(newV) && Y.isScalar(old)) {
|
|
62393
|
+
const node3 = old;
|
|
62394
|
+
node3.value = newV;
|
|
62395
|
+
if (typeof newV !== "string") delete node3.type;
|
|
62396
|
+
else if (newV.includes("\n") && node3.type !== "BLOCK_LITERAL" && node3.type !== "BLOCK_FOLDED")
|
|
62397
|
+
node3.type = "BLOCK_LITERAL";
|
|
62398
|
+
return;
|
|
62399
|
+
}
|
|
62400
|
+
const node2 = build(ctx, newV, path3);
|
|
62401
|
+
inherit(old, node2);
|
|
62402
|
+
setAt(ctx, path3, node2);
|
|
62403
|
+
}
|
|
62404
|
+
function docWarnings(doc, activeRuns = [], prev) {
|
|
62405
|
+
const out = [];
|
|
62406
|
+
const swarms = isPlain(doc.swarms) ? doc.swarms : {};
|
|
62407
|
+
for (const [name, s] of Object.entries(swarms)) {
|
|
62408
|
+
if (!isPlain(s)) continue;
|
|
62409
|
+
const agents = isPlain(s.agents) ? s.agents : {};
|
|
62410
|
+
const roles = Object.entries(agents).filter(([, r]) => isPlain(r));
|
|
62411
|
+
const max = typeof s.max_agents === "number" ? s.max_agents : DEFAULT_MAX_AGENTS;
|
|
62412
|
+
const total = roles.reduce((n, [, r]) => n + (typeof r.count === "number" ? r.count : 1), 0);
|
|
62413
|
+
if (total > max)
|
|
62414
|
+
out.push({
|
|
62415
|
+
path: `swarms.${name}.max_agents`,
|
|
62416
|
+
kind: "capacity",
|
|
62417
|
+
message: `${total} workers are configured (the counts add up) but max_agents is ${max}, so at most ${max} run at once`
|
|
62418
|
+
});
|
|
62419
|
+
const stages = Array.isArray(s.stages) ? s.stages : [];
|
|
62420
|
+
if (s.topology === "pipeline" && stages.length) {
|
|
62421
|
+
const missing = roles.map(([r]) => r).filter((r) => !stages.includes(r));
|
|
62422
|
+
if (missing.length)
|
|
62423
|
+
out.push({
|
|
62424
|
+
path: `swarms.${name}.stages`,
|
|
62425
|
+
kind: "stages",
|
|
62426
|
+
message: `${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} not listed in stages`
|
|
62427
|
+
});
|
|
62428
|
+
}
|
|
62429
|
+
for (const [role, r] of roles) {
|
|
62430
|
+
const prompt = typeof r.prompt === "string" ? r.prompt.trim() : "";
|
|
62431
|
+
if (!prompt)
|
|
62432
|
+
out.push({
|
|
62433
|
+
path: `swarms.${name}.agents.${role}.prompt`,
|
|
62434
|
+
kind: "prompt",
|
|
62435
|
+
message: "has no prompt; add one to tell the worker how to work"
|
|
62436
|
+
});
|
|
62437
|
+
else if (prompt.length > PROMPT_MAX * 0.8)
|
|
62438
|
+
out.push({
|
|
62439
|
+
path: `swarms.${name}.agents.${role}.prompt`,
|
|
62440
|
+
kind: "prompt",
|
|
62441
|
+
message: `is ${prompt.length} characters, close to the ${PROMPT_MAX.toLocaleString("en-US")} limit`
|
|
62442
|
+
});
|
|
62443
|
+
}
|
|
62444
|
+
}
|
|
62445
|
+
const prevSwarms = prev && isPlain(prev.swarms) ? prev.swarms : {};
|
|
62446
|
+
for (const run3 of activeRuns) {
|
|
62447
|
+
const now = swarms[run3.swarm];
|
|
62448
|
+
if (!isPlain(now)) {
|
|
62449
|
+
out.push({
|
|
62450
|
+
path: `swarms.${run3.swarm}`,
|
|
62451
|
+
kind: "active-run",
|
|
62452
|
+
message: `run ${run3.id} is using the swarm "${run3.swarm}", which this draft removes or renames`
|
|
62453
|
+
});
|
|
62454
|
+
continue;
|
|
62455
|
+
}
|
|
62456
|
+
const before = prevSwarms[run3.swarm];
|
|
62457
|
+
const was = isPlain(before) && isPlain(before.agents) ? Object.keys(before.agents) : [];
|
|
62458
|
+
const has = isPlain(now.agents) ? now.agents : {};
|
|
62459
|
+
for (const role of was)
|
|
62460
|
+
if (!Object.hasOwn(has, role))
|
|
62461
|
+
out.push({
|
|
62462
|
+
path: `swarms.${run3.swarm}.agents.${role}`,
|
|
62463
|
+
kind: "active-run",
|
|
62464
|
+
message: `run ${run3.id} uses the role "${role}", which this draft removes or renames`
|
|
62465
|
+
});
|
|
62466
|
+
}
|
|
62467
|
+
const enforcedBefore = !!prev && prev.enforce === true && prev.enabled !== false;
|
|
62468
|
+
if (doc.enforce === true && doc.enabled !== false && !enforcedBefore)
|
|
62469
|
+
out.push({
|
|
62470
|
+
path: "enforce",
|
|
62471
|
+
kind: "enforce",
|
|
62472
|
+
message: "with enforce on, only this file's swarm workers may run as subagents, and only during a run of their swarm (allowed_agents lists the exceptions)"
|
|
62473
|
+
});
|
|
62474
|
+
if (doc.enabled === false && prev !== null && !(prev && prev.enabled === false))
|
|
62475
|
+
out.push({
|
|
62476
|
+
path: "enabled",
|
|
62477
|
+
kind: "disable",
|
|
62478
|
+
message: "disabling swarms removes the generated agent files on the next sync"
|
|
62479
|
+
});
|
|
62480
|
+
return out;
|
|
62481
|
+
}
|
|
62482
|
+
function lineDiff(prev, next) {
|
|
62483
|
+
const a = prev.split(/\r?\n/);
|
|
62484
|
+
const b = next.split(/\r?\n/);
|
|
62485
|
+
let head2 = 0;
|
|
62486
|
+
while (head2 < a.length && head2 < b.length && a[head2] === b[head2]) head2++;
|
|
62487
|
+
let ea = a.length;
|
|
62488
|
+
let eb = b.length;
|
|
62489
|
+
while (ea > head2 && eb > head2 && a[ea - 1] === b[eb - 1]) {
|
|
62490
|
+
ea--;
|
|
62491
|
+
eb--;
|
|
62492
|
+
}
|
|
62493
|
+
const n = ea - head2;
|
|
62494
|
+
const m = eb - head2;
|
|
62495
|
+
const range = (from, to) => Array.from({ length: to - from }, (_, i2) => from + i2 + 1);
|
|
62496
|
+
if (!n && !m) return { changed: [], removed: 0 };
|
|
62497
|
+
if (!n || !m || a.length > DIFF_MAX_LINES || b.length > DIFF_MAX_LINES || n * m > DIFF_MAX_CELLS)
|
|
62498
|
+
return { changed: range(head2, eb), removed: n };
|
|
62499
|
+
const w = m + 1;
|
|
62500
|
+
const lcs = new Uint16Array((n + 1) * w);
|
|
62501
|
+
for (let i2 = n - 1; i2 >= 0; i2--)
|
|
62502
|
+
for (let j2 = m - 1; j2 >= 0; j2--)
|
|
62503
|
+
lcs[i2 * w + j2] = a[head2 + i2] === b[head2 + j2] ? lcs[(i2 + 1) * w + j2 + 1] + 1 : Math.max(lcs[(i2 + 1) * w + j2], lcs[i2 * w + j2 + 1]);
|
|
62504
|
+
const kept = /* @__PURE__ */ new Set();
|
|
62505
|
+
let i = 0;
|
|
62506
|
+
let j = 0;
|
|
62507
|
+
while (i < n && j < m) {
|
|
62508
|
+
if (a[head2 + i] === b[head2 + j]) {
|
|
62509
|
+
kept.add(j);
|
|
62510
|
+
i++;
|
|
62511
|
+
j++;
|
|
62512
|
+
} else if (lcs[(i + 1) * w + j] >= lcs[i * w + j + 1]) i++;
|
|
62513
|
+
else j++;
|
|
62514
|
+
}
|
|
62515
|
+
const changed = [];
|
|
62516
|
+
for (let k = 0; k < m; k++) if (!kept.has(k)) changed.push(head2 + k + 1);
|
|
62517
|
+
return { changed, removed: n - kept.size };
|
|
62518
|
+
}
|
|
62519
|
+
var yamlLib3, SWARM_FILE_MAX_CHARS, DEFAULT_MAX_AGENTS, PROMPT_MAX, isPlain, keyText, isMergePair, RenderFail, TOP_ORDER, DEFAULTS_ORDER, SWARM_ORDER, ROLE_ORDER, CONTEXT_ORDER, RANGE_ORDER, isScalarValue, startsWithPath, lockedAt, lockedBelow, DIFF_MAX_LINES, DIFF_MAX_CELLS;
|
|
62520
|
+
var init_edit = __esm({
|
|
62521
|
+
"src/swarm/edit.ts"() {
|
|
62522
|
+
"use strict";
|
|
62523
|
+
init_esm_shims();
|
|
62524
|
+
init_config2();
|
|
62525
|
+
SWARM_FILE_MAX_CHARS = 256e3;
|
|
62526
|
+
DEFAULT_MAX_AGENTS = 4;
|
|
62527
|
+
PROMPT_MAX = 2e4;
|
|
62528
|
+
isPlain = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
62529
|
+
keyText = (pair) => {
|
|
62530
|
+
const k = pair.key;
|
|
62531
|
+
return k && typeof k === "object" && "value" in k ? String(k.value) : String(pair.key);
|
|
62532
|
+
};
|
|
62533
|
+
isMergePair = (pair) => {
|
|
62534
|
+
const v = pair.key?.value;
|
|
62535
|
+
return v === "<<" || typeof v === "symbol" && v.description === "<<";
|
|
62536
|
+
};
|
|
62537
|
+
RenderFail = class extends Error {
|
|
62538
|
+
constructor(code2, message, locked) {
|
|
62539
|
+
super(message);
|
|
62540
|
+
this.code = code2;
|
|
62541
|
+
this.locked = locked;
|
|
62542
|
+
}
|
|
62543
|
+
code;
|
|
62544
|
+
locked;
|
|
62545
|
+
};
|
|
62546
|
+
TOP_ORDER = ["version", "enabled", "sync", "enforce", "allowed_agents", "defaults", "swarms"];
|
|
62547
|
+
DEFAULTS_ORDER = ["model", "model_range", "skills", "context"];
|
|
62548
|
+
SWARM_ORDER = [
|
|
62549
|
+
"description",
|
|
62550
|
+
"topology",
|
|
62551
|
+
"max_agents",
|
|
62552
|
+
"stages",
|
|
62553
|
+
"instructions",
|
|
62554
|
+
"context",
|
|
62555
|
+
"agents"
|
|
62556
|
+
];
|
|
62557
|
+
ROLE_ORDER = [
|
|
62558
|
+
"description",
|
|
62559
|
+
"model",
|
|
62560
|
+
"model_range",
|
|
62561
|
+
"effort",
|
|
62562
|
+
"color",
|
|
62563
|
+
"count",
|
|
62564
|
+
"max_turns",
|
|
62565
|
+
"isolation",
|
|
62566
|
+
"tools",
|
|
62567
|
+
"disallowed_tools",
|
|
62568
|
+
"skills",
|
|
62569
|
+
"scope",
|
|
62570
|
+
"memory_tags",
|
|
62571
|
+
"context",
|
|
62572
|
+
"hooks",
|
|
62573
|
+
"prompt"
|
|
62574
|
+
];
|
|
62575
|
+
CONTEXT_ORDER = ["memories", "docs", "history", "structure", "insights", "max_chars"];
|
|
62576
|
+
RANGE_ORDER = ["floor", "ceiling"];
|
|
62577
|
+
isScalarValue = (v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
62578
|
+
startsWithPath = (p2, prefix) => prefix.every((k, i) => p2[i] === k);
|
|
62579
|
+
lockedAt = (ctx, path3) => ctx.locked.some((l) => l.length <= path3.length && startsWithPath(path3, l));
|
|
62580
|
+
lockedBelow = (ctx, path3) => ctx.locked.some((l) => l.length > path3.length && startsWithPath(l, path3));
|
|
62581
|
+
DIFF_MAX_LINES = 3e3;
|
|
62582
|
+
DIFF_MAX_CELLS = 4e6;
|
|
62583
|
+
}
|
|
62584
|
+
});
|
|
62585
|
+
|
|
62586
|
+
// src/swarm/save.ts
|
|
62587
|
+
import { createHash as createHash14, randomBytes as randomBytes4 } from "crypto";
|
|
62588
|
+
import {
|
|
62589
|
+
closeSync as closeSync3,
|
|
62590
|
+
fsyncSync,
|
|
62591
|
+
linkSync as linkSync2,
|
|
62592
|
+
lstatSync as lstatSync3,
|
|
62593
|
+
mkdirSync as mkdirSync16,
|
|
62594
|
+
openSync as openSync3,
|
|
62595
|
+
readFileSync as readFileSync30,
|
|
62596
|
+
realpathSync as realpathSync7,
|
|
62597
|
+
renameSync as renameSync7,
|
|
62598
|
+
rmSync as rmSync8,
|
|
62599
|
+
statSync as statSync18,
|
|
62600
|
+
writeSync
|
|
62601
|
+
} from "fs";
|
|
62602
|
+
import { basename as basename8, dirname as dirname16, isAbsolute as isAbsolute6, relative as relative17, resolve as resolve13, sep as sep6 } from "path";
|
|
62603
|
+
function within2(child, parent) {
|
|
62604
|
+
const rel = relative17(parent, child);
|
|
62605
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep6}`) && !isAbsolute6(rel);
|
|
62606
|
+
}
|
|
62607
|
+
function locationProblem2(file3, root) {
|
|
62608
|
+
if (file3 === root || !within2(file3, root)) return "it is outside the project";
|
|
62609
|
+
let realRoot;
|
|
62610
|
+
try {
|
|
62611
|
+
realRoot = realpathSync7.native(root);
|
|
62612
|
+
} catch (err) {
|
|
62613
|
+
return `the project root could not be resolved (${err.code ?? err.message})`;
|
|
62614
|
+
}
|
|
62615
|
+
try {
|
|
62616
|
+
let dir = dirname16(file3);
|
|
62617
|
+
while (!lstatSync3(dir, { throwIfNoEntry: false }) && within2(dirname16(dir), root) && dir !== root)
|
|
62618
|
+
dir = dirname16(dir);
|
|
62619
|
+
if (!within2(realpathSync7.native(dir), realRoot))
|
|
62620
|
+
return "its folder resolves outside the project (a symlink)";
|
|
62621
|
+
const lst = lstatSync3(file3, { throwIfNoEntry: false });
|
|
62622
|
+
if (lst?.isSymbolicLink()) return "it is a symlink, and writes replace only a regular file";
|
|
62623
|
+
if (lst && !lst.isFile()) return "it is not a regular file";
|
|
62624
|
+
return void 0;
|
|
62625
|
+
} catch (err) {
|
|
62626
|
+
return `its location could not be resolved (${err.code ?? err.message})`;
|
|
62627
|
+
}
|
|
62628
|
+
}
|
|
62629
|
+
function writeAll(fd, buf) {
|
|
62630
|
+
let off = 0;
|
|
62631
|
+
while (off < buf.length) {
|
|
62632
|
+
const n = writeSync(fd, buf, off, buf.length - off);
|
|
62633
|
+
if (n <= 0) throw new Error("short write: the disk did not take the whole swarm file");
|
|
62634
|
+
off += n;
|
|
62635
|
+
}
|
|
62636
|
+
}
|
|
62637
|
+
function readCurrent(file3) {
|
|
62638
|
+
try {
|
|
62639
|
+
const bytes = readFileSync30(file3);
|
|
62640
|
+
return {
|
|
62641
|
+
text: bytes.toString("utf8"),
|
|
62642
|
+
hash: createHash14("sha256").update(bytes).digest("hex")
|
|
62643
|
+
};
|
|
62644
|
+
} catch (err) {
|
|
62645
|
+
if (err.code === "ENOENT") return null;
|
|
62646
|
+
throw err;
|
|
62647
|
+
}
|
|
62648
|
+
}
|
|
62649
|
+
function saveSwarmFile(root, text3, baseHash) {
|
|
62650
|
+
const projectRoot = resolve13(root);
|
|
62651
|
+
if (text3.length > SWARM_FILE_MAX_CHARS)
|
|
62652
|
+
throw new SwarmSaveInvalid([
|
|
62653
|
+
{ path: "", message: `the file is larger than ${SWARM_FILE_MAX_CHARS / 1e3} KB` }
|
|
62654
|
+
]);
|
|
62655
|
+
const { result, enforceOk } = checkSwarmText(text3);
|
|
62656
|
+
if (result.state === "invalid") throw new SwarmSaveInvalid(result.issues);
|
|
62657
|
+
if (!enforceOk)
|
|
62658
|
+
throw new SwarmSaveInvalid([
|
|
62659
|
+
{ path: "enforce", message: "enforce must be on a plain top-level `enforce:` line" }
|
|
62660
|
+
]);
|
|
62661
|
+
const { file: file3, rel } = swarmFile(projectRoot);
|
|
62662
|
+
const problem = locationProblem2(file3, projectRoot);
|
|
62663
|
+
if (problem) throw new SwarmSaveRefused(problem);
|
|
62664
|
+
const current = readCurrent(file3);
|
|
62665
|
+
if (baseHash === null) {
|
|
62666
|
+
if (current) throw new SwarmSaveConflict("exists", current);
|
|
62667
|
+
} else if (!current) {
|
|
62668
|
+
throw new SwarmSaveConflict("missing", null);
|
|
62669
|
+
} else if (current.hash !== baseHash) {
|
|
62670
|
+
throw new SwarmSaveConflict("changed", current);
|
|
62671
|
+
}
|
|
62672
|
+
const hash2 = hashText2(text3);
|
|
62673
|
+
if (current && current.hash === hash2) return { rel, hash: hash2, created: false };
|
|
62674
|
+
if (!current) mkdirSync16(dirname16(file3), { recursive: true });
|
|
62675
|
+
const again = locationProblem2(file3, projectRoot);
|
|
62676
|
+
if (again) throw new SwarmSaveRefused(again);
|
|
62677
|
+
const mode = current ? statSync18(file3).mode & 511 : 420;
|
|
62678
|
+
const tmp = resolve13(
|
|
62679
|
+
dirname16(file3),
|
|
62680
|
+
`.${basename8(file3)}.${process.pid}.${randomBytes4(4).toString("hex")}.tmp`
|
|
62681
|
+
);
|
|
62682
|
+
try {
|
|
62683
|
+
const fd = openSync3(tmp, "wx", mode);
|
|
62684
|
+
try {
|
|
62685
|
+
writeAll(fd, Buffer.from(text3, "utf8"));
|
|
62686
|
+
fsyncSync(fd);
|
|
62687
|
+
} finally {
|
|
62688
|
+
closeSync3(fd);
|
|
62689
|
+
}
|
|
62690
|
+
const now = readCurrent(file3);
|
|
62691
|
+
if (current === null) {
|
|
62692
|
+
if (now) throw new SwarmSaveConflict("exists", now);
|
|
62693
|
+
try {
|
|
62694
|
+
linkSync2(tmp, file3);
|
|
62695
|
+
} catch (err) {
|
|
62696
|
+
const code2 = err.code;
|
|
62697
|
+
if (code2 === "EEXIST") throw new SwarmSaveConflict("exists", readCurrent(file3));
|
|
62698
|
+
renameSync7(tmp, file3);
|
|
62699
|
+
}
|
|
62700
|
+
} else {
|
|
62701
|
+
if (!now) throw new SwarmSaveConflict("missing", null);
|
|
62702
|
+
if (now.hash !== baseHash) throw new SwarmSaveConflict("changed", now);
|
|
62703
|
+
renameSync7(tmp, file3);
|
|
62704
|
+
}
|
|
62705
|
+
} finally {
|
|
62706
|
+
rmSync8(tmp, { force: true });
|
|
62707
|
+
}
|
|
62708
|
+
return { rel, hash: hash2, created: current === null };
|
|
62709
|
+
}
|
|
62710
|
+
var SwarmSaveRefused, SwarmSaveConflict, SwarmSaveInvalid;
|
|
62711
|
+
var init_save = __esm({
|
|
62712
|
+
"src/swarm/save.ts"() {
|
|
62713
|
+
"use strict";
|
|
62714
|
+
init_esm_shims();
|
|
62715
|
+
init_config2();
|
|
62716
|
+
init_edit();
|
|
62717
|
+
SwarmSaveRefused = class extends Error {
|
|
62718
|
+
constructor(reason) {
|
|
62719
|
+
super(`refusing to write the swarm file: ${reason}`);
|
|
62720
|
+
this.reason = reason;
|
|
62721
|
+
this.name = "SwarmSaveRefused";
|
|
62722
|
+
}
|
|
62723
|
+
reason;
|
|
62724
|
+
};
|
|
62725
|
+
SwarmSaveConflict = class extends Error {
|
|
62726
|
+
constructor(reason, current) {
|
|
62727
|
+
super(
|
|
62728
|
+
reason === "exists" ? "a swarm file already exists" : reason === "missing" ? "the swarm file was removed since it was loaded" : "the swarm file changed since it was loaded"
|
|
62729
|
+
);
|
|
62730
|
+
this.reason = reason;
|
|
62731
|
+
this.current = current;
|
|
62732
|
+
this.name = "SwarmSaveConflict";
|
|
62733
|
+
}
|
|
62734
|
+
reason;
|
|
62735
|
+
current;
|
|
62736
|
+
};
|
|
62737
|
+
SwarmSaveInvalid = class extends Error {
|
|
62738
|
+
constructor(issues) {
|
|
62739
|
+
super(`the swarm file is not valid: ${issues[0]?.message ?? "see the issues"}`);
|
|
62740
|
+
this.issues = issues;
|
|
62741
|
+
this.name = "SwarmSaveInvalid";
|
|
62742
|
+
}
|
|
62743
|
+
issues;
|
|
62744
|
+
};
|
|
62745
|
+
}
|
|
62746
|
+
});
|
|
62747
|
+
|
|
62748
|
+
// src/swarm/templates.ts
|
|
62749
|
+
var READ_ONLY, SWARM_TEMPLATES;
|
|
62750
|
+
var init_templates = __esm({
|
|
62751
|
+
"src/swarm/templates.ts"() {
|
|
62752
|
+
"use strict";
|
|
62753
|
+
init_esm_shims();
|
|
62754
|
+
READ_ONLY = ["Edit", "Write", "NotebookEdit"];
|
|
62755
|
+
SWARM_TEMPLATES = [
|
|
62756
|
+
{
|
|
62757
|
+
id: "feature",
|
|
62758
|
+
name: "Feature team",
|
|
62759
|
+
description: "Plan, build, test and review a change to the codebase.",
|
|
62760
|
+
useWhen: "You have a goal that touches several files and wants a design, code, tests and a review.",
|
|
62761
|
+
swarm: {
|
|
62762
|
+
description: "Plan, build, test and review a change to the codebase.",
|
|
62763
|
+
topology: "hierarchical",
|
|
62764
|
+
max_agents: 4,
|
|
62765
|
+
instructions: "Break the goal into tasks one worker can finish in one go, each naming the files it touches.\nLet the architect design first, fan the coding tasks out, then test, then review.\n",
|
|
62766
|
+
agents: {
|
|
62767
|
+
architect: {
|
|
62768
|
+
description: "Designs the change from the code graph, the history and past decisions.",
|
|
62769
|
+
model: "opus",
|
|
62770
|
+
disallowed_tools: [...READ_ONLY],
|
|
62771
|
+
memory_tags: ["decision", "constraint"],
|
|
62772
|
+
prompt: 'Study the affected code with em_architecture, em_symbols and em_graph_impact before proposing anything.\nCheck em_recall for decisions and constraints that apply.\nPost the design under the blackboard key "design": files to change, the approach, the risks.\n'
|
|
62773
|
+
},
|
|
62774
|
+
coder: {
|
|
62775
|
+
description: "Implements one task at a time with the smallest diff that works.",
|
|
62776
|
+
count: 2,
|
|
62777
|
+
prompt: 'Read the "design" note first: em_swarm {action:"read", key:"design"}.\nBefore editing a file run em_history {action:"file", path} and respect its fix record.\nKeep the change minimal and consistent with the surrounding code, and run the relevant tests.\n'
|
|
62778
|
+
},
|
|
62779
|
+
tester: {
|
|
62780
|
+
description: "Writes and runs tests that pin the new behaviour and its edge cases.",
|
|
62781
|
+
prompt: "Cover the behaviour the task describes, including edge cases and failure paths.\nRun the tests and report exact failures. Never weaken a test to make it pass.\n"
|
|
62782
|
+
},
|
|
62783
|
+
reviewer: {
|
|
62784
|
+
description: "Adversarial reviewer that tries to break the change before it ships.",
|
|
62785
|
+
model: "opus",
|
|
62786
|
+
disallowed_tools: [...READ_ONLY],
|
|
62787
|
+
memory_tags: ["constraint", "preference"],
|
|
62788
|
+
prompt: 'Review the diff for correctness bugs, missed edge cases, broken conventions and missing tests.\nEvery finding needs a concrete failing input or scenario.\nDo not fix anything yourself: add each finding as a task for the coder role with\nem_swarm {action:"plan", tasks:[{title, detail, role:"coder"}]}.\n'
|
|
62789
|
+
}
|
|
62790
|
+
}
|
|
62791
|
+
}
|
|
62792
|
+
},
|
|
62793
|
+
{
|
|
62794
|
+
id: "review",
|
|
62795
|
+
name: "Review panel",
|
|
62796
|
+
description: "Review the working tree from several angles at once.",
|
|
62797
|
+
useWhen: "A change is ready and you want independent reviewers, each with one concern.",
|
|
62798
|
+
swarm: {
|
|
62799
|
+
description: "Review the working tree from several angles at once.",
|
|
62800
|
+
topology: "mesh",
|
|
62801
|
+
max_agents: 3,
|
|
62802
|
+
agents: {
|
|
62803
|
+
correctness: {
|
|
62804
|
+
description: "Hunts for logic errors and unhandled edge cases.",
|
|
62805
|
+
disallowed_tools: [...READ_ONLY],
|
|
62806
|
+
prompt: 'Find bugs, each with a concrete failing input. Post each under the key "finding-<n>".'
|
|
62807
|
+
},
|
|
62808
|
+
security: {
|
|
62809
|
+
description: "Looks for injection, path traversal, leaked secrets and unsafe defaults.",
|
|
62810
|
+
disallowed_tools: [...READ_ONLY],
|
|
62811
|
+
prompt: "Report only exploitable issues, each with the input that triggers it."
|
|
62812
|
+
},
|
|
62813
|
+
tests: {
|
|
62814
|
+
description: "Checks that every changed behaviour has a test that would fail without it.",
|
|
62815
|
+
disallowed_tools: [...READ_ONLY],
|
|
62816
|
+
prompt: "List untested behaviour together with the test you would add."
|
|
62817
|
+
}
|
|
62818
|
+
}
|
|
62819
|
+
}
|
|
62820
|
+
},
|
|
62821
|
+
{
|
|
62822
|
+
id: "research",
|
|
62823
|
+
name: "Research group",
|
|
62824
|
+
description: "Investigate a question from several sources and write up what was found.",
|
|
62825
|
+
useWhen: "You need an answer from the code, the docs and the history before deciding anything.",
|
|
62826
|
+
swarm: {
|
|
62827
|
+
description: "Investigate a question from several sources and write up what was found.",
|
|
62828
|
+
topology: "mesh",
|
|
62829
|
+
max_agents: 3,
|
|
62830
|
+
instructions: "Split the question into angles, one per researcher, then let the synthesizer combine the findings.\nEvery claim needs its source: a file and line, a document, or a commit.\n",
|
|
62831
|
+
agents: {
|
|
62832
|
+
researcher: {
|
|
62833
|
+
description: "Investigates one angle of the question and posts what it found.",
|
|
62834
|
+
count: 2,
|
|
62835
|
+
disallowed_tools: [...READ_ONLY],
|
|
62836
|
+
prompt: 'Answer your angle from the code graph, the indexed docs and the history (em_symbols, em_docs, em_history).\nPost the findings under the key "finding-<angle>", each with its source.'
|
|
62837
|
+
},
|
|
62838
|
+
synthesizer: {
|
|
62839
|
+
description: "Combines the findings into one answer and names what is still unknown.",
|
|
62840
|
+
disallowed_tools: [...READ_ONLY],
|
|
62841
|
+
prompt: 'Read every "finding-*" note. Post the answer under the key "answer": the conclusion, the evidence, the open questions.\nWhere findings disagree, say so rather than picking one.'
|
|
62842
|
+
}
|
|
62843
|
+
}
|
|
62844
|
+
}
|
|
62845
|
+
},
|
|
62846
|
+
{
|
|
62847
|
+
id: "bugfix",
|
|
62848
|
+
name: "Bug squad",
|
|
62849
|
+
description: "Find the cause of a bug, fix it and pin it with a test.",
|
|
62850
|
+
useWhen: "You have a failing behaviour and want the cause found before anything is changed.",
|
|
62851
|
+
swarm: {
|
|
62852
|
+
description: "Find the cause of a bug, fix it and pin it with a test.",
|
|
62853
|
+
topology: "hierarchical",
|
|
62854
|
+
max_agents: 3,
|
|
62855
|
+
instructions: "Start with the debugger: nothing is fixed until the cause is named.\nThen one coder makes the smallest fix, and the tester proves it with a test that failed before.\n",
|
|
62856
|
+
agents: {
|
|
62857
|
+
debugger: {
|
|
62858
|
+
description: "Reproduces the bug and names its root cause.",
|
|
62859
|
+
model: "opus",
|
|
62860
|
+
disallowed_tools: [...READ_ONLY],
|
|
62861
|
+
memory_tags: ["decision", "constraint"],
|
|
62862
|
+
prompt: 'Reproduce the failure first. Use em_history to see what changed around the code and em_graph_impact to see who depends on it.\nPost the root cause under the blackboard key "cause": the file and line, why it fails, and the smallest fix.'
|
|
62863
|
+
},
|
|
62864
|
+
coder: {
|
|
62865
|
+
description: "Applies the smallest fix for the named cause.",
|
|
62866
|
+
prompt: 'Read the "cause" note first: em_swarm {action:"read", key:"cause"}.\nFix that cause and nothing else, and run the tests around it.'
|
|
62867
|
+
},
|
|
62868
|
+
tester: {
|
|
62869
|
+
description: "Writes a regression test that fails without the fix and passes with it.",
|
|
62870
|
+
prompt: "Write the test from the bug report, confirm it fails on the unfixed code, then confirm it passes.\nReport exact failures. Never weaken a test to make it pass."
|
|
62871
|
+
}
|
|
62872
|
+
}
|
|
62873
|
+
}
|
|
62874
|
+
},
|
|
62875
|
+
{
|
|
62876
|
+
id: "docs",
|
|
62877
|
+
name: "Docs pipeline",
|
|
62878
|
+
description: "Write a document, edit it, then check it against the code.",
|
|
62879
|
+
useWhen: "A change needs documentation and each pass should build on the last.",
|
|
62880
|
+
swarm: {
|
|
62881
|
+
description: "Write a document, edit it, then check it against the code.",
|
|
62882
|
+
topology: "pipeline",
|
|
62883
|
+
max_agents: 3,
|
|
62884
|
+
stages: ["writer", "editor", "checker"],
|
|
62885
|
+
agents: {
|
|
62886
|
+
writer: {
|
|
62887
|
+
description: "Drafts the document from the code and the design notes.",
|
|
62888
|
+
prompt: 'Draft the document the task asks for. Read the code it describes before writing about it.\nPost the draft under the blackboard key "draft".'
|
|
62889
|
+
},
|
|
62890
|
+
editor: {
|
|
62891
|
+
description: "Tightens the draft for clarity, order and tone.",
|
|
62892
|
+
prompt: 'Read the "draft" note and improve it: cut filler, fix the order, keep every fact.\nPost the result under the key "edited".'
|
|
62893
|
+
},
|
|
62894
|
+
checker: {
|
|
62895
|
+
description: "Checks every claim in the document against the code.",
|
|
62896
|
+
disallowed_tools: [...READ_ONLY],
|
|
62897
|
+
prompt: 'Read the "edited" note. For each claim, open the code it describes and confirm it.\nPost the claims that are wrong or unverifiable under the key "corrections".'
|
|
62898
|
+
}
|
|
62899
|
+
}
|
|
62900
|
+
}
|
|
62901
|
+
},
|
|
62902
|
+
{
|
|
62903
|
+
id: "blank",
|
|
62904
|
+
name: "Blank",
|
|
62905
|
+
description: "One worker to start from.",
|
|
62906
|
+
useWhen: "None of the above fits and you want to build the team yourself.",
|
|
62907
|
+
swarm: {
|
|
62908
|
+
description: "Describe what this swarm is for.",
|
|
62909
|
+
topology: "hierarchical",
|
|
62910
|
+
max_agents: 2,
|
|
62911
|
+
agents: {
|
|
62912
|
+
worker: {
|
|
62913
|
+
description: "Describe what this worker does.",
|
|
62914
|
+
prompt: "Describe how this worker should do its job."
|
|
62915
|
+
}
|
|
62916
|
+
}
|
|
62917
|
+
}
|
|
62918
|
+
}
|
|
62919
|
+
];
|
|
62920
|
+
}
|
|
62921
|
+
});
|
|
62922
|
+
|
|
61889
62923
|
// src/ui/swarm-api.ts
|
|
61890
|
-
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
61891
|
-
import { dirname as dirname16 } from "path";
|
|
61892
62924
|
function runCounts(db, run3, now) {
|
|
61893
62925
|
const tasks = {
|
|
61894
62926
|
pending: 0,
|
|
@@ -62162,18 +63194,18 @@ function runFromId(ctx, id) {
|
|
|
62162
63194
|
return { run: run3 };
|
|
62163
63195
|
}
|
|
62164
63196
|
function initSwarm(ctx) {
|
|
62165
|
-
|
|
62166
|
-
if (where.exists) return fail2(409, `${where.rel} already exists; edit it instead`);
|
|
62167
|
-
mkdirSync16(dirname16(where.file), { recursive: true });
|
|
63197
|
+
let rel;
|
|
62168
63198
|
try {
|
|
62169
|
-
|
|
63199
|
+
rel = saveSwarmFile(ctx.root, STARTER_YAML, null).rel;
|
|
62170
63200
|
} catch (err) {
|
|
62171
|
-
if (err
|
|
62172
|
-
|
|
63201
|
+
if (err instanceof SwarmSaveRefused) return fail2(403, err.reason);
|
|
63202
|
+
if (err instanceof SwarmSaveConflict)
|
|
63203
|
+
return fail2(409, `${swarmFile(ctx.root).rel} already exists; edit it instead`);
|
|
63204
|
+
if (err instanceof SwarmSaveInvalid) return fail2(400, err.message, { issues: err.issues });
|
|
62173
63205
|
throw err;
|
|
62174
63206
|
}
|
|
62175
63207
|
const config2 = activeSwarmConfig(ctx.root);
|
|
62176
|
-
return ok2({ created:
|
|
63208
|
+
return ok2({ created: rel, sync: syncAgents(ctx.root, config2) });
|
|
62177
63209
|
}
|
|
62178
63210
|
function syncSwarm(ctx) {
|
|
62179
63211
|
const loaded = loadSwarmConfig(ctx.root);
|
|
@@ -62224,6 +63256,170 @@ function releaseSwarmWorker(ctx, body) {
|
|
|
62224
63256
|
throw err;
|
|
62225
63257
|
}
|
|
62226
63258
|
}
|
|
63259
|
+
function configMeta() {
|
|
63260
|
+
return {
|
|
63261
|
+
models: ["inherit", "haiku", "sonnet", "opus", "fable", "opusplan"],
|
|
63262
|
+
tiers: [...TIERS],
|
|
63263
|
+
colors: [...AGENT_COLORS],
|
|
63264
|
+
topologies: [...TOPOLOGIES],
|
|
63265
|
+
efforts: ["low", "medium", "high", "xhigh", "max"],
|
|
63266
|
+
defaultContext: DEFAULT_CONTEXT,
|
|
63267
|
+
limits: CONFIG_LIMITS
|
|
63268
|
+
};
|
|
63269
|
+
}
|
|
63270
|
+
function activeRunsOf(ctx) {
|
|
63271
|
+
try {
|
|
63272
|
+
return getStorage(ctx).swarm.runs({ status: "active", limit: RUNS_LIMIT_MAX }).map((r) => ({ id: r.id, swarm: r.swarm, goal: r.goal }));
|
|
63273
|
+
} catch {
|
|
63274
|
+
return [];
|
|
63275
|
+
}
|
|
63276
|
+
}
|
|
63277
|
+
function swarmConfigDoc(ctx) {
|
|
63278
|
+
const read2 = readSwarmDoc(ctx.root);
|
|
63279
|
+
const activeRuns = activeRunsOf(ctx);
|
|
63280
|
+
return {
|
|
63281
|
+
state: read2.state,
|
|
63282
|
+
file: read2.rel,
|
|
63283
|
+
text: read2.text,
|
|
63284
|
+
hash: read2.hash,
|
|
63285
|
+
doc: read2.doc,
|
|
63286
|
+
issues: read2.issues,
|
|
63287
|
+
warnings: read2.doc ? docWarnings(read2.doc, activeRuns, read2.doc) : [],
|
|
63288
|
+
locked: read2.locked,
|
|
63289
|
+
starter: read2.state === "absent" ? starterDoc() : void 0,
|
|
63290
|
+
activeRuns,
|
|
63291
|
+
meta: configMeta()
|
|
63292
|
+
};
|
|
63293
|
+
}
|
|
63294
|
+
function swarmTemplates() {
|
|
63295
|
+
return {
|
|
63296
|
+
templates: SWARM_TEMPLATES.map((t) => ({
|
|
63297
|
+
id: t.id,
|
|
63298
|
+
name: t.name,
|
|
63299
|
+
description: t.description,
|
|
63300
|
+
useWhen: t.useWhen,
|
|
63301
|
+
topology: t.swarm.topology ?? "hierarchical",
|
|
63302
|
+
roles: Object.entries(t.swarm.agents).map(([role, r]) => ({
|
|
63303
|
+
role,
|
|
63304
|
+
model: r.model ?? "inherit",
|
|
63305
|
+
count: r.count ?? 1
|
|
63306
|
+
})),
|
|
63307
|
+
swarm: t.swarm
|
|
63308
|
+
}))
|
|
63309
|
+
};
|
|
63310
|
+
}
|
|
63311
|
+
async function prepareConfig(ctx, body) {
|
|
63312
|
+
const parsedBody = ConfigBody.safeParse(body);
|
|
63313
|
+
if (!parsedBody.success)
|
|
63314
|
+
return {
|
|
63315
|
+
reply: fail2(400, parsedBody.error.issues[0]?.message ?? "invalid body", {
|
|
63316
|
+
issues: parsedBody.error.issues.map((i) => ({
|
|
63317
|
+
path: i.path.join("."),
|
|
63318
|
+
message: i.message
|
|
63319
|
+
}))
|
|
63320
|
+
})
|
|
63321
|
+
};
|
|
63322
|
+
const b = parsedBody.data;
|
|
63323
|
+
const read2 = readSwarmDoc(ctx.root);
|
|
63324
|
+
if (read2.state === "invalid" && read2.text === null && read2.issues.length > 0)
|
|
63325
|
+
return { reply: fail2(500, read2.issues[0]?.message ?? `cannot read ${read2.rel}`) };
|
|
63326
|
+
if (read2.hash !== b.baseHash)
|
|
63327
|
+
return {
|
|
63328
|
+
reply: fail2(
|
|
63329
|
+
409,
|
|
63330
|
+
read2.hash === null ? "the swarm file was removed since it was loaded" : b.baseHash === null ? "a swarm file already exists" : "the swarm file changed since it was loaded",
|
|
63331
|
+
{ current: read2.hash === null ? null : { text: read2.text, hash: read2.hash } }
|
|
63332
|
+
)
|
|
63333
|
+
};
|
|
63334
|
+
const meta4 = { file: read2.file, rel: read2.rel };
|
|
63335
|
+
let text3;
|
|
63336
|
+
let issues = [];
|
|
63337
|
+
let draft = null;
|
|
63338
|
+
if (b.doc !== void 0) {
|
|
63339
|
+
draft = b.doc;
|
|
63340
|
+
const r = renderSwarmDoc(read2.text, draft, b.renames ?? [], meta4);
|
|
63341
|
+
if (!r.ok) return { reply: fail2(422, r.error, { locked: r.locked ?? read2.locked }) };
|
|
63342
|
+
text3 = r.text;
|
|
63343
|
+
if (r.result.state === "invalid") issues = r.result.issues;
|
|
63344
|
+
} else {
|
|
63345
|
+
text3 = b.text;
|
|
63346
|
+
const { result, enforceOk } = checkSwarmText(text3, meta4);
|
|
63347
|
+
if (result.state === "invalid") issues = result.issues;
|
|
63348
|
+
if (!enforceOk)
|
|
63349
|
+
issues = [
|
|
63350
|
+
...issues,
|
|
63351
|
+
{
|
|
63352
|
+
path: "enforce",
|
|
63353
|
+
message: "the `enforce:` line must be a plain top-level `enforce: true|false`"
|
|
63354
|
+
}
|
|
63355
|
+
];
|
|
63356
|
+
try {
|
|
63357
|
+
const Y = await import("yaml");
|
|
63358
|
+
draft = Y.parse(text3, { merge: true, maxAliasCount: 200 });
|
|
63359
|
+
} catch {
|
|
63360
|
+
draft = null;
|
|
63361
|
+
}
|
|
63362
|
+
}
|
|
63363
|
+
const diff2 = lineDiff(read2.text ?? "", text3);
|
|
63364
|
+
const warnings = draft && typeof draft === "object" ? docWarnings(draft, activeRunsOf(ctx), read2.doc) : [];
|
|
63365
|
+
return {
|
|
63366
|
+
parsed: b,
|
|
63367
|
+
p: {
|
|
63368
|
+
text: text3,
|
|
63369
|
+
// A no-op save keeps the on-disk hash (the text round-trip differs for invalid UTF-8).
|
|
63370
|
+
hash: read2.text === text3 && read2.hash ? read2.hash : hashText2(text3),
|
|
63371
|
+
issues,
|
|
63372
|
+
warnings,
|
|
63373
|
+
changed: diff2.changed,
|
|
63374
|
+
removed: diff2.removed,
|
|
63375
|
+
locked: read2.locked,
|
|
63376
|
+
baseText: read2.text,
|
|
63377
|
+
noop: read2.text === text3
|
|
63378
|
+
}
|
|
63379
|
+
};
|
|
63380
|
+
}
|
|
63381
|
+
async function validateConfig(ctx, body) {
|
|
63382
|
+
const r = await prepareConfig(ctx, body);
|
|
63383
|
+
if ("reply" in r) return r.reply;
|
|
63384
|
+
const { p: p2 } = r;
|
|
63385
|
+
return ok2({
|
|
63386
|
+
ok: p2.issues.length === 0,
|
|
63387
|
+
text: p2.text,
|
|
63388
|
+
hash: p2.hash,
|
|
63389
|
+
issues: p2.issues,
|
|
63390
|
+
warnings: p2.warnings,
|
|
63391
|
+
changed: p2.changed,
|
|
63392
|
+
removed: p2.removed,
|
|
63393
|
+
locked: p2.locked
|
|
63394
|
+
});
|
|
63395
|
+
}
|
|
63396
|
+
async function saveConfig(ctx, body) {
|
|
63397
|
+
const r = await prepareConfig(ctx, body);
|
|
63398
|
+
if ("reply" in r) return r.reply;
|
|
63399
|
+
const { p: p2, parsed } = r;
|
|
63400
|
+
if (p2.issues.length) return fail2(400, "the swarm file is not valid", { issues: p2.issues });
|
|
63401
|
+
let created = false;
|
|
63402
|
+
if (!p2.noop) {
|
|
63403
|
+
try {
|
|
63404
|
+
created = saveSwarmFile(ctx.root, p2.text, parsed.baseHash).created;
|
|
63405
|
+
} catch (err) {
|
|
63406
|
+
if (err instanceof SwarmSaveRefused) return fail2(403, err.reason);
|
|
63407
|
+
if (err instanceof SwarmSaveConflict) return fail2(409, err.message, { current: err.current });
|
|
63408
|
+
if (err instanceof SwarmSaveInvalid) return fail2(400, err.message, { issues: err.issues });
|
|
63409
|
+
throw err;
|
|
63410
|
+
}
|
|
63411
|
+
}
|
|
63412
|
+
const sync = parsed.sync ? syncAgents(ctx.root, activeSwarmConfig(ctx.root)) : null;
|
|
63413
|
+
return ok2({
|
|
63414
|
+
saved: !p2.noop,
|
|
63415
|
+
created,
|
|
63416
|
+
changed: p2.changed,
|
|
63417
|
+
hash: p2.hash,
|
|
63418
|
+
text: p2.text,
|
|
63419
|
+
warnings: p2.warnings,
|
|
63420
|
+
sync
|
|
63421
|
+
});
|
|
63422
|
+
}
|
|
62227
63423
|
async function swarmRoute(ctx, req) {
|
|
62228
63424
|
const { path: path3, method, query } = req;
|
|
62229
63425
|
const isGet = method === "GET" || method === "HEAD";
|
|
@@ -62276,6 +63472,24 @@ async function swarmRoute(ctx, req) {
|
|
|
62276
63472
|
now: Date.now()
|
|
62277
63473
|
});
|
|
62278
63474
|
}
|
|
63475
|
+
if (path3 === "/api/swarm/config") {
|
|
63476
|
+
if (!isGet) return fail2(405, "GET only");
|
|
63477
|
+
return ok2(swarmConfigDoc(ctx));
|
|
63478
|
+
}
|
|
63479
|
+
if (path3 === "/api/swarm/templates") {
|
|
63480
|
+
if (!isGet) return fail2(405, "GET only");
|
|
63481
|
+
return ok2(swarmTemplates());
|
|
63482
|
+
}
|
|
63483
|
+
if (path3 === "/api/swarm/config/validate" || path3 === "/api/swarm/config/save") {
|
|
63484
|
+
if (method !== "POST") return fail2(405, "POST only");
|
|
63485
|
+
let cfgBody;
|
|
63486
|
+
try {
|
|
63487
|
+
cfgBody = await readBody();
|
|
63488
|
+
} catch {
|
|
63489
|
+
return fail2(400, "invalid JSON body");
|
|
63490
|
+
}
|
|
63491
|
+
return path3.endsWith("/validate") ? validateConfig(ctx, cfgBody) : saveConfig(ctx, cfgBody);
|
|
63492
|
+
}
|
|
62279
63493
|
if (path3 === "/api/swarm/init") {
|
|
62280
63494
|
if (method !== "POST") return fail2(405, "POST only");
|
|
62281
63495
|
return initSwarm(ctx);
|
|
@@ -62306,15 +63520,21 @@ async function swarmRoute(ctx, req) {
|
|
|
62306
63520
|
}
|
|
62307
63521
|
return fail2(404, "not found");
|
|
62308
63522
|
}
|
|
62309
|
-
var RUN_ID_RE, SEGMENT_GAP_MS, EVENTS_PAGE, READ_PAGE, TIMELINE_EVENTS_MAX, SNAPSHOT_EVENTS, TASK_TEXT_MAX, TASKS_SINCE_OVERLAP_MS, RUNS_LIMIT, RUNS_LIMIT_MAX, FINISH_STATUSES, ok2, fail2, ioOf, clipText;
|
|
63523
|
+
var RUN_ID_RE, SEGMENT_GAP_MS, EVENTS_PAGE, READ_PAGE, TIMELINE_EVENTS_MAX, SNAPSHOT_EVENTS, TASK_TEXT_MAX, TASKS_SINCE_OVERLAP_MS, RUNS_LIMIT, RUNS_LIMIT_MAX, FINISH_STATUSES, ok2, fail2, ioOf, clipText, CfgName, ConfigBody, CONFIG_LIMITS;
|
|
62310
63524
|
var init_swarm_api = __esm({
|
|
62311
63525
|
"src/ui/swarm-api.ts"() {
|
|
62312
63526
|
"use strict";
|
|
62313
63527
|
init_esm_shims();
|
|
63528
|
+
init_zod();
|
|
63529
|
+
init_types();
|
|
62314
63530
|
init_storage();
|
|
62315
63531
|
init_agents();
|
|
62316
63532
|
init_config2();
|
|
63533
|
+
init_edit();
|
|
62317
63534
|
init_runtime();
|
|
63535
|
+
init_save();
|
|
63536
|
+
init_templates();
|
|
63537
|
+
init_types2();
|
|
62318
63538
|
RUN_ID_RE = /^\d{8}-[0-9a-f]{6}$/;
|
|
62319
63539
|
SEGMENT_GAP_MS = 6e4;
|
|
62320
63540
|
EVENTS_PAGE = 200;
|
|
@@ -62339,19 +63559,44 @@ var init_swarm_api = __esm({
|
|
|
62339
63559
|
return e.kind === "tool" || e.kind === "tool_error" ? "other" : "swarm";
|
|
62340
63560
|
};
|
|
62341
63561
|
clipText = (s) => s !== null && s.length > TASK_TEXT_MAX ? s.slice(0, TASK_TEXT_MAX) : s;
|
|
63562
|
+
CfgName = external_exports.string().min(1).max(64);
|
|
63563
|
+
ConfigBody = external_exports.strictObject({
|
|
63564
|
+
doc: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
63565
|
+
text: external_exports.string().max(SWARM_FILE_MAX_CHARS).optional(),
|
|
63566
|
+
renames: external_exports.array(external_exports.strictObject({ swarm: CfgName, role: CfgName.optional(), to: CfgName })).max(50).optional(),
|
|
63567
|
+
baseHash: external_exports.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
63568
|
+
sync: external_exports.boolean().optional()
|
|
63569
|
+
}).refine((b) => b.doc === void 0 !== (b.text === void 0), {
|
|
63570
|
+
message: "send exactly one of doc or text"
|
|
63571
|
+
});
|
|
63572
|
+
CONFIG_LIMITS = {
|
|
63573
|
+
name: 32,
|
|
63574
|
+
agentName: 64,
|
|
63575
|
+
description: 500,
|
|
63576
|
+
prompt: 2e4,
|
|
63577
|
+
maxAgents: 16,
|
|
63578
|
+
count: 8,
|
|
63579
|
+
maxTurns: 500,
|
|
63580
|
+
memories: 10,
|
|
63581
|
+
docs: 10,
|
|
63582
|
+
maxChars: [500, 9e3],
|
|
63583
|
+
fileChars: SWARM_FILE_MAX_CHARS
|
|
63584
|
+
};
|
|
62342
63585
|
}
|
|
62343
63586
|
});
|
|
62344
63587
|
|
|
62345
63588
|
// src/ui/server.ts
|
|
62346
63589
|
var server_exports = {};
|
|
62347
63590
|
__export(server_exports, {
|
|
63591
|
+
requestRoot: () => requestRoot,
|
|
63592
|
+
resetProjectListCache: () => resetProjectListCache,
|
|
62348
63593
|
serve: () => serve,
|
|
62349
63594
|
uiDir: () => uiDir
|
|
62350
63595
|
});
|
|
62351
63596
|
import { spawn as spawn2 } from "child_process";
|
|
62352
|
-
import { existsSync as existsSync31, readFileSync as
|
|
63597
|
+
import { existsSync as existsSync31, readFileSync as readFileSync31, statSync as statSync19 } from "fs";
|
|
62353
63598
|
import { createServer } from "http";
|
|
62354
|
-
import { extname as extname4, join as join38, normalize as normalize8 } from "path";
|
|
63599
|
+
import { extname as extname4, join as join38, normalize as normalize8, resolve as resolve14 } from "path";
|
|
62355
63600
|
import { URL as URL2 } from "url";
|
|
62356
63601
|
function json2(res, status, body) {
|
|
62357
63602
|
res.writeHead(status, {
|
|
@@ -62375,12 +63620,13 @@ function strList(v) {
|
|
|
62375
63620
|
function uiDir() {
|
|
62376
63621
|
return process.env.EMINIAR_UI_DIR || join38(pluginRoot(), "dist", "ui");
|
|
62377
63622
|
}
|
|
62378
|
-
function originAllowed(req, port) {
|
|
63623
|
+
function originAllowed(req, port, api) {
|
|
62379
63624
|
const host = req.headers.host ?? "";
|
|
62380
63625
|
const ok3 = (h) => h === `127.0.0.1:${port}` || h === `localhost:${port}` || h === `[::1]:${port}`;
|
|
62381
63626
|
if (!ok3(host)) return false;
|
|
62382
63627
|
const method = req.method ?? "GET";
|
|
62383
|
-
|
|
63628
|
+
const read2 = method === "GET" || method === "HEAD";
|
|
63629
|
+
if (read2 && !api) return true;
|
|
62384
63630
|
const origin = req.headers.origin;
|
|
62385
63631
|
if (origin) {
|
|
62386
63632
|
try {
|
|
@@ -62391,6 +63637,7 @@ function originAllowed(req, port) {
|
|
|
62391
63637
|
}
|
|
62392
63638
|
const site = req.headers["sec-fetch-site"];
|
|
62393
63639
|
if (site && site !== "same-origin" && site !== "none") return false;
|
|
63640
|
+
if (read2) return true;
|
|
62394
63641
|
const type = String(req.headers["content-type"] ?? "");
|
|
62395
63642
|
return type.startsWith("application/json");
|
|
62396
63643
|
}
|
|
@@ -62399,34 +63646,60 @@ function serveStatic(res, p2) {
|
|
|
62399
63646
|
const rel = p2 === "/" ? "index.html" : p2.replace(/^\/+/, "");
|
|
62400
63647
|
const file3 = normalize8(join38(dir, rel));
|
|
62401
63648
|
if (!file3.startsWith(normalize8(dir))) return false;
|
|
62402
|
-
if (!existsSync31(file3) || !
|
|
63649
|
+
if (!existsSync31(file3) || !statSync19(file3).isFile()) return false;
|
|
62403
63650
|
const type = MIME[extname4(file3).toLowerCase()] ?? "application/octet-stream";
|
|
62404
63651
|
if (rel === "index.html") {
|
|
62405
63652
|
const stamp = (name) => {
|
|
62406
63653
|
try {
|
|
62407
|
-
return `/${name}?v=${Math.floor(
|
|
63654
|
+
return `/${name}?v=${Math.floor(statSync19(join38(dir, name)).mtimeMs)}`;
|
|
62408
63655
|
} catch {
|
|
62409
63656
|
return `/${name}`;
|
|
62410
63657
|
}
|
|
62411
63658
|
};
|
|
62412
|
-
const html =
|
|
63659
|
+
const html = readFileSync31(file3, "utf8").replace('"/app.global.js"', `"${stamp("app.global.js")}"`).replace('"/styles.css"', `"${stamp("styles.css")}"`);
|
|
62413
63660
|
res.writeHead(200, { "content-type": type, "cache-control": "no-store" });
|
|
62414
63661
|
res.end(html);
|
|
62415
63662
|
return true;
|
|
62416
63663
|
}
|
|
62417
63664
|
res.writeHead(200, { "content-type": type, "cache-control": "no-cache" });
|
|
62418
|
-
res.end(
|
|
63665
|
+
res.end(readFileSync31(file3));
|
|
62419
63666
|
return true;
|
|
62420
63667
|
}
|
|
63668
|
+
function requestRoot(asked, defaultRoot) {
|
|
63669
|
+
if (!asked || defaultRoot && resolve14(asked) === resolve14(defaultRoot)) return defaultRoot;
|
|
63670
|
+
const want = resolve14(asked);
|
|
63671
|
+
try {
|
|
63672
|
+
for (const p2 of listedProjects()) if (p2.root && resolve14(p2.root) === want) return p2.root;
|
|
63673
|
+
} catch {
|
|
63674
|
+
}
|
|
63675
|
+
return defaultRoot;
|
|
63676
|
+
}
|
|
63677
|
+
function listedProjects() {
|
|
63678
|
+
let mtime = -1;
|
|
63679
|
+
try {
|
|
63680
|
+
mtime = statSync19(paths().projects).mtimeMs;
|
|
63681
|
+
} catch {
|
|
63682
|
+
}
|
|
63683
|
+
const now = Date.now();
|
|
63684
|
+
if (projectList && projectList.mtime === mtime && now - projectList.at < PROJECT_LIST_TTL_MS)
|
|
63685
|
+
return projectList.list;
|
|
63686
|
+
const list2 = listProjects();
|
|
63687
|
+
projectList = { at: now, mtime, list: list2 };
|
|
63688
|
+
return list2;
|
|
63689
|
+
}
|
|
63690
|
+
function resetProjectListCache() {
|
|
63691
|
+
projectList = void 0;
|
|
63692
|
+
}
|
|
62421
63693
|
async function serve(opts) {
|
|
62422
63694
|
const defaultRoot = opts.root;
|
|
62423
63695
|
const server = createServer(async (req, res) => {
|
|
62424
63696
|
try {
|
|
62425
|
-
if (!originAllowed(req, opts.port)) return json2(res, 403, { error: "forbidden origin" });
|
|
62426
63697
|
const url3 = new URL2(req.url ?? "/", "http://127.0.0.1");
|
|
62427
63698
|
const p2 = url3.pathname;
|
|
63699
|
+
if (!originAllowed(req, opts.port, p2.startsWith("/api/")))
|
|
63700
|
+
return json2(res, 403, { error: "forbidden origin" });
|
|
62428
63701
|
const q = url3.searchParams;
|
|
62429
|
-
const root = q.get("root")
|
|
63702
|
+
const root = requestRoot(q.get("root"), defaultRoot);
|
|
62430
63703
|
const ctx = () => ctxFor(root);
|
|
62431
63704
|
const num6 = (k, d) => Number(q.get(k) ?? d) || d;
|
|
62432
63705
|
const str3 = (k) => q.get(k)?.trim() || void 0;
|
|
@@ -62805,7 +64078,10 @@ async function serve(opts) {
|
|
|
62805
64078
|
categories: strList(q.get("category"))
|
|
62806
64079
|
})
|
|
62807
64080
|
);
|
|
62808
|
-
if (p2 === "/api/doctor")
|
|
64081
|
+
if (p2 === "/api/doctor") {
|
|
64082
|
+
const fix = method === "POST" && (await readJson4(req)).fix === true;
|
|
64083
|
+
return json2(res, 200, await doctorPayload(fix));
|
|
64084
|
+
}
|
|
62809
64085
|
if (p2 === "/api/actions") {
|
|
62810
64086
|
if (method !== "POST") return json2(res, 405, { error: "POST only" });
|
|
62811
64087
|
const body = await readJson4(req);
|
|
@@ -62821,9 +64097,9 @@ async function serve(opts) {
|
|
|
62821
64097
|
json2(res, 500, { error: err.message });
|
|
62822
64098
|
}
|
|
62823
64099
|
});
|
|
62824
|
-
await new Promise((
|
|
64100
|
+
await new Promise((resolve16, reject) => {
|
|
62825
64101
|
server.once("error", reject);
|
|
62826
|
-
server.listen(opts.port, "127.0.0.1",
|
|
64102
|
+
server.listen(opts.port, "127.0.0.1", resolve16);
|
|
62827
64103
|
});
|
|
62828
64104
|
const url2 = `http://127.0.0.1:${opts.port}/`;
|
|
62829
64105
|
console.log(`eminiar dashboard at ${url2} (Ctrl-C to stop)`);
|
|
@@ -62833,11 +64109,12 @@ async function serve(opts) {
|
|
|
62833
64109
|
}
|
|
62834
64110
|
await new Promise(() => void 0);
|
|
62835
64111
|
}
|
|
62836
|
-
var MIME, FALLBACK_PAGE;
|
|
64112
|
+
var MIME, FALLBACK_PAGE, PROJECT_LIST_TTL_MS, projectList;
|
|
62837
64113
|
var init_server = __esm({
|
|
62838
64114
|
"src/ui/server.ts"() {
|
|
62839
64115
|
"use strict";
|
|
62840
64116
|
init_esm_shims();
|
|
64117
|
+
init_paths();
|
|
62841
64118
|
init_version();
|
|
62842
64119
|
init_adjudicator_api();
|
|
62843
64120
|
init_api2();
|
|
@@ -62860,6 +64137,7 @@ var init_server = __esm({
|
|
|
62860
64137
|
<style>body{font:14px system-ui;margin:40px;color:#1b1f24;background:#f5f6f8}code{background:#e5e7eb;padding:2px 5px;border-radius:4px}</style></head>
|
|
62861
64138
|
<body><h1>eminiar dashboard</h1><p>The frontend bundle is missing. Run <code>npm run build</code> in the eminiar checkout (or reinstall the package) and reload.</p>
|
|
62862
64139
|
<p>The JSON API is available under <code>/api/*</code>.</p></body></html>`;
|
|
64140
|
+
PROJECT_LIST_TTL_MS = 5e3;
|
|
62863
64141
|
}
|
|
62864
64142
|
});
|
|
62865
64143
|
|
|
@@ -62874,7 +64152,7 @@ var init_log2 = __esm({
|
|
|
62874
64152
|
});
|
|
62875
64153
|
|
|
62876
64154
|
// src/session/brief.ts
|
|
62877
|
-
import { existsSync as existsSync32, readFileSync as
|
|
64155
|
+
import { existsSync as existsSync32, readFileSync as readFileSync32 } from "fs";
|
|
62878
64156
|
import { join as join39 } from "path";
|
|
62879
64157
|
var init_brief2 = __esm({
|
|
62880
64158
|
"src/session/brief.ts"() {
|
|
@@ -62905,8 +64183,8 @@ var init_brief3 = __esm({
|
|
|
62905
64183
|
});
|
|
62906
64184
|
|
|
62907
64185
|
// src/swarm/identity.ts
|
|
62908
|
-
import { createHmac, randomBytes as
|
|
62909
|
-
import { mkdirSync as mkdirSync17, readFileSync as
|
|
64186
|
+
import { createHmac, randomBytes as randomBytes5, timingSafeEqual } from "crypto";
|
|
64187
|
+
import { mkdirSync as mkdirSync17, readFileSync as readFileSync33, writeFileSync as writeFileSync14 } from "fs";
|
|
62910
64188
|
import { join as join40 } from "path";
|
|
62911
64189
|
var init_identity = __esm({
|
|
62912
64190
|
"src/swarm/identity.ts"() {
|
|
@@ -62918,22 +64196,22 @@ var init_identity = __esm({
|
|
|
62918
64196
|
|
|
62919
64197
|
// src/swarm/hooks.ts
|
|
62920
64198
|
import { execFileSync } from "child_process";
|
|
62921
|
-
import { readFileSync as
|
|
62922
|
-
import { basename as
|
|
64199
|
+
import { readFileSync as readFileSync34, realpathSync as realpathSync8, statSync as statSync20 } from "fs";
|
|
64200
|
+
import { basename as basename9, dirname as dirname17, join as join41, resolve as resolve15 } from "path";
|
|
62923
64201
|
function coordinationRoot(root) {
|
|
62924
64202
|
try {
|
|
62925
64203
|
const dotGit = join41(root, ".git");
|
|
62926
|
-
if (!
|
|
62927
|
-
const m = /^gitdir:\s*(.+?)\s*$/m.exec(
|
|
64204
|
+
if (!statSync20(dotGit).isFile()) return root;
|
|
64205
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync34(dotGit, "utf8"));
|
|
62928
64206
|
if (!m) return root;
|
|
62929
|
-
const gitdir =
|
|
64207
|
+
const gitdir = resolve15(root, m[1]);
|
|
62930
64208
|
let common;
|
|
62931
64209
|
try {
|
|
62932
|
-
common =
|
|
64210
|
+
common = resolve15(gitdir, readFileSync34(join41(gitdir, "commondir"), "utf8").trim());
|
|
62933
64211
|
} catch {
|
|
62934
64212
|
return root;
|
|
62935
64213
|
}
|
|
62936
|
-
if (
|
|
64214
|
+
if (basename9(common) === ".git") return realpathSync8(dirname17(common));
|
|
62937
64215
|
const out = execFileSync("git", ["worktree", "list", "--porcelain"], {
|
|
62938
64216
|
cwd: root,
|
|
62939
64217
|
encoding: "utf8",
|
|
@@ -62942,8 +64220,8 @@ function coordinationRoot(root) {
|
|
|
62942
64220
|
});
|
|
62943
64221
|
const first = /^worktree (.+)$/m.exec(out)?.[1];
|
|
62944
64222
|
if (!first || /^bare$/m.test(out.split("\n\n")[0] ?? "")) return root;
|
|
62945
|
-
const main =
|
|
62946
|
-
return main !==
|
|
64223
|
+
const main = realpathSync8(first);
|
|
64224
|
+
return main !== realpathSync8(common) && statSync20(join41(main, ".git"), { throwIfNoEntry: false }) ? main : root;
|
|
62947
64225
|
} catch {
|
|
62948
64226
|
return root;
|
|
62949
64227
|
}
|
|
@@ -62970,7 +64248,7 @@ __export(cli_exports2, {
|
|
|
62970
64248
|
SWARM_USAGE: () => SWARM_USAGE,
|
|
62971
64249
|
swarmCommand: () => swarmCommand
|
|
62972
64250
|
});
|
|
62973
|
-
import { mkdirSync as mkdirSync18, writeFileSync as
|
|
64251
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync15 } from "fs";
|
|
62974
64252
|
import { dirname as dirname18 } from "path";
|
|
62975
64253
|
import { parseArgs as parseArgs2 } from "util";
|
|
62976
64254
|
async function storage2(ctx) {
|
|
@@ -62998,12 +64276,12 @@ function readerWatch(stream) {
|
|
|
62998
64276
|
stream?.on("error", onError);
|
|
62999
64277
|
return {
|
|
63000
64278
|
gone: () => gone || !!stream && (stream.destroyed || !stream.writable),
|
|
63001
|
-
wait: (ms4) => new Promise((
|
|
64279
|
+
wait: (ms4) => new Promise((resolve16) => {
|
|
63002
64280
|
const timer = setTimeout(done, ms4);
|
|
63003
64281
|
function done() {
|
|
63004
64282
|
clearTimeout(timer);
|
|
63005
64283
|
wake = void 0;
|
|
63006
|
-
|
|
64284
|
+
resolve16();
|
|
63007
64285
|
}
|
|
63008
64286
|
wake = done;
|
|
63009
64287
|
})
|
|
@@ -63047,7 +64325,7 @@ async function swarmCommand(args, callerCtx, io = defaultIO, opts = {}) {
|
|
|
63047
64325
|
return 1;
|
|
63048
64326
|
}
|
|
63049
64327
|
mkdirSync18(dirname18(where.file), { recursive: true });
|
|
63050
|
-
|
|
64328
|
+
writeFileSync15(where.file, STARTER_YAML);
|
|
63051
64329
|
const loaded = loadSwarmConfig(root);
|
|
63052
64330
|
if (loaded.state !== "ok") {
|
|
63053
64331
|
io.err(`${where.rel} was written but does not validate`);
|
|
@@ -63351,7 +64629,7 @@ __export(statusline_exports, {
|
|
|
63351
64629
|
renderStatusline: () => renderStatusline,
|
|
63352
64630
|
usageSegments: () => usageSegments
|
|
63353
64631
|
});
|
|
63354
|
-
import { existsSync as existsSync33, readFileSync as
|
|
64632
|
+
import { existsSync as existsSync33, readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
|
|
63355
64633
|
function epochMs(v) {
|
|
63356
64634
|
if (typeof v === "number" && Number.isFinite(v)) return v < 1e12 ? v * 1e3 : v;
|
|
63357
64635
|
if (typeof v === "string") {
|
|
@@ -63414,7 +64692,7 @@ function renderStatusline(raw) {
|
|
|
63414
64692
|
const cache5 = paths().statuslineCache;
|
|
63415
64693
|
try {
|
|
63416
64694
|
if (existsSync33(cache5)) {
|
|
63417
|
-
const c = JSON.parse(
|
|
64695
|
+
const c = JSON.parse(readFileSync35(cache5, "utf8"));
|
|
63418
64696
|
if (Date.now() - c.at < CACHE_TTL_MS && c.key === key) return c.line;
|
|
63419
64697
|
}
|
|
63420
64698
|
} catch {
|
|
@@ -63445,7 +64723,7 @@ function renderStatusline(raw) {
|
|
|
63445
64723
|
line = `eminiar \xB7 unavailable (${err.message.slice(0, 40)})`;
|
|
63446
64724
|
}
|
|
63447
64725
|
try {
|
|
63448
|
-
|
|
64726
|
+
writeFileSync16(cache5, JSON.stringify({ at: Date.now(), line, key }));
|
|
63449
64727
|
} catch {
|
|
63450
64728
|
}
|
|
63451
64729
|
return line;
|
|
@@ -64034,10 +65312,10 @@ var commands = {
|
|
|
64034
65312
|
}
|
|
64035
65313
|
};
|
|
64036
65314
|
function flushed(stream) {
|
|
64037
|
-
return new Promise((
|
|
64038
|
-
if (stream.destroyed || !stream.writable) return
|
|
64039
|
-
stream.on("error", () =>
|
|
64040
|
-
stream.write("", () =>
|
|
65315
|
+
return new Promise((resolve16) => {
|
|
65316
|
+
if (stream.destroyed || !stream.writable) return resolve16();
|
|
65317
|
+
stream.on("error", () => resolve16());
|
|
65318
|
+
stream.write("", () => resolve16());
|
|
64041
65319
|
});
|
|
64042
65320
|
}
|
|
64043
65321
|
async function exitFlushed(code2) {
|