@askexenow/exe-os 0.9.111 → 0.9.113
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/README.md +9 -7
- package/dist/bin/agentic-ontology-backfill.js +62 -12
- package/dist/bin/agentic-reflection-backfill.js +37 -2
- package/dist/bin/agentic-semantic-label.js +37 -2
- package/dist/bin/backfill-conversations.js +61 -11
- package/dist/bin/backfill-responses.js +62 -12
- package/dist/bin/backfill-vectors.js +37 -2
- package/dist/bin/bulk-sync-postgres.js +63 -13
- package/dist/bin/cleanup-stale-review-tasks.js +83 -16
- package/dist/bin/cli.js +312 -80
- package/dist/bin/exe-agent-config.js +7 -1
- package/dist/bin/exe-agent.js +29 -3
- package/dist/bin/exe-assign.js +62 -12
- package/dist/bin/exe-boot.js +500 -151
- package/dist/bin/exe-call.js +46 -5
- package/dist/bin/exe-cloud.js +101 -16
- package/dist/bin/exe-dispatch.js +827 -27
- package/dist/bin/exe-doctor.js +61 -11
- package/dist/bin/exe-export-behaviors.js +67 -14
- package/dist/bin/exe-forget.js +62 -12
- package/dist/bin/exe-gateway.js +147 -27
- package/dist/bin/exe-heartbeat.js +83 -16
- package/dist/bin/exe-kill.js +62 -12
- package/dist/bin/exe-launch-agent.js +83 -15
- package/dist/bin/exe-new-employee.js +176 -8
- package/dist/bin/exe-pending-messages.js +83 -16
- package/dist/bin/exe-pending-notifications.js +83 -16
- package/dist/bin/exe-pending-reviews.js +83 -16
- package/dist/bin/exe-rename.js +62 -12
- package/dist/bin/exe-review.js +62 -12
- package/dist/bin/exe-search.js +62 -12
- package/dist/bin/exe-session-cleanup.js +949 -149
- package/dist/bin/exe-settings.js +10 -4
- package/dist/bin/exe-start-codex.js +537 -248
- package/dist/bin/exe-start-opencode.js +547 -168
- package/dist/bin/exe-status.js +83 -16
- package/dist/bin/exe-support.js +1 -1
- package/dist/bin/exe-team.js +62 -12
- package/dist/bin/git-sweep.js +827 -27
- package/dist/bin/graph-backfill.js +62 -12
- package/dist/bin/graph-export.js +62 -12
- package/dist/bin/install.js +62 -4
- package/dist/bin/intercom-check.js +949 -149
- package/dist/bin/pre-publish.js +14 -2
- package/dist/bin/scan-tasks.js +827 -27
- package/dist/bin/setup.js +99 -14
- package/dist/bin/shard-migrate.js +62 -12
- package/dist/bin/stack-update.js +1 -1
- package/dist/bin/update.js +3 -3
- package/dist/gateway/index.js +586 -26
- package/dist/hooks/bug-report-worker.js +586 -26
- package/dist/hooks/codex-stop-task-finalizer.js +977 -143
- package/dist/hooks/commit-complete.js +827 -27
- package/dist/hooks/error-recall.js +62 -12
- package/dist/hooks/ingest.js +4579 -249
- package/dist/hooks/instructions-loaded.js +62 -12
- package/dist/hooks/notification.js +62 -12
- package/dist/hooks/post-compact.js +83 -16
- package/dist/hooks/post-tool-combined.js +83 -16
- package/dist/hooks/pre-compact.js +907 -107
- package/dist/hooks/pre-tool-use.js +98 -16
- package/dist/hooks/prompt-submit.js +596 -30
- package/dist/hooks/session-end.js +909 -112
- package/dist/hooks/session-start.js +112 -17
- package/dist/hooks/stop.js +82 -15
- package/dist/hooks/subagent-stop.js +83 -16
- package/dist/hooks/summary-worker.js +81 -8
- package/dist/index.js +595 -29
- package/dist/lib/agent-config.js +16 -1
- package/dist/lib/cloud-sync.js +45 -1
- package/dist/lib/consolidation.js +16 -1
- package/dist/lib/database.js +23 -0
- package/dist/lib/db.js +23 -0
- package/dist/lib/device-registry.js +23 -0
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +16 -1
- package/dist/lib/exe-daemon.js +482 -52
- package/dist/lib/hybrid-search.js +62 -12
- package/dist/lib/license.js +3 -3
- package/dist/lib/messaging.js +21 -4
- package/dist/lib/schedules.js +37 -2
- package/dist/lib/skill-learning.js +910 -41
- package/dist/lib/status-brief.js +14 -1
- package/dist/lib/store.js +62 -12
- package/dist/lib/tasks.js +843 -93
- package/dist/lib/tmux-routing.js +766 -16
- package/dist/mcp/server.js +238 -41
- package/dist/mcp/tools/create-task.js +525 -15
- package/dist/mcp/tools/deactivate-behavior.js +33 -24
- package/dist/mcp/tools/list-tasks.js +21 -4
- package/dist/mcp/tools/send-message.js +21 -4
- package/dist/mcp/tools/update-task.js +840 -93
- package/dist/runtime/index.js +913 -107
- package/dist/tui/App.js +227 -58
- package/package.json +1 -1
package/dist/tui/App.js
CHANGED
|
@@ -719,6 +719,7 @@ __export(agent_config_exports, {
|
|
|
719
719
|
getAgentRuntime: () => getAgentRuntime,
|
|
720
720
|
loadAgentConfig: () => loadAgentConfig,
|
|
721
721
|
saveAgentConfig: () => saveAgentConfig,
|
|
722
|
+
setAgentMcps: () => setAgentMcps,
|
|
722
723
|
setAgentRuntime: () => setAgentRuntime
|
|
723
724
|
});
|
|
724
725
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
|
|
@@ -745,7 +746,7 @@ function getAgentRuntime(agentId) {
|
|
|
745
746
|
if (orgDefault) return orgDefault;
|
|
746
747
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
747
748
|
}
|
|
748
|
-
function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
749
|
+
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
749
750
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
750
751
|
if (!knownModels) {
|
|
751
752
|
return {
|
|
@@ -760,12 +761,26 @@ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
|
760
761
|
};
|
|
761
762
|
}
|
|
762
763
|
const config = loadAgentConfig();
|
|
764
|
+
const existing = config[agentId];
|
|
763
765
|
const entry = { runtime, model };
|
|
764
766
|
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
767
|
+
if (mcps !== void 0) {
|
|
768
|
+
entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
769
|
+
} else if (existing?.mcps) {
|
|
770
|
+
entry.mcps = existing.mcps;
|
|
771
|
+
}
|
|
765
772
|
config[agentId] = entry;
|
|
766
773
|
saveAgentConfig(config);
|
|
767
774
|
return { ok: true };
|
|
768
775
|
}
|
|
776
|
+
function setAgentMcps(agentId, mcps) {
|
|
777
|
+
const config = loadAgentConfig();
|
|
778
|
+
const existing = config[agentId] ?? getAgentRuntime(agentId);
|
|
779
|
+
existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
780
|
+
config[agentId] = existing;
|
|
781
|
+
saveAgentConfig(config);
|
|
782
|
+
return { ok: true };
|
|
783
|
+
}
|
|
769
784
|
function clearAgentRuntime(agentId) {
|
|
770
785
|
const config = loadAgentConfig();
|
|
771
786
|
delete config[agentId];
|
|
@@ -2847,6 +2862,13 @@ async function ensureSchema() {
|
|
|
2847
2862
|
} catch (e) {
|
|
2848
2863
|
logCatchDebug("migration", e);
|
|
2849
2864
|
}
|
|
2865
|
+
for (const col of ["created_by_agent TEXT", "created_by_device TEXT", "source_session_id TEXT"]) {
|
|
2866
|
+
try {
|
|
2867
|
+
await client.execute({ sql: `ALTER TABLE behaviors ADD COLUMN ${col}`, args: [] });
|
|
2868
|
+
} catch (e) {
|
|
2869
|
+
logCatchDebug("migration", e);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2850
2872
|
try {
|
|
2851
2873
|
await client.execute({
|
|
2852
2874
|
sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
|
|
@@ -4063,6 +4085,22 @@ async function ensureSchema() {
|
|
|
4063
4085
|
} catch (e) {
|
|
4064
4086
|
logCatchDebug("migration", e);
|
|
4065
4087
|
}
|
|
4088
|
+
try {
|
|
4089
|
+
await client.execute({
|
|
4090
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
4091
|
+
args: []
|
|
4092
|
+
});
|
|
4093
|
+
} catch (e) {
|
|
4094
|
+
logCatchDebug("migration", e);
|
|
4095
|
+
}
|
|
4096
|
+
try {
|
|
4097
|
+
await client.execute({
|
|
4098
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
4099
|
+
args: []
|
|
4100
|
+
});
|
|
4101
|
+
} catch (e) {
|
|
4102
|
+
logCatchDebug("migration", e);
|
|
4103
|
+
}
|
|
4066
4104
|
}
|
|
4067
4105
|
async function disposeDatabase() {
|
|
4068
4106
|
if (_walCheckpointTimer) {
|
|
@@ -4481,7 +4519,7 @@ async function assertVpsLicense(opts) {
|
|
|
4481
4519
|
}
|
|
4482
4520
|
if (!transientFailure) {
|
|
4483
4521
|
throw new Error(
|
|
4484
|
-
"License validation failed: unknown backend state. Restore network connectivity to https://askexe.com
|
|
4522
|
+
"License validation failed: unknown backend state. Restore network connectivity to https://cloud.askexe.com and retry."
|
|
4485
4523
|
);
|
|
4486
4524
|
}
|
|
4487
4525
|
const fresh = await getCachedLicense();
|
|
@@ -4518,7 +4556,7 @@ async function assertVpsLicense(opts) {
|
|
|
4518
4556
|
} catch {
|
|
4519
4557
|
}
|
|
4520
4558
|
throw new Error(
|
|
4521
|
-
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com
|
|
4559
|
+
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://cloud.askexe.com and retry. This VPS image refuses to boot after the offline grace window.`
|
|
4522
4560
|
);
|
|
4523
4561
|
}
|
|
4524
4562
|
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
@@ -4550,7 +4588,7 @@ var init_license = __esm({
|
|
|
4550
4588
|
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
4551
4589
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
4552
4590
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
4553
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
4591
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
4554
4592
|
RETRY_DELAY_MS = 500;
|
|
4555
4593
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
4556
4594
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
@@ -5071,6 +5109,19 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
5071
5109
|
args: [identifier, ...scope.args]
|
|
5072
5110
|
});
|
|
5073
5111
|
if (result.rows.length === 1) return result.rows[0];
|
|
5112
|
+
if (/^[a-f0-9]{7,12}$/i.test(identifier)) {
|
|
5113
|
+
result = await client.execute({
|
|
5114
|
+
sql: `SELECT * FROM tasks WHERE id LIKE ?`,
|
|
5115
|
+
args: [`${identifier}%`]
|
|
5116
|
+
});
|
|
5117
|
+
if (result.rows.length === 1) return result.rows[0];
|
|
5118
|
+
if (result.rows.length > 1) {
|
|
5119
|
+
const matches = result.rows.map((r) => `${String(r.id)} "${String(r.title)}" (${String(r.status)})`).join(", ");
|
|
5120
|
+
throw new Error(
|
|
5121
|
+
`Multiple tasks match short-ID "${identifier}": ${matches}. Use a longer prefix to disambiguate.`
|
|
5122
|
+
);
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5074
5125
|
result = await client.execute({
|
|
5075
5126
|
sql: `SELECT * FROM tasks WHERE task_file LIKE ?${scope.sql}`,
|
|
5076
5127
|
args: [`%${identifier}%`, ...scope.args]
|
|
@@ -5925,12 +5976,13 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
5925
5976
|
WHERE blocked_by = ? AND status = 'blocked'`,
|
|
5926
5977
|
args: [now, taskId]
|
|
5927
5978
|
});
|
|
5928
|
-
if (
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5979
|
+
if (unblocked.rowsAffected === 0) return;
|
|
5980
|
+
const ubScope = sessionScopeFilter();
|
|
5981
|
+
const unblockedRows = await client.execute({
|
|
5982
|
+
sql: `SELECT id, title, assigned_to, priority, task_file FROM tasks WHERE blocked_by IS NULL AND updated_at = ?${ubScope.sql}`,
|
|
5983
|
+
args: [now, ...ubScope.args]
|
|
5984
|
+
});
|
|
5985
|
+
if (baseDir) {
|
|
5934
5986
|
for (const ur of unblockedRows.rows) {
|
|
5935
5987
|
try {
|
|
5936
5988
|
const ubFile = path16.join(baseDir, String(ur.task_file));
|
|
@@ -5942,6 +5994,19 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
5942
5994
|
}
|
|
5943
5995
|
}
|
|
5944
5996
|
}
|
|
5997
|
+
if (unblockedRows.rows.length > 0 && !process.env.VITEST) {
|
|
5998
|
+
try {
|
|
5999
|
+
const { queueIntercom: queueIntercom2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
|
|
6000
|
+
const dispatched = /* @__PURE__ */ new Set();
|
|
6001
|
+
for (const ur of unblockedRows.rows) {
|
|
6002
|
+
const assignee = String(ur.assigned_to);
|
|
6003
|
+
if (dispatched.has(assignee)) continue;
|
|
6004
|
+
dispatched.add(assignee);
|
|
6005
|
+
queueIntercom2(`${assignee}`, `unblocked: "${String(ur.title)}" is now ready`);
|
|
6006
|
+
}
|
|
6007
|
+
} catch {
|
|
6008
|
+
}
|
|
6009
|
+
}
|
|
5945
6010
|
}
|
|
5946
6011
|
async function findNextTask(assignedTo) {
|
|
5947
6012
|
const client = getClient();
|
|
@@ -6151,6 +6216,15 @@ var init_embedder = __esm({
|
|
|
6151
6216
|
// src/lib/behaviors.ts
|
|
6152
6217
|
import crypto5 from "crypto";
|
|
6153
6218
|
async function storeBehavior(opts) {
|
|
6219
|
+
try {
|
|
6220
|
+
const { loadEmployeesSync: loadEmployeesSync2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
6221
|
+
const roster = loadEmployeesSync2();
|
|
6222
|
+
if (roster.length > 0 && !roster.some((e) => e.name === opts.agentId)) {
|
|
6223
|
+
throw new Error(`Agent "${opts.agentId}" not found in roster. Cannot store behavior for unregistered agent.`);
|
|
6224
|
+
}
|
|
6225
|
+
} catch (e) {
|
|
6226
|
+
if (e instanceof Error && e.message.includes("not found in roster")) throw e;
|
|
6227
|
+
}
|
|
6154
6228
|
const client = getClient();
|
|
6155
6229
|
const id = crypto5.randomUUID();
|
|
6156
6230
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -6161,10 +6235,18 @@ async function storeBehavior(opts) {
|
|
|
6161
6235
|
vector = new Float32Array(vec);
|
|
6162
6236
|
} catch {
|
|
6163
6237
|
}
|
|
6238
|
+
let createdByDevice = null;
|
|
6239
|
+
try {
|
|
6240
|
+
const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
6241
|
+
createdByDevice = loadDeviceId2() ?? null;
|
|
6242
|
+
} catch {
|
|
6243
|
+
}
|
|
6244
|
+
const createdByAgent = process.env.AGENT_ID ?? null;
|
|
6245
|
+
const sourceSessionId = process.env.CLAUDE_SESSION_ID ?? process.env.SESSION_ID ?? null;
|
|
6164
6246
|
await client.execute({
|
|
6165
|
-
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector)
|
|
6166
|
-
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?)`,
|
|
6167
|
-
args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now, vector ? vector.buffer : null]
|
|
6247
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at, vector, created_by_agent, created_by_device, source_session_id)
|
|
6248
|
+
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?)`,
|
|
6249
|
+
args: [id, opts.agentId, opts.projectName ?? null, opts.domain ?? null, opts.priority ?? "p1", opts.content, now, now, vector ? vector.buffer : null, createdByAgent, createdByDevice, sourceSessionId]
|
|
6168
6250
|
});
|
|
6169
6251
|
return id;
|
|
6170
6252
|
}
|
|
@@ -6596,6 +6678,12 @@ async function updateTask(input) {
|
|
|
6596
6678
|
}
|
|
6597
6679
|
}
|
|
6598
6680
|
}
|
|
6681
|
+
if (input.status === "cancelled") {
|
|
6682
|
+
try {
|
|
6683
|
+
await cascadeUnblock(taskId, input.baseDir, now);
|
|
6684
|
+
} catch {
|
|
6685
|
+
}
|
|
6686
|
+
}
|
|
6599
6687
|
if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
6600
6688
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
6601
6689
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
@@ -7127,11 +7215,12 @@ function getDispatchedBy(sessionKey) {
|
|
|
7127
7215
|
}
|
|
7128
7216
|
}
|
|
7129
7217
|
function resolveExeSession() {
|
|
7218
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
7219
|
+
const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
7220
|
+
if (fromEnv) return fromEnv;
|
|
7221
|
+
}
|
|
7130
7222
|
const mySession = getMySession();
|
|
7131
7223
|
if (!mySession) {
|
|
7132
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
7133
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
7134
|
-
}
|
|
7135
7224
|
return null;
|
|
7136
7225
|
}
|
|
7137
7226
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -7146,6 +7235,10 @@ function resolveExeSession() {
|
|
|
7146
7235
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
7147
7236
|
`
|
|
7148
7237
|
);
|
|
7238
|
+
try {
|
|
7239
|
+
registerParentExe(key, fromSessionName);
|
|
7240
|
+
} catch {
|
|
7241
|
+
}
|
|
7149
7242
|
candidate = fromSessionName;
|
|
7150
7243
|
} else {
|
|
7151
7244
|
candidate = fromCache;
|
|
@@ -9164,11 +9257,17 @@ var init_platform_procedures = __esm({
|
|
|
9164
9257
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
9165
9258
|
},
|
|
9166
9259
|
{
|
|
9167
|
-
title: "
|
|
9260
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
9168
9261
|
domain: "workflow",
|
|
9169
9262
|
priority: "p1",
|
|
9170
9263
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
9171
9264
|
},
|
|
9265
|
+
{
|
|
9266
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
9267
|
+
domain: "identity",
|
|
9268
|
+
priority: "p0",
|
|
9269
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
9270
|
+
},
|
|
9172
9271
|
{
|
|
9173
9272
|
title: "Single dispatch path \u2014 create_task only",
|
|
9174
9273
|
domain: "workflow",
|
|
@@ -9202,6 +9301,12 @@ var init_platform_procedures = __esm({
|
|
|
9202
9301
|
priority: "p0",
|
|
9203
9302
|
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
9204
9303
|
},
|
|
9304
|
+
{
|
|
9305
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
9306
|
+
domain: "security",
|
|
9307
|
+
priority: "p0",
|
|
9308
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
9309
|
+
},
|
|
9205
9310
|
{
|
|
9206
9311
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
9207
9312
|
domain: "support",
|
|
@@ -9353,7 +9458,7 @@ var init_platform_procedures = __esm({
|
|
|
9353
9458
|
title: "MCP tool dispatch \u2014 all tools use action parameter",
|
|
9354
9459
|
domain: "tool-use",
|
|
9355
9460
|
priority: "p0",
|
|
9356
|
-
content: 'exe-os MCP tools
|
|
9461
|
+
content: 'exe-os MCP tools use consolidated action-based dispatch by default (19 tools). Call domain tools with an action parameter: memory(action="recall"), task(action="create"), config(action="list_employees"), etc. Legacy mode (108 separate tools like recall_my_memory, create_task) is still available via EXE_MCP_TOOL_SURFACE=legacy but will be removed in a future version. If you see specific tool names, call them directly \u2014 both surfaces are identical. Consolidated is the default and recommended surface.'
|
|
9357
9462
|
},
|
|
9358
9463
|
{
|
|
9359
9464
|
title: "MCP tools \u2014 memory, decision, and search",
|
|
@@ -10965,6 +11070,8 @@ var tui_data_exports = {};
|
|
|
10965
11070
|
__export(tui_data_exports, {
|
|
10966
11071
|
loadMemoryDashboard: () => loadMemoryDashboard,
|
|
10967
11072
|
loadTaskList: () => loadTaskList,
|
|
11073
|
+
loadTeamBadgeCounts: () => loadTeamBadgeCounts,
|
|
11074
|
+
loadTeamDetailMetrics: () => loadTeamDetailMetrics,
|
|
10968
11075
|
loadTeamMetrics: () => loadTeamMetrics,
|
|
10969
11076
|
searchWikiMemoryRows: () => searchWikiMemoryRows
|
|
10970
11077
|
});
|
|
@@ -10993,16 +11100,20 @@ async function loadMemoryDashboard(limit) {
|
|
|
10993
11100
|
}))
|
|
10994
11101
|
};
|
|
10995
11102
|
}
|
|
10996
|
-
async function
|
|
11103
|
+
async function loadTeamBadgeCounts() {
|
|
10997
11104
|
const client = getClient();
|
|
10998
11105
|
const memoryCounts = /* @__PURE__ */ new Map();
|
|
10999
|
-
const projectsByEmployee = /* @__PURE__ */ new Map();
|
|
11000
|
-
const currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
11001
|
-
const scope = sessionScopeFilter();
|
|
11002
11106
|
const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
|
|
11003
11107
|
for (const row of memResult.rows) {
|
|
11004
11108
|
memoryCounts.set(String(row.agent_id), Number(row.cnt));
|
|
11005
11109
|
}
|
|
11110
|
+
return memoryCounts;
|
|
11111
|
+
}
|
|
11112
|
+
async function loadTeamDetailMetrics(employeeNames) {
|
|
11113
|
+
const client = getClient();
|
|
11114
|
+
const projectsByEmployee = /* @__PURE__ */ new Map();
|
|
11115
|
+
const currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
11116
|
+
const scope = sessionScopeFilter();
|
|
11006
11117
|
for (const employeeName of employeeNames) {
|
|
11007
11118
|
const [projectResult, taskResult] = await Promise.all([
|
|
11008
11119
|
client.execute({
|
|
@@ -11035,6 +11146,13 @@ async function loadTeamMetrics(employeeNames) {
|
|
|
11035
11146
|
currentTaskByEmployee.set(employeeName, String(taskResult.rows[0].title));
|
|
11036
11147
|
}
|
|
11037
11148
|
}
|
|
11149
|
+
return { projectsByEmployee, currentTaskByEmployee };
|
|
11150
|
+
}
|
|
11151
|
+
async function loadTeamMetrics(employeeNames) {
|
|
11152
|
+
const [memoryCounts, { projectsByEmployee, currentTaskByEmployee }] = await Promise.all([
|
|
11153
|
+
loadTeamBadgeCounts(),
|
|
11154
|
+
loadTeamDetailMetrics(employeeNames)
|
|
11155
|
+
]);
|
|
11038
11156
|
return { memoryCounts, projectsByEmployee, currentTaskByEmployee };
|
|
11039
11157
|
}
|
|
11040
11158
|
async function loadTaskList() {
|
|
@@ -12692,10 +12810,24 @@ function stableId(memoryId, type, content) {
|
|
|
12692
12810
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
12693
12811
|
}
|
|
12694
12812
|
function cleanText(text) {
|
|
12695
|
-
|
|
12813
|
+
let cleaned = text.replace(
|
|
12814
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
12815
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
12816
|
+
);
|
|
12817
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
12818
|
+
return cleaned;
|
|
12696
12819
|
}
|
|
12697
|
-
function
|
|
12698
|
-
|
|
12820
|
+
function splitSegments(text) {
|
|
12821
|
+
const cleaned = cleanText(text);
|
|
12822
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
12823
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
12824
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
12825
|
+
if (lines.length > 0) return lines;
|
|
12826
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
12827
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
12828
|
+
}
|
|
12829
|
+
}
|
|
12830
|
+
return segments;
|
|
12699
12831
|
}
|
|
12700
12832
|
function inferCardType(sentence, toolName) {
|
|
12701
12833
|
const lower = sentence.toLowerCase();
|
|
@@ -12727,12 +12859,12 @@ function predicateFor(type) {
|
|
|
12727
12859
|
}
|
|
12728
12860
|
}
|
|
12729
12861
|
function extractMemoryCards(row) {
|
|
12730
|
-
const
|
|
12862
|
+
const segments = splitSegments(row.raw_text);
|
|
12731
12863
|
const cards = [];
|
|
12732
|
-
for (const sentence of
|
|
12864
|
+
for (const sentence of segments) {
|
|
12733
12865
|
const type = inferCardType(sentence, row.tool_name);
|
|
12734
12866
|
const subject = extractSubject(sentence, row.agent_id);
|
|
12735
|
-
const content = sentence.length >
|
|
12867
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
12736
12868
|
cards.push({
|
|
12737
12869
|
id: stableId(row.id, type, content),
|
|
12738
12870
|
memory_id: row.id,
|
|
@@ -12828,13 +12960,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
12828
12960
|
last_accessed: String(row.timestamp)
|
|
12829
12961
|
}));
|
|
12830
12962
|
}
|
|
12831
|
-
var MAX_CARDS_PER_MEMORY,
|
|
12963
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
12832
12964
|
var init_memory_cards = __esm({
|
|
12833
12965
|
"src/lib/memory-cards.ts"() {
|
|
12834
12966
|
"use strict";
|
|
12835
12967
|
init_database();
|
|
12836
|
-
MAX_CARDS_PER_MEMORY =
|
|
12837
|
-
|
|
12968
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
12969
|
+
MAX_SEGMENT_CHARS = 500;
|
|
12970
|
+
MIN_SEGMENT_CHARS = 20;
|
|
12838
12971
|
}
|
|
12839
12972
|
});
|
|
12840
12973
|
|
|
@@ -20530,9 +20663,23 @@ var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
|
|
|
20530
20663
|
function getSessionPrompt(storedPrompt) {
|
|
20531
20664
|
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
20532
20665
|
const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
20666
|
+
let titlePrefix = "";
|
|
20667
|
+
const frontmatterMatch = withoutProcedures.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
20668
|
+
if (frontmatterMatch) {
|
|
20669
|
+
const titleMatch = frontmatterMatch[1].match(/^title:\s*(.+)$/m);
|
|
20670
|
+
const roleMatch = frontmatterMatch[1].match(/^role:\s*(.+)$/m);
|
|
20671
|
+
if (titleMatch) {
|
|
20672
|
+
const title = titleMatch[1].trim();
|
|
20673
|
+
const role = roleMatch ? roleMatch[1].trim() : "";
|
|
20674
|
+
if (title && role && title.toLowerCase() !== role.toLowerCase()) {
|
|
20675
|
+
titlePrefix = `## Your Identity
|
|
20676
|
+
You are **${title}** (specialist). `;
|
|
20677
|
+
}
|
|
20678
|
+
}
|
|
20679
|
+
}
|
|
20533
20680
|
const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
|
|
20534
20681
|
const globalBlock = getGlobalProceduresBlock();
|
|
20535
|
-
return `${globalBlock}${rolePrompt}
|
|
20682
|
+
return `${globalBlock}${titlePrefix}${rolePrompt}
|
|
20536
20683
|
${BASE_OPERATING_PROCEDURES}`;
|
|
20537
20684
|
}
|
|
20538
20685
|
|
|
@@ -21263,7 +21410,7 @@ function useOrchestrator(enabled = true) {
|
|
|
21263
21410
|
const [pendingReviews, setPendingReviews] = useState8(0);
|
|
21264
21411
|
const [isLoading, setIsLoading] = useState8(true);
|
|
21265
21412
|
const orchestratorRef = useRef5(null);
|
|
21266
|
-
const exeSessionRef = useRef5("
|
|
21413
|
+
const exeSessionRef = useRef5("");
|
|
21267
21414
|
const coordinatorNameRef = useRef5(DEFAULT_COORDINATOR_TEMPLATE_NAME);
|
|
21268
21415
|
useEffect10(() => {
|
|
21269
21416
|
if (!enabled) return;
|
|
@@ -22725,7 +22872,6 @@ function getAgentStatus(agentId) {
|
|
|
22725
22872
|
|
|
22726
22873
|
// src/tui/views/Team.tsx
|
|
22727
22874
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
22728
|
-
var DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
|
|
22729
22875
|
function roleBadgeColor(role) {
|
|
22730
22876
|
switch (role.toLowerCase()) {
|
|
22731
22877
|
case "coo":
|
|
@@ -22746,6 +22892,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22746
22892
|
const [members, setMembers] = useState12([]);
|
|
22747
22893
|
const [externals, setExternals] = useState12([]);
|
|
22748
22894
|
const [loading, setLoading] = useState12(!demo);
|
|
22895
|
+
const [badgeInFlight, setBadgeInFlight] = useState12(!demo);
|
|
22896
|
+
const [detailInFlight, setDetailInFlight] = useState12(!demo);
|
|
22749
22897
|
const [dbError, setDbError] = useState12(null);
|
|
22750
22898
|
const [selectedIdx, setSelectedIdx] = useState12(0);
|
|
22751
22899
|
const [showDetail, setShowDetail] = useState12(false);
|
|
@@ -22758,6 +22906,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22758
22906
|
setMembers(DEMO_EMPLOYEES.map((e) => ({ ...e })));
|
|
22759
22907
|
setExternals(DEMO_EXTERNAL_AGENTS);
|
|
22760
22908
|
setLoading(false);
|
|
22909
|
+
setBadgeInFlight(false);
|
|
22910
|
+
setDetailInFlight(false);
|
|
22761
22911
|
return;
|
|
22762
22912
|
}
|
|
22763
22913
|
loadTeam();
|
|
@@ -22796,33 +22946,48 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22796
22946
|
let projectsByEmployee = /* @__PURE__ */ new Map();
|
|
22797
22947
|
let currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
22798
22948
|
try {
|
|
22799
|
-
const {
|
|
22800
|
-
|
|
22801
|
-
|
|
22802
|
-
|
|
22803
|
-
|
|
22804
|
-
|
|
22805
|
-
|
|
22806
|
-
|
|
22807
|
-
|
|
22949
|
+
const { loadTeamBadgeCounts: loadTeamBadgeCounts2, loadTeamDetailMetrics: loadTeamDetailMetrics2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
|
|
22950
|
+
setBadgeInFlight(true);
|
|
22951
|
+
const badgeCountsPromise = loadTeamBadgeCounts2();
|
|
22952
|
+
const detailsPromise = loadTeamDetailMetrics2(roster.map((emp) => emp.name));
|
|
22953
|
+
memoryCounts = await badgeCountsPromise;
|
|
22954
|
+
setBadgeInFlight(false);
|
|
22955
|
+
const initialMembers = roster.map((emp) => {
|
|
22956
|
+
const agentSt = getAgentStatus(emp.name);
|
|
22957
|
+
return {
|
|
22958
|
+
name: emp.name,
|
|
22959
|
+
role: emp.role,
|
|
22960
|
+
status: agentSt.label,
|
|
22961
|
+
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
22962
|
+
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
22963
|
+
projects: void 0,
|
|
22964
|
+
currentTask: void 0,
|
|
22965
|
+
sessionName: agentSt.session
|
|
22966
|
+
};
|
|
22967
|
+
});
|
|
22968
|
+
setMembers(initialMembers);
|
|
22969
|
+
setDetailInFlight(true);
|
|
22970
|
+
const teamMetrics = await detailsPromise;
|
|
22971
|
+
projectsByEmployee = teamMetrics.projectsByEmployee;
|
|
22808
22972
|
currentTaskByEmployee = teamMetrics.currentTaskByEmployee;
|
|
22973
|
+
setDetailInFlight(false);
|
|
22974
|
+
const finalMembers = roster.map((emp) => {
|
|
22975
|
+
const agentSt = getAgentStatus(emp.name);
|
|
22976
|
+
return {
|
|
22977
|
+
name: emp.name,
|
|
22978
|
+
role: emp.role,
|
|
22979
|
+
status: agentSt.label,
|
|
22980
|
+
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
22981
|
+
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
22982
|
+
projects: projectsByEmployee.get(emp.name),
|
|
22983
|
+
currentTask: currentTaskByEmployee.get(emp.name),
|
|
22984
|
+
sessionName: agentSt.session
|
|
22985
|
+
};
|
|
22986
|
+
});
|
|
22987
|
+
setMembers(finalMembers);
|
|
22988
|
+
setDbError(null);
|
|
22809
22989
|
} catch {
|
|
22810
22990
|
}
|
|
22811
|
-
const teamData = roster.map((emp) => {
|
|
22812
|
-
const agentSt = getAgentStatus(emp.name);
|
|
22813
|
-
return {
|
|
22814
|
-
name: emp.name,
|
|
22815
|
-
role: emp.role,
|
|
22816
|
-
status: agentSt.label,
|
|
22817
|
-
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
22818
|
-
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
22819
|
-
projects: projectsByEmployee.get(emp.name),
|
|
22820
|
-
currentTask: currentTaskByEmployee.get(emp.name),
|
|
22821
|
-
sessionName: agentSt.session
|
|
22822
|
-
};
|
|
22823
|
-
});
|
|
22824
|
-
setMembers(teamData);
|
|
22825
|
-
setDbError(null);
|
|
22826
22991
|
try {
|
|
22827
22992
|
const { existsSync: existsSync20, readFileSync: readFileSync14 } = await import("fs");
|
|
22828
22993
|
const { join: join2 } = await import("path");
|
|
@@ -22844,6 +23009,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22844
23009
|
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
22845
23010
|
} finally {
|
|
22846
23011
|
setLoading(false);
|
|
23012
|
+
setBadgeInFlight(false);
|
|
23013
|
+
setDetailInFlight(false);
|
|
22847
23014
|
}
|
|
22848
23015
|
});
|
|
22849
23016
|
}
|
|
@@ -22898,6 +23065,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22898
23065
|
orch.pendingReviews,
|
|
22899
23066
|
" review(s) pending coordinator attention"
|
|
22900
23067
|
] }),
|
|
23068
|
+
badgeInFlight && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: " Loading memory counts..." }),
|
|
23069
|
+
detailInFlight && /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading employee details..." }),
|
|
22901
23070
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
22902
23071
|
/* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
|
|
22903
23072
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.113",
|
|
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",
|