@askexenow/exe-os 0.9.38 → 0.9.39
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 +34 -7
- package/dist/bin/backfill-responses.js +34 -7
- package/dist/bin/backfill-vectors.js +34 -7
- package/dist/bin/cleanup-stale-review-tasks.js +35 -8
- package/dist/bin/cli.js +72 -42
- package/dist/bin/exe-agent.js +11 -3
- package/dist/bin/exe-assign.js +34 -7
- package/dist/bin/exe-boot.js +48 -18
- package/dist/bin/exe-call.js +132 -340
- package/dist/bin/exe-dispatch.js +34 -7
- package/dist/bin/exe-doctor.js +37 -10
- package/dist/bin/exe-export-behaviors.js +36 -9
- package/dist/bin/exe-forget.js +34 -7
- package/dist/bin/exe-gateway.js +40 -12
- package/dist/bin/exe-heartbeat.js +35 -8
- package/dist/bin/exe-kill.js +34 -7
- package/dist/bin/exe-launch-agent.js +285 -1079
- package/dist/bin/exe-new-employee.js +29 -10
- package/dist/bin/exe-pending-messages.js +34 -7
- package/dist/bin/exe-pending-notifications.js +34 -7
- package/dist/bin/exe-pending-reviews.js +34 -7
- package/dist/bin/exe-rename.js +41 -13
- package/dist/bin/exe-review.js +34 -7
- package/dist/bin/exe-search.js +36 -9
- package/dist/bin/exe-session-cleanup.js +36 -9
- package/dist/bin/exe-start-codex.js +36 -9
- package/dist/bin/exe-start-opencode.js +36 -9
- package/dist/bin/exe-status.js +35 -8
- package/dist/bin/exe-team.js +34 -7
- package/dist/bin/git-sweep.js +34 -7
- package/dist/bin/graph-backfill.js +34 -7
- package/dist/bin/graph-export.js +34 -7
- package/dist/bin/install.js +2 -1
- package/dist/bin/intercom-check.js +36 -9
- package/dist/bin/scan-tasks.js +34 -7
- package/dist/bin/setup.js +18 -17
- package/dist/bin/shard-migrate.js +34 -7
- package/dist/gateway/index.js +38 -10
- package/dist/hooks/bug-report-worker.js +38 -10
- package/dist/hooks/codex-stop-task-finalizer.js +36 -9
- package/dist/hooks/commit-complete.js +34 -7
- package/dist/hooks/error-recall.js +36 -9
- package/dist/hooks/ingest.js +36 -8
- package/dist/hooks/instructions-loaded.js +42 -10
- package/dist/hooks/notification.js +34 -7
- package/dist/hooks/post-compact.js +34 -7
- package/dist/hooks/post-tool-combined.js +37 -10
- package/dist/hooks/pre-compact.js +35 -8
- package/dist/hooks/pre-tool-use.js +36 -8
- package/dist/hooks/prompt-submit.js +41 -13
- package/dist/hooks/session-end.js +35 -8
- package/dist/hooks/session-start.js +47 -14
- package/dist/hooks/stop.js +35 -8
- package/dist/hooks/subagent-stop.js +34 -7
- package/dist/hooks/summary-worker.js +43 -16
- package/dist/index.js +36 -8
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/employee-templates.js +2 -1
- package/dist/lib/employees.js +2 -1
- package/dist/lib/exe-daemon.js +136 -36
- package/dist/lib/hybrid-search.js +36 -9
- package/dist/lib/identity.js +8 -3
- package/dist/lib/schedules.js +34 -7
- package/dist/lib/store.js +34 -7
- package/dist/mcp/server.js +133 -33
- package/dist/mcp/tools/create-task.js +10 -4
- package/dist/runtime/index.js +34 -7
- package/dist/tui/App.js +40 -11
- package/package.json +1 -1
package/dist/bin/exe-call.js
CHANGED
|
@@ -126,153 +126,11 @@ var init_config = __esm({
|
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
-
// src/lib/runtime-table.ts
|
|
130
|
-
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
131
|
-
var init_runtime_table = __esm({
|
|
132
|
-
"src/lib/runtime-table.ts"() {
|
|
133
|
-
"use strict";
|
|
134
|
-
RUNTIME_TABLE = {
|
|
135
|
-
codex: {
|
|
136
|
-
binary: "codex",
|
|
137
|
-
launchMode: "interactive",
|
|
138
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
139
|
-
inlineFlag: "--no-alt-screen",
|
|
140
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
141
|
-
defaultModel: "gpt-5.5"
|
|
142
|
-
},
|
|
143
|
-
opencode: {
|
|
144
|
-
binary: "opencode",
|
|
145
|
-
launchMode: "exec",
|
|
146
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
147
|
-
inlineFlag: "",
|
|
148
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
149
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
DEFAULT_RUNTIME = "claude";
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// src/lib/agent-config.ts
|
|
157
|
-
var agent_config_exports = {};
|
|
158
|
-
__export(agent_config_exports, {
|
|
159
|
-
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
160
|
-
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
161
|
-
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
162
|
-
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
163
|
-
clearAgentRuntime: () => clearAgentRuntime,
|
|
164
|
-
getAgentRuntime: () => getAgentRuntime,
|
|
165
|
-
loadAgentConfig: () => loadAgentConfig,
|
|
166
|
-
saveAgentConfig: () => saveAgentConfig,
|
|
167
|
-
setAgentRuntime: () => setAgentRuntime
|
|
168
|
-
});
|
|
169
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
170
|
-
import path2 from "path";
|
|
171
|
-
function loadAgentConfig() {
|
|
172
|
-
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
173
|
-
try {
|
|
174
|
-
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
175
|
-
} catch {
|
|
176
|
-
return {};
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function saveAgentConfig(config) {
|
|
180
|
-
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
181
|
-
ensurePrivateDirSync(dir);
|
|
182
|
-
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
183
|
-
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
184
|
-
}
|
|
185
|
-
function getAgentRuntime(agentId) {
|
|
186
|
-
const config = loadAgentConfig();
|
|
187
|
-
const entry = config[agentId];
|
|
188
|
-
if (entry) return entry;
|
|
189
|
-
const orgDefault = config["default"];
|
|
190
|
-
if (orgDefault) return orgDefault;
|
|
191
|
-
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
192
|
-
}
|
|
193
|
-
function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
194
|
-
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
195
|
-
if (!knownModels) {
|
|
196
|
-
return {
|
|
197
|
-
ok: false,
|
|
198
|
-
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
if (!knownModels.includes(model)) {
|
|
202
|
-
return {
|
|
203
|
-
ok: false,
|
|
204
|
-
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
const config = loadAgentConfig();
|
|
208
|
-
const entry = { runtime, model };
|
|
209
|
-
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
210
|
-
config[agentId] = entry;
|
|
211
|
-
saveAgentConfig(config);
|
|
212
|
-
return { ok: true };
|
|
213
|
-
}
|
|
214
|
-
function clearAgentRuntime(agentId) {
|
|
215
|
-
const config = loadAgentConfig();
|
|
216
|
-
delete config[agentId];
|
|
217
|
-
saveAgentConfig(config);
|
|
218
|
-
}
|
|
219
|
-
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
220
|
-
var init_agent_config = __esm({
|
|
221
|
-
"src/lib/agent-config.ts"() {
|
|
222
|
-
"use strict";
|
|
223
|
-
init_config();
|
|
224
|
-
init_runtime_table();
|
|
225
|
-
init_secure_files();
|
|
226
|
-
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
227
|
-
KNOWN_RUNTIMES = {
|
|
228
|
-
claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
229
|
-
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
230
|
-
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
231
|
-
};
|
|
232
|
-
RUNTIME_LABELS = {
|
|
233
|
-
claude: "Claude Code (Anthropic)",
|
|
234
|
-
codex: "Codex (OpenAI)",
|
|
235
|
-
opencode: "OpenCode (open source)"
|
|
236
|
-
};
|
|
237
|
-
DEFAULT_MODELS = {
|
|
238
|
-
claude: "claude-opus-4.6",
|
|
239
|
-
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
240
|
-
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
|
|
245
129
|
// src/lib/employees.ts
|
|
246
|
-
var employees_exports = {};
|
|
247
|
-
__export(employees_exports, {
|
|
248
|
-
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
249
|
-
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
250
|
-
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
251
|
-
addEmployee: () => addEmployee,
|
|
252
|
-
baseAgentName: () => baseAgentName,
|
|
253
|
-
canCoordinate: () => canCoordinate,
|
|
254
|
-
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
255
|
-
getCoordinatorName: () => getCoordinatorName,
|
|
256
|
-
getEmployee: () => getEmployee,
|
|
257
|
-
getEmployeeByRole: () => getEmployeeByRole,
|
|
258
|
-
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
259
|
-
hasRole: () => hasRole,
|
|
260
|
-
hireEmployee: () => hireEmployee,
|
|
261
|
-
isCoordinatorName: () => isCoordinatorName,
|
|
262
|
-
isCoordinatorRole: () => isCoordinatorRole,
|
|
263
|
-
isMultiInstance: () => isMultiInstance,
|
|
264
|
-
loadEmployees: () => loadEmployees,
|
|
265
|
-
loadEmployeesSync: () => loadEmployeesSync,
|
|
266
|
-
normalizeRole: () => normalizeRole,
|
|
267
|
-
normalizeRosterCase: () => normalizeRosterCase,
|
|
268
|
-
registerBinSymlinks: () => registerBinSymlinks,
|
|
269
|
-
saveEmployees: () => saveEmployees,
|
|
270
|
-
validateEmployeeName: () => validateEmployeeName
|
|
271
|
-
});
|
|
272
130
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
273
|
-
import { existsSync as
|
|
131
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
274
132
|
import { execSync } from "child_process";
|
|
275
|
-
import
|
|
133
|
+
import path2 from "path";
|
|
276
134
|
import os2 from "os";
|
|
277
135
|
function normalizeRole(role) {
|
|
278
136
|
return (role ?? "").trim().toLowerCase();
|
|
@@ -286,30 +144,8 @@ function getCoordinatorEmployee(employees) {
|
|
|
286
144
|
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
287
145
|
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
288
146
|
}
|
|
289
|
-
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
290
|
-
if (!agentName) return false;
|
|
291
|
-
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
292
|
-
}
|
|
293
|
-
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
294
|
-
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
295
|
-
}
|
|
296
|
-
function validateEmployeeName(name) {
|
|
297
|
-
if (!name) {
|
|
298
|
-
return { valid: false, error: "Name is required" };
|
|
299
|
-
}
|
|
300
|
-
if (name.length > 32) {
|
|
301
|
-
return { valid: false, error: "Name must be 32 characters or fewer" };
|
|
302
|
-
}
|
|
303
|
-
if (!/^[a-z][a-z0-9]*$/.test(name)) {
|
|
304
|
-
return {
|
|
305
|
-
valid: false,
|
|
306
|
-
error: "Name must start with a letter and contain only lowercase alphanumeric characters"
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
return { valid: true };
|
|
310
|
-
}
|
|
311
147
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
312
|
-
if (!
|
|
148
|
+
if (!existsSync3(employeesPath)) {
|
|
313
149
|
return [];
|
|
314
150
|
}
|
|
315
151
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -319,14 +155,10 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
319
155
|
return [];
|
|
320
156
|
}
|
|
321
157
|
}
|
|
322
|
-
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
323
|
-
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
324
|
-
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
325
|
-
}
|
|
326
158
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
327
|
-
if (!
|
|
159
|
+
if (!existsSync3(employeesPath)) return [];
|
|
328
160
|
try {
|
|
329
|
-
return JSON.parse(
|
|
161
|
+
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
330
162
|
} catch {
|
|
331
163
|
return [];
|
|
332
164
|
}
|
|
@@ -334,167 +166,15 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
334
166
|
function getEmployee(employees, name) {
|
|
335
167
|
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
336
168
|
}
|
|
337
|
-
|
|
338
|
-
const lower = role.toLowerCase();
|
|
339
|
-
return employees.find((e) => e.role.toLowerCase() === lower);
|
|
340
|
-
}
|
|
341
|
-
function getEmployeeNamesByRole(employees, role) {
|
|
342
|
-
const lower = role.toLowerCase();
|
|
343
|
-
return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
|
|
344
|
-
}
|
|
345
|
-
function hasRole(agentName, role) {
|
|
346
|
-
const employees = loadEmployeesSync();
|
|
347
|
-
const emp = getEmployee(employees, agentName);
|
|
348
|
-
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
349
|
-
}
|
|
350
|
-
function baseAgentName(name, employees) {
|
|
351
|
-
const match = name.match(/^([a-zA-Z]+)\d+$/);
|
|
352
|
-
if (!match) return name;
|
|
353
|
-
const base = match[1];
|
|
354
|
-
const roster = employees ?? loadEmployeesSync();
|
|
355
|
-
if (getEmployee(roster, base)) return base;
|
|
356
|
-
return name;
|
|
357
|
-
}
|
|
358
|
-
function isMultiInstance(agentName, employees) {
|
|
359
|
-
const roster = employees ?? loadEmployeesSync();
|
|
360
|
-
const emp = getEmployee(roster, agentName);
|
|
361
|
-
if (!emp) return false;
|
|
362
|
-
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
363
|
-
}
|
|
364
|
-
function addEmployee(employees, employee) {
|
|
365
|
-
const normalized = { ...employee, name: employee.name.toLowerCase() };
|
|
366
|
-
if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
|
|
367
|
-
throw new Error(`Employee '${normalized.name}' already exists`);
|
|
368
|
-
}
|
|
369
|
-
return [...employees, normalized];
|
|
370
|
-
}
|
|
371
|
-
function appendToCoordinatorTeam(employee) {
|
|
372
|
-
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
373
|
-
if (!coordinator) return;
|
|
374
|
-
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
375
|
-
if (!existsSync4(idPath)) return;
|
|
376
|
-
const content = readFileSync3(idPath, "utf-8");
|
|
377
|
-
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
378
|
-
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
379
|
-
if (!teamMatch || teamMatch.index === void 0) return;
|
|
380
|
-
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
381
|
-
const nextHeading = afterTeam.match(/\n## /);
|
|
382
|
-
const entry = `
|
|
383
|
-
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
384
|
-
`;
|
|
385
|
-
let updated;
|
|
386
|
-
if (nextHeading && nextHeading.index !== void 0) {
|
|
387
|
-
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
388
|
-
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
389
|
-
} else {
|
|
390
|
-
updated = content.trimEnd() + "\n" + entry;
|
|
391
|
-
}
|
|
392
|
-
writeFileSync2(idPath, updated, "utf-8");
|
|
393
|
-
}
|
|
394
|
-
function capitalize(s) {
|
|
395
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
396
|
-
}
|
|
397
|
-
async function hireEmployee(employee) {
|
|
398
|
-
const employees = await loadEmployees();
|
|
399
|
-
const updated = addEmployee(employees, employee);
|
|
400
|
-
await saveEmployees(updated);
|
|
401
|
-
try {
|
|
402
|
-
appendToCoordinatorTeam(employee);
|
|
403
|
-
} catch {
|
|
404
|
-
}
|
|
405
|
-
try {
|
|
406
|
-
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
407
|
-
const config = loadAgentConfig2();
|
|
408
|
-
const name = employee.name.toLowerCase();
|
|
409
|
-
if (!config[name] && config["default"]) {
|
|
410
|
-
config[name] = { ...config["default"] };
|
|
411
|
-
saveAgentConfig2(config);
|
|
412
|
-
}
|
|
413
|
-
} catch {
|
|
414
|
-
}
|
|
415
|
-
return updated;
|
|
416
|
-
}
|
|
417
|
-
async function normalizeRosterCase(rosterPath) {
|
|
418
|
-
const employees = await loadEmployees(rosterPath);
|
|
419
|
-
let changed = false;
|
|
420
|
-
for (const emp of employees) {
|
|
421
|
-
if (emp.name !== emp.name.toLowerCase()) {
|
|
422
|
-
const oldName = emp.name;
|
|
423
|
-
emp.name = emp.name.toLowerCase();
|
|
424
|
-
changed = true;
|
|
425
|
-
try {
|
|
426
|
-
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
427
|
-
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
428
|
-
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
429
|
-
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
430
|
-
renameSync2(oldPath, newPath);
|
|
431
|
-
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
432
|
-
const content = readFileSync3(oldPath, "utf-8");
|
|
433
|
-
writeFileSync2(newPath, content, "utf-8");
|
|
434
|
-
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
435
|
-
unlinkSync(oldPath);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
} catch {
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (changed) {
|
|
443
|
-
await saveEmployees(employees, rosterPath);
|
|
444
|
-
}
|
|
445
|
-
return changed;
|
|
446
|
-
}
|
|
447
|
-
function findExeBin() {
|
|
448
|
-
try {
|
|
449
|
-
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
450
|
-
} catch {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
function registerBinSymlinks(name) {
|
|
455
|
-
const created = [];
|
|
456
|
-
const skipped = [];
|
|
457
|
-
const errors = [];
|
|
458
|
-
const exeBinPath = findExeBin();
|
|
459
|
-
if (!exeBinPath) {
|
|
460
|
-
errors.push("Could not find 'exe-os' in PATH");
|
|
461
|
-
return { created, skipped, errors };
|
|
462
|
-
}
|
|
463
|
-
const binDir = path3.dirname(exeBinPath);
|
|
464
|
-
let target;
|
|
465
|
-
try {
|
|
466
|
-
target = readlinkSync(exeBinPath);
|
|
467
|
-
} catch {
|
|
468
|
-
errors.push("Could not read 'exe' symlink");
|
|
469
|
-
return { created, skipped, errors };
|
|
470
|
-
}
|
|
471
|
-
for (const suffix of ["", "-opencode"]) {
|
|
472
|
-
const linkName = `${name}${suffix}`;
|
|
473
|
-
const linkPath = path3.join(binDir, linkName);
|
|
474
|
-
if (existsSync4(linkPath)) {
|
|
475
|
-
skipped.push(linkName);
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
try {
|
|
479
|
-
symlinkSync(target, linkPath);
|
|
480
|
-
created.push(linkName);
|
|
481
|
-
} catch (err) {
|
|
482
|
-
errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
return { created, skipped, errors };
|
|
486
|
-
}
|
|
487
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
169
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
488
170
|
var init_employees = __esm({
|
|
489
171
|
"src/lib/employees.ts"() {
|
|
490
172
|
"use strict";
|
|
491
173
|
init_config();
|
|
492
|
-
EMPLOYEES_PATH =
|
|
174
|
+
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
493
175
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
494
176
|
COORDINATOR_ROLE = "COO";
|
|
495
|
-
|
|
496
|
-
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
497
|
-
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
177
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
498
178
|
}
|
|
499
179
|
});
|
|
500
180
|
|
|
@@ -507,7 +187,7 @@ var init_db_retry = __esm({
|
|
|
507
187
|
|
|
508
188
|
// src/lib/database-adapter.ts
|
|
509
189
|
import os3 from "os";
|
|
510
|
-
import
|
|
190
|
+
import path3 from "path";
|
|
511
191
|
import { createRequire } from "module";
|
|
512
192
|
import { pathToFileURL } from "url";
|
|
513
193
|
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
@@ -765,7 +445,8 @@ __export(employee_templates_exports, {
|
|
|
765
445
|
});
|
|
766
446
|
function getSessionPrompt(storedPrompt) {
|
|
767
447
|
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
768
|
-
const
|
|
448
|
+
const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
449
|
+
const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
|
|
769
450
|
const globalBlock = getGlobalProceduresBlock();
|
|
770
451
|
return `${globalBlock}${rolePrompt}
|
|
771
452
|
${BASE_OPERATING_PROCEDURES}`;
|
|
@@ -1367,10 +1048,127 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
1367
1048
|
}
|
|
1368
1049
|
});
|
|
1369
1050
|
|
|
1051
|
+
// src/lib/runtime-table.ts
|
|
1052
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
1053
|
+
var init_runtime_table = __esm({
|
|
1054
|
+
"src/lib/runtime-table.ts"() {
|
|
1055
|
+
"use strict";
|
|
1056
|
+
RUNTIME_TABLE = {
|
|
1057
|
+
codex: {
|
|
1058
|
+
binary: "codex",
|
|
1059
|
+
launchMode: "interactive",
|
|
1060
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
1061
|
+
inlineFlag: "--no-alt-screen",
|
|
1062
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
1063
|
+
defaultModel: "gpt-5.5"
|
|
1064
|
+
},
|
|
1065
|
+
opencode: {
|
|
1066
|
+
binary: "opencode",
|
|
1067
|
+
launchMode: "exec",
|
|
1068
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
1069
|
+
inlineFlag: "",
|
|
1070
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
1071
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
DEFAULT_RUNTIME = "claude";
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
// src/lib/agent-config.ts
|
|
1079
|
+
var agent_config_exports = {};
|
|
1080
|
+
__export(agent_config_exports, {
|
|
1081
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
1082
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
1083
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
1084
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
1085
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
1086
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
1087
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
1088
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
1089
|
+
setAgentRuntime: () => setAgentRuntime
|
|
1090
|
+
});
|
|
1091
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
1092
|
+
import path4 from "path";
|
|
1093
|
+
function loadAgentConfig() {
|
|
1094
|
+
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
1095
|
+
try {
|
|
1096
|
+
return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
|
|
1097
|
+
} catch {
|
|
1098
|
+
return {};
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
function saveAgentConfig(config) {
|
|
1102
|
+
const dir = path4.dirname(AGENT_CONFIG_PATH);
|
|
1103
|
+
ensurePrivateDirSync(dir);
|
|
1104
|
+
writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1105
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
1106
|
+
}
|
|
1107
|
+
function getAgentRuntime(agentId) {
|
|
1108
|
+
const config = loadAgentConfig();
|
|
1109
|
+
const entry = config[agentId];
|
|
1110
|
+
if (entry) return entry;
|
|
1111
|
+
const orgDefault = config["default"];
|
|
1112
|
+
if (orgDefault) return orgDefault;
|
|
1113
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
1114
|
+
}
|
|
1115
|
+
function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
1116
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
1117
|
+
if (!knownModels) {
|
|
1118
|
+
return {
|
|
1119
|
+
ok: false,
|
|
1120
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
if (!knownModels.includes(model)) {
|
|
1124
|
+
return {
|
|
1125
|
+
ok: false,
|
|
1126
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
const config = loadAgentConfig();
|
|
1130
|
+
const entry = { runtime, model };
|
|
1131
|
+
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
1132
|
+
config[agentId] = entry;
|
|
1133
|
+
saveAgentConfig(config);
|
|
1134
|
+
return { ok: true };
|
|
1135
|
+
}
|
|
1136
|
+
function clearAgentRuntime(agentId) {
|
|
1137
|
+
const config = loadAgentConfig();
|
|
1138
|
+
delete config[agentId];
|
|
1139
|
+
saveAgentConfig(config);
|
|
1140
|
+
}
|
|
1141
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
1142
|
+
var init_agent_config = __esm({
|
|
1143
|
+
"src/lib/agent-config.ts"() {
|
|
1144
|
+
"use strict";
|
|
1145
|
+
init_config();
|
|
1146
|
+
init_runtime_table();
|
|
1147
|
+
init_secure_files();
|
|
1148
|
+
AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
|
|
1149
|
+
KNOWN_RUNTIMES = {
|
|
1150
|
+
claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
1151
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
1152
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
1153
|
+
};
|
|
1154
|
+
RUNTIME_LABELS = {
|
|
1155
|
+
claude: "Claude Code (Anthropic)",
|
|
1156
|
+
codex: "Codex (OpenAI)",
|
|
1157
|
+
opencode: "OpenCode (open source)"
|
|
1158
|
+
};
|
|
1159
|
+
DEFAULT_MODELS = {
|
|
1160
|
+
claude: "claude-opus-4.6",
|
|
1161
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
1162
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1370
1167
|
// src/bin/exe-call.ts
|
|
1371
1168
|
init_employees();
|
|
1372
1169
|
init_config();
|
|
1373
1170
|
import path5 from "path";
|
|
1171
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
1374
1172
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
1375
1173
|
import { execSync as execSync2 } from "child_process";
|
|
1376
1174
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1441,7 +1239,8 @@ if (isMainModule(import.meta.url)) {
|
|
|
1441
1239
|
process.exit(1);
|
|
1442
1240
|
}
|
|
1443
1241
|
const employee = resolveEmployee(name, employees);
|
|
1444
|
-
|
|
1242
|
+
const identityPath = path5.join(EXE_AI_DIR, "identity", `${employee.name}.md`);
|
|
1243
|
+
let prompt = existsSync5(identityPath) ? readFileSync4(identityPath, "utf-8") : employee.systemPrompt;
|
|
1445
1244
|
if (!prompt || prompt.trim().length < 20) {
|
|
1446
1245
|
const { DEFAULT_EXE: DEFAULT_EXE2, TEMPLATES: TEMPLATES2, personalizePrompt: personalizePrompt2 } = await Promise.resolve().then(() => (init_employee_templates(), employee_templates_exports));
|
|
1447
1246
|
if (employee.role === "COO") {
|
|
@@ -1453,17 +1252,10 @@ if (isMainModule(import.meta.url)) {
|
|
|
1453
1252
|
} else {
|
|
1454
1253
|
const templateKey = employee.templateName ?? employee.name;
|
|
1455
1254
|
const template = TEMPLATES2[templateKey];
|
|
1456
|
-
if (template)
|
|
1457
|
-
prompt = personalizePrompt2(template.systemPrompt, templateKey, employee.name);
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
if (prompt && prompt.length > 20) {
|
|
1461
|
-
const { saveEmployees: saveEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
1462
|
-
employee.systemPrompt = prompt;
|
|
1463
|
-
await saveEmployees2(employees);
|
|
1255
|
+
if (template) prompt = personalizePrompt2(template.systemPrompt, templateKey, employee.name);
|
|
1464
1256
|
}
|
|
1465
1257
|
}
|
|
1466
|
-
const sessionDir = await prepareSessionDir(name, getSessionPrompt(prompt));
|
|
1258
|
+
const sessionDir = await prepareSessionDir(name, getSessionPrompt(prompt ?? ""));
|
|
1467
1259
|
const env = buildSessionEnv(employee, sessionDir);
|
|
1468
1260
|
const { getAgentRuntime: getAgentRuntime2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
1469
1261
|
const rtConfig = getAgentRuntime2(employee.name);
|
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -6934,7 +6934,7 @@ __export(shard_manager_exports, {
|
|
|
6934
6934
|
shardExists: () => shardExists
|
|
6935
6935
|
});
|
|
6936
6936
|
import path19 from "path";
|
|
6937
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
|
|
6937
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync2 } from "fs";
|
|
6938
6938
|
import { createClient as createClient2 } from "@libsql/client";
|
|
6939
6939
|
function initShardManager(encryptionKey) {
|
|
6940
6940
|
_encryptionKey = encryptionKey;
|
|
@@ -6956,7 +6956,7 @@ function getShardClient(projectName) {
|
|
|
6956
6956
|
if (!_encryptionKey) {
|
|
6957
6957
|
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
6958
6958
|
}
|
|
6959
|
-
const safeName = projectName
|
|
6959
|
+
const safeName = safeShardName(projectName);
|
|
6960
6960
|
if (!safeName || safeName === "unknown") {
|
|
6961
6961
|
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
6962
6962
|
}
|
|
@@ -6978,9 +6978,12 @@ function getShardClient(projectName) {
|
|
|
6978
6978
|
return client;
|
|
6979
6979
|
}
|
|
6980
6980
|
function shardExists(projectName) {
|
|
6981
|
-
const safeName = projectName
|
|
6981
|
+
const safeName = safeShardName(projectName);
|
|
6982
6982
|
return existsSync16(path19.join(SHARDS_DIR, `${safeName}.db`));
|
|
6983
6983
|
}
|
|
6984
|
+
function safeShardName(projectName) {
|
|
6985
|
+
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6986
|
+
}
|
|
6984
6987
|
function listShards() {
|
|
6985
6988
|
if (!existsSync16(SHARDS_DIR)) return [];
|
|
6986
6989
|
return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
@@ -7074,7 +7077,8 @@ async function ensureShardSchema(client) {
|
|
|
7074
7077
|
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
7075
7078
|
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
7076
7079
|
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
7077
|
-
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
7080
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
|
|
7081
|
+
"ALTER TABLE memories ADD COLUMN deleted_at TEXT"
|
|
7078
7082
|
]) {
|
|
7079
7083
|
try {
|
|
7080
7084
|
await client.execute(col);
|
|
@@ -7170,9 +7174,32 @@ async function ensureShardSchema(client) {
|
|
|
7170
7174
|
}
|
|
7171
7175
|
}
|
|
7172
7176
|
async function getReadyShardClient(projectName) {
|
|
7173
|
-
const
|
|
7174
|
-
|
|
7175
|
-
|
|
7177
|
+
const safeName = safeShardName(projectName);
|
|
7178
|
+
let client = getShardClient(projectName);
|
|
7179
|
+
try {
|
|
7180
|
+
await ensureShardSchema(client);
|
|
7181
|
+
return client;
|
|
7182
|
+
} catch (err) {
|
|
7183
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7184
|
+
if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
|
|
7185
|
+
client.close();
|
|
7186
|
+
_shards.delete(safeName);
|
|
7187
|
+
_shardLastAccess.delete(safeName);
|
|
7188
|
+
const dbPath = path19.join(SHARDS_DIR, `${safeName}.db`);
|
|
7189
|
+
if (existsSync16(dbPath)) {
|
|
7190
|
+
const stat = statSync2(dbPath);
|
|
7191
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
7192
|
+
const archivedPath = path19.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
7193
|
+
renameSync4(dbPath, archivedPath);
|
|
7194
|
+
process.stderr.write(
|
|
7195
|
+
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
7196
|
+
`
|
|
7197
|
+
);
|
|
7198
|
+
}
|
|
7199
|
+
client = getShardClient(projectName);
|
|
7200
|
+
await ensureShardSchema(client);
|
|
7201
|
+
return client;
|
|
7202
|
+
}
|
|
7176
7203
|
}
|
|
7177
7204
|
function evictLRU() {
|
|
7178
7205
|
let oldest = null;
|