@askexenow/exe-os 0.9.112 → 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 +54 -11
- package/dist/bin/agentic-reflection-backfill.js +29 -1
- package/dist/bin/agentic-semantic-label.js +29 -1
- package/dist/bin/backfill-conversations.js +53 -10
- package/dist/bin/backfill-responses.js +54 -11
- package/dist/bin/backfill-vectors.js +29 -1
- package/dist/bin/bulk-sync-postgres.js +55 -12
- package/dist/bin/cleanup-stale-review-tasks.js +75 -15
- package/dist/bin/cli.js +293 -76
- package/dist/bin/exe-agent-config.js +7 -1
- package/dist/bin/exe-agent.js +28 -2
- package/dist/bin/exe-assign.js +54 -11
- package/dist/bin/exe-boot.js +481 -147
- package/dist/bin/exe-call.js +45 -4
- package/dist/bin/exe-cloud.js +93 -15
- package/dist/bin/exe-dispatch.js +369 -24
- package/dist/bin/exe-doctor.js +53 -10
- package/dist/bin/exe-export-behaviors.js +54 -11
- package/dist/bin/exe-forget.js +54 -11
- package/dist/bin/exe-gateway.js +128 -23
- package/dist/bin/exe-heartbeat.js +75 -15
- package/dist/bin/exe-kill.js +54 -11
- package/dist/bin/exe-launch-agent.js +70 -12
- package/dist/bin/exe-new-employee.js +175 -7
- package/dist/bin/exe-pending-messages.js +75 -15
- package/dist/bin/exe-pending-notifications.js +75 -15
- package/dist/bin/exe-pending-reviews.js +75 -15
- package/dist/bin/exe-rename.js +54 -11
- package/dist/bin/exe-review.js +54 -11
- package/dist/bin/exe-search.js +54 -11
- package/dist/bin/exe-session-cleanup.js +491 -146
- package/dist/bin/exe-settings.js +10 -4
- package/dist/bin/exe-start-codex.js +524 -245
- package/dist/bin/exe-start-opencode.js +534 -165
- package/dist/bin/exe-status.js +75 -15
- package/dist/bin/exe-support.js +1 -1
- package/dist/bin/exe-team.js +54 -11
- package/dist/bin/git-sweep.js +369 -24
- package/dist/bin/graph-backfill.js +54 -11
- package/dist/bin/graph-export.js +54 -11
- package/dist/bin/install.js +62 -4
- package/dist/bin/intercom-check.js +491 -146
- package/dist/bin/pre-publish.js +13 -1
- package/dist/bin/scan-tasks.js +369 -24
- package/dist/bin/setup.js +91 -13
- package/dist/bin/shard-migrate.js +54 -11
- package/dist/bin/stack-update.js +1 -1
- package/dist/bin/update.js +3 -3
- package/dist/gateway/index.js +128 -23
- package/dist/hooks/bug-report-worker.js +128 -23
- package/dist/hooks/codex-stop-task-finalizer.js +512 -140
- package/dist/hooks/commit-complete.js +369 -24
- package/dist/hooks/error-recall.js +54 -11
- package/dist/hooks/ingest.js +4575 -252
- package/dist/hooks/instructions-loaded.js +54 -11
- package/dist/hooks/notification.js +54 -11
- package/dist/hooks/post-compact.js +75 -15
- package/dist/hooks/post-tool-combined.js +75 -15
- package/dist/hooks/pre-compact.js +449 -104
- package/dist/hooks/pre-tool-use.js +90 -15
- package/dist/hooks/prompt-submit.js +129 -24
- package/dist/hooks/session-end.js +451 -109
- package/dist/hooks/session-start.js +104 -16
- package/dist/hooks/stop.js +74 -14
- package/dist/hooks/subagent-stop.js +75 -15
- package/dist/hooks/summary-worker.js +73 -7
- package/dist/index.js +128 -23
- package/dist/lib/agent-config.js +16 -1
- package/dist/lib/cloud-sync.js +38 -1
- package/dist/lib/consolidation.js +16 -1
- package/dist/lib/database.js +16 -0
- package/dist/lib/db.js +16 -0
- package/dist/lib/device-registry.js +16 -0
- package/dist/lib/employee-templates.js +29 -3
- package/dist/lib/employees.js +16 -1
- package/dist/lib/exe-daemon.js +268 -42
- package/dist/lib/hybrid-search.js +54 -11
- package/dist/lib/license.js +3 -3
- package/dist/lib/messaging.js +21 -4
- package/dist/lib/schedules.js +29 -1
- package/dist/lib/skill-learning.js +458 -70
- package/dist/lib/status-brief.js +14 -1
- package/dist/lib/store.js +54 -11
- package/dist/lib/tasks.js +393 -91
- package/dist/lib/tmux-routing.js +316 -14
- package/dist/mcp/server.js +169 -30
- package/dist/mcp/tools/create-task.js +75 -13
- 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 +390 -91
- package/dist/runtime/index.js +446 -101
- package/dist/tui/App.js +208 -54
- 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];
|
|
@@ -4070,6 +4085,22 @@ async function ensureSchema() {
|
|
|
4070
4085
|
} catch (e) {
|
|
4071
4086
|
logCatchDebug("migration", e);
|
|
4072
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
|
+
}
|
|
4073
4104
|
}
|
|
4074
4105
|
async function disposeDatabase() {
|
|
4075
4106
|
if (_walCheckpointTimer) {
|
|
@@ -4488,7 +4519,7 @@ async function assertVpsLicense(opts) {
|
|
|
4488
4519
|
}
|
|
4489
4520
|
if (!transientFailure) {
|
|
4490
4521
|
throw new Error(
|
|
4491
|
-
"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."
|
|
4492
4523
|
);
|
|
4493
4524
|
}
|
|
4494
4525
|
const fresh = await getCachedLicense();
|
|
@@ -4525,7 +4556,7 @@ async function assertVpsLicense(opts) {
|
|
|
4525
4556
|
} catch {
|
|
4526
4557
|
}
|
|
4527
4558
|
throw new Error(
|
|
4528
|
-
`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.`
|
|
4529
4560
|
);
|
|
4530
4561
|
}
|
|
4531
4562
|
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
@@ -4557,7 +4588,7 @@ var init_license = __esm({
|
|
|
4557
4588
|
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
4558
4589
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
4559
4590
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
4560
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
4591
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
4561
4592
|
RETRY_DELAY_MS = 500;
|
|
4562
4593
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
4563
4594
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
@@ -5078,6 +5109,19 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
5078
5109
|
args: [identifier, ...scope.args]
|
|
5079
5110
|
});
|
|
5080
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
|
+
}
|
|
5081
5125
|
result = await client.execute({
|
|
5082
5126
|
sql: `SELECT * FROM tasks WHERE task_file LIKE ?${scope.sql}`,
|
|
5083
5127
|
args: [`%${identifier}%`, ...scope.args]
|
|
@@ -5932,12 +5976,13 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
5932
5976
|
WHERE blocked_by = ? AND status = 'blocked'`,
|
|
5933
5977
|
args: [now, taskId]
|
|
5934
5978
|
});
|
|
5935
|
-
if (
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
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) {
|
|
5941
5986
|
for (const ur of unblockedRows.rows) {
|
|
5942
5987
|
try {
|
|
5943
5988
|
const ubFile = path16.join(baseDir, String(ur.task_file));
|
|
@@ -5949,6 +5994,19 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
5949
5994
|
}
|
|
5950
5995
|
}
|
|
5951
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
|
+
}
|
|
5952
6010
|
}
|
|
5953
6011
|
async function findNextTask(assignedTo) {
|
|
5954
6012
|
const client = getClient();
|
|
@@ -6158,6 +6216,15 @@ var init_embedder = __esm({
|
|
|
6158
6216
|
// src/lib/behaviors.ts
|
|
6159
6217
|
import crypto5 from "crypto";
|
|
6160
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
|
+
}
|
|
6161
6228
|
const client = getClient();
|
|
6162
6229
|
const id = crypto5.randomUUID();
|
|
6163
6230
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -6611,6 +6678,12 @@ async function updateTask(input) {
|
|
|
6611
6678
|
}
|
|
6612
6679
|
}
|
|
6613
6680
|
}
|
|
6681
|
+
if (input.status === "cancelled") {
|
|
6682
|
+
try {
|
|
6683
|
+
await cascadeUnblock(taskId, input.baseDir, now);
|
|
6684
|
+
} catch {
|
|
6685
|
+
}
|
|
6686
|
+
}
|
|
6614
6687
|
if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
6615
6688
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
6616
6689
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
@@ -7142,11 +7215,12 @@ function getDispatchedBy(sessionKey) {
|
|
|
7142
7215
|
}
|
|
7143
7216
|
}
|
|
7144
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
|
+
}
|
|
7145
7222
|
const mySession = getMySession();
|
|
7146
7223
|
if (!mySession) {
|
|
7147
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
7148
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
7149
|
-
}
|
|
7150
7224
|
return null;
|
|
7151
7225
|
}
|
|
7152
7226
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -7161,6 +7235,10 @@ function resolveExeSession() {
|
|
|
7161
7235
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
7162
7236
|
`
|
|
7163
7237
|
);
|
|
7238
|
+
try {
|
|
7239
|
+
registerParentExe(key, fromSessionName);
|
|
7240
|
+
} catch {
|
|
7241
|
+
}
|
|
7164
7242
|
candidate = fromSessionName;
|
|
7165
7243
|
} else {
|
|
7166
7244
|
candidate = fromCache;
|
|
@@ -9179,11 +9257,17 @@ var init_platform_procedures = __esm({
|
|
|
9179
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."
|
|
9180
9258
|
},
|
|
9181
9259
|
{
|
|
9182
|
-
title: "
|
|
9260
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
9183
9261
|
domain: "workflow",
|
|
9184
9262
|
priority: "p1",
|
|
9185
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."
|
|
9186
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
|
+
},
|
|
9187
9271
|
{
|
|
9188
9272
|
title: "Single dispatch path \u2014 create_task only",
|
|
9189
9273
|
domain: "workflow",
|
|
@@ -9217,6 +9301,12 @@ var init_platform_procedures = __esm({
|
|
|
9217
9301
|
priority: "p0",
|
|
9218
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."
|
|
9219
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
|
+
},
|
|
9220
9310
|
{
|
|
9221
9311
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
9222
9312
|
domain: "support",
|
|
@@ -10980,6 +11070,8 @@ var tui_data_exports = {};
|
|
|
10980
11070
|
__export(tui_data_exports, {
|
|
10981
11071
|
loadMemoryDashboard: () => loadMemoryDashboard,
|
|
10982
11072
|
loadTaskList: () => loadTaskList,
|
|
11073
|
+
loadTeamBadgeCounts: () => loadTeamBadgeCounts,
|
|
11074
|
+
loadTeamDetailMetrics: () => loadTeamDetailMetrics,
|
|
10983
11075
|
loadTeamMetrics: () => loadTeamMetrics,
|
|
10984
11076
|
searchWikiMemoryRows: () => searchWikiMemoryRows
|
|
10985
11077
|
});
|
|
@@ -11008,16 +11100,20 @@ async function loadMemoryDashboard(limit) {
|
|
|
11008
11100
|
}))
|
|
11009
11101
|
};
|
|
11010
11102
|
}
|
|
11011
|
-
async function
|
|
11103
|
+
async function loadTeamBadgeCounts() {
|
|
11012
11104
|
const client = getClient();
|
|
11013
11105
|
const memoryCounts = /* @__PURE__ */ new Map();
|
|
11014
|
-
const projectsByEmployee = /* @__PURE__ */ new Map();
|
|
11015
|
-
const currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
11016
|
-
const scope = sessionScopeFilter();
|
|
11017
11106
|
const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
|
|
11018
11107
|
for (const row of memResult.rows) {
|
|
11019
11108
|
memoryCounts.set(String(row.agent_id), Number(row.cnt));
|
|
11020
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();
|
|
11021
11117
|
for (const employeeName of employeeNames) {
|
|
11022
11118
|
const [projectResult, taskResult] = await Promise.all([
|
|
11023
11119
|
client.execute({
|
|
@@ -11050,6 +11146,13 @@ async function loadTeamMetrics(employeeNames) {
|
|
|
11050
11146
|
currentTaskByEmployee.set(employeeName, String(taskResult.rows[0].title));
|
|
11051
11147
|
}
|
|
11052
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
|
+
]);
|
|
11053
11156
|
return { memoryCounts, projectsByEmployee, currentTaskByEmployee };
|
|
11054
11157
|
}
|
|
11055
11158
|
async function loadTaskList() {
|
|
@@ -12707,10 +12810,24 @@ function stableId(memoryId, type, content) {
|
|
|
12707
12810
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
12708
12811
|
}
|
|
12709
12812
|
function cleanText(text) {
|
|
12710
|
-
|
|
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;
|
|
12711
12819
|
}
|
|
12712
|
-
function
|
|
12713
|
-
|
|
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;
|
|
12714
12831
|
}
|
|
12715
12832
|
function inferCardType(sentence, toolName) {
|
|
12716
12833
|
const lower = sentence.toLowerCase();
|
|
@@ -12742,12 +12859,12 @@ function predicateFor(type) {
|
|
|
12742
12859
|
}
|
|
12743
12860
|
}
|
|
12744
12861
|
function extractMemoryCards(row) {
|
|
12745
|
-
const
|
|
12862
|
+
const segments = splitSegments(row.raw_text);
|
|
12746
12863
|
const cards = [];
|
|
12747
|
-
for (const sentence of
|
|
12864
|
+
for (const sentence of segments) {
|
|
12748
12865
|
const type = inferCardType(sentence, row.tool_name);
|
|
12749
12866
|
const subject = extractSubject(sentence, row.agent_id);
|
|
12750
|
-
const content = sentence.length >
|
|
12867
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
12751
12868
|
cards.push({
|
|
12752
12869
|
id: stableId(row.id, type, content),
|
|
12753
12870
|
memory_id: row.id,
|
|
@@ -12843,13 +12960,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
12843
12960
|
last_accessed: String(row.timestamp)
|
|
12844
12961
|
}));
|
|
12845
12962
|
}
|
|
12846
|
-
var MAX_CARDS_PER_MEMORY,
|
|
12963
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
12847
12964
|
var init_memory_cards = __esm({
|
|
12848
12965
|
"src/lib/memory-cards.ts"() {
|
|
12849
12966
|
"use strict";
|
|
12850
12967
|
init_database();
|
|
12851
|
-
MAX_CARDS_PER_MEMORY =
|
|
12852
|
-
|
|
12968
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
12969
|
+
MAX_SEGMENT_CHARS = 500;
|
|
12970
|
+
MIN_SEGMENT_CHARS = 20;
|
|
12853
12971
|
}
|
|
12854
12972
|
});
|
|
12855
12973
|
|
|
@@ -20545,9 +20663,23 @@ var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
|
|
|
20545
20663
|
function getSessionPrompt(storedPrompt) {
|
|
20546
20664
|
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
20547
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
|
+
}
|
|
20548
20680
|
const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
|
|
20549
20681
|
const globalBlock = getGlobalProceduresBlock();
|
|
20550
|
-
return `${globalBlock}${rolePrompt}
|
|
20682
|
+
return `${globalBlock}${titlePrefix}${rolePrompt}
|
|
20551
20683
|
${BASE_OPERATING_PROCEDURES}`;
|
|
20552
20684
|
}
|
|
20553
20685
|
|
|
@@ -21278,7 +21410,7 @@ function useOrchestrator(enabled = true) {
|
|
|
21278
21410
|
const [pendingReviews, setPendingReviews] = useState8(0);
|
|
21279
21411
|
const [isLoading, setIsLoading] = useState8(true);
|
|
21280
21412
|
const orchestratorRef = useRef5(null);
|
|
21281
|
-
const exeSessionRef = useRef5("
|
|
21413
|
+
const exeSessionRef = useRef5("");
|
|
21282
21414
|
const coordinatorNameRef = useRef5(DEFAULT_COORDINATOR_TEMPLATE_NAME);
|
|
21283
21415
|
useEffect10(() => {
|
|
21284
21416
|
if (!enabled) return;
|
|
@@ -22740,7 +22872,6 @@ function getAgentStatus(agentId) {
|
|
|
22740
22872
|
|
|
22741
22873
|
// src/tui/views/Team.tsx
|
|
22742
22874
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
22743
|
-
var DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
|
|
22744
22875
|
function roleBadgeColor(role) {
|
|
22745
22876
|
switch (role.toLowerCase()) {
|
|
22746
22877
|
case "coo":
|
|
@@ -22761,6 +22892,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22761
22892
|
const [members, setMembers] = useState12([]);
|
|
22762
22893
|
const [externals, setExternals] = useState12([]);
|
|
22763
22894
|
const [loading, setLoading] = useState12(!demo);
|
|
22895
|
+
const [badgeInFlight, setBadgeInFlight] = useState12(!demo);
|
|
22896
|
+
const [detailInFlight, setDetailInFlight] = useState12(!demo);
|
|
22764
22897
|
const [dbError, setDbError] = useState12(null);
|
|
22765
22898
|
const [selectedIdx, setSelectedIdx] = useState12(0);
|
|
22766
22899
|
const [showDetail, setShowDetail] = useState12(false);
|
|
@@ -22773,6 +22906,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22773
22906
|
setMembers(DEMO_EMPLOYEES.map((e) => ({ ...e })));
|
|
22774
22907
|
setExternals(DEMO_EXTERNAL_AGENTS);
|
|
22775
22908
|
setLoading(false);
|
|
22909
|
+
setBadgeInFlight(false);
|
|
22910
|
+
setDetailInFlight(false);
|
|
22776
22911
|
return;
|
|
22777
22912
|
}
|
|
22778
22913
|
loadTeam();
|
|
@@ -22811,33 +22946,48 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22811
22946
|
let projectsByEmployee = /* @__PURE__ */ new Map();
|
|
22812
22947
|
let currentTaskByEmployee = /* @__PURE__ */ new Map();
|
|
22813
22948
|
try {
|
|
22814
|
-
const {
|
|
22815
|
-
|
|
22816
|
-
|
|
22817
|
-
|
|
22818
|
-
|
|
22819
|
-
|
|
22820
|
-
|
|
22821
|
-
|
|
22822
|
-
|
|
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;
|
|
22823
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);
|
|
22824
22989
|
} catch {
|
|
22825
22990
|
}
|
|
22826
|
-
const teamData = roster.map((emp) => {
|
|
22827
|
-
const agentSt = getAgentStatus(emp.name);
|
|
22828
|
-
return {
|
|
22829
|
-
name: emp.name,
|
|
22830
|
-
role: emp.role,
|
|
22831
|
-
status: agentSt.label,
|
|
22832
|
-
activity: agentSt.label === "active" ? "Processing..." : "",
|
|
22833
|
-
memoryCount: memoryCounts.get(emp.name) ?? 0,
|
|
22834
|
-
projects: projectsByEmployee.get(emp.name),
|
|
22835
|
-
currentTask: currentTaskByEmployee.get(emp.name),
|
|
22836
|
-
sessionName: agentSt.session
|
|
22837
|
-
};
|
|
22838
|
-
});
|
|
22839
|
-
setMembers(teamData);
|
|
22840
|
-
setDbError(null);
|
|
22841
22991
|
try {
|
|
22842
22992
|
const { existsSync: existsSync20, readFileSync: readFileSync14 } = await import("fs");
|
|
22843
22993
|
const { join: join2 } = await import("path");
|
|
@@ -22859,6 +23009,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22859
23009
|
setDbError(err instanceof Error ? err.message : "Unknown error");
|
|
22860
23010
|
} finally {
|
|
22861
23011
|
setLoading(false);
|
|
23012
|
+
setBadgeInFlight(false);
|
|
23013
|
+
setDetailInFlight(false);
|
|
22862
23014
|
}
|
|
22863
23015
|
});
|
|
22864
23016
|
}
|
|
@@ -22913,6 +23065,8 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
22913
23065
|
orch.pendingReviews,
|
|
22914
23066
|
" review(s) pending coordinator attention"
|
|
22915
23067
|
] }),
|
|
23068
|
+
badgeInFlight && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: " Loading memory counts..." }),
|
|
23069
|
+
detailInFlight && /* @__PURE__ */ jsx12(Text, { color: "#6B4C9A", children: " Loading employee details..." }),
|
|
22916
23070
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
22917
23071
|
/* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
|
|
22918
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",
|