@askexenow/exe-os 0.9.112 → 0.9.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/bin/agentic-ontology-backfill.js +54 -11
- package/dist/bin/agentic-reflection-backfill.js +29 -1
- package/dist/bin/agentic-semantic-label.js +29 -1
- package/dist/bin/backfill-conversations.js +53 -10
- package/dist/bin/backfill-responses.js +54 -11
- package/dist/bin/backfill-vectors.js +29 -1
- package/dist/bin/bulk-sync-postgres.js +55 -12
- package/dist/bin/cleanup-stale-review-tasks.js +75 -15
- package/dist/bin/cli.js +293 -76
- package/dist/bin/exe-agent-config.js +7 -1
- package/dist/bin/exe-agent.js +28 -2
- package/dist/bin/exe-assign.js +54 -11
- package/dist/bin/exe-boot.js +481 -147
- package/dist/bin/exe-call.js +45 -4
- package/dist/bin/exe-cloud.js +93 -15
- package/dist/bin/exe-dispatch.js +369 -24
- package/dist/bin/exe-doctor.js +53 -10
- package/dist/bin/exe-export-behaviors.js +54 -11
- package/dist/bin/exe-forget.js +54 -11
- package/dist/bin/exe-gateway.js +128 -23
- package/dist/bin/exe-heartbeat.js +75 -15
- package/dist/bin/exe-kill.js +54 -11
- package/dist/bin/exe-launch-agent.js +70 -12
- package/dist/bin/exe-new-employee.js +175 -7
- package/dist/bin/exe-pending-messages.js +75 -15
- package/dist/bin/exe-pending-notifications.js +75 -15
- package/dist/bin/exe-pending-reviews.js +75 -15
- package/dist/bin/exe-rename.js +54 -11
- package/dist/bin/exe-review.js +54 -11
- package/dist/bin/exe-search.js +54 -11
- package/dist/bin/exe-session-cleanup.js +491 -146
- package/dist/bin/exe-settings.js +10 -4
- package/dist/bin/exe-start-codex.js +524 -245
- package/dist/bin/exe-start-opencode.js +534 -165
- package/dist/bin/exe-status.js +75 -15
- package/dist/bin/exe-support.js +1 -1
- package/dist/bin/exe-team.js +54 -11
- package/dist/bin/git-sweep.js +369 -24
- package/dist/bin/graph-backfill.js +54 -11
- package/dist/bin/graph-export.js +54 -11
- package/dist/bin/install.js +62 -4
- package/dist/bin/intercom-check.js +491 -146
- package/dist/bin/pre-publish.js +13 -1
- package/dist/bin/scan-tasks.js +369 -24
- package/dist/bin/setup.js +91 -13
- package/dist/bin/shard-migrate.js +54 -11
- package/dist/bin/stack-update.js +1 -1
- package/dist/bin/update.js +3 -3
- package/dist/gateway/index.js +128 -23
- package/dist/hooks/bug-report-worker.js +128 -23
- package/dist/hooks/codex-stop-task-finalizer.js +512 -140
- package/dist/hooks/commit-complete.js +369 -24
- package/dist/hooks/error-recall.js +54 -11
- package/dist/hooks/ingest.js +4575 -252
- package/dist/hooks/instructions-loaded.js +54 -11
- package/dist/hooks/notification.js +54 -11
- package/dist/hooks/post-compact.js +75 -15
- package/dist/hooks/post-tool-combined.js +75 -15
- package/dist/hooks/pre-compact.js +449 -104
- package/dist/hooks/pre-tool-use.js +90 -15
- package/dist/hooks/prompt-submit.js +129 -24
- package/dist/hooks/session-end.js +451 -109
- package/dist/hooks/session-start.js +104 -16
- package/dist/hooks/stop.js +74 -14
- package/dist/hooks/subagent-stop.js +75 -15
- package/dist/hooks/summary-worker.js +73 -7
- package/dist/index.js +128 -23
- package/dist/lib/agent-config.js +16 -1
- package/dist/lib/cloud-sync.js +38 -1
- package/dist/lib/consolidation.js +16 -1
- package/dist/lib/database.js +16 -0
- package/dist/lib/db.js +16 -0
- package/dist/lib/device-registry.js +16 -0
- package/dist/lib/employee-templates.js +29 -3
- package/dist/lib/employees.js +16 -1
- package/dist/lib/exe-daemon.js +268 -42
- package/dist/lib/hybrid-search.js +54 -11
- package/dist/lib/license.js +3 -3
- package/dist/lib/messaging.js +21 -4
- package/dist/lib/schedules.js +29 -1
- package/dist/lib/skill-learning.js +458 -70
- package/dist/lib/status-brief.js +14 -1
- package/dist/lib/store.js +54 -11
- package/dist/lib/tasks.js +393 -91
- package/dist/lib/tmux-routing.js +316 -14
- package/dist/mcp/server.js +169 -30
- package/dist/mcp/tools/create-task.js +75 -13
- package/dist/mcp/tools/deactivate-behavior.js +33 -24
- package/dist/mcp/tools/list-tasks.js +21 -4
- package/dist/mcp/tools/send-message.js +21 -4
- package/dist/mcp/tools/update-task.js +390 -91
- package/dist/runtime/index.js +446 -101
- package/dist/tui/App.js +208 -54
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
6
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
7
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
8
|
}) : x)(function(x) {
|
|
@@ -14,6 +16,15 @@ var __export = (target, all) => {
|
|
|
14
16
|
for (var name in all)
|
|
15
17
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
18
|
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
17
28
|
|
|
18
29
|
// src/lib/secure-files.ts
|
|
19
30
|
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
@@ -177,6 +188,7 @@ __export(agent_config_exports, {
|
|
|
177
188
|
getAgentRuntime: () => getAgentRuntime,
|
|
178
189
|
loadAgentConfig: () => loadAgentConfig,
|
|
179
190
|
saveAgentConfig: () => saveAgentConfig,
|
|
191
|
+
setAgentMcps: () => setAgentMcps,
|
|
180
192
|
setAgentRuntime: () => setAgentRuntime
|
|
181
193
|
});
|
|
182
194
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
@@ -203,7 +215,7 @@ function getAgentRuntime(agentId) {
|
|
|
203
215
|
if (orgDefault) return orgDefault;
|
|
204
216
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
205
217
|
}
|
|
206
|
-
function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
218
|
+
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
207
219
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
208
220
|
if (!knownModels) {
|
|
209
221
|
return {
|
|
@@ -218,12 +230,26 @@ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
|
218
230
|
};
|
|
219
231
|
}
|
|
220
232
|
const config = loadAgentConfig();
|
|
233
|
+
const existing = config[agentId];
|
|
221
234
|
const entry = { runtime, model };
|
|
222
235
|
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
236
|
+
if (mcps !== void 0) {
|
|
237
|
+
entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
238
|
+
} else if (existing?.mcps) {
|
|
239
|
+
entry.mcps = existing.mcps;
|
|
240
|
+
}
|
|
223
241
|
config[agentId] = entry;
|
|
224
242
|
saveAgentConfig(config);
|
|
225
243
|
return { ok: true };
|
|
226
244
|
}
|
|
245
|
+
function setAgentMcps(agentId, mcps) {
|
|
246
|
+
const config = loadAgentConfig();
|
|
247
|
+
const existing = config[agentId] ?? getAgentRuntime(agentId);
|
|
248
|
+
existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
249
|
+
config[agentId] = existing;
|
|
250
|
+
saveAgentConfig(config);
|
|
251
|
+
return { ok: true };
|
|
252
|
+
}
|
|
227
253
|
function clearAgentRuntime(agentId) {
|
|
228
254
|
const config = loadAgentConfig();
|
|
229
255
|
delete config[agentId];
|
|
@@ -256,6 +282,32 @@ var init_agent_config = __esm({
|
|
|
256
282
|
});
|
|
257
283
|
|
|
258
284
|
// src/lib/employees.ts
|
|
285
|
+
var employees_exports = {};
|
|
286
|
+
__export(employees_exports, {
|
|
287
|
+
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
288
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
289
|
+
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
290
|
+
addEmployee: () => addEmployee,
|
|
291
|
+
baseAgentName: () => baseAgentName,
|
|
292
|
+
canCoordinate: () => canCoordinate,
|
|
293
|
+
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
294
|
+
getCoordinatorName: () => getCoordinatorName,
|
|
295
|
+
getEmployee: () => getEmployee,
|
|
296
|
+
getEmployeeByRole: () => getEmployeeByRole,
|
|
297
|
+
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
298
|
+
hasRole: () => hasRole,
|
|
299
|
+
hireEmployee: () => hireEmployee,
|
|
300
|
+
isCoordinatorName: () => isCoordinatorName,
|
|
301
|
+
isCoordinatorRole: () => isCoordinatorRole,
|
|
302
|
+
isMultiInstance: () => isMultiInstance,
|
|
303
|
+
loadEmployees: () => loadEmployees,
|
|
304
|
+
loadEmployeesSync: () => loadEmployeesSync,
|
|
305
|
+
normalizeRole: () => normalizeRole,
|
|
306
|
+
normalizeRosterCase: () => normalizeRosterCase,
|
|
307
|
+
registerBinSymlinks: () => registerBinSymlinks,
|
|
308
|
+
saveEmployees: () => saveEmployees,
|
|
309
|
+
validateEmployeeName: () => validateEmployeeName
|
|
310
|
+
});
|
|
259
311
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
260
312
|
import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
261
313
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -270,6 +322,16 @@ function isCoordinatorRole(role) {
|
|
|
270
322
|
function getCoordinatorEmployee(employees) {
|
|
271
323
|
return employees.find((e) => isCoordinatorRole(e.role));
|
|
272
324
|
}
|
|
325
|
+
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
326
|
+
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
327
|
+
}
|
|
328
|
+
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
329
|
+
if (!agentName) return false;
|
|
330
|
+
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
331
|
+
}
|
|
332
|
+
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
333
|
+
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
334
|
+
}
|
|
273
335
|
function validateEmployeeName(name) {
|
|
274
336
|
if (!name) {
|
|
275
337
|
return { valid: false, error: "Name is required" };
|
|
@@ -308,6 +370,36 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
308
370
|
return [];
|
|
309
371
|
}
|
|
310
372
|
}
|
|
373
|
+
function getEmployee(employees, name) {
|
|
374
|
+
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
375
|
+
}
|
|
376
|
+
function getEmployeeByRole(employees, role) {
|
|
377
|
+
const lower = role.toLowerCase();
|
|
378
|
+
return employees.find((e) => e.role.toLowerCase() === lower);
|
|
379
|
+
}
|
|
380
|
+
function getEmployeeNamesByRole(employees, role) {
|
|
381
|
+
const lower = role.toLowerCase();
|
|
382
|
+
return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
|
|
383
|
+
}
|
|
384
|
+
function hasRole(agentName, role) {
|
|
385
|
+
const employees = loadEmployeesSync();
|
|
386
|
+
const emp = getEmployee(employees, agentName);
|
|
387
|
+
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
388
|
+
}
|
|
389
|
+
function baseAgentName(name, employees) {
|
|
390
|
+
const match = name.match(/^([a-zA-Z]+)\d+$/);
|
|
391
|
+
if (!match) return name;
|
|
392
|
+
const base = match[1];
|
|
393
|
+
const roster = employees ?? loadEmployeesSync();
|
|
394
|
+
if (getEmployee(roster, base)) return base;
|
|
395
|
+
return name;
|
|
396
|
+
}
|
|
397
|
+
function isMultiInstance(agentName, employees) {
|
|
398
|
+
const roster = employees ?? loadEmployeesSync();
|
|
399
|
+
const emp = getEmployee(roster, agentName);
|
|
400
|
+
if (!emp) return false;
|
|
401
|
+
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
402
|
+
}
|
|
311
403
|
function addEmployee(employees, employee) {
|
|
312
404
|
const { systemPrompt: _legacyPrompt, ...rest } = employee;
|
|
313
405
|
const normalized = { ...rest, name: employee.name.toLowerCase() };
|
|
@@ -362,6 +454,36 @@ async function hireEmployee(employee) {
|
|
|
362
454
|
}
|
|
363
455
|
return updated;
|
|
364
456
|
}
|
|
457
|
+
async function normalizeRosterCase(rosterPath) {
|
|
458
|
+
const employees = await loadEmployees(rosterPath);
|
|
459
|
+
let changed = false;
|
|
460
|
+
for (const emp of employees) {
|
|
461
|
+
if (emp.name !== emp.name.toLowerCase()) {
|
|
462
|
+
const oldName = emp.name;
|
|
463
|
+
emp.name = emp.name.toLowerCase();
|
|
464
|
+
changed = true;
|
|
465
|
+
try {
|
|
466
|
+
const identityDir = path4.join(os2.homedir(), ".exe-os", "identity");
|
|
467
|
+
const oldPath = path4.join(identityDir, `${oldName}.md`);
|
|
468
|
+
const newPath = path4.join(identityDir, `${emp.name}.md`);
|
|
469
|
+
if (existsSync5(oldPath) && !existsSync5(newPath)) {
|
|
470
|
+
renameSync2(oldPath, newPath);
|
|
471
|
+
} else if (existsSync5(oldPath) && oldPath !== newPath) {
|
|
472
|
+
const content = readFileSync4(oldPath, "utf-8");
|
|
473
|
+
writeFileSync3(newPath, content, "utf-8");
|
|
474
|
+
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
475
|
+
unlinkSync2(oldPath);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
} catch {
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (changed) {
|
|
483
|
+
await saveEmployees(employees, rosterPath);
|
|
484
|
+
}
|
|
485
|
+
return changed;
|
|
486
|
+
}
|
|
365
487
|
function findExeBin() {
|
|
366
488
|
try {
|
|
367
489
|
return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
@@ -402,13 +524,15 @@ function registerBinSymlinks(name) {
|
|
|
402
524
|
}
|
|
403
525
|
return { created, skipped, errors };
|
|
404
526
|
}
|
|
405
|
-
var EMPLOYEES_PATH, COORDINATOR_ROLE, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
527
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
406
528
|
var init_employees = __esm({
|
|
407
529
|
"src/lib/employees.ts"() {
|
|
408
530
|
"use strict";
|
|
409
531
|
init_config();
|
|
410
532
|
EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
|
|
533
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
411
534
|
COORDINATOR_ROLE = "COO";
|
|
535
|
+
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
412
536
|
IDENTITY_DIR = path4.join(EXE_AI_DIR, "identity");
|
|
413
537
|
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
414
538
|
}
|
|
@@ -1295,6 +1419,16 @@ import { chmodSync as chmodSync4, existsSync as existsSync12, mkdirSync as mkdir
|
|
|
1295
1419
|
import { randomBytes } from "crypto";
|
|
1296
1420
|
import path11 from "path";
|
|
1297
1421
|
import os7 from "os";
|
|
1422
|
+
function resolveDefaultAgentId() {
|
|
1423
|
+
if (process.env.AGENT_ID && process.env.AGENT_ID !== "default") return process.env.AGENT_ID;
|
|
1424
|
+
try {
|
|
1425
|
+
const { loadEmployeesSync: loadEmployeesSync2 } = (init_employees(), __toCommonJS(employees_exports));
|
|
1426
|
+
const coo = loadEmployeesSync2().find((e) => e.role === "COO");
|
|
1427
|
+
if (coo) return coo.name;
|
|
1428
|
+
} catch {
|
|
1429
|
+
}
|
|
1430
|
+
return "exe";
|
|
1431
|
+
}
|
|
1298
1432
|
function mcpHttpPort() {
|
|
1299
1433
|
return process.env.EXE_MCP_PORT || DEFAULT_MCP_HTTP_PORT;
|
|
1300
1434
|
}
|
|
@@ -1324,11 +1458,14 @@ function readOrCreateDaemonToken(homeDir = os7.homedir()) {
|
|
|
1324
1458
|
function buildMcpHttpHeaders(homeDir = os7.homedir(), opts = {}) {
|
|
1325
1459
|
const agentId = opts.useShellPlaceholders ? "${AGENT_ID:-exe}" : opts.agentId ?? DEFAULT_MCP_HTTP_AGENT_ID;
|
|
1326
1460
|
const agentRole = opts.useShellPlaceholders ? "${AGENT_ROLE:-COO}" : opts.agentRole ?? DEFAULT_MCP_HTTP_AGENT_ROLE;
|
|
1327
|
-
|
|
1461
|
+
const sessionName = opts.useShellPlaceholders ? "$(tmux display-message -p '#{session_name}' 2>/dev/null || echo '')" : process.env.EXE_SESSION_NAME ?? "";
|
|
1462
|
+
const headers = {
|
|
1328
1463
|
Authorization: `Bearer ${readOrCreateDaemonToken(homeDir)}`,
|
|
1329
1464
|
"X-Agent-Id": agentId,
|
|
1330
1465
|
"X-Agent-Role": agentRole
|
|
1331
1466
|
};
|
|
1467
|
+
if (sessionName) headers["X-Exe-Session"] = sessionName;
|
|
1468
|
+
return headers;
|
|
1332
1469
|
}
|
|
1333
1470
|
function buildClaudeHttpMcpEntry(homeDir = os7.homedir()) {
|
|
1334
1471
|
return {
|
|
@@ -1342,19 +1479,22 @@ var init_mcp_http_config = __esm({
|
|
|
1342
1479
|
"src/adapters/mcp-http-config.ts"() {
|
|
1343
1480
|
"use strict";
|
|
1344
1481
|
DEFAULT_MCP_HTTP_PORT = "48739";
|
|
1345
|
-
DEFAULT_MCP_HTTP_AGENT_ID =
|
|
1482
|
+
DEFAULT_MCP_HTTP_AGENT_ID = resolveDefaultAgentId();
|
|
1346
1483
|
DEFAULT_MCP_HTTP_AGENT_ROLE = "COO";
|
|
1347
1484
|
}
|
|
1348
1485
|
});
|
|
1349
1486
|
|
|
1350
1487
|
// src/adapters/runtime-hook-manifest.ts
|
|
1488
|
+
function isLegacyHomeDirHookCommand(command) {
|
|
1489
|
+
return LEGACY_HOME_DIR_HOOK_PATTERNS.some((pattern) => command.includes(pattern));
|
|
1490
|
+
}
|
|
1351
1491
|
function commandHasAnyMarker(command, markers) {
|
|
1352
1492
|
return markers.some((marker) => command.includes(marker));
|
|
1353
1493
|
}
|
|
1354
1494
|
function isLegacySplitPostToolCommand(command) {
|
|
1355
1495
|
return commandHasAnyMarker(command, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS);
|
|
1356
1496
|
}
|
|
1357
|
-
var EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
1497
|
+
var EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS, LEGACY_HOME_DIR_HOOK_PATTERNS;
|
|
1358
1498
|
var init_runtime_hook_manifest = __esm({
|
|
1359
1499
|
"src/adapters/runtime-hook-manifest.ts"() {
|
|
1360
1500
|
"use strict";
|
|
@@ -1487,6 +1627,14 @@ var init_runtime_hook_manifest = __esm({
|
|
|
1487
1627
|
"dist/hooks/error-recall.js",
|
|
1488
1628
|
"dist/hooks/ingest-worker.js"
|
|
1489
1629
|
];
|
|
1630
|
+
LEGACY_HOME_DIR_HOOK_PATTERNS = [
|
|
1631
|
+
".exe-os/hooks/",
|
|
1632
|
+
// Old hook storage path (pre-npm-package era)
|
|
1633
|
+
"log-prefix.js",
|
|
1634
|
+
// Removed hook from early versions
|
|
1635
|
+
"approval-bridge.log"
|
|
1636
|
+
// Removed log redirect from early versions
|
|
1637
|
+
];
|
|
1490
1638
|
}
|
|
1491
1639
|
});
|
|
1492
1640
|
|
|
@@ -1966,6 +2114,14 @@ async function mergeHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
1966
2114
|
];
|
|
1967
2115
|
let added = 0;
|
|
1968
2116
|
let skipped = 0;
|
|
2117
|
+
for (const eventKey of Object.keys(settings.hooks)) {
|
|
2118
|
+
const groups = settings.hooks[eventKey];
|
|
2119
|
+
if (!Array.isArray(groups)) continue;
|
|
2120
|
+
settings.hooks[eventKey] = groups.map((g) => ({
|
|
2121
|
+
...g,
|
|
2122
|
+
hooks: g.hooks.filter((h) => !isLegacyHomeDirHookCommand(h.command))
|
|
2123
|
+
})).filter((g) => g.hooks.length > 0);
|
|
2124
|
+
}
|
|
1969
2125
|
const postToolGroups = settings.hooks["PostToolUse"];
|
|
1970
2126
|
if (Array.isArray(postToolGroups)) {
|
|
1971
2127
|
settings.hooks["PostToolUse"] = postToolGroups.map((g) => ({
|
|
@@ -2680,11 +2836,17 @@ var PLATFORM_PROCEDURES = [
|
|
|
2680
2836
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
2681
2837
|
},
|
|
2682
2838
|
{
|
|
2683
|
-
title: "
|
|
2839
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
2684
2840
|
domain: "workflow",
|
|
2685
2841
|
priority: "p1",
|
|
2686
2842
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
2687
2843
|
},
|
|
2844
|
+
{
|
|
2845
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
2846
|
+
domain: "identity",
|
|
2847
|
+
priority: "p0",
|
|
2848
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
2849
|
+
},
|
|
2688
2850
|
{
|
|
2689
2851
|
title: "Single dispatch path \u2014 create_task only",
|
|
2690
2852
|
domain: "workflow",
|
|
@@ -2718,6 +2880,12 @@ var PLATFORM_PROCEDURES = [
|
|
|
2718
2880
|
priority: "p0",
|
|
2719
2881
|
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."
|
|
2720
2882
|
},
|
|
2883
|
+
{
|
|
2884
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
2885
|
+
domain: "security",
|
|
2886
|
+
priority: "p0",
|
|
2887
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
2888
|
+
},
|
|
2721
2889
|
{
|
|
2722
2890
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
2723
2891
|
domain: "support",
|
|
@@ -3305,7 +3473,7 @@ import { jwtVerify, importSPKI } from "jose";
|
|
|
3305
3473
|
var LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
3306
3474
|
var CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
3307
3475
|
var DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
3308
|
-
var API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
3476
|
+
var API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
3309
3477
|
var RETRY_DELAY_MS = 500;
|
|
3310
3478
|
async function fetchRetry(url, init) {
|
|
3311
3479
|
try {
|
|
@@ -3259,6 +3259,22 @@ async function ensureSchema() {
|
|
|
3259
3259
|
} catch (e) {
|
|
3260
3260
|
logCatchDebug("migration", e);
|
|
3261
3261
|
}
|
|
3262
|
+
try {
|
|
3263
|
+
await client.execute({
|
|
3264
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3265
|
+
args: []
|
|
3266
|
+
});
|
|
3267
|
+
} catch (e) {
|
|
3268
|
+
logCatchDebug("migration", e);
|
|
3269
|
+
}
|
|
3270
|
+
try {
|
|
3271
|
+
await client.execute({
|
|
3272
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3273
|
+
args: []
|
|
3274
|
+
});
|
|
3275
|
+
} catch (e) {
|
|
3276
|
+
logCatchDebug("migration", e);
|
|
3277
|
+
}
|
|
3262
3278
|
}
|
|
3263
3279
|
async function disposeDatabase() {
|
|
3264
3280
|
if (_walCheckpointTimer) {
|
|
@@ -3609,7 +3625,7 @@ var init_license = __esm({
|
|
|
3609
3625
|
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
3610
3626
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
3611
3627
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
3612
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
3628
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
3613
3629
|
}
|
|
3614
3630
|
});
|
|
3615
3631
|
|
|
@@ -3662,6 +3678,18 @@ function extractRootExe(name) {
|
|
|
3662
3678
|
const parts = name.split("-").filter(Boolean);
|
|
3663
3679
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
3664
3680
|
}
|
|
3681
|
+
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
3682
|
+
if (!existsSync12(SESSION_CACHE)) {
|
|
3683
|
+
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3684
|
+
}
|
|
3685
|
+
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3686
|
+
const filePath = path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3687
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3688
|
+
parentExe: rootExe,
|
|
3689
|
+
dispatchedBy: dispatchedBy || rootExe,
|
|
3690
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3691
|
+
}));
|
|
3692
|
+
}
|
|
3665
3693
|
function getParentExe(sessionKey) {
|
|
3666
3694
|
try {
|
|
3667
3695
|
const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
@@ -3671,11 +3699,12 @@ function getParentExe(sessionKey) {
|
|
|
3671
3699
|
}
|
|
3672
3700
|
}
|
|
3673
3701
|
function resolveExeSession() {
|
|
3702
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
3703
|
+
const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3704
|
+
if (fromEnv) return fromEnv;
|
|
3705
|
+
}
|
|
3674
3706
|
const mySession = getMySession();
|
|
3675
3707
|
if (!mySession) {
|
|
3676
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
3677
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
3678
|
-
}
|
|
3679
3708
|
return null;
|
|
3680
3709
|
}
|
|
3681
3710
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -3690,6 +3719,10 @@ function resolveExeSession() {
|
|
|
3690
3719
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
3691
3720
|
`
|
|
3692
3721
|
);
|
|
3722
|
+
try {
|
|
3723
|
+
registerParentExe(key, fromSessionName);
|
|
3724
|
+
} catch {
|
|
3725
|
+
}
|
|
3693
3726
|
candidate = fromSessionName;
|
|
3694
3727
|
} else {
|
|
3695
3728
|
candidate = fromCache;
|
|
@@ -4853,11 +4886,17 @@ var init_platform_procedures = __esm({
|
|
|
4853
4886
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
4854
4887
|
},
|
|
4855
4888
|
{
|
|
4856
|
-
title: "
|
|
4889
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4857
4890
|
domain: "workflow",
|
|
4858
4891
|
priority: "p1",
|
|
4859
4892
|
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
4860
4893
|
},
|
|
4894
|
+
{
|
|
4895
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
4896
|
+
domain: "identity",
|
|
4897
|
+
priority: "p0",
|
|
4898
|
+
content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
|
|
4899
|
+
},
|
|
4861
4900
|
{
|
|
4862
4901
|
title: "Single dispatch path \u2014 create_task only",
|
|
4863
4902
|
domain: "workflow",
|
|
@@ -4891,6 +4930,12 @@ var init_platform_procedures = __esm({
|
|
|
4891
4930
|
priority: "p0",
|
|
4892
4931
|
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."
|
|
4893
4932
|
},
|
|
4933
|
+
{
|
|
4934
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
4935
|
+
domain: "security",
|
|
4936
|
+
priority: "p0",
|
|
4937
|
+
content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
|
|
4938
|
+
},
|
|
4894
4939
|
{
|
|
4895
4940
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4896
4941
|
domain: "support",
|
|
@@ -5176,10 +5221,24 @@ function stableId(memoryId, type, content) {
|
|
|
5176
5221
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
5177
5222
|
}
|
|
5178
5223
|
function cleanText(text) {
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5224
|
+
let cleaned = text.replace(
|
|
5225
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
5226
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
5227
|
+
);
|
|
5228
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
5229
|
+
return cleaned;
|
|
5230
|
+
}
|
|
5231
|
+
function splitSegments(text) {
|
|
5232
|
+
const cleaned = cleanText(text);
|
|
5233
|
+
const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
|
|
5234
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5235
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
5236
|
+
if (lines.length > 0) return lines;
|
|
5237
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
5238
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
return segments;
|
|
5183
5242
|
}
|
|
5184
5243
|
function inferCardType(sentence, toolName) {
|
|
5185
5244
|
const lower = sentence.toLowerCase();
|
|
@@ -5211,12 +5270,12 @@ function predicateFor(type) {
|
|
|
5211
5270
|
}
|
|
5212
5271
|
}
|
|
5213
5272
|
function extractMemoryCards(row) {
|
|
5214
|
-
const
|
|
5273
|
+
const segments = splitSegments(row.raw_text);
|
|
5215
5274
|
const cards = [];
|
|
5216
|
-
for (const sentence of
|
|
5275
|
+
for (const sentence of segments) {
|
|
5217
5276
|
const type = inferCardType(sentence, row.tool_name);
|
|
5218
5277
|
const subject = extractSubject(sentence, row.agent_id);
|
|
5219
|
-
const content = sentence.length >
|
|
5278
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
5220
5279
|
cards.push({
|
|
5221
5280
|
id: stableId(row.id, type, content),
|
|
5222
5281
|
memory_id: row.id,
|
|
@@ -5312,13 +5371,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
5312
5371
|
last_accessed: String(row.timestamp)
|
|
5313
5372
|
}));
|
|
5314
5373
|
}
|
|
5315
|
-
var MAX_CARDS_PER_MEMORY,
|
|
5374
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
5316
5375
|
var init_memory_cards = __esm({
|
|
5317
5376
|
"src/lib/memory-cards.ts"() {
|
|
5318
5377
|
"use strict";
|
|
5319
5378
|
init_database();
|
|
5320
|
-
MAX_CARDS_PER_MEMORY =
|
|
5321
|
-
|
|
5379
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
5380
|
+
MAX_SEGMENT_CHARS = 500;
|
|
5381
|
+
MIN_SEGMENT_CHARS = 20;
|
|
5322
5382
|
}
|
|
5323
5383
|
});
|
|
5324
5384
|
|