@askexenow/exe-os 0.9.353 → 0.9.354
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +1 -1
- package/dist/bin/deferred-daemon-restart.js +2 -2
- package/dist/bin/exe-agent.js +3 -3
- package/dist/bin/exe-memory-reads.js +40 -2
- package/dist/bin/install.js +2 -2
- package/dist/{chunk-UYN4TVRC.js → chunk-N7GR3WNB.js} +1 -1
- package/dist/{chunk-QHIGW5SG.js → chunk-VKKXVQED.js} +27 -3
- package/dist/{exe-key-5HXW4TUE.js → exe-key-7KNEW6NE.js} +2 -2
- package/dist/hooks/manifest.json +1 -1
- package/dist/mcp/register-tools.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/memory-isolation-RJJI3MDS.js +138 -0
- package/package.json +1 -1
- package/release-notes.json +19 -22
package/dist/bin/cli.js
CHANGED
|
@@ -201,7 +201,7 @@ if (args.includes("--global")) {
|
|
|
201
201
|
process.exit(1);
|
|
202
202
|
}
|
|
203
203
|
} else if (args[0] === "key") {
|
|
204
|
-
const { main: runKey } = await import("../exe-key-
|
|
204
|
+
const { main: runKey } = await import("../exe-key-7KNEW6NE.js");
|
|
205
205
|
await runKey(args.slice(1));
|
|
206
206
|
} else if (args[0] === "grant") {
|
|
207
207
|
const { main: runGrant } = await import("./exe-grant.js");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
computeMcpSurfaceHash
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-N7GR3WNB.js";
|
|
5
5
|
import "../chunk-WCGNCH3Q.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-VKKXVQED.js";
|
|
7
7
|
import "../chunk-557C2IGL.js";
|
|
8
8
|
import "../chunk-MJVNOOF5.js";
|
|
9
9
|
import "../chunk-3KTQG6IB.js";
|
package/dist/bin/exe-agent.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
FileWriteTool
|
|
4
|
+
} from "../chunk-XEKO37NM.js";
|
|
2
5
|
import {
|
|
3
6
|
FileEditTool
|
|
4
7
|
} from "../chunk-R4WMF32C.js";
|
|
@@ -14,9 +17,6 @@ import {
|
|
|
14
17
|
import {
|
|
15
18
|
GrepTool
|
|
16
19
|
} from "../chunk-EIT6J37V.js";
|
|
17
|
-
import {
|
|
18
|
-
FileWriteTool
|
|
19
|
-
} from "../chunk-XEKO37NM.js";
|
|
20
20
|
import {
|
|
21
21
|
createTerminalRenderer,
|
|
22
22
|
renderAgentEvents
|
|
@@ -122,6 +122,35 @@ async function getPrecisionAtK(options) {
|
|
|
122
122
|
};
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
|
+
function aggregateTaskPrecision(perTask, k, since) {
|
|
126
|
+
const tasks = perTask.length;
|
|
127
|
+
let retrieved = 0;
|
|
128
|
+
let reused = 0;
|
|
129
|
+
let macroSum = 0;
|
|
130
|
+
for (const p of perTask) {
|
|
131
|
+
retrieved += p.retrieved;
|
|
132
|
+
reused += p.reused;
|
|
133
|
+
macroSum += p.precision;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
k,
|
|
137
|
+
since,
|
|
138
|
+
tasks,
|
|
139
|
+
retrieved,
|
|
140
|
+
reused,
|
|
141
|
+
microPrecision: retrieved > 0 ? reused / retrieved : 0,
|
|
142
|
+
macroPrecision: tasks > 0 ? macroSum / tasks : 0
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function getOverallPrecisionAtK(options) {
|
|
146
|
+
const k = options?.k ?? 5;
|
|
147
|
+
const perTask = await getPrecisionAtK({
|
|
148
|
+
k,
|
|
149
|
+
since: options?.since,
|
|
150
|
+
limit: options?.limit ?? 1e3
|
|
151
|
+
});
|
|
152
|
+
return aggregateTaskPrecision(perTask, k, options?.since ?? null);
|
|
153
|
+
}
|
|
125
154
|
async function getReadCountsByMemory(options) {
|
|
126
155
|
const args = [];
|
|
127
156
|
let filter = "";
|
|
@@ -217,10 +246,11 @@ async function main() {
|
|
|
217
246
|
}
|
|
218
247
|
return;
|
|
219
248
|
}
|
|
249
|
+
const overall = await getOverallPrecisionAtK({ k: args.k, since: args.since });
|
|
220
250
|
const precision = await getPrecisionAtK({ k: args.k, since: args.since, limit: 25 });
|
|
221
251
|
const topRead = await getReadCountsByMemory({ since: args.since, limit: 15 });
|
|
222
252
|
if (args.json) {
|
|
223
|
-
console.log(JSON.stringify({ k: args.k, precision, topRead }, null, 2));
|
|
253
|
+
console.log(JSON.stringify({ k: args.k, overall, precision, topRead }, null, 2));
|
|
224
254
|
return;
|
|
225
255
|
}
|
|
226
256
|
if (precision.length === 0 && topRead.length === 0) {
|
|
@@ -228,7 +258,15 @@ async function main() {
|
|
|
228
258
|
console.log("Reads are logged on every recall unless EXE_READ_LOG=0.");
|
|
229
259
|
return;
|
|
230
260
|
}
|
|
231
|
-
|
|
261
|
+
const light = (v) => v >= 0.5 ? "\u{1F7E2}" : v >= 0.2 ? "\u{1F7E0}" : "\u{1F534}";
|
|
262
|
+
const window = overall.since ? `since ${overall.since}` : "all time";
|
|
263
|
+
console.log(`Search-quality telemetry \u2014 precision@${args.k} (${window})
|
|
264
|
+
`);
|
|
265
|
+
console.log(
|
|
266
|
+
` Overall ${light(overall.microPrecision)} ${(overall.microPrecision * 100).toFixed(1)}% micro ${light(overall.macroPrecision)} ${(overall.macroPrecision * 100).toFixed(1)}% macro (${overall.tasks} tasks, ${overall.reused}/${overall.retrieved} reused)
|
|
267
|
+
`
|
|
268
|
+
);
|
|
269
|
+
console.log(`Precision@${args.k} by task
|
|
232
270
|
`);
|
|
233
271
|
console.log(
|
|
234
272
|
"NOTE: 'used' is a PROXY \u2014 a memory re-read by a later search in the same\ntask. exe-os has no explicit citation signal. Treat as implicit feedback.\n"
|
package/dist/bin/install.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import "../chunk-XBOLFVMD.js";
|
|
13
13
|
import {
|
|
14
14
|
computeMcpSurfaceHash
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-N7GR3WNB.js";
|
|
16
16
|
import {
|
|
17
17
|
buildDaemonLaunchdPlist,
|
|
18
18
|
buildWatchdogLaunchdPlist,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
generateSessionWrappers
|
|
25
25
|
} from "../chunk-CVTWQZOR.js";
|
|
26
26
|
import "../chunk-WCGNCH3Q.js";
|
|
27
|
-
import "../chunk-
|
|
27
|
+
import "../chunk-VKKXVQED.js";
|
|
28
28
|
import "../chunk-557C2IGL.js";
|
|
29
29
|
import "../chunk-MJVNOOF5.js";
|
|
30
30
|
import "../chunk-3KTQG6IB.js";
|
|
@@ -14165,12 +14165,12 @@ function buildHandlers9() {
|
|
|
14165
14165
|
function registerDiagnostics(server) {
|
|
14166
14166
|
const handlers = buildHandlers9();
|
|
14167
14167
|
const toolNames = Array.from(handlers.keys());
|
|
14168
|
-
toolNames.push("tool_search", "drift", "merge_agent_memories", "agent_liveness", "steward_check", "steward_audit_log", "steward_override", "daemon_restarts", "timers", "spawn_failures", "orchestration_health", "work_map", "work_state");
|
|
14168
|
+
toolNames.push("tool_search", "drift", "merge_agent_memories", "memory_isolation", "agent_liveness", "steward_check", "steward_audit_log", "steward_override", "daemon_restarts", "timers", "spawn_failures", "orchestration_health", "work_map", "work_state");
|
|
14169
14169
|
server.registerTool(
|
|
14170
14170
|
"diagnostics",
|
|
14171
14171
|
{
|
|
14172
14172
|
title: "Diagnostics",
|
|
14173
|
-
description: `System diagnostics and admin operations. Actions: ${toolNames.join(", ")}. Covers health checks, update status, cloud status, key management, employee rename, semantic tool discovery (tool_search), identity drift detection (drift), agent liveness monitoring (agent_liveness), agent memory reassignment (merge_agent_memories), steward identity gate (steward_check, steward_audit_log, steward_override), daemon restart forensics (daemon_restarts \u2014 'why did the daemon restart?': restart-cause breakdown, slowest-timer leaderboard, event-loop-block frequency), timer health dashboard (timers \u2014 'which background timer is about to take the daemon down?': per-timer last/avg/p95/max tick duration, watchdog trips past the 10s event-loop-block budget, whether the timer is executing right now, projected next fire \u2014 sorted worst-first; read-only over already-emitted daemon health logs), and orchestration-health visibility: spawn_failures ('why did dispatch fail?': tmux spawn fail count + cause breakdown path_not_found/claude_launch_failed/timeout + success-vs-fail ratio), orchestration_health ('is the box healthy / is the spiral happening?': load/core, event-loop lag, direct-SQLite-fallback count, event-loop blocks), and work_map ('who's doing what / who died and why?': live sessions \xD7 role \xD7 task \xD7 worktree flag, plus recent session deaths with cause/load + worktree violations), plus work_state ('where were we in this session?': one-row rolling session snapshot).`,
|
|
14173
|
+
description: `System diagnostics and admin operations. Actions: ${toolNames.join(", ")}. Covers health checks, update status, cloud status, key management, employee rename, semantic tool discovery (tool_search), identity drift detection (drift), agent liveness monitoring (agent_liveness), agent memory reassignment (merge_agent_memories), agent memory isolation scoring (memory_isolation \u2014 'how unique is each agent's memory vs how much does it overlap others?': graph-entity-set Jaccard overlap + per-agent uniqueness score; read-only, no embeddings, bounded scan), steward identity gate (steward_check, steward_audit_log, steward_override), daemon restart forensics (daemon_restarts \u2014 'why did the daemon restart?': restart-cause breakdown, slowest-timer leaderboard, event-loop-block frequency), timer health dashboard (timers \u2014 'which background timer is about to take the daemon down?': per-timer last/avg/p95/max tick duration, watchdog trips past the 10s event-loop-block budget, whether the timer is executing right now, projected next fire \u2014 sorted worst-first; read-only over already-emitted daemon health logs), and orchestration-health visibility: spawn_failures ('why did dispatch fail?': tmux spawn fail count + cause breakdown path_not_found/claude_launch_failed/timeout + success-vs-fail ratio), orchestration_health ('is the box healthy / is the spiral happening?': load/core, event-loop lag, direct-SQLite-fallback count, event-loop blocks), and work_map ('who's doing what / who died and why?': live sessions \xD7 role \xD7 task \xD7 worktree flag, plus recent session deaths with cause/load + worktree violations), plus work_state ('where were we in this session?': one-row rolling session snapshot).`,
|
|
14174
14174
|
inputSchema: {
|
|
14175
14175
|
action: z99.string().describe(`Diagnostic operation: ${toolNames.join(", ")}`),
|
|
14176
14176
|
// Pass-through params used by various sub-tools
|
|
@@ -14187,7 +14187,8 @@ function registerDiagnostics(server) {
|
|
|
14187
14187
|
operation: z99.string().optional().describe("Operation name for steward_check/steward_override"),
|
|
14188
14188
|
target: z99.string().optional().describe("Target resource for steward_check/steward_override"),
|
|
14189
14189
|
reason: z99.string().optional().describe("Override reason for steward_override"),
|
|
14190
|
-
session_scope: z99.string().optional().describe("Coordinator session scope for work_state (for example exe1).")
|
|
14190
|
+
session_scope: z99.string().optional().describe("Coordinator session scope for work_state / memory_isolation (for example exe1). memory_isolation defaults to the current session."),
|
|
14191
|
+
all_scopes: z99.boolean().optional().describe("memory_isolation admin opt-in: score across ALL session scopes (defaults false \u2014 scoped to current coordinator session).")
|
|
14191
14192
|
}
|
|
14192
14193
|
},
|
|
14193
14194
|
async (input, extra) => {
|
|
@@ -14256,6 +14257,9 @@ function registerDiagnostics(server) {
|
|
|
14256
14257
|
if (action === "merge_agent_memories") {
|
|
14257
14258
|
return handleMergeAgentMemories(input);
|
|
14258
14259
|
}
|
|
14260
|
+
if (action === "memory_isolation") {
|
|
14261
|
+
return handleMemoryIsolation(input);
|
|
14262
|
+
}
|
|
14259
14263
|
if (action === "steward_check" || action === "steward_audit_log" || action === "steward_override") {
|
|
14260
14264
|
return handleSteward(action, input);
|
|
14261
14265
|
}
|
|
@@ -14368,6 +14372,26 @@ async function handleMergeAgentMemories(input) {
|
|
|
14368
14372
|
};
|
|
14369
14373
|
}
|
|
14370
14374
|
}
|
|
14375
|
+
async function handleMemoryIsolation(input) {
|
|
14376
|
+
try {
|
|
14377
|
+
const { queryMemoryIsolation, formatMemoryIsolationReport } = await import("./memory-isolation-RJJI3MDS.js");
|
|
14378
|
+
const agentId = typeof input.agent_id === "string" ? input.agent_id : void 0;
|
|
14379
|
+
const allScopes = input.all_scopes === true;
|
|
14380
|
+
const sessionScope = typeof input.session_scope === "string" ? input.session_scope : void 0;
|
|
14381
|
+
const result3 = await queryMemoryIsolation({ agentId, sessionScope, allScopes });
|
|
14382
|
+
const asJson = input.format === "json";
|
|
14383
|
+
const text5 = asJson ? JSON.stringify({ focusAgentId: agentId ?? null, ...result3 }, null, 2) : formatMemoryIsolationReport(result3, agentId);
|
|
14384
|
+
return { content: [{ type: "text", text: text5 }] };
|
|
14385
|
+
} catch (err) {
|
|
14386
|
+
return {
|
|
14387
|
+
content: [{
|
|
14388
|
+
type: "text",
|
|
14389
|
+
text: `memory_isolation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
14390
|
+
}],
|
|
14391
|
+
isError: true
|
|
14392
|
+
};
|
|
14393
|
+
}
|
|
14394
|
+
}
|
|
14371
14395
|
async function handleSpawnFailures() {
|
|
14372
14396
|
try {
|
|
14373
14397
|
const { getOrchestrationMetrics } = await import("./orchestration-events-ZZWLYO67.js");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
computeMcpSurfaceHash
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-N7GR3WNB.js";
|
|
5
5
|
import "./chunk-WCGNCH3Q.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-VKKXVQED.js";
|
|
7
7
|
import "./chunk-557C2IGL.js";
|
|
8
8
|
import "./chunk-MJVNOOF5.js";
|
|
9
9
|
import "./chunk-3KTQG6IB.js";
|
package/dist/hooks/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"generatedAt": "2026-07-
|
|
3
|
+
"generatedAt": "2026-07-27T12:06:50.878Z",
|
|
4
4
|
"hashes": {
|
|
5
5
|
"bug-report-worker.js": "21eb4f7a8d56654065d1141a06bc498481b62df84d51943bbe43eb5fb529d6e1",
|
|
6
6
|
"codex-stop-task-finalizer.js": "0bbe8c188a3f416c2d60f39e68e1590c8361be362cbfa129cb7a92fb04b4d694",
|
package/dist/mcp/server.js
CHANGED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import "./chunk-MLKGABMK.js";
|
|
2
|
+
|
|
3
|
+
// src/lib/memory-isolation.ts
|
|
4
|
+
function pairKey(a, b) {
|
|
5
|
+
return a < b ? JSON.stringify([a, b]) : JSON.stringify([b, a]);
|
|
6
|
+
}
|
|
7
|
+
function computeMemoryIsolation(rows, sampled = false) {
|
|
8
|
+
const agentEntities = /* @__PURE__ */ new Map();
|
|
9
|
+
const entityAgents = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const { agentId, entityId } of rows) {
|
|
11
|
+
if (!agentId || !entityId) continue;
|
|
12
|
+
let ae = agentEntities.get(agentId);
|
|
13
|
+
if (!ae) {
|
|
14
|
+
ae = /* @__PURE__ */ new Set();
|
|
15
|
+
agentEntities.set(agentId, ae);
|
|
16
|
+
}
|
|
17
|
+
ae.add(entityId);
|
|
18
|
+
let ea = entityAgents.get(entityId);
|
|
19
|
+
if (!ea) {
|
|
20
|
+
ea = /* @__PURE__ */ new Set();
|
|
21
|
+
entityAgents.set(entityId, ea);
|
|
22
|
+
}
|
|
23
|
+
ea.add(agentId);
|
|
24
|
+
}
|
|
25
|
+
const uniqueCount = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const agentId of agentEntities.keys()) uniqueCount.set(agentId, 0);
|
|
27
|
+
const pairShared = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const agents2 of entityAgents.values()) {
|
|
29
|
+
if (agents2.size === 1) {
|
|
30
|
+
const only = agents2.values().next().value;
|
|
31
|
+
uniqueCount.set(only, (uniqueCount.get(only) ?? 0) + 1);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const list = Array.from(agents2);
|
|
35
|
+
for (let i = 0; i < list.length; i++) {
|
|
36
|
+
for (let j = i + 1; j < list.length; j++) {
|
|
37
|
+
const key = pairKey(list[i], list[j]);
|
|
38
|
+
pairShared.set(key, (pairShared.get(key) ?? 0) + 1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const agentIds = Array.from(agentEntities.keys()).sort();
|
|
43
|
+
const agents = agentIds.map((agentId) => {
|
|
44
|
+
const mySet = agentEntities.get(agentId);
|
|
45
|
+
const entityCount = mySet.size;
|
|
46
|
+
const uniqueEntityCount = uniqueCount.get(agentId) ?? 0;
|
|
47
|
+
const overlaps = [];
|
|
48
|
+
for (const other of agentIds) {
|
|
49
|
+
if (other === agentId) continue;
|
|
50
|
+
const shared = pairShared.get(pairKey(agentId, other)) ?? 0;
|
|
51
|
+
const otherSize = agentEntities.get(other).size;
|
|
52
|
+
const union = entityCount + otherSize - shared;
|
|
53
|
+
const jaccard = union > 0 ? shared / union : 0;
|
|
54
|
+
overlaps.push({ agentId: other, jaccard, sharedEntities: shared });
|
|
55
|
+
}
|
|
56
|
+
let topOverlap = null;
|
|
57
|
+
let sum = 0;
|
|
58
|
+
for (const o of overlaps) {
|
|
59
|
+
sum += o.jaccard;
|
|
60
|
+
if (!topOverlap || o.jaccard > topOverlap.jaccard) topOverlap = o;
|
|
61
|
+
}
|
|
62
|
+
const meanOverlap = overlaps.length > 0 ? sum / overlaps.length : 0;
|
|
63
|
+
return {
|
|
64
|
+
agentId,
|
|
65
|
+
entityCount,
|
|
66
|
+
uniqueEntityCount,
|
|
67
|
+
uniquenessScore: entityCount > 0 ? uniqueEntityCount / entityCount : 0,
|
|
68
|
+
meanOverlap,
|
|
69
|
+
topOverlap
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
agentCount: agentIds.length,
|
|
74
|
+
totalEntities: entityAgents.size,
|
|
75
|
+
sampled,
|
|
76
|
+
agents
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var MEMORY_ISOLATION_ROW_CAP = 5e4;
|
|
80
|
+
async function queryMemoryIsolation(opts = {}) {
|
|
81
|
+
const rowCap = Math.max(1, Math.min(opts.rowCap ?? MEMORY_ISOLATION_ROW_CAP, MEMORY_ISOLATION_ROW_CAP));
|
|
82
|
+
const { getClient } = await import("./lib/database.js");
|
|
83
|
+
const client = await getClient();
|
|
84
|
+
let scopeClause = "";
|
|
85
|
+
const args = [];
|
|
86
|
+
if (!opts.allScopes) {
|
|
87
|
+
const { resolveExeSession } = await import("./lib/tmux-routing.js");
|
|
88
|
+
const scope = opts.sessionScope !== void 0 ? opts.sessionScope : resolveExeSession();
|
|
89
|
+
scopeClause = " AND (m.session_scope = ? OR m.session_scope IS NULL)";
|
|
90
|
+
args.push(scope);
|
|
91
|
+
}
|
|
92
|
+
args.push(rowCap + 1);
|
|
93
|
+
const result = await client.execute({
|
|
94
|
+
sql: `
|
|
95
|
+
SELECT DISTINCT m.agent_id AS agent_id, em.entity_id AS entity_id
|
|
96
|
+
FROM entity_memories em
|
|
97
|
+
JOIN memories m ON m.id = em.memory_id
|
|
98
|
+
WHERE m.agent_id IS NOT NULL AND m.agent_id != ''${scopeClause}
|
|
99
|
+
ORDER BY m.agent_id, em.entity_id
|
|
100
|
+
LIMIT ?
|
|
101
|
+
`,
|
|
102
|
+
args
|
|
103
|
+
});
|
|
104
|
+
const allRows = result.rows.map((r) => ({
|
|
105
|
+
agentId: String(r.agent_id),
|
|
106
|
+
entityId: String(r.entity_id)
|
|
107
|
+
}));
|
|
108
|
+
const sampled = allRows.length > rowCap;
|
|
109
|
+
const rows = sampled ? allRows.slice(0, rowCap) : allRows;
|
|
110
|
+
return computeMemoryIsolation(rows, sampled);
|
|
111
|
+
}
|
|
112
|
+
function formatMemoryIsolationReport(result, focusAgentId) {
|
|
113
|
+
if (result.agentCount === 0) {
|
|
114
|
+
return "No agent\u2194entity associations found. The graph has no entities linked to agent memories yet.";
|
|
115
|
+
}
|
|
116
|
+
const lines = [];
|
|
117
|
+
lines.push("Agent memory isolation \u2014 uniqueness vs overlap (graph-entity Jaccard)");
|
|
118
|
+
lines.push(
|
|
119
|
+
`agents=${result.agentCount} entities=${result.totalEntities}${result.sampled ? " (SAMPLED \u2014 hit scan cap)" : ""}`
|
|
120
|
+
);
|
|
121
|
+
lines.push("");
|
|
122
|
+
const sorted = [...result.agents].sort((a, b) => b.uniquenessScore - a.uniquenessScore);
|
|
123
|
+
for (const a of sorted) {
|
|
124
|
+
const focus = a.agentId === focusAgentId ? "\u2192 " : " ";
|
|
125
|
+
const icon = a.uniquenessScore >= 0.66 ? "\u{1F7E2}" : a.uniquenessScore >= 0.33 ? "\u{1F7E0}" : "\u{1F534}";
|
|
126
|
+
const top = a.topOverlap ? ` top-overlap=${a.topOverlap.agentId}(J=${a.topOverlap.jaccard.toFixed(2)}, shared=${a.topOverlap.sharedEntities})` : " top-overlap=none";
|
|
127
|
+
lines.push(
|
|
128
|
+
`${focus}${icon} ${a.agentId} uniqueness=${a.uniquenessScore.toFixed(2)} entities=${a.entityCount} unique=${a.uniqueEntityCount} meanOverlap=${a.meanOverlap.toFixed(2)}${top}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return lines.join("\n");
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
MEMORY_ISOLATION_ROW_CAP,
|
|
135
|
+
computeMemoryIsolation,
|
|
136
|
+
formatMemoryIsolationReport,
|
|
137
|
+
queryMemoryIsolation
|
|
138
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.354",
|
|
4
4
|
"description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
package/release-notes.json
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"current": "0.9.
|
|
2
|
+
"current": "0.9.354",
|
|
3
3
|
"notes": {
|
|
4
|
-
"0.9.
|
|
5
|
-
"version": "0.9.
|
|
4
|
+
"0.9.354": {
|
|
5
|
+
"version": "0.9.354",
|
|
6
6
|
"date": "2026-07-27",
|
|
7
7
|
"features": [],
|
|
8
8
|
"fixes": [],
|
|
9
9
|
"security": [],
|
|
10
10
|
"other": [
|
|
11
|
-
"v0.9.
|
|
11
|
+
"v0.9.354 — memory-isolation scoring + search-quality precision reporting (#491)"
|
|
12
12
|
],
|
|
13
13
|
"migration_notes": []
|
|
14
14
|
},
|
|
15
|
+
"0.9.353": {
|
|
16
|
+
"version": "0.9.353",
|
|
17
|
+
"date": "2026-07-27",
|
|
18
|
+
"features": [
|
|
19
|
+
"Opus 5.0 (claude-opus-5.0) is now a first-class selectable model across the claude + opencode runtimes, with aliases (opus, opus-5, opus5) and spawn-time validation — fixes multi-customer reports that Opus 5.0 was rejected as unavailable (#480)"
|
|
20
|
+
],
|
|
21
|
+
"fixes": [
|
|
22
|
+
"employee-session spawn cwd is derived from the roster/project root instead of a prior task's stale or deleted worktree, and refuses cleanly (releasing the spawn lock) rather than hard-failing tmux new-session when no valid directory resolves (e1b1444b) (#481)",
|
|
23
|
+
"intercom nudge delivery now confirms the Enter submission on an idle employee pane and re-queues half-delivered (typed-but-unsubmitted) nudges, so a dispatched agent no longer sits idle with an open task when the submit keystroke is dropped (e4889b61) (#483)",
|
|
24
|
+
"ERP deploy health probe resolves its HTTP Host header from the configured stack domain (ERP_SITE_NAME) instead of a hardcoded 'localhost', so a Host-routed Frappe/ERPNext deployment no longer 404s and rolls back an otherwise-healthy release (9747e6e6) (#484)"
|
|
25
|
+
],
|
|
26
|
+
"security": [],
|
|
27
|
+
"other": [],
|
|
28
|
+
"migration_notes": []
|
|
29
|
+
},
|
|
15
30
|
"0.9.352": {
|
|
16
31
|
"version": "0.9.352",
|
|
17
32
|
"date": "2026-07-25",
|
|
@@ -49,24 +64,6 @@
|
|
|
49
64
|
"security": [],
|
|
50
65
|
"other": [],
|
|
51
66
|
"migration_notes": []
|
|
52
|
-
},
|
|
53
|
-
"0.9.349": {
|
|
54
|
-
"version": "0.9.349",
|
|
55
|
-
"date": "2026-07-23",
|
|
56
|
-
"features": [
|
|
57
|
-
"dedicated release lane on build-my-4 — tag-publish + stack-image builds never queue behind PR CI (#465)",
|
|
58
|
-
"fetch-and-scope-check before dispatching fix work (#462)"
|
|
59
|
-
],
|
|
60
|
-
"fixes": [
|
|
61
|
-
"monitor-hub healthcheck probes /app/beszel not /beszel — fixes permanent false-unhealthy on the deploy surface (ae971a4d) (#467)",
|
|
62
|
-
"erp healthchecks use ps not pgrep, and erp-nginx re-resolves its upstream after stack-update recreate (c8fb434f, 9bd1d9f7) (#466)",
|
|
63
|
-
"stack manifest is signed inside the write path (d84537ac) (#461)",
|
|
64
|
-
"fail-loud manifest-derived seeding for stack releases (#460)",
|
|
65
|
-
"landViaPR resolves the release PR by head-sha identity, not branch recency (#459)"
|
|
66
|
-
],
|
|
67
|
-
"security": [],
|
|
68
|
-
"other": [],
|
|
69
|
-
"migration_notes": []
|
|
70
67
|
}
|
|
71
68
|
}
|
|
72
69
|
}
|