@askexenow/exe-os 0.9.61 → 0.9.63
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/deploy/stack-manifests/v0.9.json +62 -13
- package/dist/bin/backfill-conversations.js +210 -2
- package/dist/bin/backfill-responses.js +210 -2
- package/dist/bin/backfill-vectors.js +47 -2
- package/dist/bin/cleanup-stale-review-tasks.js +210 -2
- package/dist/bin/cli.js +488 -25
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +2 -2
- package/dist/bin/exe-assign.js +210 -2
- package/dist/bin/exe-boot.js +47 -2
- package/dist/bin/exe-call.js +2 -2
- package/dist/bin/exe-cloud.js +2 -2
- package/dist/bin/exe-dispatch.js +210 -2
- package/dist/bin/exe-doctor.js +2691 -1212
- package/dist/bin/exe-export-behaviors.js +210 -2
- package/dist/bin/exe-forget.js +264 -2
- package/dist/bin/exe-gateway.js +210 -2
- package/dist/bin/exe-heartbeat.js +212 -4
- package/dist/bin/exe-kill.js +210 -2
- package/dist/bin/exe-launch-agent.js +210 -2
- package/dist/bin/exe-link.js +47 -2
- package/dist/bin/exe-new-employee.js +113 -3
- package/dist/bin/exe-pending-messages.js +210 -2
- package/dist/bin/exe-pending-notifications.js +210 -2
- package/dist/bin/exe-pending-reviews.js +210 -2
- package/dist/bin/exe-rename.js +210 -2
- package/dist/bin/exe-review.js +210 -2
- package/dist/bin/exe-search.js +234 -3
- package/dist/bin/exe-session-cleanup.js +210 -2
- package/dist/bin/exe-settings.js +2 -2
- package/dist/bin/exe-start-codex.js +322 -4
- package/dist/bin/exe-start-opencode.js +336 -4
- package/dist/bin/exe-status.js +210 -2
- package/dist/bin/exe-team.js +210 -2
- package/dist/bin/git-sweep.js +210 -2
- package/dist/bin/graph-backfill.js +210 -2
- package/dist/bin/graph-export.js +210 -2
- package/dist/bin/install.js +113 -3
- package/dist/bin/intercom-check.js +210 -2
- package/dist/bin/scan-tasks.js +210 -2
- package/dist/bin/setup.js +47 -2
- package/dist/bin/shard-migrate.js +210 -2
- package/dist/bin/stack-update.js +158 -13
- package/dist/bin/update.js +2 -2
- package/dist/gateway/index.js +210 -2
- package/dist/hooks/bug-report-worker.js +321 -44
- package/dist/hooks/codex-stop-task-finalizer.js +210 -2
- package/dist/hooks/commit-complete.js +210 -2
- package/dist/hooks/error-recall.js +234 -3
- package/dist/hooks/exe-heartbeat-hook.js +2 -2
- package/dist/hooks/ingest-worker.js +2 -2
- package/dist/hooks/ingest.js +210 -2
- package/dist/hooks/instructions-loaded.js +210 -2
- package/dist/hooks/notification.js +210 -2
- package/dist/hooks/post-compact.js +210 -2
- package/dist/hooks/post-tool-combined.js +234 -3
- package/dist/hooks/pre-compact.js +446 -111
- package/dist/hooks/pre-tool-use.js +210 -2
- package/dist/hooks/prompt-submit.js +234 -3
- package/dist/hooks/session-end.js +347 -124
- package/dist/hooks/session-start.js +236 -5
- package/dist/hooks/stop.js +210 -2
- package/dist/hooks/subagent-stop.js +210 -2
- package/dist/hooks/summary-worker.js +171 -74
- package/dist/index.js +210 -2
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +47 -2
- package/dist/lib/config.js +2 -2
- package/dist/lib/consolidation.js +2 -2
- package/dist/lib/database.js +47 -2
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +47 -2
- package/dist/lib/device-registry.js +47 -2
- package/dist/lib/embedder.js +2 -2
- package/dist/lib/employee-templates.js +2 -2
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +592 -10
- package/dist/lib/hybrid-search.js +234 -3
- package/dist/lib/identity.js +2 -2
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +2 -2
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +47 -2
- package/dist/lib/skill-learning.js +2 -2
- package/dist/lib/store.js +210 -2
- package/dist/lib/task-router.js +2 -2
- package/dist/lib/tasks.js +2 -2
- package/dist/lib/tmux-routing.js +2 -2
- package/dist/lib/token-spend.js +2 -2
- package/dist/mcp/server.js +608 -10
- package/dist/mcp/tools/complete-reminder.js +2 -2
- package/dist/mcp/tools/create-reminder.js +2 -2
- package/dist/mcp/tools/create-task.js +2 -2
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +2 -2
- package/dist/mcp/tools/list-tasks.js +2 -2
- package/dist/mcp/tools/send-message.js +2 -2
- package/dist/mcp/tools/update-task.js +2 -2
- package/dist/runtime/index.js +210 -2
- package/dist/tui/App.js +210 -2
- package/package.json +3 -2
- package/stack.release.json +23 -7
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -624,8 +624,8 @@ var init_config = __esm({
|
|
|
624
624
|
rerankerAutoTrigger: {
|
|
625
625
|
enabled: true,
|
|
626
626
|
broadQueryMinCardinality: 5e4,
|
|
627
|
-
fetchTopK:
|
|
628
|
-
returnTopK:
|
|
627
|
+
fetchTopK: 200,
|
|
628
|
+
returnTopK: 20
|
|
629
629
|
}
|
|
630
630
|
},
|
|
631
631
|
graphRagEnabled: true,
|
|
@@ -3367,6 +3367,51 @@ async function ensureSchema() {
|
|
|
3367
3367
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3368
3368
|
END;
|
|
3369
3369
|
`);
|
|
3370
|
+
await client.executeMultiple(`
|
|
3371
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3372
|
+
id TEXT PRIMARY KEY,
|
|
3373
|
+
memory_id TEXT NOT NULL,
|
|
3374
|
+
agent_id TEXT NOT NULL,
|
|
3375
|
+
session_id TEXT NOT NULL,
|
|
3376
|
+
project_name TEXT,
|
|
3377
|
+
timestamp TEXT NOT NULL,
|
|
3378
|
+
card_type TEXT NOT NULL,
|
|
3379
|
+
subject TEXT,
|
|
3380
|
+
predicate TEXT,
|
|
3381
|
+
object TEXT,
|
|
3382
|
+
content TEXT NOT NULL,
|
|
3383
|
+
source_ref TEXT,
|
|
3384
|
+
confidence REAL DEFAULT 0.6,
|
|
3385
|
+
active INTEGER DEFAULT 1,
|
|
3386
|
+
created_at TEXT NOT NULL
|
|
3387
|
+
);
|
|
3388
|
+
|
|
3389
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3390
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3391
|
+
|
|
3392
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3393
|
+
ON memory_cards(memory_id);
|
|
3394
|
+
|
|
3395
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3396
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3397
|
+
|
|
3398
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3399
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3400
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3401
|
+
END;
|
|
3402
|
+
|
|
3403
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3404
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3405
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3406
|
+
END;
|
|
3407
|
+
|
|
3408
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3409
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3410
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3411
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3412
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3413
|
+
END;
|
|
3414
|
+
`);
|
|
3370
3415
|
try {
|
|
3371
3416
|
await client.execute({
|
|
3372
3417
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4669,6 +4714,164 @@ ${p.content}`).join("\n\n");
|
|
|
4669
4714
|
}
|
|
4670
4715
|
});
|
|
4671
4716
|
|
|
4717
|
+
// src/lib/memory-cards.ts
|
|
4718
|
+
var memory_cards_exports = {};
|
|
4719
|
+
__export(memory_cards_exports, {
|
|
4720
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4721
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4722
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4723
|
+
});
|
|
4724
|
+
import { createHash as createHash2 } from "crypto";
|
|
4725
|
+
function stableId(memoryId, type, content) {
|
|
4726
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4727
|
+
}
|
|
4728
|
+
function cleanText(text) {
|
|
4729
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4730
|
+
}
|
|
4731
|
+
function splitSentences(text) {
|
|
4732
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4733
|
+
}
|
|
4734
|
+
function inferCardType(sentence, toolName) {
|
|
4735
|
+
const lower = sentence.toLowerCase();
|
|
4736
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4737
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4738
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4739
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4740
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4741
|
+
return "fact";
|
|
4742
|
+
}
|
|
4743
|
+
function extractSubject(sentence, agentId) {
|
|
4744
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4745
|
+
return explicit?.[1] ?? agentId;
|
|
4746
|
+
}
|
|
4747
|
+
function predicateFor(type) {
|
|
4748
|
+
switch (type) {
|
|
4749
|
+
case "preference":
|
|
4750
|
+
return "prefers";
|
|
4751
|
+
case "belief_update":
|
|
4752
|
+
return "updated";
|
|
4753
|
+
case "decision":
|
|
4754
|
+
return "decided";
|
|
4755
|
+
case "event":
|
|
4756
|
+
return "happened";
|
|
4757
|
+
case "code":
|
|
4758
|
+
return "implemented";
|
|
4759
|
+
default:
|
|
4760
|
+
return "states";
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
function extractMemoryCards(row) {
|
|
4764
|
+
const sentences = splitSentences(row.raw_text);
|
|
4765
|
+
const cards = [];
|
|
4766
|
+
for (const sentence of sentences) {
|
|
4767
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4768
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4769
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4770
|
+
cards.push({
|
|
4771
|
+
id: stableId(row.id, type, content),
|
|
4772
|
+
memory_id: row.id,
|
|
4773
|
+
agent_id: row.agent_id,
|
|
4774
|
+
session_id: row.session_id,
|
|
4775
|
+
project_name: row.project_name ?? null,
|
|
4776
|
+
timestamp: row.timestamp,
|
|
4777
|
+
card_type: type,
|
|
4778
|
+
subject,
|
|
4779
|
+
predicate: predicateFor(type),
|
|
4780
|
+
object: content,
|
|
4781
|
+
content,
|
|
4782
|
+
source_ref: row.id,
|
|
4783
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4784
|
+
});
|
|
4785
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4786
|
+
}
|
|
4787
|
+
return cards;
|
|
4788
|
+
}
|
|
4789
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4790
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4791
|
+
if (cards.length === 0) return 0;
|
|
4792
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4793
|
+
const client = getClient();
|
|
4794
|
+
const stmts = cards.map((card) => ({
|
|
4795
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4796
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4797
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4798
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4799
|
+
args: [
|
|
4800
|
+
card.id,
|
|
4801
|
+
card.memory_id,
|
|
4802
|
+
card.agent_id,
|
|
4803
|
+
card.session_id,
|
|
4804
|
+
card.project_name,
|
|
4805
|
+
card.timestamp,
|
|
4806
|
+
card.card_type,
|
|
4807
|
+
card.subject,
|
|
4808
|
+
card.predicate,
|
|
4809
|
+
card.object,
|
|
4810
|
+
card.content,
|
|
4811
|
+
card.source_ref,
|
|
4812
|
+
card.confidence,
|
|
4813
|
+
now
|
|
4814
|
+
]
|
|
4815
|
+
}));
|
|
4816
|
+
await client.batch(stmts, "write");
|
|
4817
|
+
return cards.length;
|
|
4818
|
+
}
|
|
4819
|
+
function buildMatchExpr(queryText) {
|
|
4820
|
+
const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
|
|
4821
|
+
if (terms.length === 0) return null;
|
|
4822
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4823
|
+
}
|
|
4824
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4825
|
+
const limit = options?.limit ?? 10;
|
|
4826
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4827
|
+
if (!matchExpr) return [];
|
|
4828
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4829
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4830
|
+
FROM memory_cards c
|
|
4831
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4832
|
+
WHERE memory_cards_fts MATCH ?
|
|
4833
|
+
AND c.agent_id = ?
|
|
4834
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4835
|
+
const args = [matchExpr, agentId];
|
|
4836
|
+
if (options?.projectName) {
|
|
4837
|
+
sql += ` AND c.project_name = ?`;
|
|
4838
|
+
args.push(options.projectName);
|
|
4839
|
+
}
|
|
4840
|
+
if (options?.since) {
|
|
4841
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4842
|
+
args.push(options.since);
|
|
4843
|
+
}
|
|
4844
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4845
|
+
args.push(limit);
|
|
4846
|
+
const result = await getClient().execute({ sql, args });
|
|
4847
|
+
return result.rows.map((row) => ({
|
|
4848
|
+
id: `card:${String(row.id)}`,
|
|
4849
|
+
agent_id: String(row.agent_id),
|
|
4850
|
+
agent_role: "memory_card",
|
|
4851
|
+
session_id: String(row.session_id),
|
|
4852
|
+
timestamp: String(row.timestamp),
|
|
4853
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4854
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4855
|
+
has_error: false,
|
|
4856
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4857
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4858
|
+
vector: [],
|
|
4859
|
+
importance: 6,
|
|
4860
|
+
status: "active",
|
|
4861
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4862
|
+
last_accessed: String(row.timestamp)
|
|
4863
|
+
}));
|
|
4864
|
+
}
|
|
4865
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4866
|
+
var init_memory_cards = __esm({
|
|
4867
|
+
"src/lib/memory-cards.ts"() {
|
|
4868
|
+
"use strict";
|
|
4869
|
+
init_database();
|
|
4870
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4871
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4872
|
+
}
|
|
4873
|
+
});
|
|
4874
|
+
|
|
4672
4875
|
// src/lib/store.ts
|
|
4673
4876
|
var store_exports = {};
|
|
4674
4877
|
__export(store_exports, {
|
|
@@ -5007,6 +5210,11 @@ async function flushBatch() {
|
|
|
5007
5210
|
const globalClient = getClient();
|
|
5008
5211
|
const globalStmts = batch.map(buildStmt);
|
|
5009
5212
|
await globalClient.batch(globalStmts, "write");
|
|
5213
|
+
try {
|
|
5214
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
5215
|
+
await insertMemoryCardsForBatch2(batch);
|
|
5216
|
+
} catch {
|
|
5217
|
+
}
|
|
5010
5218
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
5011
5219
|
_pendingRecords.splice(0, batch.length);
|
|
5012
5220
|
try {
|
|
@@ -277,8 +277,8 @@ var init_config = __esm({
|
|
|
277
277
|
rerankerAutoTrigger: {
|
|
278
278
|
enabled: true,
|
|
279
279
|
broadQueryMinCardinality: 5e4,
|
|
280
|
-
fetchTopK:
|
|
281
|
-
returnTopK:
|
|
280
|
+
fetchTopK: 200,
|
|
281
|
+
returnTopK: 20
|
|
282
282
|
}
|
|
283
283
|
},
|
|
284
284
|
graphRagEnabled: true,
|
|
@@ -2751,6 +2751,51 @@ async function ensureSchema() {
|
|
|
2751
2751
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
2752
2752
|
END;
|
|
2753
2753
|
`);
|
|
2754
|
+
await client.executeMultiple(`
|
|
2755
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
2756
|
+
id TEXT PRIMARY KEY,
|
|
2757
|
+
memory_id TEXT NOT NULL,
|
|
2758
|
+
agent_id TEXT NOT NULL,
|
|
2759
|
+
session_id TEXT NOT NULL,
|
|
2760
|
+
project_name TEXT,
|
|
2761
|
+
timestamp TEXT NOT NULL,
|
|
2762
|
+
card_type TEXT NOT NULL,
|
|
2763
|
+
subject TEXT,
|
|
2764
|
+
predicate TEXT,
|
|
2765
|
+
object TEXT,
|
|
2766
|
+
content TEXT NOT NULL,
|
|
2767
|
+
source_ref TEXT,
|
|
2768
|
+
confidence REAL DEFAULT 0.6,
|
|
2769
|
+
active INTEGER DEFAULT 1,
|
|
2770
|
+
created_at TEXT NOT NULL
|
|
2771
|
+
);
|
|
2772
|
+
|
|
2773
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
2774
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
2775
|
+
|
|
2776
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
2777
|
+
ON memory_cards(memory_id);
|
|
2778
|
+
|
|
2779
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
2780
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
2781
|
+
|
|
2782
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
2783
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
2784
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
2785
|
+
END;
|
|
2786
|
+
|
|
2787
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
2788
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
2789
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
2790
|
+
END;
|
|
2791
|
+
|
|
2792
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
2793
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
2794
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
2795
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
2796
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
2797
|
+
END;
|
|
2798
|
+
`);
|
|
2754
2799
|
try {
|
|
2755
2800
|
await client.execute({
|
|
2756
2801
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4040,6 +4085,164 @@ ${p.content}`).join("\n\n");
|
|
|
4040
4085
|
}
|
|
4041
4086
|
});
|
|
4042
4087
|
|
|
4088
|
+
// src/lib/memory-cards.ts
|
|
4089
|
+
var memory_cards_exports = {};
|
|
4090
|
+
__export(memory_cards_exports, {
|
|
4091
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4092
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4093
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4094
|
+
});
|
|
4095
|
+
import { createHash as createHash2 } from "crypto";
|
|
4096
|
+
function stableId(memoryId, type, content) {
|
|
4097
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4098
|
+
}
|
|
4099
|
+
function cleanText(text) {
|
|
4100
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4101
|
+
}
|
|
4102
|
+
function splitSentences(text) {
|
|
4103
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4104
|
+
}
|
|
4105
|
+
function inferCardType(sentence, toolName) {
|
|
4106
|
+
const lower = sentence.toLowerCase();
|
|
4107
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4108
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4109
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4110
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4111
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4112
|
+
return "fact";
|
|
4113
|
+
}
|
|
4114
|
+
function extractSubject(sentence, agentId) {
|
|
4115
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4116
|
+
return explicit?.[1] ?? agentId;
|
|
4117
|
+
}
|
|
4118
|
+
function predicateFor(type) {
|
|
4119
|
+
switch (type) {
|
|
4120
|
+
case "preference":
|
|
4121
|
+
return "prefers";
|
|
4122
|
+
case "belief_update":
|
|
4123
|
+
return "updated";
|
|
4124
|
+
case "decision":
|
|
4125
|
+
return "decided";
|
|
4126
|
+
case "event":
|
|
4127
|
+
return "happened";
|
|
4128
|
+
case "code":
|
|
4129
|
+
return "implemented";
|
|
4130
|
+
default:
|
|
4131
|
+
return "states";
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
function extractMemoryCards(row) {
|
|
4135
|
+
const sentences = splitSentences(row.raw_text);
|
|
4136
|
+
const cards = [];
|
|
4137
|
+
for (const sentence of sentences) {
|
|
4138
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4139
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4140
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4141
|
+
cards.push({
|
|
4142
|
+
id: stableId(row.id, type, content),
|
|
4143
|
+
memory_id: row.id,
|
|
4144
|
+
agent_id: row.agent_id,
|
|
4145
|
+
session_id: row.session_id,
|
|
4146
|
+
project_name: row.project_name ?? null,
|
|
4147
|
+
timestamp: row.timestamp,
|
|
4148
|
+
card_type: type,
|
|
4149
|
+
subject,
|
|
4150
|
+
predicate: predicateFor(type),
|
|
4151
|
+
object: content,
|
|
4152
|
+
content,
|
|
4153
|
+
source_ref: row.id,
|
|
4154
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4155
|
+
});
|
|
4156
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4157
|
+
}
|
|
4158
|
+
return cards;
|
|
4159
|
+
}
|
|
4160
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4161
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4162
|
+
if (cards.length === 0) return 0;
|
|
4163
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4164
|
+
const client = getClient();
|
|
4165
|
+
const stmts = cards.map((card) => ({
|
|
4166
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4167
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4168
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4169
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4170
|
+
args: [
|
|
4171
|
+
card.id,
|
|
4172
|
+
card.memory_id,
|
|
4173
|
+
card.agent_id,
|
|
4174
|
+
card.session_id,
|
|
4175
|
+
card.project_name,
|
|
4176
|
+
card.timestamp,
|
|
4177
|
+
card.card_type,
|
|
4178
|
+
card.subject,
|
|
4179
|
+
card.predicate,
|
|
4180
|
+
card.object,
|
|
4181
|
+
card.content,
|
|
4182
|
+
card.source_ref,
|
|
4183
|
+
card.confidence,
|
|
4184
|
+
now
|
|
4185
|
+
]
|
|
4186
|
+
}));
|
|
4187
|
+
await client.batch(stmts, "write");
|
|
4188
|
+
return cards.length;
|
|
4189
|
+
}
|
|
4190
|
+
function buildMatchExpr(queryText) {
|
|
4191
|
+
const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
|
|
4192
|
+
if (terms.length === 0) return null;
|
|
4193
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4194
|
+
}
|
|
4195
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4196
|
+
const limit = options?.limit ?? 10;
|
|
4197
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4198
|
+
if (!matchExpr) return [];
|
|
4199
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4200
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4201
|
+
FROM memory_cards c
|
|
4202
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4203
|
+
WHERE memory_cards_fts MATCH ?
|
|
4204
|
+
AND c.agent_id = ?
|
|
4205
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4206
|
+
const args = [matchExpr, agentId];
|
|
4207
|
+
if (options?.projectName) {
|
|
4208
|
+
sql += ` AND c.project_name = ?`;
|
|
4209
|
+
args.push(options.projectName);
|
|
4210
|
+
}
|
|
4211
|
+
if (options?.since) {
|
|
4212
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4213
|
+
args.push(options.since);
|
|
4214
|
+
}
|
|
4215
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4216
|
+
args.push(limit);
|
|
4217
|
+
const result = await getClient().execute({ sql, args });
|
|
4218
|
+
return result.rows.map((row) => ({
|
|
4219
|
+
id: `card:${String(row.id)}`,
|
|
4220
|
+
agent_id: String(row.agent_id),
|
|
4221
|
+
agent_role: "memory_card",
|
|
4222
|
+
session_id: String(row.session_id),
|
|
4223
|
+
timestamp: String(row.timestamp),
|
|
4224
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4225
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4226
|
+
has_error: false,
|
|
4227
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4228
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4229
|
+
vector: [],
|
|
4230
|
+
importance: 6,
|
|
4231
|
+
status: "active",
|
|
4232
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4233
|
+
last_accessed: String(row.timestamp)
|
|
4234
|
+
}));
|
|
4235
|
+
}
|
|
4236
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4237
|
+
var init_memory_cards = __esm({
|
|
4238
|
+
"src/lib/memory-cards.ts"() {
|
|
4239
|
+
"use strict";
|
|
4240
|
+
init_database();
|
|
4241
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4242
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4243
|
+
}
|
|
4244
|
+
});
|
|
4245
|
+
|
|
4043
4246
|
// src/lib/store.ts
|
|
4044
4247
|
var store_exports = {};
|
|
4045
4248
|
__export(store_exports, {
|
|
@@ -4378,6 +4581,11 @@ async function flushBatch() {
|
|
|
4378
4581
|
const globalClient = getClient();
|
|
4379
4582
|
const globalStmts = batch.map(buildStmt);
|
|
4380
4583
|
await globalClient.batch(globalStmts, "write");
|
|
4584
|
+
try {
|
|
4585
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
4586
|
+
await insertMemoryCardsForBatch2(batch);
|
|
4587
|
+
} catch {
|
|
4588
|
+
}
|
|
4381
4589
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4382
4590
|
_pendingRecords.splice(0, batch.length);
|
|
4383
4591
|
try {
|
|
@@ -5136,7 +5344,7 @@ var init_tasks_review = __esm({
|
|
|
5136
5344
|
|
|
5137
5345
|
// src/bin/exe-heartbeat.ts
|
|
5138
5346
|
init_database();
|
|
5139
|
-
import { createHash as
|
|
5347
|
+
import { createHash as createHash3 } from "crypto";
|
|
5140
5348
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
5141
5349
|
import os12 from "os";
|
|
5142
5350
|
import path17 from "path";
|
|
@@ -5264,7 +5472,7 @@ function writeMarker(marker) {
|
|
|
5264
5472
|
}
|
|
5265
5473
|
}
|
|
5266
5474
|
function hashOutput(text) {
|
|
5267
|
-
return
|
|
5475
|
+
return createHash3("sha256").update(text).digest("hex");
|
|
5268
5476
|
}
|
|
5269
5477
|
async function queryPendingReviews() {
|
|
5270
5478
|
let sessionScope;
|