@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.
Files changed (95) hide show
  1. package/README.md +9 -7
  2. package/dist/bin/agentic-ontology-backfill.js +54 -11
  3. package/dist/bin/agentic-reflection-backfill.js +29 -1
  4. package/dist/bin/agentic-semantic-label.js +29 -1
  5. package/dist/bin/backfill-conversations.js +53 -10
  6. package/dist/bin/backfill-responses.js +54 -11
  7. package/dist/bin/backfill-vectors.js +29 -1
  8. package/dist/bin/bulk-sync-postgres.js +55 -12
  9. package/dist/bin/cleanup-stale-review-tasks.js +75 -15
  10. package/dist/bin/cli.js +293 -76
  11. package/dist/bin/exe-agent-config.js +7 -1
  12. package/dist/bin/exe-agent.js +28 -2
  13. package/dist/bin/exe-assign.js +54 -11
  14. package/dist/bin/exe-boot.js +481 -147
  15. package/dist/bin/exe-call.js +45 -4
  16. package/dist/bin/exe-cloud.js +93 -15
  17. package/dist/bin/exe-dispatch.js +369 -24
  18. package/dist/bin/exe-doctor.js +53 -10
  19. package/dist/bin/exe-export-behaviors.js +54 -11
  20. package/dist/bin/exe-forget.js +54 -11
  21. package/dist/bin/exe-gateway.js +128 -23
  22. package/dist/bin/exe-heartbeat.js +75 -15
  23. package/dist/bin/exe-kill.js +54 -11
  24. package/dist/bin/exe-launch-agent.js +70 -12
  25. package/dist/bin/exe-new-employee.js +175 -7
  26. package/dist/bin/exe-pending-messages.js +75 -15
  27. package/dist/bin/exe-pending-notifications.js +75 -15
  28. package/dist/bin/exe-pending-reviews.js +75 -15
  29. package/dist/bin/exe-rename.js +54 -11
  30. package/dist/bin/exe-review.js +54 -11
  31. package/dist/bin/exe-search.js +54 -11
  32. package/dist/bin/exe-session-cleanup.js +491 -146
  33. package/dist/bin/exe-settings.js +10 -4
  34. package/dist/bin/exe-start-codex.js +524 -245
  35. package/dist/bin/exe-start-opencode.js +534 -165
  36. package/dist/bin/exe-status.js +75 -15
  37. package/dist/bin/exe-support.js +1 -1
  38. package/dist/bin/exe-team.js +54 -11
  39. package/dist/bin/git-sweep.js +369 -24
  40. package/dist/bin/graph-backfill.js +54 -11
  41. package/dist/bin/graph-export.js +54 -11
  42. package/dist/bin/install.js +62 -4
  43. package/dist/bin/intercom-check.js +491 -146
  44. package/dist/bin/pre-publish.js +13 -1
  45. package/dist/bin/scan-tasks.js +369 -24
  46. package/dist/bin/setup.js +91 -13
  47. package/dist/bin/shard-migrate.js +54 -11
  48. package/dist/bin/stack-update.js +1 -1
  49. package/dist/bin/update.js +3 -3
  50. package/dist/gateway/index.js +128 -23
  51. package/dist/hooks/bug-report-worker.js +128 -23
  52. package/dist/hooks/codex-stop-task-finalizer.js +512 -140
  53. package/dist/hooks/commit-complete.js +369 -24
  54. package/dist/hooks/error-recall.js +54 -11
  55. package/dist/hooks/ingest.js +4575 -252
  56. package/dist/hooks/instructions-loaded.js +54 -11
  57. package/dist/hooks/notification.js +54 -11
  58. package/dist/hooks/post-compact.js +75 -15
  59. package/dist/hooks/post-tool-combined.js +75 -15
  60. package/dist/hooks/pre-compact.js +449 -104
  61. package/dist/hooks/pre-tool-use.js +90 -15
  62. package/dist/hooks/prompt-submit.js +129 -24
  63. package/dist/hooks/session-end.js +451 -109
  64. package/dist/hooks/session-start.js +104 -16
  65. package/dist/hooks/stop.js +74 -14
  66. package/dist/hooks/subagent-stop.js +75 -15
  67. package/dist/hooks/summary-worker.js +73 -7
  68. package/dist/index.js +128 -23
  69. package/dist/lib/agent-config.js +16 -1
  70. package/dist/lib/cloud-sync.js +38 -1
  71. package/dist/lib/consolidation.js +16 -1
  72. package/dist/lib/database.js +16 -0
  73. package/dist/lib/db.js +16 -0
  74. package/dist/lib/device-registry.js +16 -0
  75. package/dist/lib/employee-templates.js +29 -3
  76. package/dist/lib/employees.js +16 -1
  77. package/dist/lib/exe-daemon.js +268 -42
  78. package/dist/lib/hybrid-search.js +54 -11
  79. package/dist/lib/license.js +3 -3
  80. package/dist/lib/messaging.js +21 -4
  81. package/dist/lib/schedules.js +29 -1
  82. package/dist/lib/skill-learning.js +458 -70
  83. package/dist/lib/status-brief.js +14 -1
  84. package/dist/lib/store.js +54 -11
  85. package/dist/lib/tasks.js +393 -91
  86. package/dist/lib/tmux-routing.js +316 -14
  87. package/dist/mcp/server.js +169 -30
  88. package/dist/mcp/tools/create-task.js +75 -13
  89. package/dist/mcp/tools/deactivate-behavior.js +33 -24
  90. package/dist/mcp/tools/list-tasks.js +21 -4
  91. package/dist/mcp/tools/send-message.js +21 -4
  92. package/dist/mcp/tools/update-task.js +390 -91
  93. package/dist/runtime/index.js +446 -101
  94. package/dist/tui/App.js +208 -54
  95. package/package.json +1 -1
@@ -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: "Customer orchestration maturity \u2014 recommend, never trap",
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 Operating Officer" };
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];
@@ -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/cloud and retry."
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/cloud and retry. This VPS image refuses to boot after the offline grace window.`
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/cloud";
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: "Customer orchestration maturity \u2014 recommend, never trap",
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
- return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
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 splitSentences(text) {
7227
- return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
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 sentences = splitSentences(row.raw_text);
7322
+ const segments = splitSegments(row.raw_text);
7260
7323
  const cards = [];
7261
- for (const sentence of sentences) {
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 > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
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, MAX_SENTENCE_CHARS;
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 = 6;
7366
- MAX_SENTENCE_CHARS = 360;
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/cloud]: ") || "https://askexe.com/cloud";
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
- console.log(` Encryption key: \u2713 present (${fingerprint}...)`);
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
  }