@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-status.js
CHANGED
|
@@ -3271,6 +3271,22 @@ async function ensureSchema() {
|
|
|
3271
3271
|
} catch (e) {
|
|
3272
3272
|
logCatchDebug("migration", e);
|
|
3273
3273
|
}
|
|
3274
|
+
try {
|
|
3275
|
+
await client.execute({
|
|
3276
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3277
|
+
args: []
|
|
3278
|
+
});
|
|
3279
|
+
} catch (e) {
|
|
3280
|
+
logCatchDebug("migration", e);
|
|
3281
|
+
}
|
|
3282
|
+
try {
|
|
3283
|
+
await client.execute({
|
|
3284
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3285
|
+
args: []
|
|
3286
|
+
});
|
|
3287
|
+
} catch (e) {
|
|
3288
|
+
logCatchDebug("migration", e);
|
|
3289
|
+
}
|
|
3274
3290
|
}
|
|
3275
3291
|
async function disposeDatabase() {
|
|
3276
3292
|
if (_walCheckpointTimer) {
|
|
@@ -4394,11 +4410,17 @@ var init_platform_procedures = __esm({
|
|
|
4394
4410
|
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."
|
|
4395
4411
|
},
|
|
4396
4412
|
{
|
|
4397
|
-
title: "
|
|
4413
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4398
4414
|
domain: "workflow",
|
|
4399
4415
|
priority: "p1",
|
|
4400
4416
|
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."
|
|
4401
4417
|
},
|
|
4418
|
+
{
|
|
4419
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
4420
|
+
domain: "identity",
|
|
4421
|
+
priority: "p0",
|
|
4422
|
+
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."
|
|
4423
|
+
},
|
|
4402
4424
|
{
|
|
4403
4425
|
title: "Single dispatch path \u2014 create_task only",
|
|
4404
4426
|
domain: "workflow",
|
|
@@ -4432,6 +4454,12 @@ var init_platform_procedures = __esm({
|
|
|
4432
4454
|
priority: "p0",
|
|
4433
4455
|
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."
|
|
4434
4456
|
},
|
|
4457
|
+
{
|
|
4458
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
4459
|
+
domain: "security",
|
|
4460
|
+
priority: "p0",
|
|
4461
|
+
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."
|
|
4462
|
+
},
|
|
4435
4463
|
{
|
|
4436
4464
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4437
4465
|
domain: "support",
|
|
@@ -4717,10 +4745,24 @@ function stableId(memoryId, type, content) {
|
|
|
4717
4745
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4718
4746
|
}
|
|
4719
4747
|
function cleanText(text) {
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4748
|
+
let cleaned = text.replace(
|
|
4749
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
4750
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
4751
|
+
);
|
|
4752
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4753
|
+
return cleaned;
|
|
4754
|
+
}
|
|
4755
|
+
function splitSegments(text) {
|
|
4756
|
+
const cleaned = cleanText(text);
|
|
4757
|
+
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);
|
|
4758
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4759
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
4760
|
+
if (lines.length > 0) return lines;
|
|
4761
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4762
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
return segments;
|
|
4724
4766
|
}
|
|
4725
4767
|
function inferCardType(sentence, toolName) {
|
|
4726
4768
|
const lower = sentence.toLowerCase();
|
|
@@ -4752,12 +4794,12 @@ function predicateFor(type) {
|
|
|
4752
4794
|
}
|
|
4753
4795
|
}
|
|
4754
4796
|
function extractMemoryCards(row) {
|
|
4755
|
-
const
|
|
4797
|
+
const segments = splitSegments(row.raw_text);
|
|
4756
4798
|
const cards = [];
|
|
4757
|
-
for (const sentence of
|
|
4799
|
+
for (const sentence of segments) {
|
|
4758
4800
|
const type = inferCardType(sentence, row.tool_name);
|
|
4759
4801
|
const subject = extractSubject(sentence, row.agent_id);
|
|
4760
|
-
const content = sentence.length >
|
|
4802
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
4761
4803
|
cards.push({
|
|
4762
4804
|
id: stableId(row.id, type, content),
|
|
4763
4805
|
memory_id: row.id,
|
|
@@ -4853,13 +4895,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
4853
4895
|
last_accessed: String(row.timestamp)
|
|
4854
4896
|
}));
|
|
4855
4897
|
}
|
|
4856
|
-
var MAX_CARDS_PER_MEMORY,
|
|
4898
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
4857
4899
|
var init_memory_cards = __esm({
|
|
4858
4900
|
"src/lib/memory-cards.ts"() {
|
|
4859
4901
|
"use strict";
|
|
4860
4902
|
init_database();
|
|
4861
|
-
MAX_CARDS_PER_MEMORY =
|
|
4862
|
-
|
|
4903
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
4904
|
+
MAX_SEGMENT_CHARS = 500;
|
|
4905
|
+
MIN_SEGMENT_CHARS = 20;
|
|
4863
4906
|
}
|
|
4864
4907
|
});
|
|
4865
4908
|
|
|
@@ -6094,7 +6137,7 @@ var init_license = __esm({
|
|
|
6094
6137
|
LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
|
|
6095
6138
|
CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
6096
6139
|
DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
|
|
6097
|
-
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
6140
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
6098
6141
|
}
|
|
6099
6142
|
});
|
|
6100
6143
|
|
|
@@ -6147,6 +6190,18 @@ function extractRootExe(name) {
|
|
|
6147
6190
|
const parts = name.split("-").filter(Boolean);
|
|
6148
6191
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
6149
6192
|
}
|
|
6193
|
+
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
6194
|
+
if (!existsSync14(SESSION_CACHE)) {
|
|
6195
|
+
mkdirSync7(SESSION_CACHE, { recursive: true });
|
|
6196
|
+
}
|
|
6197
|
+
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
6198
|
+
const filePath = path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
6199
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
6200
|
+
parentExe: rootExe,
|
|
6201
|
+
dispatchedBy: dispatchedBy || rootExe,
|
|
6202
|
+
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6203
|
+
}));
|
|
6204
|
+
}
|
|
6150
6205
|
function getParentExe(sessionKey) {
|
|
6151
6206
|
try {
|
|
6152
6207
|
const data = JSON.parse(readFileSync9(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
@@ -6156,11 +6211,12 @@ function getParentExe(sessionKey) {
|
|
|
6156
6211
|
}
|
|
6157
6212
|
}
|
|
6158
6213
|
function resolveExeSession() {
|
|
6214
|
+
if (process.env.EXE_SESSION_NAME) {
|
|
6215
|
+
const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
6216
|
+
if (fromEnv) return fromEnv;
|
|
6217
|
+
}
|
|
6159
6218
|
const mySession = getMySession();
|
|
6160
6219
|
if (!mySession) {
|
|
6161
|
-
if (process.env.EXE_SESSION_NAME) {
|
|
6162
|
-
return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
|
|
6163
|
-
}
|
|
6164
6220
|
return null;
|
|
6165
6221
|
}
|
|
6166
6222
|
const fromSessionName = extractRootExe(mySession);
|
|
@@ -6175,6 +6231,10 @@ function resolveExeSession() {
|
|
|
6175
6231
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
6176
6232
|
`
|
|
6177
6233
|
);
|
|
6234
|
+
try {
|
|
6235
|
+
registerParentExe(key, fromSessionName);
|
|
6236
|
+
} catch {
|
|
6237
|
+
}
|
|
6178
6238
|
candidate = fromSessionName;
|
|
6179
6239
|
} else {
|
|
6180
6240
|
candidate = fromCache;
|
package/dist/bin/exe-support.js
CHANGED
|
@@ -232,7 +232,7 @@ import { jwtVerify, importSPKI } from "jose";
|
|
|
232
232
|
var LICENSE_PATH = path2.join(EXE_AI_DIR, "license.key");
|
|
233
233
|
var CACHE_PATH = path2.join(EXE_AI_DIR, "license-cache.json");
|
|
234
234
|
var DEVICE_ID_PATH = path2.join(EXE_AI_DIR, "device-id");
|
|
235
|
-
var API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com
|
|
235
|
+
var API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
|
|
236
236
|
function loadLicense() {
|
|
237
237
|
try {
|
|
238
238
|
if (!existsSync3(LICENSE_PATH)) return null;
|
package/dist/bin/exe-team.js
CHANGED
|
@@ -3260,6 +3260,22 @@ async function ensureSchema() {
|
|
|
3260
3260
|
} catch (e) {
|
|
3261
3261
|
logCatchDebug("migration", e);
|
|
3262
3262
|
}
|
|
3263
|
+
try {
|
|
3264
|
+
await client.execute({
|
|
3265
|
+
sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
|
|
3266
|
+
args: []
|
|
3267
|
+
});
|
|
3268
|
+
} catch (e) {
|
|
3269
|
+
logCatchDebug("migration", e);
|
|
3270
|
+
}
|
|
3271
|
+
try {
|
|
3272
|
+
await client.execute({
|
|
3273
|
+
sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
|
|
3274
|
+
args: []
|
|
3275
|
+
});
|
|
3276
|
+
} catch (e) {
|
|
3277
|
+
logCatchDebug("migration", e);
|
|
3278
|
+
}
|
|
3263
3279
|
}
|
|
3264
3280
|
async function disposeDatabase() {
|
|
3265
3281
|
if (_walCheckpointTimer) {
|
|
@@ -4383,11 +4399,17 @@ var init_platform_procedures = __esm({
|
|
|
4383
4399
|
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."
|
|
4384
4400
|
},
|
|
4385
4401
|
{
|
|
4386
|
-
title: "
|
|
4402
|
+
title: "Orchestration phase guidance \u2014 recommend, never trap",
|
|
4387
4403
|
domain: "workflow",
|
|
4388
4404
|
priority: "p1",
|
|
4389
4405
|
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."
|
|
4390
4406
|
},
|
|
4407
|
+
{
|
|
4408
|
+
title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
|
|
4409
|
+
domain: "identity",
|
|
4410
|
+
priority: "p0",
|
|
4411
|
+
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."
|
|
4412
|
+
},
|
|
4391
4413
|
{
|
|
4392
4414
|
title: "Single dispatch path \u2014 create_task only",
|
|
4393
4415
|
domain: "workflow",
|
|
@@ -4421,6 +4443,12 @@ var init_platform_procedures = __esm({
|
|
|
4421
4443
|
priority: "p0",
|
|
4422
4444
|
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."
|
|
4423
4445
|
},
|
|
4446
|
+
{
|
|
4447
|
+
title: "Destructive operations \u2014 mandatory reviewer gate",
|
|
4448
|
+
domain: "security",
|
|
4449
|
+
priority: "p0",
|
|
4450
|
+
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."
|
|
4451
|
+
},
|
|
4424
4452
|
{
|
|
4425
4453
|
title: "Customer patch triage \u2014 upstream bug vs customization",
|
|
4426
4454
|
domain: "support",
|
|
@@ -4706,10 +4734,24 @@ function stableId(memoryId, type, content) {
|
|
|
4706
4734
|
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4707
4735
|
}
|
|
4708
4736
|
function cleanText(text) {
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4737
|
+
let cleaned = text.replace(
|
|
4738
|
+
/```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
|
|
4739
|
+
(_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
|
|
4740
|
+
);
|
|
4741
|
+
cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4742
|
+
return cleaned;
|
|
4743
|
+
}
|
|
4744
|
+
function splitSegments(text) {
|
|
4745
|
+
const cleaned = cleanText(text);
|
|
4746
|
+
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);
|
|
4747
|
+
if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4748
|
+
const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
|
|
4749
|
+
if (lines.length > 0) return lines;
|
|
4750
|
+
if (cleaned.length >= MIN_SEGMENT_CHARS) {
|
|
4751
|
+
return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
return segments;
|
|
4713
4755
|
}
|
|
4714
4756
|
function inferCardType(sentence, toolName) {
|
|
4715
4757
|
const lower = sentence.toLowerCase();
|
|
@@ -4741,12 +4783,12 @@ function predicateFor(type) {
|
|
|
4741
4783
|
}
|
|
4742
4784
|
}
|
|
4743
4785
|
function extractMemoryCards(row) {
|
|
4744
|
-
const
|
|
4786
|
+
const segments = splitSegments(row.raw_text);
|
|
4745
4787
|
const cards = [];
|
|
4746
|
-
for (const sentence of
|
|
4788
|
+
for (const sentence of segments) {
|
|
4747
4789
|
const type = inferCardType(sentence, row.tool_name);
|
|
4748
4790
|
const subject = extractSubject(sentence, row.agent_id);
|
|
4749
|
-
const content = sentence.length >
|
|
4791
|
+
const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
|
|
4750
4792
|
cards.push({
|
|
4751
4793
|
id: stableId(row.id, type, content),
|
|
4752
4794
|
memory_id: row.id,
|
|
@@ -4842,13 +4884,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
|
4842
4884
|
last_accessed: String(row.timestamp)
|
|
4843
4885
|
}));
|
|
4844
4886
|
}
|
|
4845
|
-
var MAX_CARDS_PER_MEMORY,
|
|
4887
|
+
var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
|
|
4846
4888
|
var init_memory_cards = __esm({
|
|
4847
4889
|
"src/lib/memory-cards.ts"() {
|
|
4848
4890
|
"use strict";
|
|
4849
4891
|
init_database();
|
|
4850
|
-
MAX_CARDS_PER_MEMORY =
|
|
4851
|
-
|
|
4892
|
+
MAX_CARDS_PER_MEMORY = 8;
|
|
4893
|
+
MAX_SEGMENT_CHARS = 500;
|
|
4894
|
+
MIN_SEGMENT_CHARS = 20;
|
|
4852
4895
|
}
|
|
4853
4896
|
});
|
|
4854
4897
|
|