@askexenow/exe-os 0.9.112 → 0.9.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/bin/agentic-ontology-backfill.js +54 -11
- package/dist/bin/agentic-reflection-backfill.js +29 -1
- package/dist/bin/agentic-semantic-label.js +29 -1
- package/dist/bin/backfill-conversations.js +53 -10
- package/dist/bin/backfill-responses.js +54 -11
- package/dist/bin/backfill-vectors.js +29 -1
- package/dist/bin/bulk-sync-postgres.js +55 -12
- package/dist/bin/cleanup-stale-review-tasks.js +75 -15
- package/dist/bin/cli.js +293 -76
- package/dist/bin/exe-agent-config.js +7 -1
- package/dist/bin/exe-agent.js +28 -2
- package/dist/bin/exe-assign.js +54 -11
- package/dist/bin/exe-boot.js +481 -147
- package/dist/bin/exe-call.js +45 -4
- package/dist/bin/exe-cloud.js +93 -15
- package/dist/bin/exe-dispatch.js +369 -24
- package/dist/bin/exe-doctor.js +53 -10
- package/dist/bin/exe-export-behaviors.js +54 -11
- package/dist/bin/exe-forget.js +54 -11
- package/dist/bin/exe-gateway.js +128 -23
- package/dist/bin/exe-heartbeat.js +75 -15
- package/dist/bin/exe-kill.js +54 -11
- package/dist/bin/exe-launch-agent.js +70 -12
- package/dist/bin/exe-new-employee.js +175 -7
- package/dist/bin/exe-pending-messages.js +75 -15
- package/dist/bin/exe-pending-notifications.js +75 -15
- package/dist/bin/exe-pending-reviews.js +75 -15
- package/dist/bin/exe-rename.js +54 -11
- package/dist/bin/exe-review.js +54 -11
- package/dist/bin/exe-search.js +54 -11
- package/dist/bin/exe-session-cleanup.js +491 -146
- package/dist/bin/exe-settings.js +10 -4
- package/dist/bin/exe-start-codex.js +524 -245
- package/dist/bin/exe-start-opencode.js +534 -165
- package/dist/bin/exe-status.js +75 -15
- package/dist/bin/exe-support.js +1 -1
- package/dist/bin/exe-team.js +54 -11
- package/dist/bin/git-sweep.js +369 -24
- package/dist/bin/graph-backfill.js +54 -11
- package/dist/bin/graph-export.js +54 -11
- package/dist/bin/install.js +62 -4
- package/dist/bin/intercom-check.js +491 -146
- package/dist/bin/pre-publish.js +13 -1
- package/dist/bin/scan-tasks.js +369 -24
- package/dist/bin/setup.js +91 -13
- package/dist/bin/shard-migrate.js +54 -11
- package/dist/bin/stack-update.js +1 -1
- package/dist/bin/update.js +3 -3
- package/dist/gateway/index.js +128 -23
- package/dist/hooks/bug-report-worker.js +128 -23
- package/dist/hooks/codex-stop-task-finalizer.js +512 -140
- package/dist/hooks/commit-complete.js +369 -24
- package/dist/hooks/error-recall.js +54 -11
- package/dist/hooks/ingest.js +4575 -252
- package/dist/hooks/instructions-loaded.js +54 -11
- package/dist/hooks/notification.js +54 -11
- package/dist/hooks/post-compact.js +75 -15
- package/dist/hooks/post-tool-combined.js +75 -15
- package/dist/hooks/pre-compact.js +449 -104
- package/dist/hooks/pre-tool-use.js +90 -15
- package/dist/hooks/prompt-submit.js +129 -24
- package/dist/hooks/session-end.js +451 -109
- package/dist/hooks/session-start.js +104 -16
- package/dist/hooks/stop.js +74 -14
- package/dist/hooks/subagent-stop.js +75 -15
- package/dist/hooks/summary-worker.js +73 -7
- package/dist/index.js +128 -23
- package/dist/lib/agent-config.js +16 -1
- package/dist/lib/cloud-sync.js +38 -1
- package/dist/lib/consolidation.js +16 -1
- package/dist/lib/database.js +16 -0
- package/dist/lib/db.js +16 -0
- package/dist/lib/device-registry.js +16 -0
- package/dist/lib/employee-templates.js +29 -3
- package/dist/lib/employees.js +16 -1
- package/dist/lib/exe-daemon.js +268 -42
- package/dist/lib/hybrid-search.js +54 -11
- package/dist/lib/license.js +3 -3
- package/dist/lib/messaging.js +21 -4
- package/dist/lib/schedules.js +29 -1
- package/dist/lib/skill-learning.js +458 -70
- package/dist/lib/status-brief.js +14 -1
- package/dist/lib/store.js +54 -11
- package/dist/lib/tasks.js +393 -91
- package/dist/lib/tmux-routing.js +316 -14
- package/dist/mcp/server.js +169 -30
- package/dist/mcp/tools/create-task.js +75 -13
- package/dist/mcp/tools/deactivate-behavior.js +33 -24
- package/dist/mcp/tools/list-tasks.js +21 -4
- package/dist/mcp/tools/send-message.js +21 -4
- package/dist/mcp/tools/update-task.js +390 -91
- package/dist/runtime/index.js +446 -101
- package/dist/tui/App.js +208 -54
- package/package.json +1 -1
package/dist/bin/exe-call.js
CHANGED
|
@@ -290,11 +290,17 @@ var init_platform_procedures = __esm({
|
|
|
290
290
|
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."
|
|
291
291
|
},
|
|
292
292
|
{
|
|
293
|
-
title: "
|
|
293
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
294
294
|
domain: "workflow",
|
|
295
295
|
priority: "p1",
|
|
296
296
|
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."
|
|
297
297
|
},
|
|
298
|
+
{
|
|
299
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
300
|
+
domain: "identity",
|
|
301
|
+
priority: "p0",
|
|
302
|
+
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."
|
|
303
|
+
},
|
|
298
304
|
{
|
|
299
305
|
title: "Single dispatch path \u2014 create_task only",
|
|
300
306
|
domain: "workflow",
|
|
@@ -328,6 +334,12 @@ var init_platform_procedures = __esm({
|
|
|
328
334
|
priority: "p0",
|
|
329
335
|
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."
|
|
330
336
|
},
|
|
337
|
+
{
|
|
338
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
339
|
+
domain: "security",
|
|
340
|
+
priority: "p0",
|
|
341
|
+
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."
|
|
342
|
+
},
|
|
331
343
|
{
|
|
332
344
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
333
345
|
domain: "support",
|
|
@@ -573,9 +585,23 @@ __export(employee_templates_exports, {
|
|
|
573
585
|
function getSessionPrompt(storedPrompt) {
|
|
574
586
|
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
575
587
|
const withoutProcedures = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
588
|
+
let titlePrefix = "";
|
|
589
|
+
const frontmatterMatch = withoutProcedures.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
590
|
+
if (frontmatterMatch) {
|
|
591
|
+
const titleMatch = frontmatterMatch[1].match(/^title:\s*(.+)$/m);
|
|
592
|
+
const roleMatch = frontmatterMatch[1].match(/^role:\s*(.+)$/m);
|
|
593
|
+
if (titleMatch) {
|
|
594
|
+
const title = titleMatch[1].trim();
|
|
595
|
+
const role = roleMatch ? roleMatch[1].trim() : "";
|
|
596
|
+
if (title && role && title.toLowerCase() !== role.toLowerCase()) {
|
|
597
|
+
titlePrefix = `## Your Identity
|
|
598
|
+
You are **${title}** (specialist). `;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
576
602
|
const rolePrompt = withoutProcedures.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").replace(/<!--[\s\S]*?-->/g, "").trimStart();
|
|
577
603
|
const globalBlock = getGlobalProceduresBlock();
|
|
578
|
-
return `${globalBlock}${rolePrompt}
|
|
604
|
+
return `${globalBlock}${titlePrefix}${rolePrompt}
|
|
579
605
|
${BASE_OPERATING_PROCEDURES}`;
|
|
580
606
|
}
|
|
581
607
|
function buildCustomEmployeePrompt(name, role) {
|
|
@@ -594,7 +620,7 @@ function personalizePrompt(prompt, templateName, actualName) {
|
|
|
594
620
|
return prompt.replace(new RegExp(`\\bYou are ${escaped}\\b`, "g"), `You are ${actualName}`);
|
|
595
621
|
}
|
|
596
622
|
function renderClientCOOTemplate(vars) {
|
|
597
|
-
const resolved = { ...vars, title: vars.title || "Chief
|
|
623
|
+
const resolved = { ...vars, title: vars.title || "Chief of Staff" };
|
|
598
624
|
for (const key of CLIENT_COO_PLACEHOLDERS) {
|
|
599
625
|
const value = resolved[key];
|
|
600
626
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -1238,6 +1264,7 @@ __export(agent_config_exports, {
|
|
|
1238
1264
|
getAgentRuntime: () => getAgentRuntime,
|
|
1239
1265
|
loadAgentConfig: () => loadAgentConfig,
|
|
1240
1266
|
saveAgentConfig: () => saveAgentConfig,
|
|
1267
|
+
setAgentMcps: () => setAgentMcps,
|
|
1241
1268
|
setAgentRuntime: () => setAgentRuntime
|
|
1242
1269
|
});
|
|
1243
1270
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
|
|
@@ -1264,7 +1291,7 @@ function getAgentRuntime(agentId) {
|
|
|
1264
1291
|
if (orgDefault) return orgDefault;
|
|
1265
1292
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
1266
1293
|
}
|
|
1267
|
-
function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
1294
|
+
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
1268
1295
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
1269
1296
|
if (!knownModels) {
|
|
1270
1297
|
return {
|
|
@@ -1279,12 +1306,26 @@ function setAgentRuntime(agentId, runtime, model, reasoning_effort) {
|
|
|
1279
1306
|
};
|
|
1280
1307
|
}
|
|
1281
1308
|
const config = loadAgentConfig();
|
|
1309
|
+
const existing = config[agentId];
|
|
1282
1310
|
const entry = { runtime, model };
|
|
1283
1311
|
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
1312
|
+
if (mcps !== void 0) {
|
|
1313
|
+
entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
1314
|
+
} else if (existing?.mcps) {
|
|
1315
|
+
entry.mcps = existing.mcps;
|
|
1316
|
+
}
|
|
1284
1317
|
config[agentId] = entry;
|
|
1285
1318
|
saveAgentConfig(config);
|
|
1286
1319
|
return { ok: true };
|
|
1287
1320
|
}
|
|
1321
|
+
function setAgentMcps(agentId, mcps) {
|
|
1322
|
+
const config = loadAgentConfig();
|
|
1323
|
+
const existing = config[agentId] ?? getAgentRuntime(agentId);
|
|
1324
|
+
existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
1325
|
+
config[agentId] = existing;
|
|
1326
|
+
saveAgentConfig(config);
|
|
1327
|
+
return { ok: true };
|
|
1328
|
+
}
|
|
1288
1329
|
function clearAgentRuntime(agentId) {
|
|
1289
1330
|
const config = loadAgentConfig();
|
|
1290
1331
|
delete config[agentId];
|
package/dist/bin/exe-cloud.js
CHANGED
|
@@ -3772,6 +3772,22 @@ async function ensureSchema() {
|
|
|
3772
3772
|
} catch (e) {
|
|
3773
3773
|
logCatchDebug("migration", e);
|
|
3774
3774
|
}
|
|
3775
|
+
try {
|
|
3776
|
+
await client.execute({
|
|
3777
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3778
|
+
args: []
|
|
3779
|
+
});
|
|
3780
|
+
} catch (e) {
|
|
3781
|
+
logCatchDebug("migration", e);
|
|
3782
|
+
}
|
|
3783
|
+
try {
|
|
3784
|
+
await client.execute({
|
|
3785
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3786
|
+
args: []
|
|
3787
|
+
});
|
|
3788
|
+
} catch (e) {
|
|
3789
|
+
logCatchDebug("migration", e);
|
|
3790
|
+
}
|
|
3775
3791
|
}
|
|
3776
3792
|
async function disposeDatabase() {
|
|
3777
3793
|
if (_walCheckpointTimer) {
|
|
@@ -4269,7 +4285,7 @@ async function assertVpsLicense(opts) {
|
|
|
4269
4285
|
}
|
|
4270
4286
|
if (!transientFailure) {
|
|
4271
4287
|
throw new Error(
|
|
4272
|
-
"License validation failed: unknown backend state. Restore network connectivity to https://askexe.com
|
|
4288
|
+
"License validation failed: unknown backend state. Restore network connectivity to https://cloud.askexe.com and retry."
|
|
4273
4289
|
);
|
|
4274
4290
|
}
|
|
4275
4291
|
const fresh = await getCachedLicense();
|
|
@@ -4306,7 +4322,7 @@ async function assertVpsLicense(opts) {
|
|
|
4306
4322
|
} catch {
|
|
4307
4323
|
}
|
|
4308
4324
|
throw new Error(
|
|
4309
|
-
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com
|
|
4325
|
+
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://cloud.askexe.com and retry. This VPS image refuses to boot after the offline grace window.`
|
|
4310
4326
|
);
|
|
4311
4327
|
}
|
|
4312
4328
|
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
@@ -4338,7 +4354,7 @@ var init_license = __esm({
|
|
|
4338
4354
|
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
4339
4355
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
4340
4356
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
4341
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
4357
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
4342
4358
|
RETRY_DELAY_MS = 500;
|
|
4343
4359
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
4344
4360
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
@@ -5141,6 +5157,27 @@ async function cloudSync(config) {
|
|
|
5141
5157
|
if (stmts.length > 0) await client.batch(stmts, "write");
|
|
5142
5158
|
pulled = pullResult.records.length;
|
|
5143
5159
|
} else {
|
|
5160
|
+
try {
|
|
5161
|
+
const incomingIds = pullResult.records.map((r) => sqlSafe(r.id));
|
|
5162
|
+
if (incomingIds.length > 0) {
|
|
5163
|
+
const ph = incomingIds.map(() => "?").join(",");
|
|
5164
|
+
const existing = await client.execute({
|
|
5165
|
+
sql: `SELECT id, version, timestamp FROM memories WHERE id IN (${ph})`,
|
|
5166
|
+
args: incomingIds
|
|
5167
|
+
});
|
|
5168
|
+
const localMap = new Map(existing.rows.map((r) => [String(r.id), r]));
|
|
5169
|
+
for (const rec of pullResult.records) {
|
|
5170
|
+
const local = localMap.get(String(rec.id));
|
|
5171
|
+
if (local && Number(local.version) > 0 && Number(local.version) !== Number(rec.version ?? 0)) {
|
|
5172
|
+
process.stderr.write(
|
|
5173
|
+
`[cloud-sync] CONFLICT: memory ${String(rec.id).slice(0, 8)} \u2014 local v${local.version} vs remote v${rec.version ?? 0}. Remote wins (LWW).
|
|
5174
|
+
`
|
|
5175
|
+
);
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
}
|
|
5179
|
+
} catch {
|
|
5180
|
+
}
|
|
5144
5181
|
const stmts = pullResult.records.map((rec) => ({
|
|
5145
5182
|
sql: `INSERT OR REPLACE INTO memories
|
|
5146
5183
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
@@ -6898,11 +6935,17 @@ var init_platform_procedures = __esm({
|
|
|
6898
6935
|
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."
|
|
6899
6936
|
},
|
|
6900
6937
|
{
|
|
6901
|
-
title: "
|
|
6938
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
6902
6939
|
domain: "workflow",
|
|
6903
6940
|
priority: "p1",
|
|
6904
6941
|
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."
|
|
6905
6942
|
},
|
|
6943
|
+
{
|
|
6944
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
6945
|
+
domain: "identity",
|
|
6946
|
+
priority: "p0",
|
|
6947
|
+
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."
|
|
6948
|
+
},
|
|
6906
6949
|
{
|
|
6907
6950
|
title: "Single dispatch path \u2014 create_task only",
|
|
6908
6951
|
domain: "workflow",
|
|
@@ -6936,6 +6979,12 @@ var init_platform_procedures = __esm({
|
|
|
6936
6979
|
priority: "p0",
|
|
6937
6980
|
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."
|
|
6938
6981
|
},
|
|
6982
|
+
{
|
|
6983
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
6984
|
+
domain: "security",
|
|
6985
|
+
priority: "p0",
|
|
6986
|
+
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."
|
|
6987
|
+
},
|
|
6939
6988
|
{
|
|
6940
6989
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
6941
6990
|
domain: "support",
|
|
@@ -7221,10 +7270,24 @@ function stableId(memoryId, type, content) {
|
|
|
7221
7270
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
7222
7271
|
}
|
|
7223
7272
|
function cleanText(text) {
|
|
7224
|
-
|
|
7273
|
+
let cleaned = text.replace(
|
|
7274
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
7275
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
7276
|
+
);
|
|
7277
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
7278
|
+
return cleaned;
|
|
7225
7279
|
}
|
|
7226
|
-
function
|
|
7227
|
-
|
|
7280
|
+
function splitSegments(text) {
|
|
7281
|
+
const cleaned = cleanText(text);
|
|
7282
|
+
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);
|
|
7283
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
7284
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
7285
|
+
if (lines.length > 0) return lines;
|
|
7286
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
7287
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
7288
|
+
}
|
|
7289
|
+
}
|
|
7290
|
+
return segments;
|
|
7228
7291
|
}
|
|
7229
7292
|
function inferCardType(sentence, toolName) {
|
|
7230
7293
|
const lower = sentence.toLowerCase();
|
|
@@ -7256,12 +7319,12 @@ function predicateFor(type) {
|
|
|
7256
7319
|
}
|
|
7257
7320
|
}
|
|
7258
7321
|
function extractMemoryCards(row) {
|
|
7259
|
-
const
|
|
7322
|
+
const segments = splitSegments(row.raw_text);
|
|
7260
7323
|
const cards = [];
|
|
7261
|
-
for (const sentence of
|
|
7324
|
+
for (const sentence of segments) {
|
|
7262
7325
|
const type = inferCardType(sentence, row.tool_name);
|
|
7263
7326
|
const subject = extractSubject(sentence, row.agent_id);
|
|
7264
|
-
const content = sentence.length >
|
|
7327
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
7265
7328
|
cards.push({
|
|
7266
7329
|
id: stableId(row.id, type, content),
|
|
7267
7330
|
memory_id: row.id,
|
|
@@ -7357,13 +7420,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
7357
7420
|
last_accessed: String(row.timestamp)
|
|
7358
7421
|
}));
|
|
7359
7422
|
}
|
|
7360
|
-
var MAX_CARDS_PER_MEMORY,
|
|
7423
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
7361
7424
|
var init_memory_cards = __esm({
|
|
7362
7425
|
"src/lib/memory-cards.ts"() {
|
|
7363
7426
|
"use strict";
|
|
7364
7427
|
init_database();
|
|
7365
|
-
MAX_CARDS_PER_MEMORY =
|
|
7366
|
-
|
|
7428
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
7429
|
+
MAX_SEGMENT_CHARS = 500;
|
|
7430
|
+
MIN_SEGMENT_CHARS = 20;
|
|
7367
7431
|
}
|
|
7368
7432
|
});
|
|
7369
7433
|
|
|
@@ -8486,7 +8550,7 @@ async function setupMode() {
|
|
|
8486
8550
|
rl.close();
|
|
8487
8551
|
return;
|
|
8488
8552
|
}
|
|
8489
|
-
const endpoint = await ask(rl, " Endpoint [https://askexe.com
|
|
8553
|
+
const endpoint = await ask(rl, " Endpoint [https://cloud.askexe.com]: ") || "https://cloud.askexe.com";
|
|
8490
8554
|
console.log(" Validating...");
|
|
8491
8555
|
try {
|
|
8492
8556
|
assertSecureEndpoint(endpoint);
|
|
@@ -8552,6 +8616,14 @@ async function setupMode() {
|
|
|
8552
8616
|
}
|
|
8553
8617
|
console.log("");
|
|
8554
8618
|
}
|
|
8619
|
+
try {
|
|
8620
|
+
const keyInfo = await getKeyStorageInfo();
|
|
8621
|
+
if (keyInfo.kind !== "missing") {
|
|
8622
|
+
console.log(` \u2713 Encryption key: ${keyInfo.note}`);
|
|
8623
|
+
}
|
|
8624
|
+
} catch {
|
|
8625
|
+
}
|
|
8626
|
+
console.log("");
|
|
8555
8627
|
console.log(BAR);
|
|
8556
8628
|
console.log(latestConfig.cloud?.apiKey ? " Setup complete. Cloud sync is connected." : " Setup complete. Cloud sync is not configured yet.");
|
|
8557
8629
|
console.log(BAR);
|
|
@@ -8643,7 +8715,13 @@ async function statusMode() {
|
|
|
8643
8715
|
console.log("");
|
|
8644
8716
|
if (key) {
|
|
8645
8717
|
const fingerprint = key.toString("hex").slice(0, 8);
|
|
8646
|
-
|
|
8718
|
+
let storageNote = "";
|
|
8719
|
+
try {
|
|
8720
|
+
const keyInfo = await getKeyStorageInfo();
|
|
8721
|
+
if (keyInfo.kind !== "missing") storageNote = ` [${keyInfo.note}]`;
|
|
8722
|
+
} catch {
|
|
8723
|
+
}
|
|
8724
|
+
console.log(` Encryption key: \u2713 present (${fingerprint}...)${storageNote}`);
|
|
8647
8725
|
} else {
|
|
8648
8726
|
console.log(" Encryption key: \u2717 not found \u2014 run /exe-setup");
|
|
8649
8727
|
}
|