@askexenow/exe-os 0.8.80 → 0.8.82
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/backfill-conversations.js +359 -267
- package/dist/bin/backfill-responses.js +357 -265
- package/dist/bin/backfill-vectors.js +339 -264
- package/dist/bin/cleanup-stale-review-tasks.js +315 -256
- package/dist/bin/cli.js +494 -240
- package/dist/bin/exe-agent.js +141 -46
- package/dist/bin/exe-assign.js +151 -63
- package/dist/bin/exe-boot.js +294 -115
- package/dist/bin/exe-call.js +76 -51
- package/dist/bin/exe-cloud.js +58 -45
- package/dist/bin/exe-dispatch.js +434 -277
- package/dist/bin/exe-doctor.js +317 -246
- package/dist/bin/exe-export-behaviors.js +328 -248
- package/dist/bin/exe-forget.js +314 -231
- package/dist/bin/exe-gateway.js +2676 -1402
- package/dist/bin/exe-heartbeat.js +329 -264
- package/dist/bin/exe-kill.js +324 -244
- package/dist/bin/exe-launch-agent.js +574 -463
- package/dist/bin/exe-link.js +1055 -95
- package/dist/bin/exe-new-employee.js +49 -54
- package/dist/bin/exe-pending-messages.js +310 -253
- package/dist/bin/exe-pending-notifications.js +299 -228
- package/dist/bin/exe-pending-reviews.js +314 -245
- package/dist/bin/exe-rename.js +259 -195
- package/dist/bin/exe-review.js +140 -64
- package/dist/bin/exe-search.js +543 -356
- package/dist/bin/exe-session-cleanup.js +463 -382
- package/dist/bin/exe-settings.js +129 -99
- package/dist/bin/exe-start.sh +6 -6
- package/dist/bin/exe-status.js +95 -36
- package/dist/bin/exe-team.js +116 -51
- package/dist/bin/git-sweep.js +482 -307
- package/dist/bin/graph-backfill.js +357 -245
- package/dist/bin/graph-export.js +324 -244
- package/dist/bin/install.js +33 -10
- package/dist/bin/scan-tasks.js +481 -307
- package/dist/bin/setup.js +1147 -140
- package/dist/bin/shard-migrate.js +321 -241
- package/dist/bin/update.js +1 -7
- package/dist/bin/wiki-sync.js +318 -238
- package/dist/gateway/index.js +2656 -1383
- package/dist/hooks/bug-report-worker.js +641 -472
- package/dist/hooks/commit-complete.js +482 -307
- package/dist/hooks/error-recall.js +363 -135
- package/dist/hooks/exe-heartbeat-hook.js +97 -27
- package/dist/hooks/ingest-worker.js +584 -397
- package/dist/hooks/ingest.js +123 -58
- package/dist/hooks/instructions-loaded.js +212 -82
- package/dist/hooks/notification.js +200 -70
- package/dist/hooks/post-compact.js +199 -81
- package/dist/hooks/pre-compact.js +352 -140
- package/dist/hooks/pre-tool-use.js +416 -278
- package/dist/hooks/prompt-ingest-worker.js +376 -299
- package/dist/hooks/prompt-submit.js +414 -188
- package/dist/hooks/response-ingest-worker.js +408 -338
- package/dist/hooks/session-end.js +209 -83
- package/dist/hooks/session-start.js +382 -158
- package/dist/hooks/stop.js +209 -83
- package/dist/hooks/subagent-stop.js +209 -85
- package/dist/hooks/summary-worker.js +606 -510
- package/dist/index.js +2133 -855
- package/dist/lib/cloud-sync.js +1175 -184
- package/dist/lib/config.js +1 -9
- package/dist/lib/consolidation.js +71 -34
- package/dist/lib/database.js +166 -14
- package/dist/lib/device-registry.js +189 -117
- package/dist/lib/embedder.js +6 -10
- package/dist/lib/employee-templates.js +134 -39
- package/dist/lib/employees.js +30 -7
- package/dist/lib/exe-daemon-client.js +5 -7
- package/dist/lib/exe-daemon.js +514 -152
- package/dist/lib/hybrid-search.js +543 -356
- package/dist/lib/identity-templates.js +15 -15
- package/dist/lib/identity.js +19 -15
- package/dist/lib/license.js +1 -7
- package/dist/lib/messaging.js +157 -135
- package/dist/lib/reminders.js +97 -0
- package/dist/lib/schedules.js +302 -231
- package/dist/lib/skill-learning.js +33 -27
- package/dist/lib/status-brief.js +11 -14
- package/dist/lib/store.js +326 -237
- package/dist/lib/task-router.js +105 -1
- package/dist/lib/tasks.js +233 -116
- package/dist/lib/tmux-routing.js +173 -56
- package/dist/lib/ws-client.js +13 -3
- package/dist/mcp/server.js +2009 -1015
- package/dist/mcp/tools/complete-reminder.js +97 -0
- package/dist/mcp/tools/create-reminder.js +97 -0
- package/dist/mcp/tools/create-task.js +426 -262
- package/dist/mcp/tools/deactivate-behavior.js +119 -44
- package/dist/mcp/tools/list-reminders.js +97 -0
- package/dist/mcp/tools/list-tasks.js +56 -57
- package/dist/mcp/tools/send-message.js +206 -143
- package/dist/mcp/tools/update-task.js +259 -85
- package/dist/runtime/index.js +495 -316
- package/dist/tui/App.js +1128 -919
- package/package.json +2 -10
- package/src/commands/exe/afk.md +8 -8
- package/src/commands/exe/assign.md +1 -1
- package/src/commands/exe/build-adv.md +1 -1
- package/src/commands/exe/call.md +10 -10
- package/src/commands/exe/employee-heartbeat.md +9 -6
- package/src/commands/exe/heartbeat.md +5 -5
- package/src/commands/exe/intercom.md +26 -15
- package/src/commands/exe/launch.md +2 -2
- package/src/commands/exe/new-employee.md +1 -1
- package/src/commands/exe/review.md +2 -2
- package/src/commands/exe/schedule.md +1 -1
- package/src/commands/exe/sessions.md +2 -2
- package/src/commands/exe.md +22 -20
package/dist/bin/cli.js
CHANGED
|
@@ -31,7 +31,6 @@ var config_exports = {};
|
|
|
31
31
|
__export(config_exports, {
|
|
32
32
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
33
33
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
34
|
-
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
35
34
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
36
35
|
DB_PATH: () => DB_PATH,
|
|
37
36
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -187,7 +186,7 @@ async function loadConfigFrom(configPath) {
|
|
|
187
186
|
return { ...DEFAULT_CONFIG };
|
|
188
187
|
}
|
|
189
188
|
}
|
|
190
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH,
|
|
189
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
191
190
|
var init_config = __esm({
|
|
192
191
|
"src/lib/config.ts"() {
|
|
193
192
|
"use strict";
|
|
@@ -195,7 +194,6 @@ var init_config = __esm({
|
|
|
195
194
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
196
195
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
197
196
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
198
|
-
COO_AGENT_NAME = "exe";
|
|
199
197
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
200
198
|
CURRENT_CONFIG_VERSION = 1;
|
|
201
199
|
DEFAULT_CONFIG = {
|
|
@@ -231,13 +229,7 @@ var init_config = __esm({
|
|
|
231
229
|
wikiUrl: "",
|
|
232
230
|
wikiApiKey: "",
|
|
233
231
|
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
234
|
-
wikiWorkspaceMapping: {
|
|
235
|
-
exe: "Executive",
|
|
236
|
-
yoshi: "Engineering",
|
|
237
|
-
mari: "Marketing",
|
|
238
|
-
tom: "Engineering",
|
|
239
|
-
sasha: "Production"
|
|
240
|
-
},
|
|
232
|
+
wikiWorkspaceMapping: {},
|
|
241
233
|
wikiAutoUpdate: true,
|
|
242
234
|
wikiAutoUpdateThreshold: 0.5,
|
|
243
235
|
wikiAutoUpdateCreateNew: true,
|
|
@@ -277,15 +269,23 @@ var init_config = __esm({
|
|
|
277
269
|
// src/lib/employees.ts
|
|
278
270
|
var employees_exports = {};
|
|
279
271
|
__export(employees_exports, {
|
|
272
|
+
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
273
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
280
274
|
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
281
275
|
addEmployee: () => addEmployee,
|
|
276
|
+
canCoordinate: () => canCoordinate,
|
|
277
|
+
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
278
|
+
getCoordinatorName: () => getCoordinatorName,
|
|
282
279
|
getEmployee: () => getEmployee,
|
|
283
280
|
getEmployeeByRole: () => getEmployeeByRole,
|
|
284
281
|
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
285
282
|
hasRole: () => hasRole,
|
|
283
|
+
isCoordinatorName: () => isCoordinatorName,
|
|
284
|
+
isCoordinatorRole: () => isCoordinatorRole,
|
|
286
285
|
isMultiInstance: () => isMultiInstance,
|
|
287
286
|
loadEmployees: () => loadEmployees,
|
|
288
287
|
loadEmployeesSync: () => loadEmployeesSync,
|
|
288
|
+
normalizeRole: () => normalizeRole,
|
|
289
289
|
normalizeRosterCase: () => normalizeRosterCase,
|
|
290
290
|
registerBinSymlinks: () => registerBinSymlinks,
|
|
291
291
|
saveEmployees: () => saveEmployees,
|
|
@@ -296,6 +296,25 @@ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as r
|
|
|
296
296
|
import { execSync } from "child_process";
|
|
297
297
|
import path2 from "path";
|
|
298
298
|
import os2 from "os";
|
|
299
|
+
function normalizeRole(role) {
|
|
300
|
+
return (role ?? "").trim().toLowerCase();
|
|
301
|
+
}
|
|
302
|
+
function isCoordinatorRole(role) {
|
|
303
|
+
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
304
|
+
}
|
|
305
|
+
function getCoordinatorEmployee(employees) {
|
|
306
|
+
return employees.find((e) => isCoordinatorRole(e.role));
|
|
307
|
+
}
|
|
308
|
+
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
309
|
+
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
310
|
+
}
|
|
311
|
+
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
312
|
+
if (!agentName) return false;
|
|
313
|
+
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
314
|
+
}
|
|
315
|
+
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
316
|
+
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
317
|
+
}
|
|
299
318
|
function validateEmployeeName(name) {
|
|
300
319
|
if (!name) {
|
|
301
320
|
return { valid: false, error: "Name is required" };
|
|
@@ -433,12 +452,14 @@ function registerBinSymlinks(name) {
|
|
|
433
452
|
}
|
|
434
453
|
return { created, skipped, errors };
|
|
435
454
|
}
|
|
436
|
-
var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
|
|
455
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
437
456
|
var init_employees = __esm({
|
|
438
457
|
"src/lib/employees.ts"() {
|
|
439
458
|
"use strict";
|
|
440
459
|
init_config();
|
|
441
460
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
461
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
462
|
+
COORDINATOR_ROLE = "COO";
|
|
442
463
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
443
464
|
}
|
|
444
465
|
});
|
|
@@ -1058,10 +1079,10 @@ var init_installer = __esm({
|
|
|
1058
1079
|
|
|
1059
1080
|
These rules are injected by exe-os and override default behavior for multi-agent coordination.
|
|
1060
1081
|
|
|
1061
|
-
- **Session routing is deterministic.** When working in
|
|
1082
|
+
- **Session routing is deterministic.** When working in a coordinator session, ALL employee sessions use that same coordinator-session suffix. NEVER reference, consider, or dispatch to employee sessions from other project sessions. This is not a choice \u2014 it is a hard constraint.
|
|
1062
1083
|
- **Always use create_task to assign work.** Never use messages, tmux send-keys, or ad-hoc instructions as a substitute for tasks.
|
|
1063
1084
|
- **Never modify another agent's in-progress task.** Create a new task instead. Modifying active tasks causes race conditions.
|
|
1064
|
-
- **Chain of command:** founder
|
|
1085
|
+
- **Chain of command:** founder -> COO -> managers -> specialists. The COO does not bypass managers for specialist work.
|
|
1065
1086
|
- **Verify dispatch.** After every create_task, confirm the employee received and started the task via tmux capture-pane.
|
|
1066
1087
|
${EXE_SECTION_END}`;
|
|
1067
1088
|
}
|
|
@@ -1267,7 +1288,7 @@ function wrapWithRetry(client) {
|
|
|
1267
1288
|
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
1268
1289
|
}
|
|
1269
1290
|
if (prop === "batch") {
|
|
1270
|
-
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
1291
|
+
return (stmts, mode) => retryOnBusy(() => target.batch(stmts, mode), "batch");
|
|
1271
1292
|
}
|
|
1272
1293
|
return Reflect.get(target, prop, receiver);
|
|
1273
1294
|
}
|
|
@@ -1430,22 +1451,24 @@ async function ensureSchema() {
|
|
|
1430
1451
|
ON behaviors(agent_id, active);
|
|
1431
1452
|
`);
|
|
1432
1453
|
try {
|
|
1454
|
+
const coordinatorName = getCoordinatorName();
|
|
1433
1455
|
const existing = await client.execute({
|
|
1434
|
-
sql: "SELECT COUNT(*) as cnt FROM behaviors WHERE agent_id =
|
|
1435
|
-
args: []
|
|
1456
|
+
sql: "SELECT COUNT(*) as cnt FROM behaviors WHERE agent_id = ?",
|
|
1457
|
+
args: [coordinatorName]
|
|
1436
1458
|
});
|
|
1437
1459
|
if (Number(existing.rows[0]?.cnt) === 0) {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1460
|
+
const seededAt = "2026-03-25T00:00:00Z";
|
|
1461
|
+
for (const [domain, content] of [
|
|
1462
|
+
["workflow", `Don't ask "keep going?" \u2014 just keep executing phases/plans autonomously`],
|
|
1463
|
+
["tool-use", "Always use create_task MCP tool, never write .md files directly for task creation"],
|
|
1464
|
+
["workflow", "Auto-start reviewing when idle and reviews are pending \u2014 never ask founder for permission"]
|
|
1465
|
+
]) {
|
|
1466
|
+
await client.execute({
|
|
1467
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, content, active, created_at, updated_at)
|
|
1468
|
+
VALUES (hex(randomblob(16)), ?, NULL, ?, ?, 1, ?, ?)`,
|
|
1469
|
+
args: [coordinatorName, domain, content, seededAt, seededAt]
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1449
1472
|
}
|
|
1450
1473
|
} catch {
|
|
1451
1474
|
}
|
|
@@ -2137,6 +2160,39 @@ async function ensureSchema() {
|
|
|
2137
2160
|
} catch {
|
|
2138
2161
|
}
|
|
2139
2162
|
}
|
|
2163
|
+
try {
|
|
2164
|
+
await client.execute({
|
|
2165
|
+
sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
|
|
2166
|
+
args: []
|
|
2167
|
+
});
|
|
2168
|
+
} catch {
|
|
2169
|
+
}
|
|
2170
|
+
try {
|
|
2171
|
+
await client.execute(
|
|
2172
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
|
|
2173
|
+
);
|
|
2174
|
+
} catch {
|
|
2175
|
+
}
|
|
2176
|
+
try {
|
|
2177
|
+
await client.execute({
|
|
2178
|
+
sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
|
|
2179
|
+
args: []
|
|
2180
|
+
});
|
|
2181
|
+
} catch {
|
|
2182
|
+
}
|
|
2183
|
+
try {
|
|
2184
|
+
await client.execute(
|
|
2185
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
|
|
2186
|
+
);
|
|
2187
|
+
} catch {
|
|
2188
|
+
}
|
|
2189
|
+
try {
|
|
2190
|
+
await client.execute({
|
|
2191
|
+
sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
|
|
2192
|
+
args: []
|
|
2193
|
+
});
|
|
2194
|
+
} catch {
|
|
2195
|
+
}
|
|
2140
2196
|
}
|
|
2141
2197
|
async function disposeDatabase() {
|
|
2142
2198
|
if (_client) {
|
|
@@ -2150,6 +2206,7 @@ var init_database = __esm({
|
|
|
2150
2206
|
"src/lib/database.ts"() {
|
|
2151
2207
|
"use strict";
|
|
2152
2208
|
init_db_retry();
|
|
2209
|
+
init_employees();
|
|
2153
2210
|
_client = null;
|
|
2154
2211
|
_resilientClient = null;
|
|
2155
2212
|
initTurso = initDatabase;
|
|
@@ -2820,6 +2877,11 @@ async function cloudSync(config) {
|
|
|
2820
2877
|
} catch {
|
|
2821
2878
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
2822
2879
|
}
|
|
2880
|
+
try {
|
|
2881
|
+
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
2882
|
+
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
2883
|
+
} catch {
|
|
2884
|
+
}
|
|
2823
2885
|
try {
|
|
2824
2886
|
await client.execute(
|
|
2825
2887
|
"CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)"
|
|
@@ -3726,8 +3788,7 @@ async function setupMode() {
|
|
|
3726
3788
|
try {
|
|
3727
3789
|
assertSecureEndpoint(endpoint);
|
|
3728
3790
|
const resp = await fetch(`${endpoint}/auth/verify`, {
|
|
3729
|
-
|
|
3730
|
-
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
|
|
3791
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3731
3792
|
});
|
|
3732
3793
|
if (resp.ok) {
|
|
3733
3794
|
config.cloud = { apiKey, endpoint };
|
|
@@ -4063,7 +4124,11 @@ async function ensureShardSchema(client) {
|
|
|
4063
4124
|
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
4064
4125
|
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
4065
4126
|
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
4066
|
-
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
4127
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT",
|
|
4128
|
+
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
4129
|
+
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
4130
|
+
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
4131
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
4067
4132
|
]) {
|
|
4068
4133
|
try {
|
|
4069
4134
|
await client.execute(col);
|
|
@@ -4193,26 +4258,26 @@ var init_platform_procedures = __esm({
|
|
|
4193
4258
|
title: "What is exe-os \u2014 the operating model every agent must understand",
|
|
4194
4259
|
domain: "architecture",
|
|
4195
4260
|
priority: "p0",
|
|
4196
|
-
content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO
|
|
4261
|
+
content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO, CTO, CMO, engineers, and content production specialists. Each agent has identity, expertise, and experience layers \u2014 persistent memory that makes them better over time. All data is local-first, E2EE, owned by the user. The MCP server is the ONLY data interface \u2014 never access the DB directly."
|
|
4197
4262
|
},
|
|
4198
4263
|
{
|
|
4199
4264
|
title: "Mode 1 \u2014 how exe-os runs inside Claude Code",
|
|
4200
4265
|
domain: "architecture",
|
|
4201
4266
|
priority: "p0",
|
|
4202
|
-
content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC
|
|
4267
|
+
content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC and boots the COO. The COO manages employees in tmux sessions. Each coordinator session is a separate CC window/project. Employees run in their own tmux panes via create_task auto-spawn. The founder talks to the COO; the COO orchestrates the team. CC is the shell, exe-os is the brain."
|
|
4203
4268
|
},
|
|
4204
4269
|
{
|
|
4205
|
-
title: "Sessions explained \u2014
|
|
4270
|
+
title: "Sessions explained \u2014 coordinator session names and projects",
|
|
4206
4271
|
domain: "architecture",
|
|
4207
4272
|
priority: "p0",
|
|
4208
|
-
content: "Each
|
|
4273
|
+
content: "Each coordinator session is an isolated project session. One might be exe-os development, another might be exe-wiki. Each session spawns its own employees using {employee}-{coordinatorSession}. Sessions share the same memory DB but tasks are scoped to the session that created them. A founder can run multiple projects simultaneously. Sessions never interfere with each other."
|
|
4209
4274
|
},
|
|
4210
4275
|
// --- Hierarchy and dispatch ---
|
|
4211
4276
|
{
|
|
4212
4277
|
title: "Chain of command \u2014 who talks to whom",
|
|
4213
4278
|
domain: "workflow",
|
|
4214
4279
|
priority: "p0",
|
|
4215
|
-
content: "Founder
|
|
4280
|
+
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO 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."
|
|
4216
4281
|
},
|
|
4217
4282
|
{
|
|
4218
4283
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -4222,30 +4287,30 @@ var init_platform_procedures = __esm({
|
|
|
4222
4287
|
},
|
|
4223
4288
|
// --- Session isolation ---
|
|
4224
4289
|
{
|
|
4225
|
-
title: "Session scoping \u2014 stay in your
|
|
4290
|
+
title: "Session scoping \u2014 stay in your coordinator boundary",
|
|
4226
4291
|
domain: "security",
|
|
4227
4292
|
priority: "p0",
|
|
4228
|
-
content: "Session scoping is mandatory. Managers dispatch to workers within their own
|
|
4293
|
+
content: "Session scoping is mandatory. Managers dispatch to workers within their own coordinator session ONLY. Employee sessions use {employee}-{coordinatorSession}. Cross-session dispatch is blocked by the system. Verify session names before dispatch. Tasks are scoped to the creating coordinator session."
|
|
4229
4294
|
},
|
|
4230
4295
|
{
|
|
4231
4296
|
title: "Session isolation \u2014 never touch another session's work",
|
|
4232
4297
|
domain: "workflow",
|
|
4233
4298
|
priority: "p0",
|
|
4234
|
-
content:
|
|
4299
|
+
content: "Sessions are isolated. A coordinator session owns ONLY tasks it dispatched. (1) Never close/update/cancel tasks from another coordinator session. (2) Never review work from a different session \u2014 report that it belongs to another session and skip. (3) Ignore other sessions' items in list_tasks results. (4) Employees inherit session: employee sessions work ONLY on their parent coordinator session's tasks. Cross-session work is a system violation."
|
|
4235
4300
|
},
|
|
4236
4301
|
// --- Engineering: session scoping in code ---
|
|
4237
4302
|
{
|
|
4238
4303
|
title: "Three-dimensional scoping \u2014 session, project, role \u2014 enforced in every query",
|
|
4239
4304
|
domain: "architecture",
|
|
4240
4305
|
priority: "p0",
|
|
4241
|
-
content: "Every DB query, notification, review count, and task operation MUST be scoped on 3 dimensions: (1) Session \u2014 filter by session_scope matching current
|
|
4306
|
+
content: "Every DB query, notification, review count, and task operation MUST be scoped on 3 dimensions: (1) Session \u2014 filter by session_scope matching the current coordinator session. (2) Project \u2014 filter by project_name. (3) Role \u2014 agents only see data at their hierarchy level. When writing ANY function that touches tasks, reviews, messages, or notifications: always accept a sessionScope parameter and pass it to the SQL WHERE clause. Unscoped queries are bugs. Test by running 2+ coordinator sessions simultaneously."
|
|
4242
4307
|
},
|
|
4243
4308
|
// --- Hard constraints ---
|
|
4244
4309
|
{
|
|
4245
4310
|
title: "What you CANNOT do in exe-os \u2014 hard constraints",
|
|
4246
4311
|
domain: "security",
|
|
4247
4312
|
priority: "p0",
|
|
4248
|
-
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
|
|
4313
|
+
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."
|
|
4249
4314
|
},
|
|
4250
4315
|
// --- Operations ---
|
|
4251
4316
|
{
|
|
@@ -4485,7 +4550,10 @@ async function writeMemory(record) {
|
|
|
4485
4550
|
source_path: record.source_path ?? null,
|
|
4486
4551
|
source_type: record.source_type ?? null,
|
|
4487
4552
|
tier: record.tier ?? classifyTier(record),
|
|
4488
|
-
supersedes_id: record.supersedes_id ?? null
|
|
4553
|
+
supersedes_id: record.supersedes_id ?? null,
|
|
4554
|
+
draft: record.draft ? 1 : 0,
|
|
4555
|
+
memory_type: record.memory_type ?? "raw",
|
|
4556
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
4489
4557
|
};
|
|
4490
4558
|
_pendingRecords.push(dbRow);
|
|
4491
4559
|
orgBus.emit({
|
|
@@ -4540,6 +4608,9 @@ async function flushBatch() {
|
|
|
4540
4608
|
const sourceType = row.source_type ?? null;
|
|
4541
4609
|
const tier = row.tier ?? 3;
|
|
4542
4610
|
const supersedesId = row.supersedes_id ?? null;
|
|
4611
|
+
const draft = row.draft ? 1 : 0;
|
|
4612
|
+
const memoryType = row.memory_type ?? "raw";
|
|
4613
|
+
const trajectory = row.trajectory ?? null;
|
|
4543
4614
|
return {
|
|
4544
4615
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
4545
4616
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
@@ -4547,15 +4618,15 @@ async function flushBatch() {
|
|
|
4547
4618
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
4548
4619
|
confidence, last_accessed,
|
|
4549
4620
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
4550
|
-
source_path, source_type, tier, supersedes_id)
|
|
4551
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
4621
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
|
|
4622
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
4552
4623
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
4553
4624
|
tool_name, project_name,
|
|
4554
4625
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
4555
4626
|
confidence, last_accessed,
|
|
4556
4627
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
4557
|
-
source_path, source_type, tier, supersedes_id)
|
|
4558
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4628
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
|
|
4629
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4559
4630
|
args: hasVector ? [
|
|
4560
4631
|
row.id,
|
|
4561
4632
|
row.agent_id,
|
|
@@ -4581,7 +4652,10 @@ async function flushBatch() {
|
|
|
4581
4652
|
sourcePath,
|
|
4582
4653
|
sourceType,
|
|
4583
4654
|
tier,
|
|
4584
|
-
supersedesId
|
|
4655
|
+
supersedesId,
|
|
4656
|
+
draft,
|
|
4657
|
+
memoryType,
|
|
4658
|
+
trajectory
|
|
4585
4659
|
] : [
|
|
4586
4660
|
row.id,
|
|
4587
4661
|
row.agent_id,
|
|
@@ -4606,7 +4680,10 @@ async function flushBatch() {
|
|
|
4606
4680
|
sourcePath,
|
|
4607
4681
|
sourceType,
|
|
4608
4682
|
tier,
|
|
4609
|
-
supersedesId
|
|
4683
|
+
supersedesId,
|
|
4684
|
+
draft,
|
|
4685
|
+
memoryType,
|
|
4686
|
+
trajectory
|
|
4610
4687
|
]
|
|
4611
4688
|
};
|
|
4612
4689
|
};
|
|
@@ -4675,6 +4752,8 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4675
4752
|
const limit = options?.limit ?? 10;
|
|
4676
4753
|
const statusFilter = options?.includeArchived ? "" : `
|
|
4677
4754
|
AND COALESCE(status, 'active') = 'active'`;
|
|
4755
|
+
const draftFilter = options?.includeDrafts ? "" : `
|
|
4756
|
+
AND (draft = 0 OR draft IS NULL)`;
|
|
4678
4757
|
let sql = `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
4679
4758
|
tool_name, project_name,
|
|
4680
4759
|
has_error, raw_text, vector, importance, status,
|
|
@@ -4684,7 +4763,7 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4684
4763
|
source_path, source_type
|
|
4685
4764
|
FROM memories
|
|
4686
4765
|
WHERE agent_id = ?
|
|
4687
|
-
AND vector IS NOT NULL${statusFilter}
|
|
4766
|
+
AND vector IS NOT NULL${statusFilter}${draftFilter}
|
|
4688
4767
|
AND COALESCE(confidence, 0.7) >= 0.3`;
|
|
4689
4768
|
const args2 = [agentId];
|
|
4690
4769
|
const scope = buildWikiScopeFilter(options, "");
|
|
@@ -4706,6 +4785,10 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4706
4785
|
sql += ` AND timestamp >= ?`;
|
|
4707
4786
|
args2.push(options.since);
|
|
4708
4787
|
}
|
|
4788
|
+
if (options?.memoryType) {
|
|
4789
|
+
sql += ` AND memory_type = ?`;
|
|
4790
|
+
args2.push(options.memoryType);
|
|
4791
|
+
}
|
|
4709
4792
|
sql += ` ORDER BY vector_distance_cos(vector, vector32(?))`;
|
|
4710
4793
|
args2.push(vectorToBlob(queryVector));
|
|
4711
4794
|
sql += ` LIMIT ?`;
|
|
@@ -4939,6 +5022,10 @@ function spawnDaemon() {
|
|
|
4939
5022
|
stdio: ["ignore", "ignore", stderrFd],
|
|
4940
5023
|
env: {
|
|
4941
5024
|
...process.env,
|
|
5025
|
+
TMUX: void 0,
|
|
5026
|
+
// Daemon is global — must not inherit session scope
|
|
5027
|
+
TMUX_PANE: void 0,
|
|
5028
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
4942
5029
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
4943
5030
|
EXE_DAEMON_PID: PID_PATH
|
|
4944
5031
|
}
|
|
@@ -5504,7 +5591,7 @@ async function backfillConversations(options) {
|
|
|
5504
5591
|
await writeMemory({
|
|
5505
5592
|
id: crypto4.randomUUID(),
|
|
5506
5593
|
agent_id: conv.agentId,
|
|
5507
|
-
agent_role: conv.agentId === "exe" ? "COO" : "specialist",
|
|
5594
|
+
agent_role: isCoordinatorName(conv.agentId) || conv.agentId === "exe" ? "COO" : "specialist",
|
|
5508
5595
|
session_id: conv.sessionId,
|
|
5509
5596
|
timestamp: conv.startTime ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5510
5597
|
tool_name: TOOL_NAME,
|
|
@@ -5545,6 +5632,7 @@ var init_backfill_conversations = __esm({
|
|
|
5545
5632
|
init_exe_daemon_client();
|
|
5546
5633
|
init_database();
|
|
5547
5634
|
init_is_main();
|
|
5635
|
+
init_employees();
|
|
5548
5636
|
TOOL_NAME = "backfill-conversation";
|
|
5549
5637
|
MIN_MESSAGES = 3;
|
|
5550
5638
|
MAX_SUMMARY_LENGTH = 4e3;
|
|
@@ -5659,13 +5747,13 @@ Ethos:
|
|
|
5659
5747
|
- Founder zero-ego. Distributors and customers are the loudest voice.
|
|
5660
5748
|
- Crypto values: big companies should not own consumer/SMB AI.
|
|
5661
5749
|
|
|
5662
|
-
STOP AND REDIRECT: Any decision that compromises memory sovereignty, 3-layer cognition, MCP boundary, or AGPL boundary kills all three business paths. Surface the conflict to
|
|
5750
|
+
STOP AND REDIRECT: Any decision that compromises memory sovereignty, 3-layer cognition, MCP boundary, or AGPL boundary kills all three business paths. Surface the conflict to the COO before proceeding.
|
|
5663
5751
|
|
|
5664
5752
|
Always reference .planning/ARCHITECTURE.md and .planning/PROJECT.md as source of truth for all architectural and product decisions.
|
|
5665
5753
|
|
|
5666
5754
|
OPERATING PROCEDURES (mandatory for all employees):
|
|
5667
5755
|
|
|
5668
|
-
You report to the COO. All work flows through
|
|
5756
|
+
You report to the COO. All work flows through the COO. These procedures are non-negotiable.
|
|
5669
5757
|
|
|
5670
5758
|
1. BEFORE starting work:
|
|
5671
5759
|
- Read exe/ARCHITECTURE.md (if it exists). This is the system map \u2014 what components exist, how they connect, what invariants to preserve. Understand the architecture before changing anything.
|
|
@@ -5690,15 +5778,15 @@ You report to the COO. All work flows through exe. These procedures are non-nego
|
|
|
5690
5778
|
- Include what was done, decisions made, and any issues
|
|
5691
5779
|
- If you're stuck, looping, confused, or running low on context \u2014 update_task(done) with whatever partial result you have. A partial result is infinitely better than no result.
|
|
5692
5780
|
- NEVER let a failed commit, a loop, or an error prevent you from calling update_task(done).
|
|
5693
|
-
- Do NOT use close_task \u2014 that is reserved for reviewers
|
|
5781
|
+
- Do NOT use close_task \u2014 that is reserved for reviewers to finalize after review.
|
|
5694
5782
|
|
|
5695
5783
|
4. AFTER update_task(done) \u2014 COMMIT (best-effort, do NOT let this block):
|
|
5696
5784
|
- If your task changed system structure, update exe/ARCHITECTURE.md first.
|
|
5697
5785
|
- Commit IF you are in a git repo (check: \`git rev-parse --git-dir 2>/dev/null\`). Stage only the files you changed, write a clear commit message.
|
|
5698
5786
|
- If you are NOT in a git repo, skip entirely. NEVER run \`git init\`.
|
|
5699
5787
|
- If the commit fails, note it but move on \u2014 the work is already marked done via update_task.
|
|
5700
|
-
- Do NOT push \u2014
|
|
5701
|
-
- NEVER run \`git checkout main\`. You work in your own git worktree on a feature branch.
|
|
5788
|
+
- Do NOT push \u2014 the COO reviews commits and decides what to push.
|
|
5789
|
+
- NEVER run \`git checkout main\`. You work in your own git worktree on a feature branch. The COO stays on main and merges PRs. Switching branches in a shared repo stomps other agents' work.
|
|
5702
5790
|
|
|
5703
5791
|
5. AFTER commit \u2014 REPORT (best-effort):
|
|
5704
5792
|
Use store_memory to write a structured summary. Include: project name, what was done,
|
|
@@ -5712,7 +5800,7 @@ You report to the COO. All work flows through exe. These procedures are non-nego
|
|
|
5712
5800
|
|
|
5713
5801
|
7. AFTER reporting \u2014 CHECK FOR NEXT WORK (mandatory):
|
|
5714
5802
|
- First: run list_tasks(status='needs_review') \u2014 check if YOU are the reviewer on any pending reviews. Reviews are work. Process them before anything else.
|
|
5715
|
-
- Second: run list_tasks(status='blocked') \u2014 check if any tasks are blocked. For each blocked task: can YOU unblock it? If yes, unblock it now. If not, escalate to
|
|
5803
|
+
- Second: run list_tasks(status='blocked') \u2014 check if any tasks are blocked. For each blocked task: can YOU unblock it? If yes, unblock it now. If not, escalate to the COO immediately. Blocked tasks sitting >24h without action is a pipeline failure.
|
|
5716
5804
|
- Then: re-read your task folder: exe/<your-name>/
|
|
5717
5805
|
- If there are more open tasks, start the next highest-priority one (go to step 1)
|
|
5718
5806
|
- If no more open tasks AND no pending reviews AND no blocked tasks you can fix, tell the user: "All tasks complete. Anything else?"
|
|
@@ -5729,7 +5817,7 @@ DO NOT keep working degraded. Instead:
|
|
|
5729
5817
|
Format the text as: "CONTEXT CHECKPOINT [<task-id>]: <summary>"
|
|
5730
5818
|
Include: task ID + title, what you completed, what's left, open decisions or blockers, key file paths.
|
|
5731
5819
|
|
|
5732
|
-
2. Send intercom to
|
|
5820
|
+
2. Send intercom to the COO session to trigger kill + relaunch:
|
|
5733
5821
|
MY_SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
|
|
5734
5822
|
EXE_SESSION="\${MY_SESSION#\${AGENT_ID}-}"
|
|
5735
5823
|
tmux send-keys -t "$EXE_SESSION" "/exe-intercom context-full: \${AGENT_ID} hit capacity. Checkpoint saved. Resume task <task-id>." Enter
|
|
@@ -5737,8 +5825,8 @@ DO NOT keep working degraded. Instead:
|
|
|
5737
5825
|
3. Stop working immediately. Do not attempt to continue with degraded context.
|
|
5738
5826
|
|
|
5739
5827
|
COMMUNICATION CHAIN \u2014 who you talk to:
|
|
5740
|
-
- You report to the COO. Your completion reports, status updates, and questions go to
|
|
5741
|
-
- Do NOT address the human user directly for decisions, permissions, or status updates. That's
|
|
5828
|
+
- You report to the COO. Your completion reports, status updates, and questions go to the COO via store_memory and update_task.
|
|
5829
|
+
- Do NOT address the human user directly for decisions, permissions, or status updates. That's the COO's job. The user talks to the COO; the COO talks to you.
|
|
5742
5830
|
- Exception: if the user sends you a direct message in your tmux window, respond to them. But default to reporting through exe.
|
|
5743
5831
|
|
|
5744
5832
|
SKILL CAPTURE (encouraged, not mandatory):
|
|
@@ -5827,21 +5915,21 @@ When you receive a large task (estimated 3+ subtasks):
|
|
|
5827
5915
|
6. Review engineer work as reviews arrive in your queue
|
|
5828
5916
|
7. When all subtasks pass review, mark the parent task done
|
|
5829
5917
|
|
|
5830
|
-
PARALLEL
|
|
5918
|
+
PARALLEL ENGINEER INSTANCES:
|
|
5831
5919
|
|
|
5832
|
-
When implementation tasks can be parallelized (touching different files/modules), spin up multiple
|
|
5920
|
+
When implementation tasks can be parallelized (touching different files/modules), spin up multiple engineer instances using git worktrees for isolation:
|
|
5833
5921
|
|
|
5834
|
-
1. Set up git worktrees BEFORE assigning: git worktree add .worktrees/
|
|
5835
|
-
2. Naming convention:
|
|
5836
|
-
3.
|
|
5837
|
-
4. Each
|
|
5838
|
-
5. After all
|
|
5839
|
-
6. Clean up worktrees after integration: git worktree remove .worktrees/
|
|
5922
|
+
1. Set up git worktrees BEFORE assigning: git worktree add .worktrees/{engineer-name}1 -b {engineer-name}1-task-name
|
|
5923
|
+
2. Naming convention: {engineer-name}1-{coordinator-session}, {engineer-name}2-{coordinator-session}
|
|
5924
|
+
3. Parallel instances share that engineer's memory partition \u2014 knowledge compounds across instances
|
|
5925
|
+
4. Each engineer instance works in its own worktree \u2014 no merge conflicts on parallel work
|
|
5926
|
+
5. After all engineer instances complete, YOU integrate: merge worktree branches, resolve any conflicts, run tests
|
|
5927
|
+
6. Clean up worktrees after integration: git worktree remove .worktrees/{engineer-name}1
|
|
5840
5928
|
|
|
5841
|
-
Use this for any decomposable implementation work.
|
|
5929
|
+
Use this for any decomposable implementation work. Use a single engineer for sequential or tightly coupled tasks.
|
|
5842
5930
|
|
|
5843
5931
|
Reviews route to the assigner: if you assign a task to an engineer, you review it.
|
|
5844
|
-
If
|
|
5932
|
+
If the COO assigns a task to you, the COO reviews it. The chain is:
|
|
5845
5933
|
COO \u2192 CTO (you review) \u2192 engineers (you review their work, COO reviews yours)
|
|
5846
5934
|
|
|
5847
5935
|
ROLE BOUNDARIES \u2014 stay in your lane:
|
|
@@ -5917,17 +6005,17 @@ USER RESEARCH
|
|
|
5917
6005
|
When reviewing work, prioritize brand consistency, audience resonance, and measurable impact. Every deliverable should serve a clear strategic goal \u2014 not just look good, but perform.
|
|
5918
6006
|
|
|
5919
6007
|
DELEGATION:
|
|
5920
|
-
- For content production tasks (video rendering, image generation, asset creation with exe-create), delegate to
|
|
5921
|
-
- You write the script/brief.
|
|
6008
|
+
- For content production tasks (video rendering, image generation, asset creation with exe-create), delegate to a Content Production Specialist via create_task. Write a clear brief with: deliverable, format, platform specs, brand guidelines, and reference assets.
|
|
6009
|
+
- You write the script/brief. The producer creates the assets. You review the output.
|
|
5922
6010
|
- For tasks within your own domain (copy, strategy, SEO, social posts), handle directly.
|
|
5923
|
-
- When
|
|
6011
|
+
- When the producer completes work, the review routes back to you automatically. Review it before marking done.`
|
|
5924
6012
|
},
|
|
5925
6013
|
tom: {
|
|
5926
6014
|
name: "tom",
|
|
5927
6015
|
role: "Principal Engineer",
|
|
5928
6016
|
systemPrompt: `You are tom, a principal engineer. You write production-grade code with zero shortcuts. You report to the CTO for technical tasks, and to the COO for organizational matters.
|
|
5929
6017
|
|
|
5930
|
-
You are the hands.
|
|
6018
|
+
You are the hands. The CTO architects and specs; you implement. You receive tasks with clear acceptance criteria and tests to pass. Your job is to make those tests green with code that a senior engineer would be proud to maintain.
|
|
5931
6019
|
|
|
5932
6020
|
STANDARDS \u2014 non-negotiable:
|
|
5933
6021
|
|
|
@@ -5968,15 +6056,15 @@ Velocity:
|
|
|
5968
6056
|
- You are optimized for throughput. Fast, correct, clean \u2014 in that order. But never sacrifice correct for fast.
|
|
5969
6057
|
|
|
5970
6058
|
Working with the CTO:
|
|
5971
|
-
-
|
|
6059
|
+
- The CTO writes specs and tests. You implement. If the spec is wrong, report it \u2014 don't silently deviate.
|
|
5972
6060
|
- If tests seem wrong, report it \u2014 don't modify them.
|
|
5973
6061
|
- Your review goes to whoever assigned the task (usually the CTO). The CTO reviews your code, not the COO.
|
|
5974
|
-
- Multiple
|
|
6062
|
+
- Multiple instances of your role can run in parallel. You may share a memory pool. If you discover something useful (a gotcha, a pattern, a workaround), store it \u2014 the next engineer session benefits.
|
|
5975
6063
|
|
|
5976
6064
|
What you do NOT do:
|
|
5977
6065
|
- Architecture decisions \u2014 that's the CTO
|
|
5978
6066
|
- Marketing, content, design \u2014 that's the CMO
|
|
5979
|
-
- Prioritization, coordination \u2014 that's
|
|
6067
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
5980
6068
|
- Spec writing, test writing \u2014 that's the CTO (unless explicitly asked)
|
|
5981
6069
|
- You implement. That's it. Do it well.`
|
|
5982
6070
|
},
|
|
@@ -5985,7 +6073,7 @@ What you do NOT do:
|
|
|
5985
6073
|
role: "Content Production Specialist",
|
|
5986
6074
|
systemPrompt: `You are sasha, the content production specialist. You turn scripts and creative briefs into finished content using the exe-create platform. You report to the COO. For creative direction, you take input from the CMO.
|
|
5987
6075
|
|
|
5988
|
-
You are the producer.
|
|
6076
|
+
You are the producer. The CMO writes the script; you make it real. The CTO builds the tools; you use them. You know every tool in the exe-create pipeline and how to get the best output from each one.
|
|
5989
6077
|
|
|
5990
6078
|
YOUR TOOLS \u2014 exe-create platform:
|
|
5991
6079
|
|
|
@@ -6023,7 +6111,7 @@ PRODUCTION PRINCIPLES:
|
|
|
6023
6111
|
|
|
6024
6112
|
1. Check budget before generating. Never burn credits without knowing the cost.
|
|
6025
6113
|
2. Iterate in drafts. Use cheaper models for exploration, premium (Kling 3.0) for finals.
|
|
6026
|
-
3. Follow the script.
|
|
6114
|
+
3. Follow the script. The CMO's creative brief is your spec. Don't improvise on brand/tone.
|
|
6027
6115
|
4. Match the platform. 16:9 for YouTube, 9:16 for TikTok/Reels, 1:1 for Instagram feed.
|
|
6028
6116
|
5. Naming convention: {project}-{type}-{version}.{ext} (e.g., launch-hero-v2.png)
|
|
6029
6117
|
6. All final assets go to exe/output/ with clear naming.
|
|
@@ -6032,7 +6120,7 @@ PRODUCTION PRINCIPLES:
|
|
|
6032
6120
|
WHAT YOU DO NOT DO:
|
|
6033
6121
|
- Marketing strategy, brand decisions, copywriting \u2014 that's the CMO
|
|
6034
6122
|
- Architecture, tool development, debugging \u2014 that's the CTO
|
|
6035
|
-
- Prioritization, coordination \u2014 that's
|
|
6123
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
6036
6124
|
- You produce. That's it. Do it well.`
|
|
6037
6125
|
},
|
|
6038
6126
|
gen: {
|
|
@@ -6721,7 +6809,7 @@ Do not repeatedly attempt tool calls that fail \u2014 switch to planning mode.
|
|
|
6721
6809
|
`;
|
|
6722
6810
|
POST_WORK_CHECKLIST = `
|
|
6723
6811
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
6724
|
-
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
6812
|
+
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
6725
6813
|
8. Check for next task \u2014 auto-chain through the queue without waiting
|
|
6726
6814
|
|
|
6727
6815
|
## Spawning Rules (mandatory)
|
|
@@ -6795,7 +6883,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
6795
6883
|
- **create_task** \u2014 assign work to specialists with clear specs
|
|
6796
6884
|
- **update_task / close_task** \u2014 finalize reviews, mark work done
|
|
6797
6885
|
- **store_behavior** \u2014 record corrections as behavioral rules (p0/p1/p2)
|
|
6798
|
-
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (
|
|
6886
|
+
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (COO/founder only)
|
|
6799
6887
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
6800
6888
|
- **send_message** \u2014 direct intercom to employees
|
|
6801
6889
|
${PLAN_MODE_COMPAT}
|
|
@@ -6806,7 +6894,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
6806
6894
|
3. Call **update_task** with status "done" and a structured result summary
|
|
6807
6895
|
4. Call **store_memory** with a report: what was done, decisions made, open items
|
|
6808
6896
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
6809
|
-
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
6897
|
+
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
6810
6898
|
8. Check for next task \u2014 auto-chain through the queue without waiting
|
|
6811
6899
|
|
|
6812
6900
|
## Spawning Rules (mandatory)
|
|
@@ -6846,7 +6934,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
6846
6934
|
|
|
6847
6935
|
- Long-term maintainability over short-term velocity.
|
|
6848
6936
|
- If a pattern exists in the codebase, follow it. Don't invent new approaches.
|
|
6849
|
-
- Decompose: 3+ independent deliverables \u2192 delegate to
|
|
6937
|
+
- Decompose: 3+ independent deliverables \u2192 delegate to engineer instances.
|
|
6850
6938
|
- Focus review on architecture: backward compatibility, tech debt, consistency with existing patterns.
|
|
6851
6939
|
- When blocked, report immediately with what you've tried and what you need.
|
|
6852
6940
|
|
|
@@ -6862,7 +6950,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
6862
6950
|
|
|
6863
6951
|
## Tools
|
|
6864
6952
|
|
|
6865
|
-
- **create_task** \u2014 assign implementation work to
|
|
6953
|
+
- **create_task** \u2014 assign implementation work to engineers with file paths, interfaces, acceptance criteria
|
|
6866
6954
|
- **list_tasks** \u2014 check engineer queues, monitor progress
|
|
6867
6955
|
- **update_task** \u2014 mark your own tasks done with result summary
|
|
6868
6956
|
- **recall_my_memory / ask_team_memory** \u2014 persist and retrieve technical decisions
|
|
@@ -6878,7 +6966,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
6878
6966
|
4. Call **update_task** with status "done" and result summary (files changed, tests, decisions)
|
|
6879
6967
|
5. Call **store_memory** with structured report for org visibility
|
|
6880
6968
|
6. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
6881
|
-
7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
6969
|
+
7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
6882
6970
|
8. Check for next task \u2014 auto-chain through the queue
|
|
6883
6971
|
|
|
6884
6972
|
## Spawning Rules (mandatory)
|
|
@@ -6912,7 +7000,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
|
|
|
6912
7000
|
- Never ship content without verifying tone, format, and channel requirements.
|
|
6913
7001
|
- SEO/AEO/GEO considerations on every piece of public content.
|
|
6914
7002
|
- Commit immediately after verification \u2014 don't wait for approval.
|
|
6915
|
-
- Report every completion with structured summary to
|
|
7003
|
+
- Report every completion with structured summary to the COO.
|
|
6916
7004
|
|
|
6917
7005
|
## Operating Principles
|
|
6918
7006
|
|
|
@@ -6946,7 +7034,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
6946
7034
|
5. Call **update_task** with status "done" and result summary
|
|
6947
7035
|
6. Call **store_memory** with structured report: deliverables, decisions, brand notes
|
|
6948
7036
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
6949
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
7037
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
6950
7038
|
9. Check for next task \u2014 auto-chain through the queue
|
|
6951
7039
|
|
|
6952
7040
|
## Spawning Rules (mandatory)
|
|
@@ -6984,7 +7072,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
6984
7072
|
|
|
6985
7073
|
## Operating Principles
|
|
6986
7074
|
|
|
6987
|
-
-
|
|
7075
|
+
- The CTO specs and reviews. You implement. If the spec is wrong, report it \u2014 don't deviate.
|
|
6988
7076
|
- Fast, correct, clean \u2014 in that order. Never sacrifice correct for fast.
|
|
6989
7077
|
- Don't over-engineer. Build what the spec asks for, nothing more.
|
|
6990
7078
|
- Three similar lines is fine. Don't abstract until there's a fourth.
|
|
@@ -6994,7 +7082,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
6994
7082
|
|
|
6995
7083
|
- Architecture decisions \u2014 that's the CTO
|
|
6996
7084
|
- Marketing, content, design \u2014 that's the CMO
|
|
6997
|
-
- Prioritization, coordination \u2014 that's
|
|
7085
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
6998
7086
|
- You implement. That's it.
|
|
6999
7087
|
|
|
7000
7088
|
## Tools
|
|
@@ -7013,7 +7101,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
7013
7101
|
5. Call **update_task** with status "done" and result (files changed, tests pass/fail, decisions)
|
|
7014
7102
|
6. Call **store_memory** with structured report
|
|
7015
7103
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
7016
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
7104
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
7017
7105
|
9. Check for next task \u2014 auto-chain through the queue
|
|
7018
7106
|
|
|
7019
7107
|
## Spawning Rules (mandatory)
|
|
@@ -7045,7 +7133,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
7045
7133
|
## Non-Negotiables
|
|
7046
7134
|
|
|
7047
7135
|
- Check budget before generating. Never burn credits without knowing the cost.
|
|
7048
|
-
- Follow the script.
|
|
7136
|
+
- Follow the script. The CMO's creative brief is your spec. Don't improvise on brand/tone.
|
|
7049
7137
|
- Match the platform: 16:9 for YouTube, 9:16 for TikTok/Reels, 1:1 for Instagram feed.
|
|
7050
7138
|
- All final assets go to exe/output/ with clear naming.
|
|
7051
7139
|
- Commit immediately after verification \u2014 don't wait for approval.
|
|
@@ -7055,7 +7143,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
7055
7143
|
- Iterate in drafts. Use cheaper models for exploration, premium for finals.
|
|
7056
7144
|
- Naming: {project}-{type}-{version}.{ext}
|
|
7057
7145
|
- Store production decisions in memory \u2014 which models worked, which prompts produced good results.
|
|
7058
|
-
-
|
|
7146
|
+
- The CMO directs creatively. The CTO builds tools. You produce. Stay in your lane.
|
|
7059
7147
|
|
|
7060
7148
|
## Tools
|
|
7061
7149
|
|
|
@@ -7074,7 +7162,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
7074
7162
|
6. Call **update_task** with status "done" and result summary
|
|
7075
7163
|
7. Call **store_memory** with structured report: deliverables, models used, cost, decisions
|
|
7076
7164
|
8. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
7077
|
-
9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
7165
|
+
9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
7078
7166
|
10. Check for next task \u2014 auto-chain through the queue
|
|
7079
7167
|
|
|
7080
7168
|
## Spawning Rules (mandatory)
|
|
@@ -7145,7 +7233,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
7145
7233
|
5. Call **update_task** with status "done" and evaluation summary
|
|
7146
7234
|
6. Call **store_memory** with structured report
|
|
7147
7235
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
7148
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
7236
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
7149
7237
|
9. Check for next task \u2014 auto-chain through the queue without waiting
|
|
7150
7238
|
|
|
7151
7239
|
## Spawning Rules (mandatory)
|
|
@@ -7497,38 +7585,74 @@ async function runSetupWizard(opts = {}) {
|
|
|
7497
7585
|
log("Exe Cloud: your memories are end-to-end encrypted, compressed, and");
|
|
7498
7586
|
log("backed up on Exe Cloud. Free for all plans. We can't read your data \u2014");
|
|
7499
7587
|
log("only your encryption key can decrypt it.");
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7588
|
+
log("");
|
|
7589
|
+
const existingKey = await ask2(rl, "Do you have an existing API key? (paste it, or press Enter to skip): ");
|
|
7590
|
+
if (existingKey && existingKey.startsWith("exe_sk_")) {
|
|
7591
|
+
const cloudEndpoint = "https://askexe.com/cloud";
|
|
7504
7592
|
try {
|
|
7505
|
-
|
|
7593
|
+
const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
7594
|
+
const deviceId = loadDeviceId2();
|
|
7595
|
+
const res = await fetch(`${cloudEndpoint}/auth/activate`, {
|
|
7506
7596
|
method: "POST",
|
|
7507
7597
|
headers: { "Content-Type": "application/json" },
|
|
7508
|
-
body: JSON.stringify({ deviceId }),
|
|
7598
|
+
body: JSON.stringify({ apiKey: existingKey, deviceId }),
|
|
7509
7599
|
signal: AbortSignal.timeout(1e4)
|
|
7510
7600
|
});
|
|
7601
|
+
if (res.ok) {
|
|
7602
|
+
const data = await res.json();
|
|
7603
|
+
if (data.valid) {
|
|
7604
|
+
cloudConfig = { apiKey: existingKey, endpoint: cloudEndpoint };
|
|
7605
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
7606
|
+
saveLicense3(existingKey);
|
|
7607
|
+
mirrorLicenseKey3(existingKey);
|
|
7608
|
+
log(`API key validated. Plan: ${data.plan}, email: ${data.email}`);
|
|
7609
|
+
log("Cloud sync configured.");
|
|
7610
|
+
} else {
|
|
7611
|
+
log("API key is invalid or expired. Proceeding with auto-provisioning.");
|
|
7612
|
+
}
|
|
7613
|
+
}
|
|
7511
7614
|
} catch {
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
signal: AbortSignal.timeout(1e4)
|
|
7518
|
-
});
|
|
7615
|
+
log("Could not validate key \u2014 saving it and proceeding.");
|
|
7616
|
+
cloudConfig = { apiKey: existingKey, endpoint: "https://askexe.com/cloud" };
|
|
7617
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
7618
|
+
saveLicense3(existingKey);
|
|
7619
|
+
mirrorLicenseKey3(existingKey);
|
|
7519
7620
|
}
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7621
|
+
}
|
|
7622
|
+
if (!cloudConfig) {
|
|
7623
|
+
try {
|
|
7624
|
+
const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
7625
|
+
const deviceId = loadDeviceId2();
|
|
7626
|
+
let res;
|
|
7627
|
+
try {
|
|
7628
|
+
res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
|
|
7629
|
+
method: "POST",
|
|
7630
|
+
headers: { "Content-Type": "application/json" },
|
|
7631
|
+
body: JSON.stringify({ deviceId }),
|
|
7632
|
+
signal: AbortSignal.timeout(1e4)
|
|
7633
|
+
});
|
|
7634
|
+
} catch {
|
|
7635
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
7636
|
+
res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
|
|
7637
|
+
method: "POST",
|
|
7638
|
+
headers: { "Content-Type": "application/json" },
|
|
7639
|
+
body: JSON.stringify({ deviceId }),
|
|
7640
|
+
signal: AbortSignal.timeout(1e4)
|
|
7641
|
+
});
|
|
7528
7642
|
}
|
|
7643
|
+
if (res.ok) {
|
|
7644
|
+
const data = await res.json();
|
|
7645
|
+
if (data.apiKey) {
|
|
7646
|
+
cloudConfig = { apiKey: data.apiKey, endpoint: "https://askexe.com/cloud" };
|
|
7647
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
7648
|
+
saveLicense3(data.apiKey);
|
|
7649
|
+
mirrorLicenseKey3(data.apiKey);
|
|
7650
|
+
log("Cloud sync activated automatically.");
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
} catch {
|
|
7654
|
+
log("Cloud sync will activate when online.");
|
|
7529
7655
|
}
|
|
7530
|
-
} catch {
|
|
7531
|
-
log("Cloud sync will activate when online.");
|
|
7532
7656
|
}
|
|
7533
7657
|
state.completedSteps.push(2);
|
|
7534
7658
|
saveSetupState(state);
|
|
@@ -10962,7 +11086,7 @@ $ npm install --save-dev react-devtools-core
|
|
|
10962
11086
|
unhideTextInstance(node, text) {
|
|
10963
11087
|
setTextNodeValue(node, text);
|
|
10964
11088
|
},
|
|
10965
|
-
getPublicInstance: (
|
|
11089
|
+
getPublicInstance: (instance2) => instance2,
|
|
10966
11090
|
hideInstance(node) {
|
|
10967
11091
|
node.yogaNode?.setDisplay(src_default.DISPLAY_NONE);
|
|
10968
11092
|
},
|
|
@@ -13518,16 +13642,16 @@ var init_render = __esm({
|
|
|
13518
13642
|
concurrent: false,
|
|
13519
13643
|
...getOptions(options)
|
|
13520
13644
|
};
|
|
13521
|
-
const
|
|
13522
|
-
|
|
13645
|
+
const instance2 = getInstance(inkOptions.stdout, () => new Ink(inkOptions), inkOptions.concurrent ?? false);
|
|
13646
|
+
instance2.render(node);
|
|
13523
13647
|
return {
|
|
13524
|
-
rerender:
|
|
13648
|
+
rerender: instance2.render,
|
|
13525
13649
|
unmount() {
|
|
13526
|
-
|
|
13650
|
+
instance2.unmount();
|
|
13527
13651
|
},
|
|
13528
|
-
waitUntilExit:
|
|
13652
|
+
waitUntilExit: instance2.waitUntilExit,
|
|
13529
13653
|
cleanup: () => instances_default.delete(inkOptions.stdout),
|
|
13530
|
-
clear:
|
|
13654
|
+
clear: instance2.clear
|
|
13531
13655
|
};
|
|
13532
13656
|
};
|
|
13533
13657
|
render_default = render;
|
|
@@ -13541,14 +13665,14 @@ var init_render = __esm({
|
|
|
13541
13665
|
return stdout;
|
|
13542
13666
|
};
|
|
13543
13667
|
getInstance = (stdout, createInstance, concurrent) => {
|
|
13544
|
-
let
|
|
13545
|
-
if (!
|
|
13546
|
-
|
|
13547
|
-
instances_default.set(stdout,
|
|
13548
|
-
} else if (
|
|
13549
|
-
console.warn(`Warning: render() was called with concurrent: ${concurrent}, but the existing instance for this stdout uses concurrent: ${
|
|
13550
|
-
}
|
|
13551
|
-
return
|
|
13668
|
+
let instance2 = instances_default.get(stdout);
|
|
13669
|
+
if (!instance2) {
|
|
13670
|
+
instance2 = createInstance();
|
|
13671
|
+
instances_default.set(stdout, instance2);
|
|
13672
|
+
} else if (instance2.isConcurrent !== concurrent) {
|
|
13673
|
+
console.warn(`Warning: render() was called with concurrent: ${concurrent}, but the existing instance for this stdout uses concurrent: ${instance2.isConcurrent}. The concurrent option only takes effect on the first render. Call unmount() first if you need to change the rendering mode.`);
|
|
13674
|
+
}
|
|
13675
|
+
return instance2;
|
|
13552
13676
|
};
|
|
13553
13677
|
}
|
|
13554
13678
|
});
|
|
@@ -14955,6 +15079,7 @@ __export(tasks_crud_exports, {
|
|
|
14955
15079
|
ensureArchitectureDoc: () => ensureArchitectureDoc,
|
|
14956
15080
|
ensureGitignoreExe: () => ensureGitignoreExe,
|
|
14957
15081
|
extractParentFromContext: () => extractParentFromContext,
|
|
15082
|
+
isTmuxSessionAlive: () => isTmuxSessionAlive,
|
|
14958
15083
|
listTasks: () => listTasks,
|
|
14959
15084
|
resolveTask: () => resolveTask,
|
|
14960
15085
|
slugify: () => slugify,
|
|
@@ -15205,6 +15330,36 @@ async function listTasks(input) {
|
|
|
15205
15330
|
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
15206
15331
|
}));
|
|
15207
15332
|
}
|
|
15333
|
+
function isTmuxSessionAlive(identifier) {
|
|
15334
|
+
if (!identifier || identifier === "unknown") return true;
|
|
15335
|
+
try {
|
|
15336
|
+
if (identifier.startsWith("%")) {
|
|
15337
|
+
const output = execSync9("tmux list-panes -a -F '#{pane_id}'", {
|
|
15338
|
+
timeout: 2e3,
|
|
15339
|
+
encoding: "utf8",
|
|
15340
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15341
|
+
});
|
|
15342
|
+
return output.split("\n").some((l) => l.trim() === identifier);
|
|
15343
|
+
} else {
|
|
15344
|
+
execSync9(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
15345
|
+
timeout: 2e3,
|
|
15346
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15347
|
+
});
|
|
15348
|
+
return true;
|
|
15349
|
+
}
|
|
15350
|
+
} catch {
|
|
15351
|
+
if (identifier.startsWith("%")) return true;
|
|
15352
|
+
try {
|
|
15353
|
+
execSync9("tmux list-sessions", {
|
|
15354
|
+
timeout: 2e3,
|
|
15355
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
15356
|
+
});
|
|
15357
|
+
return false;
|
|
15358
|
+
} catch {
|
|
15359
|
+
return true;
|
|
15360
|
+
}
|
|
15361
|
+
}
|
|
15362
|
+
}
|
|
15208
15363
|
function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
15209
15364
|
if (!taskContext) return null;
|
|
15210
15365
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
@@ -15267,13 +15422,59 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
15267
15422
|
});
|
|
15268
15423
|
if (claim.rowsAffected === 0) {
|
|
15269
15424
|
const current = await client.execute({
|
|
15270
|
-
sql: "SELECT status, assigned_tmux FROM tasks WHERE id = ?",
|
|
15425
|
+
sql: "SELECT status, assigned_tmux, assigned_by FROM tasks WHERE id = ?",
|
|
15271
15426
|
args: [taskId]
|
|
15272
15427
|
});
|
|
15273
15428
|
const cur = current.rows[0];
|
|
15274
|
-
const
|
|
15275
|
-
const
|
|
15276
|
-
|
|
15429
|
+
const curStatus = cur?.status ?? "unknown";
|
|
15430
|
+
const claimedBySession = cur?.assigned_tmux ?? "";
|
|
15431
|
+
const assignedBy = cur?.assigned_by ?? "";
|
|
15432
|
+
if (curStatus === "in_progress" && claimedBySession && !isTmuxSessionAlive(claimedBySession)) {
|
|
15433
|
+
process.stderr.write(
|
|
15434
|
+
`[tasks] Auto-releasing dead claim on ${taskId} (was ${claimedBySession})
|
|
15435
|
+
`
|
|
15436
|
+
);
|
|
15437
|
+
await client.execute({
|
|
15438
|
+
sql: "UPDATE tasks SET status = 'open', assigned_tmux = NULL, updated_at = ? WHERE id = ?",
|
|
15439
|
+
args: [now, taskId]
|
|
15440
|
+
});
|
|
15441
|
+
const retried = await client.execute({
|
|
15442
|
+
sql: `UPDATE tasks SET status = 'in_progress', assigned_tmux = ?, updated_at = ? WHERE id = ? AND status = 'open'`,
|
|
15443
|
+
args: [tmuxSession, now, taskId]
|
|
15444
|
+
});
|
|
15445
|
+
if (retried.rowsAffected > 0) {
|
|
15446
|
+
try {
|
|
15447
|
+
await writeCheckpoint({
|
|
15448
|
+
taskId,
|
|
15449
|
+
step: "reclaimed_dead_session",
|
|
15450
|
+
contextSummary: `Task reclaimed after dead session ${claimedBySession} released.`
|
|
15451
|
+
});
|
|
15452
|
+
} catch {
|
|
15453
|
+
}
|
|
15454
|
+
return { row, taskFile, now, taskId };
|
|
15455
|
+
}
|
|
15456
|
+
}
|
|
15457
|
+
if (curStatus === "in_progress" && input.callerAgentId && (input.callerAgentId === assignedBy || input.callerAgentId === "exe")) {
|
|
15458
|
+
process.stderr.write(
|
|
15459
|
+
`[tasks] Assigner override: ${input.callerAgentId} reclaiming ${taskId}
|
|
15460
|
+
`
|
|
15461
|
+
);
|
|
15462
|
+
await client.execute({
|
|
15463
|
+
sql: `UPDATE tasks SET status = 'in_progress', assigned_tmux = ?, updated_at = ? WHERE id = ?`,
|
|
15464
|
+
args: [tmuxSession, now, taskId]
|
|
15465
|
+
});
|
|
15466
|
+
try {
|
|
15467
|
+
await writeCheckpoint({
|
|
15468
|
+
taskId,
|
|
15469
|
+
step: "assigner_override",
|
|
15470
|
+
contextSummary: `Task force-reclaimed by assigner ${input.callerAgentId}.`
|
|
15471
|
+
});
|
|
15472
|
+
} catch {
|
|
15473
|
+
}
|
|
15474
|
+
return { row, taskFile, now, taskId };
|
|
15475
|
+
}
|
|
15476
|
+
const claimedBy = claimedBySession ? ` (claimed by ${claimedBySession})` : "";
|
|
15477
|
+
throw new Error(`${TASK_ALREADY_CLAIMED_PREFIX}: task ${taskId} is ${curStatus}${claimedBy}`);
|
|
15277
15478
|
}
|
|
15278
15479
|
try {
|
|
15279
15480
|
await writeCheckpoint({
|
|
@@ -15371,7 +15572,7 @@ var init_tasks_crud = __esm({
|
|
|
15371
15572
|
"use strict";
|
|
15372
15573
|
init_database();
|
|
15373
15574
|
init_task_scope();
|
|
15374
|
-
DELEGATION_KEYWORDS = /parallel|delegate|wave|
|
|
15575
|
+
DELEGATION_KEYWORDS = /parallel|delegate|wave|worktree|multi-instance/i;
|
|
15375
15576
|
TASK_ALREADY_CLAIMED_PREFIX = "TASK_ALREADY_CLAIMED";
|
|
15376
15577
|
}
|
|
15377
15578
|
});
|
|
@@ -15728,7 +15929,7 @@ function findSessionForProject(projectName) {
|
|
|
15728
15929
|
const sessions = listSessions();
|
|
15729
15930
|
for (const s of sessions) {
|
|
15730
15931
|
const proj = s.projectDir.split("/").filter(Boolean).pop();
|
|
15731
|
-
if (proj === projectName && s.agentId === "exe") return s;
|
|
15932
|
+
if (proj === projectName && (s.agentId === "exe" || isCoordinatorName(s.agentId))) return s;
|
|
15732
15933
|
}
|
|
15733
15934
|
return null;
|
|
15734
15935
|
}
|
|
@@ -15768,12 +15969,13 @@ var init_session_scope = __esm({
|
|
|
15768
15969
|
init_session_registry();
|
|
15769
15970
|
init_project_name();
|
|
15770
15971
|
init_tmux_routing();
|
|
15972
|
+
init_employees();
|
|
15771
15973
|
}
|
|
15772
15974
|
});
|
|
15773
15975
|
|
|
15774
15976
|
// src/lib/tasks-notify.ts
|
|
15775
15977
|
async function dispatchTaskToEmployee(input) {
|
|
15776
|
-
if (input.assignedTo === "exe") return { dispatched: "skipped" };
|
|
15978
|
+
if (input.assignedTo === "exe" || isCoordinatorName(input.assignedTo)) return { dispatched: "skipped" };
|
|
15777
15979
|
let crossProject = false;
|
|
15778
15980
|
if (input.projectName) {
|
|
15779
15981
|
try {
|
|
@@ -16216,6 +16418,24 @@ async function updateTask(input) {
|
|
|
16216
16418
|
});
|
|
16217
16419
|
} catch {
|
|
16218
16420
|
}
|
|
16421
|
+
const assignedAgent = String(row.assigned_to);
|
|
16422
|
+
if (!isCoordinatorName(assignedAgent)) {
|
|
16423
|
+
try {
|
|
16424
|
+
const draftClient = getClient();
|
|
16425
|
+
if (input.status === "done") {
|
|
16426
|
+
await draftClient.execute({
|
|
16427
|
+
sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
|
|
16428
|
+
args: [assignedAgent]
|
|
16429
|
+
});
|
|
16430
|
+
} else if (input.status === "cancelled") {
|
|
16431
|
+
await draftClient.execute({
|
|
16432
|
+
sql: `DELETE FROM memories WHERE agent_id = ? AND draft = 1`,
|
|
16433
|
+
args: [assignedAgent]
|
|
16434
|
+
});
|
|
16435
|
+
}
|
|
16436
|
+
} catch {
|
|
16437
|
+
}
|
|
16438
|
+
}
|
|
16219
16439
|
try {
|
|
16220
16440
|
const client = getClient();
|
|
16221
16441
|
const cascaded = await client.execute({
|
|
@@ -16234,8 +16454,8 @@ async function updateTask(input) {
|
|
|
16234
16454
|
}
|
|
16235
16455
|
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
16236
16456
|
if (isTerminal) {
|
|
16237
|
-
const
|
|
16238
|
-
if (!
|
|
16457
|
+
const isCoordinator = String(row.assigned_to) === "exe" || isCoordinatorName(String(row.assigned_to));
|
|
16458
|
+
if (!isCoordinator) {
|
|
16239
16459
|
notifyTaskDone();
|
|
16240
16460
|
}
|
|
16241
16461
|
await markTaskNotificationsRead(taskFile);
|
|
@@ -16259,7 +16479,7 @@ async function updateTask(input) {
|
|
|
16259
16479
|
}
|
|
16260
16480
|
}
|
|
16261
16481
|
}
|
|
16262
|
-
if (input.status === "done" && String(row.assigned_to) !== "exe" && !process.env.VITEST) {
|
|
16482
|
+
if (input.status === "done" && String(row.assigned_to) !== "exe" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
16263
16483
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
16264
16484
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
16265
16485
|
taskId,
|
|
@@ -16275,7 +16495,7 @@ async function updateTask(input) {
|
|
|
16275
16495
|
});
|
|
16276
16496
|
}
|
|
16277
16497
|
let nextTask;
|
|
16278
|
-
if (isTerminal && String(row.assigned_to) !== "exe") {
|
|
16498
|
+
if (isTerminal && String(row.assigned_to) !== "exe" && !isCoordinatorName(String(row.assigned_to))) {
|
|
16279
16499
|
try {
|
|
16280
16500
|
nextTask = await findNextTask(String(row.assigned_to));
|
|
16281
16501
|
} catch {
|
|
@@ -16302,12 +16522,14 @@ async function updateTask(input) {
|
|
|
16302
16522
|
async function deleteTask(taskId, baseDir) {
|
|
16303
16523
|
const client = getClient();
|
|
16304
16524
|
const { taskFile, assignedTo, assignedBy, taskSlug } = await deleteTaskCore(taskId, baseDir);
|
|
16305
|
-
const
|
|
16525
|
+
const coordinatorName = getCoordinatorName();
|
|
16526
|
+
const reviewer = assignedBy || coordinatorName;
|
|
16306
16527
|
const reviewSlug = `review-${assignedTo}-${taskSlug}`;
|
|
16307
16528
|
const reviewFile = `exe/${reviewer}/${reviewSlug}.md`;
|
|
16529
|
+
const legacyReviewFile = `exe/${coordinatorName}/${reviewSlug}.md`;
|
|
16308
16530
|
await client.execute({
|
|
16309
|
-
sql: "DELETE FROM tasks WHERE task_file = ? OR task_file = ?",
|
|
16310
|
-
args: [reviewFile, `exe/exe/${reviewSlug}.md`]
|
|
16531
|
+
sql: "DELETE FROM tasks WHERE task_file = ? OR task_file = ? OR task_file = ?",
|
|
16532
|
+
args: [reviewFile, legacyReviewFile, `exe/exe/${reviewSlug}.md`]
|
|
16311
16533
|
});
|
|
16312
16534
|
await markAsReadByTaskFile(taskFile);
|
|
16313
16535
|
await markAsReadByTaskFile(reviewFile);
|
|
@@ -16319,6 +16541,7 @@ var init_tasks = __esm({
|
|
|
16319
16541
|
init_config();
|
|
16320
16542
|
init_notifications();
|
|
16321
16543
|
init_state_bus();
|
|
16544
|
+
init_employees();
|
|
16322
16545
|
init_tasks_crud();
|
|
16323
16546
|
init_tasks_review();
|
|
16324
16547
|
init_tasks_crud();
|
|
@@ -16404,7 +16627,7 @@ function _resetLastRelaunchCache() {
|
|
|
16404
16627
|
}
|
|
16405
16628
|
async function lastResumeCreatedAtMs(agentId) {
|
|
16406
16629
|
const client = getClient();
|
|
16407
|
-
const cmScope = sessionScopeFilter();
|
|
16630
|
+
const cmScope = sessionScopeFilter(null);
|
|
16408
16631
|
const result = await client.execute({
|
|
16409
16632
|
sql: `SELECT MAX(created_at) AS last_created_at
|
|
16410
16633
|
FROM tasks
|
|
@@ -16429,7 +16652,7 @@ async function createOrRefreshResumeTask(agentId, projectDir, openTasks) {
|
|
|
16429
16652
|
const client = getClient();
|
|
16430
16653
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
16431
16654
|
const context = buildResumeContext(agentId, openTasks);
|
|
16432
|
-
const rdScope = sessionScopeFilter();
|
|
16655
|
+
const rdScope = sessionScopeFilter(null);
|
|
16433
16656
|
const existing = await client.execute({
|
|
16434
16657
|
sql: `SELECT id FROM tasks
|
|
16435
16658
|
WHERE assigned_to = ?
|
|
@@ -16463,7 +16686,7 @@ async function pollCapacityDead() {
|
|
|
16463
16686
|
const transport = getTransport();
|
|
16464
16687
|
const relaunched = [];
|
|
16465
16688
|
const registered = listSessions().filter(
|
|
16466
|
-
(s) => s.agentId !== "exe"
|
|
16689
|
+
(s) => s.agentId !== "exe" && !isCoordinatorName(s.agentId)
|
|
16467
16690
|
);
|
|
16468
16691
|
if (registered.length === 0) return [];
|
|
16469
16692
|
let liveSessions;
|
|
@@ -16523,7 +16746,7 @@ async function pollCapacityDead() {
|
|
|
16523
16746
|
reason: "capacity"
|
|
16524
16747
|
});
|
|
16525
16748
|
const client = getClient();
|
|
16526
|
-
const rlScope = sessionScopeFilter();
|
|
16749
|
+
const rlScope = sessionScopeFilter(null);
|
|
16527
16750
|
const openTasks = await client.execute({
|
|
16528
16751
|
sql: `SELECT id, title, priority, task_file, status
|
|
16529
16752
|
FROM tasks
|
|
@@ -16577,6 +16800,7 @@ var init_capacity_monitor = __esm({
|
|
|
16577
16800
|
init_session_kill_telemetry();
|
|
16578
16801
|
init_tmux_routing();
|
|
16579
16802
|
init_task_scope();
|
|
16803
|
+
init_employees();
|
|
16580
16804
|
CAPACITY_PATTERNS = [
|
|
16581
16805
|
/conversation is too long/i,
|
|
16582
16806
|
/maximum context length/i,
|
|
@@ -16715,7 +16939,7 @@ function getMySession() {
|
|
|
16715
16939
|
function isRootSession(name) {
|
|
16716
16940
|
return name.length > 0 && !name.includes("-");
|
|
16717
16941
|
}
|
|
16718
|
-
function employeeSessionName(employee, exeSession,
|
|
16942
|
+
function employeeSessionName(employee, exeSession, instance2) {
|
|
16719
16943
|
if (!isRootSession(exeSession)) {
|
|
16720
16944
|
const root = extractRootExe(exeSession);
|
|
16721
16945
|
if (root) {
|
|
@@ -16726,11 +16950,11 @@ function employeeSessionName(employee, exeSession, instance) {
|
|
|
16726
16950
|
exeSession = root;
|
|
16727
16951
|
} else {
|
|
16728
16952
|
throw new Error(
|
|
16729
|
-
`Invalid
|
|
16953
|
+
`Invalid coordinator session "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name.`
|
|
16730
16954
|
);
|
|
16731
16955
|
}
|
|
16732
16956
|
}
|
|
16733
|
-
const suffix =
|
|
16957
|
+
const suffix = instance2 != null && instance2 > 0 ? String(instance2) : "";
|
|
16734
16958
|
const name = `${employee}${suffix}-${exeSession}`;
|
|
16735
16959
|
if (!VALID_SESSION_NAME.test(name)) {
|
|
16736
16960
|
throw new Error(
|
|
@@ -16746,8 +16970,10 @@ function parseParentExe(sessionName, agentId) {
|
|
|
16746
16970
|
return match?.[1] ?? null;
|
|
16747
16971
|
}
|
|
16748
16972
|
function extractRootExe(name) {
|
|
16749
|
-
|
|
16750
|
-
|
|
16973
|
+
if (!name) return null;
|
|
16974
|
+
if (!name.includes("-")) return name;
|
|
16975
|
+
const parts = name.split("-").filter(Boolean);
|
|
16976
|
+
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
16751
16977
|
}
|
|
16752
16978
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
16753
16979
|
if (!existsSync22(SESSION_CACHE)) {
|
|
@@ -16892,12 +17118,14 @@ function isSessionBusy(sessionName) {
|
|
|
16892
17118
|
return state === "thinking" || state === "tool";
|
|
16893
17119
|
}
|
|
16894
17120
|
function isExeSession(sessionName) {
|
|
16895
|
-
|
|
17121
|
+
const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
|
|
17122
|
+
const coordinatorName = getCoordinatorName();
|
|
17123
|
+
return matchesBaseWithInstance(coordinatorName) || matchesBaseWithInstance("exe");
|
|
16896
17124
|
}
|
|
16897
17125
|
function sendIntercom(targetSession) {
|
|
16898
17126
|
const transport = getTransport();
|
|
16899
17127
|
if (isExeSession(targetSession)) {
|
|
16900
|
-
logIntercom(`
|
|
17128
|
+
logIntercom(`SKIP_COORDINATOR \u2192 ${targetSession} (coordinator sessions use prompt-submit hook)`);
|
|
16901
17129
|
return "skipped_exe";
|
|
16902
17130
|
}
|
|
16903
17131
|
if (isDebounced(targetSession)) {
|
|
@@ -16949,7 +17177,7 @@ function notifyParentExe(sessionKey) {
|
|
|
16949
17177
|
if (result === "failed") {
|
|
16950
17178
|
const rootExe = resolveExeSession();
|
|
16951
17179
|
if (rootExe && rootExe !== target) {
|
|
16952
|
-
process.stderr.write(`[intercom] notifyParentExe: dispatcher ${target} dead, falling back to root
|
|
17180
|
+
process.stderr.write(`[intercom] notifyParentExe: dispatcher ${target} dead, falling back to root coordinator session ${rootExe}
|
|
16953
17181
|
`);
|
|
16954
17182
|
const fallback = sendIntercom(rootExe);
|
|
16955
17183
|
return fallback !== "failed";
|
|
@@ -16959,8 +17187,8 @@ function notifyParentExe(sessionKey) {
|
|
|
16959
17187
|
return true;
|
|
16960
17188
|
}
|
|
16961
17189
|
function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
16962
|
-
if (employeeName === "exe") {
|
|
16963
|
-
return { status: "failed", sessionName: "", error: "
|
|
17190
|
+
if (employeeName === "exe" || isCoordinatorName(employeeName)) {
|
|
17191
|
+
return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
|
|
16964
17192
|
}
|
|
16965
17193
|
try {
|
|
16966
17194
|
assertEmployeeLimitSync();
|
|
@@ -16969,8 +17197,8 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
16969
17197
|
return { status: "failed", sessionName: "", error: err.message };
|
|
16970
17198
|
}
|
|
16971
17199
|
}
|
|
16972
|
-
if (
|
|
16973
|
-
const bare = employeeName.
|
|
17200
|
+
if (employeeName.includes("-")) {
|
|
17201
|
+
const bare = employeeName.split("-")[0].replace(/\d+$/, "");
|
|
16974
17202
|
return {
|
|
16975
17203
|
status: "failed",
|
|
16976
17204
|
sessionName: "",
|
|
@@ -16989,7 +17217,7 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
16989
17217
|
return {
|
|
16990
17218
|
status: "failed",
|
|
16991
17219
|
sessionName: "",
|
|
16992
|
-
error: `Invalid
|
|
17220
|
+
error: `Invalid coordinator session "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name.`
|
|
16993
17221
|
};
|
|
16994
17222
|
}
|
|
16995
17223
|
}
|
|
@@ -17146,8 +17374,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
17146
17374
|
const ctxContent = [
|
|
17147
17375
|
`## Session Context`,
|
|
17148
17376
|
`You are running in tmux session: ${sessionName}.`,
|
|
17149
|
-
`Your parent
|
|
17150
|
-
`Your employees (if any) use the -${exeSession} suffix
|
|
17377
|
+
`Your parent coordinator session is ${exeSession}.`,
|
|
17378
|
+
`Your employees (if any) use the -${exeSession} suffix.`
|
|
17151
17379
|
].join("\n");
|
|
17152
17380
|
writeFileSync12(ctxFile, ctxContent);
|
|
17153
17381
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
@@ -17251,6 +17479,7 @@ var init_tmux_routing = __esm({
|
|
|
17251
17479
|
init_provider_table();
|
|
17252
17480
|
init_intercom_queue();
|
|
17253
17481
|
init_plan_limits();
|
|
17482
|
+
init_employees();
|
|
17254
17483
|
SPAWN_LOCK_DIR = path26.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
17255
17484
|
SESSION_CACHE = path26.join(os10.homedir(), ".exe-os", "session-cache");
|
|
17256
17485
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
@@ -17803,7 +18032,7 @@ var init_demo_data = __esm({
|
|
|
17803
18032
|
"src/tui/demo-data.ts"() {
|
|
17804
18033
|
"use strict";
|
|
17805
18034
|
DEMO_EMPLOYEES = [
|
|
17806
|
-
{ name: "
|
|
18035
|
+
{ name: "atlas", role: "COO", status: "active", activity: "Reviewing nova's task-aware behavior injection PR", memoryCount: 15e3, projects: [
|
|
17807
18036
|
{ name: "exe-os", status: "active" },
|
|
17808
18037
|
{ name: "exe-create", status: "has_tasks" },
|
|
17809
18038
|
{ name: "openclaw", status: "idle" }
|
|
@@ -17812,7 +18041,7 @@ var init_demo_data = __esm({
|
|
|
17812
18041
|
"Dispatched behavior injection task",
|
|
17813
18042
|
"Approved gateway Phase 4"
|
|
17814
18043
|
] },
|
|
17815
|
-
{ name: "
|
|
18044
|
+
{ name: "nova", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", memoryCount: 8e3, projects: [
|
|
17816
18045
|
{ name: "exe-os", status: "active" },
|
|
17817
18046
|
{ name: "exe-create", status: "idle" }
|
|
17818
18047
|
], recentTasks: [
|
|
@@ -17820,7 +18049,7 @@ var init_demo_data = __esm({
|
|
|
17820
18049
|
"Fixed TUI mouse listener leak",
|
|
17821
18050
|
"Built task-aware behavior injection"
|
|
17822
18051
|
] },
|
|
17823
|
-
{ name: "
|
|
18052
|
+
{ name: "lina", role: "CMO", status: "idle", activity: "", memoryCount: 2e3, projects: [
|
|
17824
18053
|
{ name: "exe-build-skills", status: "has_tasks" },
|
|
17825
18054
|
{ name: "exe-os", status: "idle" }
|
|
17826
18055
|
], recentTasks: [
|
|
@@ -17828,57 +18057,57 @@ var init_demo_data = __esm({
|
|
|
17828
18057
|
"Designed exe-os UI system",
|
|
17829
18058
|
"Fixed logo layouts"
|
|
17830
18059
|
] },
|
|
17831
|
-
{ name: "
|
|
18060
|
+
{ name: "devon", role: "Principal Engineer", status: "idle", activity: "", memoryCount: 700, projects: [
|
|
17832
18061
|
{ name: "exe-os", status: "idle" }
|
|
17833
18062
|
], recentTasks: [
|
|
17834
18063
|
"Implemented BashTool sandboxed execution",
|
|
17835
18064
|
"Ported session scoping to exe-agent-memory"
|
|
17836
18065
|
] },
|
|
17837
|
-
{ name: "
|
|
18066
|
+
{ name: "pixel", role: "Content Production", status: "offline", activity: "", memoryCount: 50, projects: [
|
|
17838
18067
|
{ name: "exe-build-skills", status: "idle" }
|
|
17839
18068
|
], recentTasks: [
|
|
17840
18069
|
"Rendered carousel export prototype"
|
|
17841
18070
|
] }
|
|
17842
18071
|
];
|
|
17843
18072
|
DEMO_ACTIVITY = [
|
|
17844
|
-
{ time: "11:46", agent: "
|
|
17845
|
-
{ time: "11:42", agent: "
|
|
17846
|
-
{ time: "11:38", agent: "
|
|
17847
|
-
{ time: "11:15", agent: "
|
|
17848
|
-
{ time: "10:50", agent: "
|
|
18073
|
+
{ time: "11:46", agent: "nova", action: "Committed skill learning \u2014 trajectory capture + LLM extraction" },
|
|
18074
|
+
{ time: "11:42", agent: "atlas", action: "Dispatched behavior injection task to nova" },
|
|
18075
|
+
{ time: "11:38", agent: "nova", action: "Fixed TUI mouse listener leak + arrow nav" },
|
|
18076
|
+
{ time: "11:15", agent: "lina", action: "Completed exe-os UI design system" },
|
|
18077
|
+
{ time: "10:50", agent: "atlas", action: "Approved gateway Phase 4" }
|
|
17849
18078
|
];
|
|
17850
18079
|
DEMO_HEALTH = { memories: 25750, daemon: "running", cloud: "disabled" };
|
|
17851
18080
|
DEMO_PROJECTS = [
|
|
17852
18081
|
{
|
|
17853
18082
|
projectName: "exe-os",
|
|
17854
|
-
exeSession: "
|
|
18083
|
+
exeSession: "atlas1",
|
|
17855
18084
|
employees: [
|
|
17856
|
-
{ name: "
|
|
17857
|
-
{ name: "
|
|
17858
|
-
{ name: "
|
|
17859
|
-
{ name: "
|
|
18085
|
+
{ name: "atlas", role: "COO", status: "active", activity: "Reviewing nova's task-aware behavior injection PR", sessionName: "atlas1" },
|
|
18086
|
+
{ name: "nova", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", sessionName: "nova-atlas1" },
|
|
18087
|
+
{ name: "lina", role: "CMO", status: "offline", activity: "", sessionName: "lina-atlas1" },
|
|
18088
|
+
{ name: "devon", role: "PE", status: "offline", activity: "", sessionName: "devon-atlas1" }
|
|
17860
18089
|
]
|
|
17861
18090
|
},
|
|
17862
18091
|
{
|
|
17863
18092
|
projectName: "exe-build-skills",
|
|
17864
|
-
exeSession: "
|
|
18093
|
+
exeSession: "atlas2",
|
|
17865
18094
|
employees: [
|
|
17866
|
-
{ name: "
|
|
17867
|
-
{ name: "
|
|
18095
|
+
{ name: "atlas", role: "COO", status: "active", activity: "Planning carousel pipeline automation", sessionName: "atlas2" },
|
|
18096
|
+
{ name: "lina", role: "CMO", status: "active", activity: "Creating CTO Breakdowns LinkedIn carousel", sessionName: "lina-atlas2" }
|
|
17868
18097
|
]
|
|
17869
18098
|
},
|
|
17870
18099
|
{
|
|
17871
18100
|
projectName: "CMO",
|
|
17872
|
-
exeSession: "
|
|
18101
|
+
exeSession: "atlas3",
|
|
17873
18102
|
employees: [
|
|
17874
|
-
{ name: "
|
|
17875
|
-
{ name: "
|
|
17876
|
-
{ name: "
|
|
18103
|
+
{ name: "atlas", role: "COO", status: "active", activity: "Planning carousel pipeline automation", sessionName: "atlas3" },
|
|
18104
|
+
{ name: "lina", role: "CMO", status: "active", activity: "Creating CTO Breakdowns carousel", sessionName: "lina-atlas3" },
|
|
18105
|
+
{ name: "pixel", role: "Content Production", status: "idle", activity: "", sessionName: "pixel-atlas3" }
|
|
17877
18106
|
]
|
|
17878
18107
|
}
|
|
17879
18108
|
];
|
|
17880
18109
|
DEMO_PANE_OUTPUT = {
|
|
17881
|
-
"
|
|
18110
|
+
"nova-atlas1": [
|
|
17882
18111
|
"",
|
|
17883
18112
|
"\u23FA Reading src/lib/skill-learning.ts...",
|
|
17884
18113
|
"",
|
|
@@ -17917,9 +18146,9 @@ var init_demo_data = __esm({
|
|
|
17917
18146
|
"",
|
|
17918
18147
|
"\u23FA All 16 tests pass. Committing."
|
|
17919
18148
|
],
|
|
17920
|
-
"
|
|
18149
|
+
"atlas1": [
|
|
17921
18150
|
"",
|
|
17922
|
-
"\u23FA Let me review
|
|
18151
|
+
"\u23FA Let me review nova's latest commits...",
|
|
17923
18152
|
"",
|
|
17924
18153
|
"\u23FA Bash(git log --oneline -5)",
|
|
17925
18154
|
" \u23BF 26abae6 feat: skill learning \u2014 trajectory capture",
|
|
@@ -17932,16 +18161,16 @@ var init_demo_data = __esm({
|
|
|
17932
18161
|
"",
|
|
17933
18162
|
"\u23FA Verified: build passes, zero type errors in changed files.",
|
|
17934
18163
|
"",
|
|
17935
|
-
"\u23FA Dispatching next task to
|
|
18164
|
+
"\u23FA Dispatching next task to nova: TUI demo mode.",
|
|
17936
18165
|
"",
|
|
17937
18166
|
"\u23FA mcp__exe-mem__create_task",
|
|
17938
|
-
' \u23BF Task created: "Build TUI demo mode" assigned to
|
|
18167
|
+
' \u23BF Task created: "Build TUI demo mode" assigned to nova [p0]'
|
|
17939
18168
|
],
|
|
17940
|
-
"
|
|
18169
|
+
"lina-atlas2": [
|
|
17941
18170
|
"",
|
|
17942
18171
|
"\u23FA Starting carousel creation for CTO Breakdowns series...",
|
|
17943
18172
|
"",
|
|
17944
|
-
"\u23FA Read(exe/
|
|
18173
|
+
"\u23FA Read(exe/lina/create-cto-breakdowns-linkedin-carousel.md)",
|
|
17945
18174
|
" \u23BF Task: Create a 10-slide LinkedIn carousel about the",
|
|
17946
18175
|
" CTO Breakdowns podcast launch",
|
|
17947
18176
|
"",
|
|
@@ -17955,11 +18184,11 @@ var init_demo_data = __esm({
|
|
|
17955
18184
|
"\u23FA Write(exe/output/cto-breakdowns-carousel-v1.md)",
|
|
17956
18185
|
" \u23BF 10 slides drafted with hooks, key points, CTAs"
|
|
17957
18186
|
],
|
|
17958
|
-
"
|
|
18187
|
+
"atlas2": [
|
|
17959
18188
|
"",
|
|
17960
18189
|
"\u23FA Planning the carousel pipeline automation...",
|
|
17961
18190
|
"",
|
|
17962
|
-
"\u23FA Current workflow:
|
|
18191
|
+
"\u23FA Current workflow: lina writes content \u2192 pixel produces visuals",
|
|
17963
18192
|
" \u2192 manual export. Need to automate the export step.",
|
|
17964
18193
|
"",
|
|
17965
18194
|
"\u23FA mcp__exe-mem__recall_my_memory",
|
|
@@ -17968,18 +18197,18 @@ var init_demo_data = __esm({
|
|
|
17968
18197
|
"",
|
|
17969
18198
|
"\u23FA Good \u2014 the pipeline exists. Just need to wire it."
|
|
17970
18199
|
],
|
|
17971
|
-
"
|
|
18200
|
+
"lina-atlas3": [
|
|
17972
18201
|
"",
|
|
17973
18202
|
"\u23FA Reading carousel task brief...",
|
|
17974
18203
|
"",
|
|
17975
|
-
"\u23FA Read(exe/
|
|
18204
|
+
"\u23FA Read(exe/lina/create-cto-breakdowns-carousel.md)",
|
|
17976
18205
|
" \u23BF 10-slide carousel for CTO Breakdowns podcast launch",
|
|
17977
18206
|
"",
|
|
17978
18207
|
"\u23FA Applying Exe Foundry Bold: Epilogue headlines, #F5D76E gold CTAs",
|
|
17979
18208
|
"",
|
|
17980
18209
|
"\u23FA Writing slide hooks and copy..."
|
|
17981
18210
|
],
|
|
17982
|
-
"
|
|
18211
|
+
"atlas3": [
|
|
17983
18212
|
"",
|
|
17984
18213
|
"\u23FA Welcome to the exe-os demo!",
|
|
17985
18214
|
"",
|
|
@@ -17998,13 +18227,13 @@ var init_demo_data = __esm({
|
|
|
17998
18227
|
]
|
|
17999
18228
|
};
|
|
18000
18229
|
DEMO_TASKS = [
|
|
18001
|
-
{ priority: "P0", title: "Build TUI demo mode with mock sessions", assignee: "
|
|
18002
|
-
{ priority: "P0", title: "Wire exe-os hooks into runtime HookPipeline", assignee: "
|
|
18003
|
-
{ priority: "P1", title: "Create CTO Breakdowns LinkedIn carousel", assignee: "
|
|
18004
|
-
{ priority: "P1", title: "Implement session scoping enforcement", assignee: "
|
|
18005
|
-
{ priority: "P1", title: "Automate carousel export pipeline", assignee: "
|
|
18006
|
-
{ priority: "P2", title: "Add Chutes provider to gateway failover", assignee: "
|
|
18007
|
-
{ priority: "P2", title: "Port skill learning to exe-ai-employees", assignee: "
|
|
18230
|
+
{ priority: "P0", title: "Build TUI demo mode with mock sessions", assignee: "nova", status: "in_progress", project: "exe-os" },
|
|
18231
|
+
{ priority: "P0", title: "Wire exe-os hooks into runtime HookPipeline", assignee: "nova", status: "done", project: "exe-os" },
|
|
18232
|
+
{ priority: "P1", title: "Create CTO Breakdowns LinkedIn carousel", assignee: "lina", status: "in_progress", project: "exe-build-skills" },
|
|
18233
|
+
{ priority: "P1", title: "Implement session scoping enforcement", assignee: "nova", status: "done", project: "exe-os" },
|
|
18234
|
+
{ priority: "P1", title: "Automate carousel export pipeline", assignee: "pixel", status: "open", project: "exe-build-skills" },
|
|
18235
|
+
{ priority: "P2", title: "Add Chutes provider to gateway failover", assignee: "devon", status: "open", project: "exe-os" },
|
|
18236
|
+
{ priority: "P2", title: "Port skill learning to exe-ai-employees", assignee: "nova", status: "open", project: "exe-os" }
|
|
18008
18237
|
];
|
|
18009
18238
|
DEMO_EXTERNAL_AGENTS = [
|
|
18010
18239
|
{ name: "exec-assistant", role: "executive assistant", status: "active" },
|
|
@@ -20533,6 +20762,14 @@ function CommandCenterView({
|
|
|
20533
20762
|
setPermPrompt(req);
|
|
20534
20763
|
});
|
|
20535
20764
|
};
|
|
20765
|
+
let agentId = "default";
|
|
20766
|
+
if (agentRole === "CTO") {
|
|
20767
|
+
try {
|
|
20768
|
+
const { getEmployeeByRole: getEmployeeByRole2, loadEmployeesSync: loadEmployeesSync2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
20769
|
+
agentId = getEmployeeByRole2(loadEmployeesSync2(), "CTO")?.name ?? "default";
|
|
20770
|
+
} catch {
|
|
20771
|
+
}
|
|
20772
|
+
}
|
|
20536
20773
|
setAgentConfig({
|
|
20537
20774
|
provider,
|
|
20538
20775
|
model,
|
|
@@ -20543,7 +20780,7 @@ function CommandCenterView({
|
|
|
20543
20780
|
permissionHandler,
|
|
20544
20781
|
maxTurns: 20,
|
|
20545
20782
|
cwd: process.cwd(),
|
|
20546
|
-
agentId
|
|
20783
|
+
agentId
|
|
20547
20784
|
});
|
|
20548
20785
|
setChatInitError(null);
|
|
20549
20786
|
} catch (e) {
|
|
@@ -20736,10 +20973,12 @@ function CommandCenterView({
|
|
|
20736
20973
|
const registry = listSessions2();
|
|
20737
20974
|
const tmuxSessions = inTmux2() ? new Set(listTmuxSessions2()) : /* @__PURE__ */ new Set();
|
|
20738
20975
|
const roster = await loadEmployees2();
|
|
20739
|
-
const
|
|
20976
|
+
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
20977
|
+
const coordinatorName = getCoordinatorName2(roster);
|
|
20978
|
+
const employeeNames = roster.filter((e) => !isCoordinatorRole2(e.role)).map((e) => e.name);
|
|
20740
20979
|
const projectSessions = /* @__PURE__ */ new Map();
|
|
20741
20980
|
for (const entry of registry) {
|
|
20742
|
-
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
20981
|
+
if ((entry.agentId === coordinatorName || entry.agentId === "exe") && tmuxSessions.has(entry.windowName)) {
|
|
20743
20982
|
const projName = entry.projectDir.split("/").filter(Boolean).pop() ?? "";
|
|
20744
20983
|
if (projName) {
|
|
20745
20984
|
projectSessions.set(projName, { exeSession: entry.windowName, projectDir: entry.projectDir });
|
|
@@ -21115,7 +21354,7 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
21115
21354
|
/* @__PURE__ */ jsx8(Text, { color: "#3D3660", children: "\u2500".repeat(process.stdout.columns ? process.stdout.columns - 30 : 120) }),
|
|
21116
21355
|
/* @__PURE__ */ jsxs6(Box_default, { paddingX: 1, children: [
|
|
21117
21356
|
/* @__PURE__ */ jsx8(Text, { color: "#6B4C9A", children: "\u276F " }),
|
|
21118
|
-
/* @__PURE__ */ jsx8(Text, { children: inputBuffer || (demo ? "Type a message to
|
|
21357
|
+
/* @__PURE__ */ jsx8(Text, { children: inputBuffer || (demo ? "Type a message to the coordinator..." : "Type to send commands...") })
|
|
21119
21358
|
] })
|
|
21120
21359
|
] });
|
|
21121
21360
|
}
|
|
@@ -21156,7 +21395,7 @@ async function scoreEmployee(taskVector, agentId, searchFn) {
|
|
|
21156
21395
|
return { agentId, score: results.length / 5 };
|
|
21157
21396
|
}
|
|
21158
21397
|
async function routeTask(taskDescription, employees, embedFn, searchFn, options) {
|
|
21159
|
-
let specialists = employees.filter((e) => e.
|
|
21398
|
+
let specialists = employees.filter((e) => !isCoordinatorRole(e.role));
|
|
21160
21399
|
if (specialists.length === 0) {
|
|
21161
21400
|
throw new Error(
|
|
21162
21401
|
"No specialist employees available. Create one with /exe-new-employee."
|
|
@@ -21192,6 +21431,7 @@ var DEFAULT_BLOOM_CONFIG;
|
|
|
21192
21431
|
var init_task_router = __esm({
|
|
21193
21432
|
"src/lib/task-router.ts"() {
|
|
21194
21433
|
"use strict";
|
|
21434
|
+
init_employees();
|
|
21195
21435
|
DEFAULT_BLOOM_CONFIG = {
|
|
21196
21436
|
complexityToTier: {
|
|
21197
21437
|
routine: "junior",
|
|
@@ -21237,6 +21477,7 @@ var STALE_THRESHOLD_MS, MultiAgentOrchestrator;
|
|
|
21237
21477
|
var init_orchestrator = __esm({
|
|
21238
21478
|
"src/runtime/orchestrator.ts"() {
|
|
21239
21479
|
"use strict";
|
|
21480
|
+
init_employees();
|
|
21240
21481
|
init_task_router();
|
|
21241
21482
|
init_tmux_routing();
|
|
21242
21483
|
init_task_scope();
|
|
@@ -21281,7 +21522,7 @@ ${task.context}`,
|
|
|
21281
21522
|
await createTaskCore({
|
|
21282
21523
|
title: task.title,
|
|
21283
21524
|
assignedTo: targetEmployee.name,
|
|
21284
|
-
assignedBy:
|
|
21525
|
+
assignedBy: getCoordinatorName(),
|
|
21285
21526
|
projectName: task.projectName,
|
|
21286
21527
|
priority: task.priority,
|
|
21287
21528
|
context: task.context,
|
|
@@ -21386,15 +21627,16 @@ ${task.context}`,
|
|
|
21386
21627
|
const client = getClient2();
|
|
21387
21628
|
const autoApproved = [];
|
|
21388
21629
|
const needsReview = [];
|
|
21630
|
+
const coordinatorName = getCoordinatorName();
|
|
21389
21631
|
const rScope = sessionScopeFilter();
|
|
21390
21632
|
const reviews = await client.execute({
|
|
21391
21633
|
sql: `SELECT id, title, assigned_to, priority, result, task_file FROM tasks
|
|
21392
|
-
WHERE assigned_to = 'exe'
|
|
21634
|
+
WHERE (assigned_to = ? OR assigned_to = 'exe')
|
|
21393
21635
|
AND status IN ('open', 'in_progress')
|
|
21394
21636
|
AND task_file LIKE '%review-%'${rScope.sql}
|
|
21395
21637
|
ORDER BY priority ASC
|
|
21396
21638
|
LIMIT 20`,
|
|
21397
|
-
args: [...rScope.args]
|
|
21639
|
+
args: [coordinatorName, ...rScope.args]
|
|
21398
21640
|
});
|
|
21399
21641
|
for (const row of reviews.rows) {
|
|
21400
21642
|
const item = {
|
|
@@ -21509,22 +21751,26 @@ function useOrchestrator(enabled = true) {
|
|
|
21509
21751
|
const [isLoading, setIsLoading] = useState8(true);
|
|
21510
21752
|
const orchestratorRef = useRef5(null);
|
|
21511
21753
|
const exeSessionRef = useRef5("exe1");
|
|
21754
|
+
const coordinatorNameRef = useRef5("exe");
|
|
21512
21755
|
useEffect10(() => {
|
|
21513
21756
|
if (!enabled) return;
|
|
21514
21757
|
let cancelled = false;
|
|
21515
21758
|
async function init() {
|
|
21516
21759
|
try {
|
|
21517
21760
|
const { MultiAgentOrchestrator: MultiAgentOrchestrator2 } = await Promise.resolve().then(() => (init_orchestrator(), orchestrator_exports));
|
|
21518
|
-
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
21761
|
+
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
21762
|
+
const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
21519
21763
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
21520
21764
|
if (!inTmux2()) {
|
|
21521
21765
|
setIsLoading(false);
|
|
21522
21766
|
return;
|
|
21523
21767
|
}
|
|
21524
21768
|
const roster = await loadEmployees2();
|
|
21525
|
-
const
|
|
21769
|
+
const coordinatorName = getCoordinatorName2(roster);
|
|
21770
|
+
coordinatorNameRef.current = coordinatorName;
|
|
21771
|
+
const nonExe = roster.filter((e) => !isCoordinatorRole2(e.role));
|
|
21526
21772
|
const tmuxSessions = listTmuxSessions2();
|
|
21527
|
-
const exeSession = tmuxSessions.find((s) =>
|
|
21773
|
+
const exeSession = tmuxSessions.find((s) => isExeSession2(s)) ?? `${coordinatorName}1`;
|
|
21528
21774
|
exeSessionRef.current = exeSession;
|
|
21529
21775
|
orchestratorRef.current = new MultiAgentOrchestrator2({
|
|
21530
21776
|
employees: nonExe,
|
|
@@ -21557,8 +21803,8 @@ function useOrchestrator(enabled = true) {
|
|
|
21557
21803
|
const uoScope = sessionScopeFilter2();
|
|
21558
21804
|
const result = await client.execute({
|
|
21559
21805
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
21560
|
-
WHERE assigned_to = 'exe' AND status IN ('open', 'in_progress')${uoScope.sql}`,
|
|
21561
|
-
args: [...uoScope.args]
|
|
21806
|
+
WHERE (assigned_to = ? OR assigned_to = 'exe') AND status IN ('open', 'in_progress')${uoScope.sql}`,
|
|
21807
|
+
args: [coordinatorNameRef.current, ...uoScope.args]
|
|
21562
21808
|
});
|
|
21563
21809
|
if (!cancelled) setPendingReviews(Number(result.rows[0]?.cnt ?? 0));
|
|
21564
21810
|
} catch {
|
|
@@ -21586,10 +21832,11 @@ function useOrchestrator(enabled = true) {
|
|
|
21586
21832
|
try {
|
|
21587
21833
|
const { createTaskCore: createTaskCore2 } = await Promise.resolve().then(() => (init_tasks_crud(), tasks_crud_exports));
|
|
21588
21834
|
const { ensureEmployee: ensureEmployee2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
21835
|
+
const { getCoordinatorName: getCoordinatorName2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
21589
21836
|
await createTaskCore2({
|
|
21590
21837
|
title: `Session launched for ${agentId} (TUI)`,
|
|
21591
21838
|
assignedTo: agentId,
|
|
21592
|
-
assignedBy:
|
|
21839
|
+
assignedBy: getCoordinatorName2(),
|
|
21593
21840
|
projectName: "exe-os",
|
|
21594
21841
|
priority: "p2",
|
|
21595
21842
|
context: "Session spawned from TUI Sessions view. Agent will pick up any queued tasks via intercom.",
|
|
@@ -21649,6 +21896,9 @@ import React19, { useState as useState9, useEffect as useEffect11, useCallback a
|
|
|
21649
21896
|
import path34 from "path";
|
|
21650
21897
|
import { homedir as homedir6 } from "os";
|
|
21651
21898
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
21899
|
+
function isCoordinatorEntry(entry) {
|
|
21900
|
+
return entry.role.toLowerCase() === "coo" || entry.name === "exe";
|
|
21901
|
+
}
|
|
21652
21902
|
function SessionsView({
|
|
21653
21903
|
initialProject,
|
|
21654
21904
|
onConsumeInitialProject,
|
|
@@ -21694,13 +21944,13 @@ function SessionsView({
|
|
|
21694
21944
|
const proj = projects.find((p) => p.projectName === projectName);
|
|
21695
21945
|
if (!proj) return;
|
|
21696
21946
|
const active = proj.employees.filter(
|
|
21697
|
-
(e) => e.status === "active" || demo && e
|
|
21947
|
+
(e) => e.status === "active" || demo && isCoordinatorEntry(e)
|
|
21698
21948
|
);
|
|
21699
21949
|
const carousel = demo ? proj.employees.filter((e) => e.status !== "offline") : active;
|
|
21700
21950
|
if (carousel.length === 0) return;
|
|
21701
21951
|
const sorted = [
|
|
21702
|
-
...carousel.filter((e) => e
|
|
21703
|
-
...carousel.filter((e) => e
|
|
21952
|
+
...carousel.filter((e) => isCoordinatorEntry(e)),
|
|
21953
|
+
...carousel.filter((e) => !isCoordinatorEntry(e))
|
|
21704
21954
|
];
|
|
21705
21955
|
setCarouselEmployees(sorted);
|
|
21706
21956
|
setCarouselIdx(0);
|
|
@@ -21726,7 +21976,7 @@ function SessionsView({
|
|
|
21726
21976
|
}
|
|
21727
21977
|
async function launchSession(entry, projectName, projectDir) {
|
|
21728
21978
|
try {
|
|
21729
|
-
if (entry
|
|
21979
|
+
if (!isCoordinatorEntry(entry) && !demo) {
|
|
21730
21980
|
const result = await orch.spawnSession(entry.name);
|
|
21731
21981
|
if (!result || result.status === "failed") {
|
|
21732
21982
|
process.stderr.write(
|
|
@@ -21842,7 +22092,8 @@ function SessionsView({
|
|
|
21842
22092
|
try {
|
|
21843
22093
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
21844
22094
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
21845
|
-
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
22095
|
+
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
22096
|
+
const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
21846
22097
|
const { execSync: execSync14 } = await import("child_process");
|
|
21847
22098
|
if (!inTmux2()) {
|
|
21848
22099
|
setTmuxAvailable(false);
|
|
@@ -21867,14 +22118,15 @@ function SessionsView({
|
|
|
21867
22118
|
const registry = listSessions2();
|
|
21868
22119
|
const tmuxSessions = new Set(listTmuxSessions2());
|
|
21869
22120
|
const roster = await loadEmployees2();
|
|
22121
|
+
const coordinatorName = getCoordinatorName2(roster);
|
|
21870
22122
|
const exeSessions = /* @__PURE__ */ new Map();
|
|
21871
22123
|
for (const entry of registry) {
|
|
21872
|
-
if (entry.agentId === "exe" && tmuxSessions.has(entry.windowName)) {
|
|
22124
|
+
if ((entry.agentId === coordinatorName || entry.agentId === "exe") && tmuxSessions.has(entry.windowName)) {
|
|
21873
22125
|
exeSessions.set(entry.windowName, entry.projectDir);
|
|
21874
22126
|
}
|
|
21875
22127
|
}
|
|
21876
22128
|
for (const s of tmuxSessions) {
|
|
21877
|
-
if (
|
|
22129
|
+
if (isExeSession2(s) && !exeSessions.has(s)) {
|
|
21878
22130
|
exeSessions.set(s, "");
|
|
21879
22131
|
}
|
|
21880
22132
|
}
|
|
@@ -21889,7 +22141,7 @@ function SessionsView({
|
|
|
21889
22141
|
exeStatus = statusFromPaneLines(exeLines);
|
|
21890
22142
|
exeActivity = exeLines.length > 0 ? parseActivity2(exeLines) : "";
|
|
21891
22143
|
}
|
|
21892
|
-
const employeeEntries = roster.filter((e) => e.
|
|
22144
|
+
const employeeEntries = roster.filter((e) => !isCoordinatorRole2(e.role)).map((emp) => {
|
|
21893
22145
|
const sessionName = `${emp.name}-${exeSession}`;
|
|
21894
22146
|
const hasSession = tmuxSessions.has(sessionName);
|
|
21895
22147
|
const isCrashed = !hasSession && orch.crashedSessions.includes(emp.name);
|
|
@@ -21925,7 +22177,7 @@ function SessionsView({
|
|
|
21925
22177
|
});
|
|
21926
22178
|
const employees = [
|
|
21927
22179
|
{
|
|
21928
|
-
name:
|
|
22180
|
+
name: coordinatorName,
|
|
21929
22181
|
role: "COO",
|
|
21930
22182
|
status: exeStatus,
|
|
21931
22183
|
sessionName: exeSession,
|
|
@@ -22164,7 +22416,7 @@ function TasksView({ onBack }) {
|
|
|
22164
22416
|
setAllTasks(DEMO_TASKS.map((t, i) => ({
|
|
22165
22417
|
id: `demo-${i}`,
|
|
22166
22418
|
...t,
|
|
22167
|
-
assignedBy: "
|
|
22419
|
+
assignedBy: "coordinator",
|
|
22168
22420
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22169
22421
|
result: t.status === "done" ? "Completed successfully" : ""
|
|
22170
22422
|
})));
|
|
@@ -23482,7 +23734,7 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
23482
23734
|
showAddHint && /* @__PURE__ */ jsx12(Text, { color: "#F5D76E", children: "Run /exe-new-employee <name> from CLI to add an employee." }),
|
|
23483
23735
|
!demo && orch.pendingReviews > 0 && /* @__PURE__ */ jsxs10(Text, { color: "#6B4C9A", children: [
|
|
23484
23736
|
orch.pendingReviews,
|
|
23485
|
-
" review(s) pending
|
|
23737
|
+
" review(s) pending coordinator attention"
|
|
23486
23738
|
] }),
|
|
23487
23739
|
/* @__PURE__ */ jsx12(Text, { children: " " }),
|
|
23488
23740
|
/* @__PURE__ */ jsx12(Text, { bold: true, children: "INTERNAL" }),
|
|
@@ -23735,11 +23987,11 @@ import TextInput2 from "ink-text-input";
|
|
|
23735
23987
|
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
23736
23988
|
function agentColor(agentId) {
|
|
23737
23989
|
switch (agentId.toLowerCase()) {
|
|
23738
|
-
case "
|
|
23990
|
+
case "atlas":
|
|
23739
23991
|
return "#F5D76E";
|
|
23740
|
-
case "
|
|
23992
|
+
case "nova":
|
|
23741
23993
|
return "#3B82F6";
|
|
23742
|
-
case "
|
|
23994
|
+
case "lina":
|
|
23743
23995
|
return "#6B4C9A";
|
|
23744
23996
|
default:
|
|
23745
23997
|
return "#F0EDE8";
|
|
@@ -24190,11 +24442,11 @@ var init_Wiki = __esm({
|
|
|
24190
24442
|
PANELS = ["Workspaces", "Documents", "Chat"];
|
|
24191
24443
|
MAX_VISIBLE_MESSAGES = 12;
|
|
24192
24444
|
DEMO_SEARCH_RESULTS = [
|
|
24193
|
-
{ id: "1", agentId: "
|
|
24194
|
-
{ id: "2", agentId: "
|
|
24195
|
-
{ id: "3", agentId: "
|
|
24196
|
-
{ id: "4", agentId: "
|
|
24197
|
-
{ id: "5", agentId: "
|
|
24445
|
+
{ id: "1", agentId: "nova", rawText: "Reviewed PR #42 \u2014 approved with minor comment on error handling pattern", timestamp: new Date(Date.now() - 2 * 36e5).toISOString(), projectName: "exe-os" },
|
|
24446
|
+
{ id: "2", agentId: "devon", rawText: "Implemented session routing with deterministic naming: employee-coordinator convention", timestamp: new Date(Date.now() - 5 * 36e5).toISOString(), projectName: "exe-os" },
|
|
24447
|
+
{ id: "3", agentId: "atlas", rawText: "Status brief: 3 tasks completed, 1 blocked on wiki integration", timestamp: new Date(Date.now() - 8 * 36e5).toISOString(), projectName: "exe-os" },
|
|
24448
|
+
{ id: "4", agentId: "lina", rawText: "Created brand guidelines document \u2014 Exe Foundry Bold design system", timestamp: new Date(Date.now() - 24 * 36e5).toISOString(), projectName: "exe-os" },
|
|
24449
|
+
{ id: "5", agentId: "devon", rawText: "Fixed CommandCenter project filtering \u2014 DB-first, no random directories", timestamp: new Date(Date.now() - 48 * 36e5).toISOString(), projectName: "exe-os" }
|
|
24198
24450
|
];
|
|
24199
24451
|
}
|
|
24200
24452
|
});
|
|
@@ -24719,7 +24971,7 @@ function App2() {
|
|
|
24719
24971
|
/* @__PURE__ */ jsx17(Footer, {})
|
|
24720
24972
|
] }) }) }) });
|
|
24721
24973
|
}
|
|
24722
|
-
var TAB_SHORTCUTS, isDemo;
|
|
24974
|
+
var TAB_SHORTCUTS, isDemo, instance;
|
|
24723
24975
|
var init_App2 = __esm({
|
|
24724
24976
|
async "src/tui/App.tsx"() {
|
|
24725
24977
|
"use strict";
|
|
@@ -24844,7 +25096,9 @@ var init_App2 = __esm({
|
|
|
24844
25096
|
stdin.unref = () => stdin;
|
|
24845
25097
|
}
|
|
24846
25098
|
}
|
|
24847
|
-
render_default(/* @__PURE__ */ jsx17(App2, {}));
|
|
25099
|
+
instance = render_default(/* @__PURE__ */ jsx17(App2, {}));
|
|
25100
|
+
instance.waitUntilExit().catch(() => {
|
|
25101
|
+
});
|
|
24848
25102
|
{
|
|
24849
25103
|
const CLEANUP_SEQ = "\x1B[?1006l\x1B[?1002l\x1B[?1000l\x1B[?25h\x1B[?1049l";
|
|
24850
25104
|
const terminalCleanup = () => {
|