@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/gateway/index.js
CHANGED
|
@@ -623,8 +623,8 @@ var init_config = __esm({
|
|
|
623
623
|
rerankerAutoTrigger: {
|
|
624
624
|
enabled: true,
|
|
625
625
|
broadQueryMinCardinality: 5e4,
|
|
626
|
-
fetchTopK:
|
|
627
|
-
returnTopK:
|
|
626
|
+
fetchTopK: 200,
|
|
627
|
+
returnTopK: 20
|
|
628
628
|
}
|
|
629
629
|
},
|
|
630
630
|
graphRagEnabled: true,
|
|
@@ -3366,6 +3366,51 @@ async function ensureSchema() {
|
|
|
3366
3366
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3367
3367
|
END;
|
|
3368
3368
|
`);
|
|
3369
|
+
await client.executeMultiple(`
|
|
3370
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3371
|
+
id TEXT PRIMARY KEY,
|
|
3372
|
+
memory_id TEXT NOT NULL,
|
|
3373
|
+
agent_id TEXT NOT NULL,
|
|
3374
|
+
session_id TEXT NOT NULL,
|
|
3375
|
+
project_name TEXT,
|
|
3376
|
+
timestamp TEXT NOT NULL,
|
|
3377
|
+
card_type TEXT NOT NULL,
|
|
3378
|
+
subject TEXT,
|
|
3379
|
+
predicate TEXT,
|
|
3380
|
+
object TEXT,
|
|
3381
|
+
content TEXT NOT NULL,
|
|
3382
|
+
source_ref TEXT,
|
|
3383
|
+
confidence REAL DEFAULT 0.6,
|
|
3384
|
+
active INTEGER DEFAULT 1,
|
|
3385
|
+
created_at TEXT NOT NULL
|
|
3386
|
+
);
|
|
3387
|
+
|
|
3388
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3389
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3390
|
+
|
|
3391
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3392
|
+
ON memory_cards(memory_id);
|
|
3393
|
+
|
|
3394
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3395
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3396
|
+
|
|
3397
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3398
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3399
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3400
|
+
END;
|
|
3401
|
+
|
|
3402
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3403
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3404
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3405
|
+
END;
|
|
3406
|
+
|
|
3407
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3408
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3409
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3410
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3411
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3412
|
+
END;
|
|
3413
|
+
`);
|
|
3369
3414
|
try {
|
|
3370
3415
|
await client.execute({
|
|
3371
3416
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4668,6 +4713,164 @@ ${p.content}`).join("\n\n");
|
|
|
4668
4713
|
}
|
|
4669
4714
|
});
|
|
4670
4715
|
|
|
4716
|
+
// src/lib/memory-cards.ts
|
|
4717
|
+
var memory_cards_exports = {};
|
|
4718
|
+
__export(memory_cards_exports, {
|
|
4719
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4720
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4721
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4722
|
+
});
|
|
4723
|
+
import { createHash as createHash2 } from "crypto";
|
|
4724
|
+
function stableId(memoryId, type, content) {
|
|
4725
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4726
|
+
}
|
|
4727
|
+
function cleanText(text) {
|
|
4728
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4729
|
+
}
|
|
4730
|
+
function splitSentences(text) {
|
|
4731
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4732
|
+
}
|
|
4733
|
+
function inferCardType(sentence, toolName) {
|
|
4734
|
+
const lower = sentence.toLowerCase();
|
|
4735
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4736
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4737
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4738
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4739
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4740
|
+
return "fact";
|
|
4741
|
+
}
|
|
4742
|
+
function extractSubject(sentence, agentId) {
|
|
4743
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4744
|
+
return explicit?.[1] ?? agentId;
|
|
4745
|
+
}
|
|
4746
|
+
function predicateFor(type) {
|
|
4747
|
+
switch (type) {
|
|
4748
|
+
case "preference":
|
|
4749
|
+
return "prefers";
|
|
4750
|
+
case "belief_update":
|
|
4751
|
+
return "updated";
|
|
4752
|
+
case "decision":
|
|
4753
|
+
return "decided";
|
|
4754
|
+
case "event":
|
|
4755
|
+
return "happened";
|
|
4756
|
+
case "code":
|
|
4757
|
+
return "implemented";
|
|
4758
|
+
default:
|
|
4759
|
+
return "states";
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
function extractMemoryCards(row) {
|
|
4763
|
+
const sentences = splitSentences(row.raw_text);
|
|
4764
|
+
const cards = [];
|
|
4765
|
+
for (const sentence of sentences) {
|
|
4766
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4767
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4768
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4769
|
+
cards.push({
|
|
4770
|
+
id: stableId(row.id, type, content),
|
|
4771
|
+
memory_id: row.id,
|
|
4772
|
+
agent_id: row.agent_id,
|
|
4773
|
+
session_id: row.session_id,
|
|
4774
|
+
project_name: row.project_name ?? null,
|
|
4775
|
+
timestamp: row.timestamp,
|
|
4776
|
+
card_type: type,
|
|
4777
|
+
subject,
|
|
4778
|
+
predicate: predicateFor(type),
|
|
4779
|
+
object: content,
|
|
4780
|
+
content,
|
|
4781
|
+
source_ref: row.id,
|
|
4782
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4783
|
+
});
|
|
4784
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4785
|
+
}
|
|
4786
|
+
return cards;
|
|
4787
|
+
}
|
|
4788
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4789
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4790
|
+
if (cards.length === 0) return 0;
|
|
4791
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4792
|
+
const client = getClient();
|
|
4793
|
+
const stmts = cards.map((card) => ({
|
|
4794
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4795
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4796
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4797
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4798
|
+
args: [
|
|
4799
|
+
card.id,
|
|
4800
|
+
card.memory_id,
|
|
4801
|
+
card.agent_id,
|
|
4802
|
+
card.session_id,
|
|
4803
|
+
card.project_name,
|
|
4804
|
+
card.timestamp,
|
|
4805
|
+
card.card_type,
|
|
4806
|
+
card.subject,
|
|
4807
|
+
card.predicate,
|
|
4808
|
+
card.object,
|
|
4809
|
+
card.content,
|
|
4810
|
+
card.source_ref,
|
|
4811
|
+
card.confidence,
|
|
4812
|
+
now
|
|
4813
|
+
]
|
|
4814
|
+
}));
|
|
4815
|
+
await client.batch(stmts, "write");
|
|
4816
|
+
return cards.length;
|
|
4817
|
+
}
|
|
4818
|
+
function buildMatchExpr(queryText) {
|
|
4819
|
+
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);
|
|
4820
|
+
if (terms.length === 0) return null;
|
|
4821
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4822
|
+
}
|
|
4823
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4824
|
+
const limit = options?.limit ?? 10;
|
|
4825
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4826
|
+
if (!matchExpr) return [];
|
|
4827
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4828
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4829
|
+
FROM memory_cards c
|
|
4830
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4831
|
+
WHERE memory_cards_fts MATCH ?
|
|
4832
|
+
AND c.agent_id = ?
|
|
4833
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4834
|
+
const args = [matchExpr, agentId];
|
|
4835
|
+
if (options?.projectName) {
|
|
4836
|
+
sql += ` AND c.project_name = ?`;
|
|
4837
|
+
args.push(options.projectName);
|
|
4838
|
+
}
|
|
4839
|
+
if (options?.since) {
|
|
4840
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4841
|
+
args.push(options.since);
|
|
4842
|
+
}
|
|
4843
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4844
|
+
args.push(limit);
|
|
4845
|
+
const result = await getClient().execute({ sql, args });
|
|
4846
|
+
return result.rows.map((row) => ({
|
|
4847
|
+
id: `card:${String(row.id)}`,
|
|
4848
|
+
agent_id: String(row.agent_id),
|
|
4849
|
+
agent_role: "memory_card",
|
|
4850
|
+
session_id: String(row.session_id),
|
|
4851
|
+
timestamp: String(row.timestamp),
|
|
4852
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4853
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4854
|
+
has_error: false,
|
|
4855
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4856
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4857
|
+
vector: [],
|
|
4858
|
+
importance: 6,
|
|
4859
|
+
status: "active",
|
|
4860
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4861
|
+
last_accessed: String(row.timestamp)
|
|
4862
|
+
}));
|
|
4863
|
+
}
|
|
4864
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4865
|
+
var init_memory_cards = __esm({
|
|
4866
|
+
"src/lib/memory-cards.ts"() {
|
|
4867
|
+
"use strict";
|
|
4868
|
+
init_database();
|
|
4869
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4870
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4871
|
+
}
|
|
4872
|
+
});
|
|
4873
|
+
|
|
4671
4874
|
// src/lib/store.ts
|
|
4672
4875
|
var store_exports = {};
|
|
4673
4876
|
__export(store_exports, {
|
|
@@ -5006,6 +5209,11 @@ async function flushBatch() {
|
|
|
5006
5209
|
const globalClient = getClient();
|
|
5007
5210
|
const globalStmts = batch.map(buildStmt);
|
|
5008
5211
|
await globalClient.batch(globalStmts, "write");
|
|
5212
|
+
try {
|
|
5213
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
5214
|
+
await insertMemoryCardsForBatch2(batch);
|
|
5215
|
+
} catch {
|
|
5216
|
+
}
|
|
5009
5217
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
5010
5218
|
_pendingRecords.splice(0, batch.length);
|
|
5011
5219
|
try {
|
|
@@ -312,8 +312,8 @@ var init_config = __esm({
|
|
|
312
312
|
rerankerAutoTrigger: {
|
|
313
313
|
enabled: true,
|
|
314
314
|
broadQueryMinCardinality: 5e4,
|
|
315
|
-
fetchTopK:
|
|
316
|
-
returnTopK:
|
|
315
|
+
fetchTopK: 200,
|
|
316
|
+
returnTopK: 20
|
|
317
317
|
}
|
|
318
318
|
},
|
|
319
319
|
graphRagEnabled: true,
|
|
@@ -3121,6 +3121,51 @@ async function ensureSchema() {
|
|
|
3121
3121
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
3122
3122
|
END;
|
|
3123
3123
|
`);
|
|
3124
|
+
await client.executeMultiple(`
|
|
3125
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
3126
|
+
id TEXT PRIMARY KEY,
|
|
3127
|
+
memory_id TEXT NOT NULL,
|
|
3128
|
+
agent_id TEXT NOT NULL,
|
|
3129
|
+
session_id TEXT NOT NULL,
|
|
3130
|
+
project_name TEXT,
|
|
3131
|
+
timestamp TEXT NOT NULL,
|
|
3132
|
+
card_type TEXT NOT NULL,
|
|
3133
|
+
subject TEXT,
|
|
3134
|
+
predicate TEXT,
|
|
3135
|
+
object TEXT,
|
|
3136
|
+
content TEXT NOT NULL,
|
|
3137
|
+
source_ref TEXT,
|
|
3138
|
+
confidence REAL DEFAULT 0.6,
|
|
3139
|
+
active INTEGER DEFAULT 1,
|
|
3140
|
+
created_at TEXT NOT NULL
|
|
3141
|
+
);
|
|
3142
|
+
|
|
3143
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
3144
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
3145
|
+
|
|
3146
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
3147
|
+
ON memory_cards(memory_id);
|
|
3148
|
+
|
|
3149
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
3150
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
3151
|
+
|
|
3152
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
3153
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3154
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3155
|
+
END;
|
|
3156
|
+
|
|
3157
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
3158
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3159
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3160
|
+
END;
|
|
3161
|
+
|
|
3162
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
3163
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
3164
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
3165
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
3166
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
3167
|
+
END;
|
|
3168
|
+
`);
|
|
3124
3169
|
try {
|
|
3125
3170
|
await client.execute({
|
|
3126
3171
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -4410,6 +4455,164 @@ ${p.content}`).join("\n\n");
|
|
|
4410
4455
|
}
|
|
4411
4456
|
});
|
|
4412
4457
|
|
|
4458
|
+
// src/lib/memory-cards.ts
|
|
4459
|
+
var memory_cards_exports = {};
|
|
4460
|
+
__export(memory_cards_exports, {
|
|
4461
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
4462
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
4463
|
+
searchMemoryCards: () => searchMemoryCards
|
|
4464
|
+
});
|
|
4465
|
+
import { createHash as createHash2 } from "crypto";
|
|
4466
|
+
function stableId(memoryId, type, content) {
|
|
4467
|
+
return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
4468
|
+
}
|
|
4469
|
+
function cleanText(text) {
|
|
4470
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4471
|
+
}
|
|
4472
|
+
function splitSentences(text) {
|
|
4473
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
4474
|
+
}
|
|
4475
|
+
function inferCardType(sentence, toolName) {
|
|
4476
|
+
const lower = sentence.toLowerCase();
|
|
4477
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
4478
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
4479
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
4480
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
4481
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
4482
|
+
return "fact";
|
|
4483
|
+
}
|
|
4484
|
+
function extractSubject(sentence, agentId) {
|
|
4485
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
4486
|
+
return explicit?.[1] ?? agentId;
|
|
4487
|
+
}
|
|
4488
|
+
function predicateFor(type) {
|
|
4489
|
+
switch (type) {
|
|
4490
|
+
case "preference":
|
|
4491
|
+
return "prefers";
|
|
4492
|
+
case "belief_update":
|
|
4493
|
+
return "updated";
|
|
4494
|
+
case "decision":
|
|
4495
|
+
return "decided";
|
|
4496
|
+
case "event":
|
|
4497
|
+
return "happened";
|
|
4498
|
+
case "code":
|
|
4499
|
+
return "implemented";
|
|
4500
|
+
default:
|
|
4501
|
+
return "states";
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
function extractMemoryCards(row) {
|
|
4505
|
+
const sentences = splitSentences(row.raw_text);
|
|
4506
|
+
const cards = [];
|
|
4507
|
+
for (const sentence of sentences) {
|
|
4508
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
4509
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
4510
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
4511
|
+
cards.push({
|
|
4512
|
+
id: stableId(row.id, type, content),
|
|
4513
|
+
memory_id: row.id,
|
|
4514
|
+
agent_id: row.agent_id,
|
|
4515
|
+
session_id: row.session_id,
|
|
4516
|
+
project_name: row.project_name ?? null,
|
|
4517
|
+
timestamp: row.timestamp,
|
|
4518
|
+
card_type: type,
|
|
4519
|
+
subject,
|
|
4520
|
+
predicate: predicateFor(type),
|
|
4521
|
+
object: content,
|
|
4522
|
+
content,
|
|
4523
|
+
source_ref: row.id,
|
|
4524
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
4525
|
+
});
|
|
4526
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
4527
|
+
}
|
|
4528
|
+
return cards;
|
|
4529
|
+
}
|
|
4530
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
4531
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
4532
|
+
if (cards.length === 0) return 0;
|
|
4533
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4534
|
+
const client = getClient();
|
|
4535
|
+
const stmts = cards.map((card) => ({
|
|
4536
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
4537
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
4538
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
4539
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
4540
|
+
args: [
|
|
4541
|
+
card.id,
|
|
4542
|
+
card.memory_id,
|
|
4543
|
+
card.agent_id,
|
|
4544
|
+
card.session_id,
|
|
4545
|
+
card.project_name,
|
|
4546
|
+
card.timestamp,
|
|
4547
|
+
card.card_type,
|
|
4548
|
+
card.subject,
|
|
4549
|
+
card.predicate,
|
|
4550
|
+
card.object,
|
|
4551
|
+
card.content,
|
|
4552
|
+
card.source_ref,
|
|
4553
|
+
card.confidence,
|
|
4554
|
+
now
|
|
4555
|
+
]
|
|
4556
|
+
}));
|
|
4557
|
+
await client.batch(stmts, "write");
|
|
4558
|
+
return cards.length;
|
|
4559
|
+
}
|
|
4560
|
+
function buildMatchExpr(queryText) {
|
|
4561
|
+
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);
|
|
4562
|
+
if (terms.length === 0) return null;
|
|
4563
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
4564
|
+
}
|
|
4565
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
4566
|
+
const limit = options?.limit ?? 10;
|
|
4567
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
4568
|
+
if (!matchExpr) return [];
|
|
4569
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
4570
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
4571
|
+
FROM memory_cards c
|
|
4572
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
4573
|
+
WHERE memory_cards_fts MATCH ?
|
|
4574
|
+
AND c.agent_id = ?
|
|
4575
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
4576
|
+
const args = [matchExpr, agentId];
|
|
4577
|
+
if (options?.projectName) {
|
|
4578
|
+
sql += ` AND c.project_name = ?`;
|
|
4579
|
+
args.push(options.projectName);
|
|
4580
|
+
}
|
|
4581
|
+
if (options?.since) {
|
|
4582
|
+
sql += ` AND c.timestamp >= ?`;
|
|
4583
|
+
args.push(options.since);
|
|
4584
|
+
}
|
|
4585
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
4586
|
+
args.push(limit);
|
|
4587
|
+
const result = await getClient().execute({ sql, args });
|
|
4588
|
+
return result.rows.map((row) => ({
|
|
4589
|
+
id: `card:${String(row.id)}`,
|
|
4590
|
+
agent_id: String(row.agent_id),
|
|
4591
|
+
agent_role: "memory_card",
|
|
4592
|
+
session_id: String(row.session_id),
|
|
4593
|
+
timestamp: String(row.timestamp),
|
|
4594
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
4595
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
4596
|
+
has_error: false,
|
|
4597
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
4598
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
4599
|
+
vector: [],
|
|
4600
|
+
importance: 6,
|
|
4601
|
+
status: "active",
|
|
4602
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
4603
|
+
last_accessed: String(row.timestamp)
|
|
4604
|
+
}));
|
|
4605
|
+
}
|
|
4606
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
4607
|
+
var init_memory_cards = __esm({
|
|
4608
|
+
"src/lib/memory-cards.ts"() {
|
|
4609
|
+
"use strict";
|
|
4610
|
+
init_database();
|
|
4611
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
4612
|
+
MAX_SENTENCE_CHARS = 360;
|
|
4613
|
+
}
|
|
4614
|
+
});
|
|
4615
|
+
|
|
4413
4616
|
// src/lib/store.ts
|
|
4414
4617
|
var store_exports = {};
|
|
4415
4618
|
__export(store_exports, {
|
|
@@ -4748,6 +4951,11 @@ async function flushBatch() {
|
|
|
4748
4951
|
const globalClient = getClient();
|
|
4749
4952
|
const globalStmts = batch.map(buildStmt);
|
|
4750
4953
|
await globalClient.batch(globalStmts, "write");
|
|
4954
|
+
try {
|
|
4955
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
4956
|
+
await insertMemoryCardsForBatch2(batch);
|
|
4957
|
+
} catch {
|
|
4958
|
+
}
|
|
4751
4959
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4752
4960
|
_pendingRecords.splice(0, batch.length);
|
|
4753
4961
|
try {
|
|
@@ -8684,54 +8892,98 @@ async function fastDbInit() {
|
|
|
8684
8892
|
// src/adapters/claude/hooks/bug-report-worker.ts
|
|
8685
8893
|
init_database();
|
|
8686
8894
|
init_tasks();
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8895
|
+
|
|
8896
|
+
// src/lib/bug-intake.ts
|
|
8897
|
+
import { createHash as createHash3, randomUUID as randomUUID4 } from "crypto";
|
|
8898
|
+
var BUG_INTAKE_SCHEMA_VERSION = 1;
|
|
8899
|
+
function firstMeaningfulLine(text) {
|
|
8900
|
+
return text.split("\n").find((line) => line.trim().length > 0)?.trim().slice(0, 80) ?? "unknown error";
|
|
8901
|
+
}
|
|
8902
|
+
function stableFingerprint(input) {
|
|
8903
|
+
const basis = [
|
|
8904
|
+
input.source,
|
|
8905
|
+
input.toolName ?? "unknown",
|
|
8906
|
+
firstMeaningfulLine(input.errorText ?? ""),
|
|
8907
|
+
input.projectName ?? "unknown"
|
|
8908
|
+
].join("|");
|
|
8909
|
+
return createHash3("sha256").update(basis).digest("hex").slice(0, 16);
|
|
8910
|
+
}
|
|
8911
|
+
function hashLicense(licenseKey) {
|
|
8912
|
+
if (!licenseKey) return void 0;
|
|
8913
|
+
return createHash3("sha256").update(licenseKey).digest("hex").slice(0, 16);
|
|
8914
|
+
}
|
|
8915
|
+
function buildBugIntake(input) {
|
|
8916
|
+
const toolName = input.toolName ?? "unknown";
|
|
8917
|
+
const errorText = input.errorText ?? "";
|
|
8918
|
+
const summary = firstMeaningfulLine(errorText);
|
|
8919
|
+
const fingerprint = input.fingerprint && input.fingerprint.trim().length > 0 ? input.fingerprint.trim() : stableFingerprint(input);
|
|
8920
|
+
return {
|
|
8921
|
+
schemaVersion: BUG_INTAKE_SCHEMA_VERSION,
|
|
8922
|
+
id: randomUUID4(),
|
|
8923
|
+
source: input.source,
|
|
8924
|
+
createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
8925
|
+
fingerprint,
|
|
8926
|
+
severity: input.severity ?? "p1",
|
|
8927
|
+
title: `[auto-bug] ${toolName}: ${summary.slice(0, 60)}`,
|
|
8928
|
+
summary,
|
|
8929
|
+
reporterAgentId: input.reporterAgentId ?? "unknown",
|
|
8930
|
+
reporterAgentRole: input.reporterAgentRole ?? "employee",
|
|
8931
|
+
projectName: input.projectName ?? "unknown",
|
|
8932
|
+
toolName,
|
|
8933
|
+
errorText,
|
|
8934
|
+
toolInput: input.toolInput ?? "{}",
|
|
8935
|
+
runtime: input.runtime,
|
|
8936
|
+
repo: input.repo,
|
|
8937
|
+
licenseKeyHash: hashLicense(input.licenseKey),
|
|
8938
|
+
labels: ["auto-bug", input.source, toolName].filter(Boolean)
|
|
8939
|
+
};
|
|
8940
|
+
}
|
|
8941
|
+
function buildBugIntakeFromEnv(env = process.env) {
|
|
8942
|
+
return buildBugIntake({
|
|
8943
|
+
source: "hook",
|
|
8944
|
+
toolName: env.BUG_TOOL_NAME,
|
|
8945
|
+
errorText: env.BUG_ERROR_TEXT,
|
|
8946
|
+
toolInput: env.BUG_TOOL_INPUT,
|
|
8947
|
+
fingerprint: env.BUG_FINGERPRINT,
|
|
8948
|
+
reporterAgentId: env.BUG_AGENT_ID,
|
|
8949
|
+
reporterAgentRole: env.BUG_AGENT_ROLE,
|
|
8950
|
+
projectName: env.BUG_PROJECT_NAME,
|
|
8951
|
+
runtime: env.EXE_RUNTIME,
|
|
8952
|
+
repo: env.EXE_REPO,
|
|
8953
|
+
licenseKey: env.EXE_LICENSE_KEY
|
|
8710
8954
|
});
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
return;
|
|
8715
|
-
}
|
|
8716
|
-
const errorSummary = errorText.split("\n").find((line) => line.trim().length > 0)?.trim().slice(0, 60) ?? "unknown error";
|
|
8717
|
-
const context = [
|
|
8955
|
+
}
|
|
8956
|
+
function formatBugIntakeTaskContext(record) {
|
|
8957
|
+
return [
|
|
8718
8958
|
"## Auto-detected system bug",
|
|
8719
8959
|
"",
|
|
8720
|
-
`**
|
|
8721
|
-
`**
|
|
8722
|
-
`**
|
|
8723
|
-
`**
|
|
8960
|
+
`**Schema:** bug-intake/v${record.schemaVersion}`,
|
|
8961
|
+
`**Source:** ${record.source}`,
|
|
8962
|
+
`**Detected by:** ${record.reporterAgentId} (${record.reporterAgentRole})`,
|
|
8963
|
+
`**Tool:** ${record.toolName}`,
|
|
8964
|
+
`**Timestamp:** ${record.createdAt}`,
|
|
8965
|
+
`**Fingerprint:** ${record.fingerprint}`,
|
|
8966
|
+
`**Severity:** ${record.severity}`,
|
|
8967
|
+
record.runtime ? `**Runtime:** ${record.runtime}` : void 0,
|
|
8968
|
+
record.repo ? `**Repo:** ${record.repo}` : void 0,
|
|
8969
|
+
record.licenseKeyHash ? `**License hash:** ${record.licenseKeyHash}` : void 0,
|
|
8724
8970
|
"",
|
|
8725
8971
|
"## Error output",
|
|
8726
8972
|
"",
|
|
8727
8973
|
"```",
|
|
8728
|
-
errorText.slice(0,
|
|
8974
|
+
record.errorText.slice(0, 2e3),
|
|
8729
8975
|
"```",
|
|
8730
8976
|
"",
|
|
8731
8977
|
"## Tool input (reproduction context)",
|
|
8732
8978
|
"",
|
|
8733
8979
|
"```json",
|
|
8734
|
-
toolInput.slice(0,
|
|
8980
|
+
record.toolInput.slice(0, 1e3),
|
|
8981
|
+
"```",
|
|
8982
|
+
"",
|
|
8983
|
+
"## Normalized intake JSON",
|
|
8984
|
+
"",
|
|
8985
|
+
"```json",
|
|
8986
|
+
JSON.stringify(record, null, 2),
|
|
8735
8987
|
"```",
|
|
8736
8988
|
"",
|
|
8737
8989
|
"## Triage notes",
|
|
@@ -8739,19 +8991,44 @@ async function main() {
|
|
|
8739
8991
|
"- Classification: system bug (auto-detected)",
|
|
8740
8992
|
"- Review this error \u2014 fix if real, close if false positive",
|
|
8741
8993
|
"- If false positive: add the error pattern to USER_ERROR_PATTERNS in error-detector.ts"
|
|
8742
|
-
].join("\n");
|
|
8994
|
+
].filter((line) => line !== void 0).join("\n");
|
|
8995
|
+
}
|
|
8996
|
+
|
|
8997
|
+
// src/adapters/claude/hooks/bug-report-worker.ts
|
|
8998
|
+
async function main() {
|
|
8999
|
+
const intake = buildBugIntakeFromEnv(process.env);
|
|
9000
|
+
await fastDbInit();
|
|
9001
|
+
const client = getClient();
|
|
9002
|
+
const { loadEmployeesSync: loadEmployeesSync2, getEmployeeByRole: getEmployeeByRole2, getCoordinatorName: getCoordinatorName2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
9003
|
+
const employees = loadEmployeesSync2();
|
|
9004
|
+
const coordinatorName = getCoordinatorName2(employees);
|
|
9005
|
+
const ctoName = getEmployeeByRole2(employees, "CTO")?.name ?? coordinatorName;
|
|
9006
|
+
const existing = await client.execute({
|
|
9007
|
+
sql: `SELECT id FROM tasks
|
|
9008
|
+
WHERE assigned_to = ?
|
|
9009
|
+
AND status IN ('open', 'in_progress')
|
|
9010
|
+
AND title LIKE '[auto-bug]%'
|
|
9011
|
+
AND (context LIKE ? OR task_file LIKE ?)
|
|
9012
|
+
LIMIT 1`,
|
|
9013
|
+
args: [ctoName, `%${intake.fingerprint}%`, `%${intake.fingerprint.slice(0, 8)}%`]
|
|
9014
|
+
});
|
|
9015
|
+
if (existing.rows.length > 0) {
|
|
9016
|
+
process.stderr.write(`[bug-report-worker] Duplicate found for fingerprint ${intake.fingerprint}, skipping
|
|
9017
|
+
`);
|
|
9018
|
+
return;
|
|
9019
|
+
}
|
|
8743
9020
|
await createTask({
|
|
8744
|
-
title:
|
|
9021
|
+
title: intake.title,
|
|
8745
9022
|
assignedTo: ctoName,
|
|
8746
9023
|
assignedBy: "system",
|
|
8747
|
-
projectName,
|
|
8748
|
-
priority:
|
|
8749
|
-
context,
|
|
9024
|
+
projectName: intake.projectName,
|
|
9025
|
+
priority: intake.severity,
|
|
9026
|
+
context: formatBugIntakeTaskContext(intake),
|
|
8750
9027
|
baseDir: process.cwd(),
|
|
8751
9028
|
skipDispatch: true,
|
|
8752
9029
|
reviewer: coordinatorName
|
|
8753
9030
|
});
|
|
8754
|
-
process.stderr.write(`[bug-report-worker] Created auto-bug task for ${toolName}: ${
|
|
9031
|
+
process.stderr.write(`[bug-report-worker] Created auto-bug task for ${intake.toolName}: ${intake.summary}
|
|
8755
9032
|
`);
|
|
8756
9033
|
}
|
|
8757
9034
|
main().catch((err) => {
|