mcp-agents-memory 0.9.19 → 0.9.20
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.ko.md +1 -0
- package/README.md +1 -0
- package/build/index.js +713 -319
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -106,6 +106,7 @@
|
|
|
106
106
|
mcp-agents-memory coldpath # MCP 서버 없이 Cold Path 워커만 도는 데몬 (systemd 권장)
|
|
107
107
|
```
|
|
108
108
|
데몬은 PostgreSQL advisory lock으로 **싱글톤** 보장 — 인스턴스가 몇 개든 락을 잡은 1개만 처리한다(중복 방지·자동 failover).
|
|
109
|
+
- **버즈 (선택)**: `mcp-agents-memory buzz-ingest`는 지정한 신원이 멤버인 버즈 방의 채팅을 공식 `buzz` CLI로 한 건씩 메모리에 옮긴다. 타이머로 돌리고, 설정은 CHANGELOG 0.9.20 참고.
|
|
109
110
|
|
|
110
111
|
### Cold Path LLM 백엔드 (config로 교체)
|
|
111
112
|
|
package/README.md
CHANGED
|
@@ -107,6 +107,7 @@ When several machines share **one** database, the Cold Path (tagging / profiling
|
|
|
107
107
|
mcp-agents-memory coldpath # Cold Path worker only, no MCP server (systemd recommended)
|
|
108
108
|
```
|
|
109
109
|
The daemon is a **singleton** via a PostgreSQL advisory lock — no matter how many instances exist, only the one holding the lock processes (dedup + automatic failover).
|
|
110
|
+
- **Buzz (optional)**: `mcp-agents-memory buzz-ingest` copies chat messages from the Buzz rooms a given identity is a member of into memory, one row per message, through the official `buzz` CLI. Run it from a timer; see CHANGELOG 0.9.20 for the settings.
|
|
110
111
|
|
|
111
112
|
### Cold Path LLM backend
|
|
112
113
|
|
package/build/index.js
CHANGED
|
@@ -12924,7 +12924,7 @@ var require_agent = __commonJS({
|
|
|
12924
12924
|
var { Duplex } = __require("stream");
|
|
12925
12925
|
var { resolve } = __require("path");
|
|
12926
12926
|
var { readFile } = __require("fs");
|
|
12927
|
-
var { execFile, spawn: spawn2 } = __require("child_process");
|
|
12927
|
+
var { execFile: execFile2, spawn: spawn2 } = __require("child_process");
|
|
12928
12928
|
var { isParsedKey, parseKey } = require_keyParser();
|
|
12929
12929
|
var {
|
|
12930
12930
|
makeBufferParser,
|
|
@@ -13145,7 +13145,7 @@ var require_agent = __commonJS({
|
|
|
13145
13145
|
if (err3) {
|
|
13146
13146
|
if (triedCygpath)
|
|
13147
13147
|
return cb(new Error("Invalid cygwin unix socket path"));
|
|
13148
|
-
|
|
13148
|
+
execFile2("cygpath", ["-w", socketPath], (err4, stdout, stderr) => {
|
|
13149
13149
|
if (err4 || stdout.length === 0)
|
|
13150
13150
|
return cb(new Error("Invalid cygwin unix socket path"));
|
|
13151
13151
|
triedCygpath = true;
|
|
@@ -32739,6 +32739,353 @@ var require_dist2 = __commonJS({
|
|
|
32739
32739
|
}
|
|
32740
32740
|
});
|
|
32741
32741
|
|
|
32742
|
+
// src/auto_save/buzz_envelope.ts
|
|
32743
|
+
function isNostrMetaLine(line) {
|
|
32744
|
+
return /^Tags: \[\[".*\]\]\s*$/.test(line) && /[0-9a-f]{64}/.test(line) || /^Parsed: (?:root=[0-9a-f]{64}|mentions=\[.*\([0-9a-f]{64}\))/.test(line);
|
|
32745
|
+
}
|
|
32746
|
+
function skipWhitespace(s, i) {
|
|
32747
|
+
while (i < s.length && /\s/.test(s[i])) i++;
|
|
32748
|
+
return i;
|
|
32749
|
+
}
|
|
32750
|
+
function locateBuzzContext(text) {
|
|
32751
|
+
if (!text.startsWith("<base>")) return CONTEXT_OPEN.test(text.slice(0, 12)) ? { rest: text, pos: 0 } : null;
|
|
32752
|
+
const baseEnd = text.indexOf("</base>");
|
|
32753
|
+
if (baseEnd < 0) return null;
|
|
32754
|
+
const rest = text.slice(baseEnd + "</base>".length);
|
|
32755
|
+
let pos = skipWhitespace(rest, 0);
|
|
32756
|
+
for (; ; ) {
|
|
32757
|
+
const name = PREAMBLE_BLOCKS.find((b) => rest.startsWith(`<${b}>`, pos));
|
|
32758
|
+
if (!name) break;
|
|
32759
|
+
const close = rest.indexOf(`</${name}>`, pos);
|
|
32760
|
+
if (close < 0) return null;
|
|
32761
|
+
pos = skipWhitespace(rest, close + name.length + 3);
|
|
32762
|
+
}
|
|
32763
|
+
return CONTEXT_OPEN.test(rest.slice(pos, pos + 12)) ? { rest, pos } : null;
|
|
32764
|
+
}
|
|
32765
|
+
function cleanBuzzEnvelope(message) {
|
|
32766
|
+
try {
|
|
32767
|
+
const text = message.trimStart();
|
|
32768
|
+
if (!text.startsWith("<base>")) return null;
|
|
32769
|
+
const loc = locateBuzzContext(text);
|
|
32770
|
+
if (!loc) return null;
|
|
32771
|
+
const { rest, pos } = loc;
|
|
32772
|
+
const bodyStart = rest.indexOf("\n", pos) + 1;
|
|
32773
|
+
const contextClose = rest.indexOf(CONTEXT_CLOSE, bodyStart - 1);
|
|
32774
|
+
if (contextClose < 0) return null;
|
|
32775
|
+
const contextBody = rest.slice(bodyStart, contextClose).replace(/\r$/, "");
|
|
32776
|
+
const tail = rest.slice(contextClose + CONTEXT_CLOSE.length);
|
|
32777
|
+
let turnStart = 0;
|
|
32778
|
+
const history = HISTORY_OPEN.exec(tail);
|
|
32779
|
+
if (history) {
|
|
32780
|
+
const closeTag = `</${history[1]}>`;
|
|
32781
|
+
const close = tail.indexOf(closeTag, history[0].length);
|
|
32782
|
+
if (close < 0) return null;
|
|
32783
|
+
turnStart = close + closeTag.length;
|
|
32784
|
+
}
|
|
32785
|
+
if (TURN_IN_DROPPED.test(rest.slice(0, pos)) || TURN_IN_DROPPED.test(tail.slice(0, turnStart))) return null;
|
|
32786
|
+
const turn = tail.slice(turnStart);
|
|
32787
|
+
if (!TURN_OPEN.test(turn)) return null;
|
|
32788
|
+
const turnText = turn.split("\n").filter((line) => !isNostrMetaLine(line)).join("\n").trim();
|
|
32789
|
+
if (!turnText) return null;
|
|
32790
|
+
const cleaned = `<context>
|
|
32791
|
+
${contextBody}
|
|
32792
|
+
</context>
|
|
32793
|
+
|
|
32794
|
+
${turnText}`;
|
|
32795
|
+
if (cleaned.length >= message.length) return null;
|
|
32796
|
+
return cleaned;
|
|
32797
|
+
} catch {
|
|
32798
|
+
return null;
|
|
32799
|
+
}
|
|
32800
|
+
}
|
|
32801
|
+
function buzzEmbeddingText(message) {
|
|
32802
|
+
try {
|
|
32803
|
+
if (!message.startsWith("<context>\n")) return message;
|
|
32804
|
+
const close = message.indexOf(CONTEXT_CLOSE);
|
|
32805
|
+
if (close < 0) return message;
|
|
32806
|
+
const turn = message.slice(close + CONTEXT_CLOSE.length);
|
|
32807
|
+
if (!TURN_OPEN.test(turn)) return message;
|
|
32808
|
+
const text = turn.split("\n").filter((line) => !EVENT_HEADER.test(line) && !isNostrMetaLine(line)).map(
|
|
32809
|
+
(line) => (
|
|
32810
|
+
// `$` 없이: 끝까지 되짚는 역추적을 막는다 (긴 줄에서 제곱 시간)
|
|
32811
|
+
line.replace(/^From: (.*?) \(npub:.*/, "From: $1").replace(/^Channel: (\S+) \(#[0-9a-f-]+\)/, "Channel: $1")
|
|
32812
|
+
)
|
|
32813
|
+
).join("\n").trim();
|
|
32814
|
+
return text || message;
|
|
32815
|
+
} catch {
|
|
32816
|
+
return message;
|
|
32817
|
+
}
|
|
32818
|
+
}
|
|
32819
|
+
function venueFromBuzzContext(message) {
|
|
32820
|
+
if (!CONTEXT_OPEN.test(message.slice(0, 12))) return null;
|
|
32821
|
+
const end = message.indexOf(CONTEXT_CLOSE);
|
|
32822
|
+
if (end < 0) return null;
|
|
32823
|
+
const lines = message.slice(0, end).split("\n").map((l) => l.replace(/\r$/, ""));
|
|
32824
|
+
const scope = lines.find((l) => l.startsWith("Scope: "))?.slice("Scope: ".length).trim();
|
|
32825
|
+
if (scope !== "thread" && scope !== "channel" && scope !== "dm") return null;
|
|
32826
|
+
if (scope === "dm") return "buzz:dm";
|
|
32827
|
+
const channel = lines.find((l) => l.startsWith("Channel: "))?.trimEnd();
|
|
32828
|
+
const m = channel ? /^Channel: (.+?) \(#[0-9a-f-]{36}\)$/.exec(channel) : null;
|
|
32829
|
+
return m ? `buzz:${m[1]}` : "buzz";
|
|
32830
|
+
}
|
|
32831
|
+
function looksLikeBuzzTurn(message) {
|
|
32832
|
+
const text = message.trimStart();
|
|
32833
|
+
if (text.startsWith("<base>")) return true;
|
|
32834
|
+
if (!CONTEXT_OPEN.test(text.slice(0, 12))) return false;
|
|
32835
|
+
const close = text.indexOf(CONTEXT_CLOSE);
|
|
32836
|
+
return close >= 0 && TURN_OPEN.test(text.slice(close + CONTEXT_CLOSE.length));
|
|
32837
|
+
}
|
|
32838
|
+
function venueFromBuzzMessage(message) {
|
|
32839
|
+
try {
|
|
32840
|
+
const loc = locateBuzzContext(message.trimStart());
|
|
32841
|
+
return loc ? venueFromBuzzContext(loc.rest.slice(loc.pos)) : null;
|
|
32842
|
+
} catch {
|
|
32843
|
+
return null;
|
|
32844
|
+
}
|
|
32845
|
+
}
|
|
32846
|
+
var PREAMBLE_BLOCKS, HISTORY_OPEN, TURN_OPEN, TURN_IN_DROPPED, CONTEXT_OPEN, CONTEXT_CLOSE, EVENT_HEADER;
|
|
32847
|
+
var init_buzz_envelope = __esm({
|
|
32848
|
+
"src/auto_save/buzz_envelope.ts"() {
|
|
32849
|
+
"use strict";
|
|
32850
|
+
PREAMBLE_BLOCKS = ["agent-instructions", "core-memory"];
|
|
32851
|
+
HISTORY_OPEN = /^\s*<((?:thread|conversation)-context)(?:\s[^>]*)?>/;
|
|
32852
|
+
TURN_OPEN = /^\s*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/;
|
|
32853
|
+
TURN_IN_DROPPED = /(?:^|>)[ \t]*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/m;
|
|
32854
|
+
CONTEXT_OPEN = /^<context>\r?\n/;
|
|
32855
|
+
CONTEXT_CLOSE = "\n</context>";
|
|
32856
|
+
EVENT_HEADER = /^(?:Event ID: [0-9a-f]{64}|Kind: \d+|Time: \d{4}-\d{2}-\d{2}T\S+|--- Event \d+ \(.*\) ---|Note: A new message arrived while you were working\..*)\s*$/;
|
|
32857
|
+
}
|
|
32858
|
+
});
|
|
32859
|
+
|
|
32860
|
+
// src/auto_save/venue.ts
|
|
32861
|
+
import fs2 from "fs";
|
|
32862
|
+
function classifySessionVenue(firstUserText, entrypoint) {
|
|
32863
|
+
if (buzzTurnVenue(firstUserText)) return "buzz";
|
|
32864
|
+
if (entrypoint && INTERACTIVE_ENTRYPOINTS.has(entrypoint)) return "terminal";
|
|
32865
|
+
if (/\bslack\b/i.test(firstUserText.slice(0, 500))) return "slack";
|
|
32866
|
+
if (entrypoint) return "auto";
|
|
32867
|
+
return null;
|
|
32868
|
+
}
|
|
32869
|
+
function buzzTurnVenue(message) {
|
|
32870
|
+
return venueFromBuzzMessage(message) ?? (looksLikeBuzzTurn(message) ? "buzz" : null);
|
|
32871
|
+
}
|
|
32872
|
+
function lastBuzzVenueInFile(jsonlPath, uptoBytes, userText) {
|
|
32873
|
+
const fd = fs2.openSync(jsonlPath, "r");
|
|
32874
|
+
try {
|
|
32875
|
+
let end = uptoBytes;
|
|
32876
|
+
let carry = Buffer.alloc(0);
|
|
32877
|
+
while (end > 0 && uptoBytes - end < TAIL_CAP) {
|
|
32878
|
+
const start = Math.max(0, end - TAIL_CHUNK);
|
|
32879
|
+
const chunk = Buffer.allocUnsafe(end - start);
|
|
32880
|
+
fs2.readSync(fd, chunk, 0, chunk.length, start);
|
|
32881
|
+
const buf = carry.length ? Buffer.concat([chunk, carry]) : chunk;
|
|
32882
|
+
const firstNl = start > 0 ? buf.indexOf(NEWLINE) : -1;
|
|
32883
|
+
carry = firstNl >= 0 ? buf.subarray(0, firstNl) : start > 0 ? buf : Buffer.alloc(0);
|
|
32884
|
+
const whole = firstNl >= 0 ? buf.subarray(firstNl + 1) : start > 0 ? Buffer.alloc(0) : buf;
|
|
32885
|
+
const lines = whole.toString("utf-8").split("\n");
|
|
32886
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
32887
|
+
const text = lines[i] ? userText(lines[i]) : null;
|
|
32888
|
+
const venue = text ? buzzTurnVenue(text) : null;
|
|
32889
|
+
if (venue) return venue;
|
|
32890
|
+
}
|
|
32891
|
+
end = start;
|
|
32892
|
+
}
|
|
32893
|
+
return null;
|
|
32894
|
+
} finally {
|
|
32895
|
+
fs2.closeSync(fd);
|
|
32896
|
+
}
|
|
32897
|
+
}
|
|
32898
|
+
var INTERACTIVE_ENTRYPOINTS, TAIL_CHUNK, TAIL_CAP, NEWLINE;
|
|
32899
|
+
var init_venue = __esm({
|
|
32900
|
+
"src/auto_save/venue.ts"() {
|
|
32901
|
+
"use strict";
|
|
32902
|
+
init_buzz_envelope();
|
|
32903
|
+
INTERACTIVE_ENTRYPOINTS = /* @__PURE__ */ new Set(["cli", "claude-vscode"]);
|
|
32904
|
+
TAIL_CHUNK = 4 * 1024 * 1024;
|
|
32905
|
+
TAIL_CAP = 64 * 1024 * 1024;
|
|
32906
|
+
NEWLINE = 10;
|
|
32907
|
+
}
|
|
32908
|
+
});
|
|
32909
|
+
|
|
32910
|
+
// src/hot_path.ts
|
|
32911
|
+
function missingOptionalColumn(err3, sql, cols) {
|
|
32912
|
+
const e = err3;
|
|
32913
|
+
if (e.code !== "42703") return void 0;
|
|
32914
|
+
const at = Number(e.position);
|
|
32915
|
+
const named = at > 0 ? /^[a-z_]+/.exec(sql.slice(at - 1))?.[0] : void 0;
|
|
32916
|
+
return cols.find(([c]) => named ? c === named : !!e.message?.includes(c))?.[0];
|
|
32917
|
+
}
|
|
32918
|
+
async function insertRawMemory(params) {
|
|
32919
|
+
const {
|
|
32920
|
+
user_id,
|
|
32921
|
+
agent_platform,
|
|
32922
|
+
agent_model,
|
|
32923
|
+
subagent = false,
|
|
32924
|
+
subagent_model = null,
|
|
32925
|
+
subagent_role = null,
|
|
32926
|
+
role,
|
|
32927
|
+
message,
|
|
32928
|
+
is_pinned = false,
|
|
32929
|
+
p_tag_id = null,
|
|
32930
|
+
d_tag = [],
|
|
32931
|
+
embedding = null,
|
|
32932
|
+
external_uuid = null,
|
|
32933
|
+
device_name = null
|
|
32934
|
+
} = params;
|
|
32935
|
+
const embeddingSql = embedding && embedding.length > 0 ? `[${embedding.join(",")}]` : null;
|
|
32936
|
+
const tagProcessed = p_tag_id !== null;
|
|
32937
|
+
const cleaned = role === "user" && !is_pinned && p_tag_id === null && embeddingSql === null ? cleanBuzzEnvelope(message) : null;
|
|
32938
|
+
const venue = params.venue ?? (role === "user" ? buzzTurnVenue(cleaned ?? message) : null);
|
|
32939
|
+
const raw = cleaned !== null ? message : params.raw_message ?? null;
|
|
32940
|
+
const optional2 = [];
|
|
32941
|
+
if (raw !== null) optional2.push(["raw_message", raw]);
|
|
32942
|
+
if (venue) optional2.push(["venue", venue]);
|
|
32943
|
+
const buildInsert = (cols2) => {
|
|
32944
|
+
const text = cleaned !== null && cols2.some(([c]) => c === "raw_message") ? cleaned : message;
|
|
32945
|
+
const extra = [
|
|
32946
|
+
...cols2,
|
|
32947
|
+
...params.created_at ? [["created_at", params.created_at]] : []
|
|
32948
|
+
];
|
|
32949
|
+
const sql = `INSERT INTO memory (
|
|
32950
|
+
user_id, agent_platform, agent_model,
|
|
32951
|
+
subagent, subagent_model, subagent_role,
|
|
32952
|
+
role, message,
|
|
32953
|
+
p_tag_id, d_tag, embedding,
|
|
32954
|
+
is_pinned, tag_processed, external_uuid,
|
|
32955
|
+
device_name${extra.map(([c]) => `, ${c}`).join("")}
|
|
32956
|
+
) VALUES (
|
|
32957
|
+
$1, $2, $3,
|
|
32958
|
+
$4, $5, $6,
|
|
32959
|
+
$7, $8,
|
|
32960
|
+
$9, $10::text[], $11::halfvec,
|
|
32961
|
+
$12, $13, $14,
|
|
32962
|
+
$15${extra.map((_, i) => `, $${16 + i}`).join("")}
|
|
32963
|
+
)
|
|
32964
|
+
ON CONFLICT (external_uuid) WHERE external_uuid IS NOT NULL
|
|
32965
|
+
DO NOTHING
|
|
32966
|
+
RETURNING id, created_at`;
|
|
32967
|
+
const values = [
|
|
32968
|
+
user_id,
|
|
32969
|
+
agent_platform,
|
|
32970
|
+
agent_model,
|
|
32971
|
+
subagent,
|
|
32972
|
+
subagent_model,
|
|
32973
|
+
subagent_role,
|
|
32974
|
+
role,
|
|
32975
|
+
text,
|
|
32976
|
+
p_tag_id,
|
|
32977
|
+
d_tag,
|
|
32978
|
+
embeddingSql,
|
|
32979
|
+
is_pinned,
|
|
32980
|
+
tagProcessed,
|
|
32981
|
+
external_uuid,
|
|
32982
|
+
device_name,
|
|
32983
|
+
...extra.map(([, v]) => v)
|
|
32984
|
+
];
|
|
32985
|
+
return { sql, values };
|
|
32986
|
+
};
|
|
32987
|
+
let cols = optional2.filter(([c]) => !missingColumns.has(c));
|
|
32988
|
+
let result;
|
|
32989
|
+
for (; ; ) {
|
|
32990
|
+
const { sql, values } = buildInsert(cols);
|
|
32991
|
+
try {
|
|
32992
|
+
result = await db.query(sql, values);
|
|
32993
|
+
break;
|
|
32994
|
+
} catch (err3) {
|
|
32995
|
+
const missing = missingOptionalColumn(err3, sql, cols);
|
|
32996
|
+
if (!missing) throw err3;
|
|
32997
|
+
missingColumns.add(missing);
|
|
32998
|
+
console.error(
|
|
32999
|
+
`\u26A0\uFE0F [HotPath] memory.${missing} \uCE78\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \`mcp-agents-memory migrate\` \uC2E4\uD589 \uD6C4 \uC774 \uD504\uB85C\uC138\uC2A4\uB97C \uC7AC\uC2DC\uC791\uD574\uC57C ${MISSING_COLUMN_EFFECT[missing]}`
|
|
33000
|
+
);
|
|
33001
|
+
cols = cols.filter(([c]) => c !== missing);
|
|
33002
|
+
}
|
|
33003
|
+
}
|
|
33004
|
+
if (result.rows.length === 0) {
|
|
33005
|
+
const existing = await db.query(
|
|
33006
|
+
`SELECT id, created_at FROM memory WHERE external_uuid = $1 LIMIT 1`,
|
|
33007
|
+
[external_uuid]
|
|
33008
|
+
);
|
|
33009
|
+
if (existing.rows.length > 0) {
|
|
33010
|
+
const row2 = existing.rows[0];
|
|
33011
|
+
return { id: Number(row2.id), created_at: row2.created_at, inserted: false };
|
|
33012
|
+
}
|
|
33013
|
+
throw new Error(`insertRawMemory: ON CONFLICT triggered but no existing row found (external_uuid=${external_uuid})`);
|
|
33014
|
+
}
|
|
33015
|
+
const row = result.rows[0];
|
|
33016
|
+
return { id: Number(row.id), created_at: row.created_at, inserted: true };
|
|
33017
|
+
}
|
|
33018
|
+
var missingColumns, MISSING_COLUMN_EFFECT;
|
|
33019
|
+
var init_hot_path = __esm({
|
|
33020
|
+
"src/hot_path.ts"() {
|
|
33021
|
+
"use strict";
|
|
33022
|
+
init_db();
|
|
33023
|
+
init_buzz_envelope();
|
|
33024
|
+
init_venue();
|
|
33025
|
+
missingColumns = /* @__PURE__ */ new Set();
|
|
33026
|
+
MISSING_COLUMN_EFFECT = {
|
|
33027
|
+
raw_message: "Buzz \uBD09\uD22C \uC815\uB9AC\uAC00 \uC2DC\uC791\uB429\uB2C8\uB2E4. \uADF8 \uC804\uAE4C\uC9C0\uB294 \uC6D0\uBB38 \uADF8\uB300\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.",
|
|
33028
|
+
venue: "\uB300\uD654 \uC790\uB9AC(venue) \uAE30\uB85D\uC774 \uC2DC\uC791\uB429\uB2C8\uB2E4. \uADF8 \uC804\uAE4C\uC9C0\uB294 venue \uC5C6\uC774 \uC800\uC7A5\uD569\uB2C8\uB2E4."
|
|
33029
|
+
};
|
|
33030
|
+
}
|
|
33031
|
+
});
|
|
33032
|
+
|
|
33033
|
+
// src/users.ts
|
|
33034
|
+
async function getOrCreateUser(userName) {
|
|
33035
|
+
const cached2 = cache.get(userName);
|
|
33036
|
+
if (cached2 !== void 0) return cached2;
|
|
33037
|
+
const existing = await db.query(
|
|
33038
|
+
`SELECT user_id FROM users WHERE user_name = $1 LIMIT 1`,
|
|
33039
|
+
[userName]
|
|
33040
|
+
);
|
|
33041
|
+
if (existing.rows.length > 0) {
|
|
33042
|
+
const id2 = Number(existing.rows[0].user_id);
|
|
33043
|
+
cache.set(userName, id2);
|
|
33044
|
+
return id2;
|
|
33045
|
+
}
|
|
33046
|
+
const inserted = await db.query(
|
|
33047
|
+
`INSERT INTO users (user_name) VALUES ($1)
|
|
33048
|
+
ON CONFLICT (user_name) DO UPDATE SET updated_at = users.updated_at
|
|
33049
|
+
RETURNING user_id`,
|
|
33050
|
+
[userName]
|
|
33051
|
+
);
|
|
33052
|
+
const id = Number(inserted.rows[0].user_id);
|
|
33053
|
+
cache.set(userName, id);
|
|
33054
|
+
return id;
|
|
33055
|
+
}
|
|
33056
|
+
async function getDefaultUserId() {
|
|
33057
|
+
const name = process.env.USER_NAME ?? "hoon";
|
|
33058
|
+
return getOrCreateUser(name);
|
|
33059
|
+
}
|
|
33060
|
+
async function updateUserProfile(userId, field, value) {
|
|
33061
|
+
if (field === "core_profile") {
|
|
33062
|
+
await db.query(
|
|
33063
|
+
`UPDATE users SET core_profile = $1 WHERE user_id = $2`,
|
|
33064
|
+
[value, userId]
|
|
33065
|
+
);
|
|
33066
|
+
} else {
|
|
33067
|
+
await db.query(
|
|
33068
|
+
`UPDATE users SET sub_profile = $1 WHERE user_id = $2`,
|
|
33069
|
+
[value, userId]
|
|
33070
|
+
);
|
|
33071
|
+
}
|
|
33072
|
+
}
|
|
33073
|
+
async function getUserProfile(userId) {
|
|
33074
|
+
const r = await db.query(
|
|
33075
|
+
`SELECT core_profile, sub_profile FROM users WHERE user_id = $1`,
|
|
33076
|
+
[userId]
|
|
33077
|
+
);
|
|
33078
|
+
return r.rows[0] ?? { core_profile: null, sub_profile: null };
|
|
33079
|
+
}
|
|
33080
|
+
var cache;
|
|
33081
|
+
var init_users = __esm({
|
|
33082
|
+
"src/users.ts"() {
|
|
33083
|
+
"use strict";
|
|
33084
|
+
init_db();
|
|
33085
|
+
cache = /* @__PURE__ */ new Map();
|
|
33086
|
+
}
|
|
33087
|
+
});
|
|
33088
|
+
|
|
32742
33089
|
// src/setup.ts
|
|
32743
33090
|
var setup_exports = {};
|
|
32744
33091
|
__export(setup_exports, {
|
|
@@ -32763,6 +33110,326 @@ var init_setup = __esm({
|
|
|
32763
33110
|
}
|
|
32764
33111
|
});
|
|
32765
33112
|
|
|
33113
|
+
// src/auto_save/buzz_ingest.ts
|
|
33114
|
+
var buzz_ingest_exports = {};
|
|
33115
|
+
__export(buzz_ingest_exports, {
|
|
33116
|
+
authorLabel: () => authorLabel,
|
|
33117
|
+
channelVenue: () => channelVenue,
|
|
33118
|
+
chatMessage: () => chatMessage,
|
|
33119
|
+
latestEdits: () => latestEdits,
|
|
33120
|
+
listChannels: () => listChannels,
|
|
33121
|
+
newChatEvents: () => newChatEvents,
|
|
33122
|
+
ownerPubkeys: () => ownerPubkeys,
|
|
33123
|
+
parseIngestArgs: () => parseIngestArgs,
|
|
33124
|
+
runBuzzIngest: () => runBuzzIngest
|
|
33125
|
+
});
|
|
33126
|
+
import { execFile } from "node:child_process";
|
|
33127
|
+
function cliPath() {
|
|
33128
|
+
return process.env.BUZZ_CLI || "buzz";
|
|
33129
|
+
}
|
|
33130
|
+
function childEnv() {
|
|
33131
|
+
return Object.fromEntries(Object.entries(process.env).filter(([k]) => CHILD_ENV.test(k)));
|
|
33132
|
+
}
|
|
33133
|
+
function runCli(args) {
|
|
33134
|
+
return new Promise((resolve, reject) => {
|
|
33135
|
+
execFile(
|
|
33136
|
+
cliPath(),
|
|
33137
|
+
args,
|
|
33138
|
+
{ maxBuffer: 256 * 1024 * 1024, timeout: 12e4, env: childEnv() },
|
|
33139
|
+
(err3, stdout, stderr) => {
|
|
33140
|
+
if (err3) {
|
|
33141
|
+
reject(new Error(`buzz ${args.slice(0, 2).join(" ")} \uC2E4\uD328: ${String(stderr || err3.message).trim().slice(0, 500)}`));
|
|
33142
|
+
return;
|
|
33143
|
+
}
|
|
33144
|
+
try {
|
|
33145
|
+
resolve(JSON.parse(stdout));
|
|
33146
|
+
} catch {
|
|
33147
|
+
reject(new BuzzShapeError(`buzz ${args.slice(0, 2).join(" ")}: JSON\uC774 \uC544\uB2CC \uCD9C\uB825`));
|
|
33148
|
+
}
|
|
33149
|
+
}
|
|
33150
|
+
);
|
|
33151
|
+
});
|
|
33152
|
+
}
|
|
33153
|
+
function asEvent(v) {
|
|
33154
|
+
const e = v;
|
|
33155
|
+
const ok4 = e && typeof e === "object" && typeof e.id === "string" && HEX64.test(e.id) && typeof e.pubkey === "string" && HEX64.test(e.pubkey) && Number.isInteger(e.created_at) && Number.isInteger(e.kind) && typeof e.content === "string" && Array.isArray(e.tags) && e.tags.every((t) => Array.isArray(t) && t.every((x) => typeof x === "string"));
|
|
33156
|
+
if (!ok4) throw new BuzzShapeError(`\uC608\uC0C1\uACFC \uB2E4\uB978 \uC774\uBCA4\uD2B8 \uBAA8\uC591: ${JSON.stringify(v).slice(0, 200)}`);
|
|
33157
|
+
return e;
|
|
33158
|
+
}
|
|
33159
|
+
function asArray(v, what) {
|
|
33160
|
+
if (!Array.isArray(v)) throw new BuzzShapeError(`${what}: \uBC30\uC5F4\uC774 \uC544\uB2CC \uCD9C\uB825`);
|
|
33161
|
+
return v;
|
|
33162
|
+
}
|
|
33163
|
+
async function listChannels() {
|
|
33164
|
+
const parse3 = (v) => asArray(v, "channels list").map((c) => {
|
|
33165
|
+
const ch = c;
|
|
33166
|
+
if (typeof ch?.channel_id !== "string" || !UUID.test(ch.channel_id) || typeof ch.name !== "string") {
|
|
33167
|
+
throw new BuzzShapeError(`\uC608\uC0C1\uACFC \uB2E4\uB978 \uCC44\uB110 \uBAA8\uC591: ${JSON.stringify(c).slice(0, 200)}`);
|
|
33168
|
+
}
|
|
33169
|
+
return { id: ch.channel_id, name: ch.name };
|
|
33170
|
+
});
|
|
33171
|
+
const all = parse3(await runCli(["channels", "list", "--member"]));
|
|
33172
|
+
if (all.length === 0) throw new BuzzShapeError("channels list --member: CLI \uC2E0\uC6D0\uC774 \uBA64\uBC84\uC778 \uBC29\uC774 \uD558\uB098\uB3C4 \uC5C6\uC74C");
|
|
33173
|
+
const priv = new Set(parse3(await runCli(["channels", "list", "--member", "--visibility", "private"])).map((c) => c.id));
|
|
33174
|
+
return all.map((c) => ({ ...c, private: priv.has(c.id) }));
|
|
33175
|
+
}
|
|
33176
|
+
function channelVenue(ch) {
|
|
33177
|
+
const name = ch.name.trim();
|
|
33178
|
+
if (!name) return "buzz";
|
|
33179
|
+
return ch.private && name === "DM" ? "buzz:dm" : `buzz:${name}`;
|
|
33180
|
+
}
|
|
33181
|
+
async function getPage(channelId, kinds, before) {
|
|
33182
|
+
const args = ["messages", "get", "--channel", channelId, "--limit", String(PAGE), "--kinds", kinds.join(",")];
|
|
33183
|
+
if (before !== void 0) args.push("--before", String(before));
|
|
33184
|
+
return asArray(await runCli(args), "messages get").map(asEvent);
|
|
33185
|
+
}
|
|
33186
|
+
async function knownIds(eventIds) {
|
|
33187
|
+
if (eventIds.length === 0) return /* @__PURE__ */ new Set();
|
|
33188
|
+
const r = await db.query(
|
|
33189
|
+
`SELECT external_uuid FROM memory WHERE external_uuid = ANY($1::text[])`,
|
|
33190
|
+
[eventIds.map((id) => `buzz:${id}`)]
|
|
33191
|
+
);
|
|
33192
|
+
return new Set(r.rows.map((row) => String(row.external_uuid).slice("buzz:".length)));
|
|
33193
|
+
}
|
|
33194
|
+
async function pageBack(channelId, kinds, visit) {
|
|
33195
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33196
|
+
let before;
|
|
33197
|
+
for (let pages = 0; ; pages++) {
|
|
33198
|
+
if (pages >= MAX_PAGES_PER_CHANNEL) {
|
|
33199
|
+
throw new BuzzShapeError(`${channelId}: ${MAX_PAGES_PER_CHANNEL}\uCABD\uC744 \uB118\uACA8\uB3C4 \uB05D\uB098\uC9C0 \uC54A\uC74C`);
|
|
33200
|
+
}
|
|
33201
|
+
const page = await getPage(channelId, kinds, before);
|
|
33202
|
+
if (page.length === 0) {
|
|
33203
|
+
if (before === void 0) return;
|
|
33204
|
+
throw new BuzzShapeError(`${channelId}: \uC774\uC5B4\uC9C0\uB294 \uCABD\uC774 \uBE44\uC5B4 \uC788\uC74C`);
|
|
33205
|
+
}
|
|
33206
|
+
const unseen = page.filter((e) => !seen.has(e.id));
|
|
33207
|
+
if (unseen.length === 0) {
|
|
33208
|
+
if (page.length >= PAGE) throw new BuzzShapeError(`${channelId}: \uCABD \uB118\uAE40\uC774 \uC55E\uC73C\uB85C \uAC00\uC9C0 \uC54A\uC74C`);
|
|
33209
|
+
return;
|
|
33210
|
+
}
|
|
33211
|
+
for (const e of unseen) seen.add(e.id);
|
|
33212
|
+
if (!await visit(page, unseen)) return;
|
|
33213
|
+
before = Math.min(...page.map((e) => e.created_at)) + 1;
|
|
33214
|
+
}
|
|
33215
|
+
}
|
|
33216
|
+
async function newChatEvents(channelId) {
|
|
33217
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
33218
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
33219
|
+
let stopBelow;
|
|
33220
|
+
await pageBack(channelId, [KIND_CHAT], async (page, unseen) => {
|
|
33221
|
+
const chats = unseen.filter((e) => e.kind === KIND_CHAT);
|
|
33222
|
+
const known = await knownIds(chats.map((e) => e.id));
|
|
33223
|
+
for (const e of chats) if (!known.has(e.id)) fresh.set(e.id, e);
|
|
33224
|
+
if (known.size > 0 && stopBelow === void 0) {
|
|
33225
|
+
const newestKnown = Math.max(...chats.filter((e) => known.has(e.id)).map((e) => e.created_at));
|
|
33226
|
+
stopBelow = Math.min(newestKnown, nowSec) - LOOKBACK_SEC;
|
|
33227
|
+
}
|
|
33228
|
+
return !(stopBelow !== void 0 && Math.min(...page.map((e) => e.created_at)) < stopBelow);
|
|
33229
|
+
});
|
|
33230
|
+
return [...fresh.values()];
|
|
33231
|
+
}
|
|
33232
|
+
async function recentEvents(channelId, kinds, floor) {
|
|
33233
|
+
const out = [];
|
|
33234
|
+
await pageBack(channelId, kinds, async (page, unseen) => {
|
|
33235
|
+
out.push(...unseen.filter((e) => kinds.includes(e.kind)));
|
|
33236
|
+
return floor !== void 0 && Math.min(...page.map((e) => e.created_at)) >= floor;
|
|
33237
|
+
});
|
|
33238
|
+
return out;
|
|
33239
|
+
}
|
|
33240
|
+
async function displayNames(pubkeys) {
|
|
33241
|
+
const self2 = asArray(await runCli(["users", "get"]), "users get").map((u) => u?.pubkey).find((pk) => typeof pk === "string" && HEX64.test(pk));
|
|
33242
|
+
if (!self2) {
|
|
33243
|
+
throw new BuzzShapeError("users get: CLI \uC2E0\uC6D0\uC758 \uD504\uB85C\uD544\uC774 \uC548 \uBCF4\uC784 \u2014 \uC774\uB984 \uC751\uB2F5\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC74C (\uC2E0\uC6D0\uC5D0 \uD504\uB85C\uD544\uC744 \uB123\uC5B4 \uC8FC\uC138\uC694)");
|
|
33244
|
+
}
|
|
33245
|
+
const names = /* @__PURE__ */ new Map();
|
|
33246
|
+
for (let i = 0; i < pubkeys.length; i += 20) {
|
|
33247
|
+
const chunk = pubkeys.slice(i, i + 20);
|
|
33248
|
+
const ask = chunk.includes(self2) ? chunk : [...chunk, self2];
|
|
33249
|
+
const out = asArray(await runCli(["users", "get", ...ask.flatMap((pk) => ["--pubkey", pk])]), "users get");
|
|
33250
|
+
const profiles = out.map((u) => u);
|
|
33251
|
+
if (!profiles.some((p) => p?.pubkey === self2)) {
|
|
33252
|
+
throw new BuzzShapeError("users get: \uC790\uAE30 \uD504\uB85C\uD544\uC774 \uBE60\uC9C4 \uC751\uB2F5 \u2014 \uC774\uB984\uC744 \uBBFF\uC744 \uC218 \uC5C6\uC74C");
|
|
33253
|
+
}
|
|
33254
|
+
for (const p of profiles) {
|
|
33255
|
+
const label = [p?.display_name, p?.name].find((v) => typeof v === "string" && v.trim() !== "");
|
|
33256
|
+
if (typeof p?.pubkey === "string" && label) names.set(p.pubkey, label.trim());
|
|
33257
|
+
}
|
|
33258
|
+
}
|
|
33259
|
+
return names;
|
|
33260
|
+
}
|
|
33261
|
+
function ownerPubkeys() {
|
|
33262
|
+
const raw = process.env.BUZZ_INGEST_OWNER ?? "";
|
|
33263
|
+
const keys = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
33264
|
+
if (keys.length === 0 || !keys.every((k) => HEX64.test(k))) {
|
|
33265
|
+
throw new Error(
|
|
33266
|
+
"BUZZ_INGEST_OWNER: \uC774 \uBA54\uBAA8\uB9AC \uC8FC\uC778\uC758 \uBC84\uC988 pubkey(64\uC790\uB9AC hex)\uB97C \uC27C\uD45C\uB85C \uC801\uC5B4\uC57C \uD569\uB2C8\uB2E4 \u2014 \uADF8 \uBC16\uC758 \uC791\uC131\uC790\uB294 assistant\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4"
|
|
33267
|
+
);
|
|
33268
|
+
}
|
|
33269
|
+
return new Set(keys);
|
|
33270
|
+
}
|
|
33271
|
+
function authorLabel(pubkey, names) {
|
|
33272
|
+
return names.get(pubkey) ?? pubkey.slice(0, 8);
|
|
33273
|
+
}
|
|
33274
|
+
function chatMessage(e, names) {
|
|
33275
|
+
return `[${authorLabel(e.pubkey, names)}] ${e.content}`;
|
|
33276
|
+
}
|
|
33277
|
+
function targetOf(e) {
|
|
33278
|
+
const t = e.tags.find((tag) => tag[0] === "e" && HEX64.test(tag[1] ?? ""));
|
|
33279
|
+
return t ? t[1] : null;
|
|
33280
|
+
}
|
|
33281
|
+
function latestEdits(events) {
|
|
33282
|
+
const latest = /* @__PURE__ */ new Map();
|
|
33283
|
+
for (const e of events) {
|
|
33284
|
+
if (e.kind !== KIND_EDIT) continue;
|
|
33285
|
+
const target = targetOf(e);
|
|
33286
|
+
if (!target) continue;
|
|
33287
|
+
const cur = latest.get(target);
|
|
33288
|
+
if (!cur || e.created_at > cur.created_at || e.created_at === cur.created_at && e.id > cur.id) {
|
|
33289
|
+
latest.set(target, e);
|
|
33290
|
+
}
|
|
33291
|
+
}
|
|
33292
|
+
return latest;
|
|
33293
|
+
}
|
|
33294
|
+
async function applyEdits(edits, dryRun) {
|
|
33295
|
+
if (edits.size === 0) return 0;
|
|
33296
|
+
const r = await db.query(
|
|
33297
|
+
`SELECT external_uuid, message, raw_message FROM memory
|
|
33298
|
+
WHERE external_uuid = ANY($1::text[]) AND agent_platform = 'buzz' AND raw_message IS NOT NULL`,
|
|
33299
|
+
[[...edits.keys()].map((id) => `buzz:${id}`)]
|
|
33300
|
+
);
|
|
33301
|
+
let n = 0;
|
|
33302
|
+
for (const row of r.rows) {
|
|
33303
|
+
const edit = edits.get(String(row.external_uuid).slice("buzz:".length));
|
|
33304
|
+
const raw = row.raw_message;
|
|
33305
|
+
const msg = row.message;
|
|
33306
|
+
if (raw === edit.content || !msg.endsWith(raw)) continue;
|
|
33307
|
+
n++;
|
|
33308
|
+
if (dryRun) continue;
|
|
33309
|
+
await db.query(
|
|
33310
|
+
`UPDATE memory
|
|
33311
|
+
SET message = $2, raw_message = $3,
|
|
33312
|
+
tag_processed = FALSE, embedding = NULL, cold_error = NULL
|
|
33313
|
+
WHERE external_uuid = $1`,
|
|
33314
|
+
[row.external_uuid, msg.slice(0, msg.length - raw.length) + edit.content, edit.content]
|
|
33315
|
+
);
|
|
33316
|
+
}
|
|
33317
|
+
return n;
|
|
33318
|
+
}
|
|
33319
|
+
async function hideDeleted(targets, dryRun) {
|
|
33320
|
+
if (targets.length === 0) return 0;
|
|
33321
|
+
const uuids = targets.map((id) => `buzz:${id}`);
|
|
33322
|
+
const sql = dryRun ? `SELECT count(*)::int AS n FROM memory
|
|
33323
|
+
WHERE external_uuid = ANY($1::text[]) AND agent_platform = 'buzz' AND is_active AND NOT is_pinned` : `WITH h AS (
|
|
33324
|
+
UPDATE memory SET is_active = FALSE, archived_at = NOW()
|
|
33325
|
+
WHERE external_uuid = ANY($1::text[]) AND agent_platform = 'buzz' AND is_active AND NOT is_pinned
|
|
33326
|
+
RETURNING 1)
|
|
33327
|
+
SELECT count(*)::int AS n FROM h`;
|
|
33328
|
+
const r = await db.query(sql, [uuids]);
|
|
33329
|
+
return Number(r.rows[0]?.n ?? 0);
|
|
33330
|
+
}
|
|
33331
|
+
async function runBuzzIngest(opts = {}) {
|
|
33332
|
+
const dryRun = opts.dryRun ?? false;
|
|
33333
|
+
const max = opts.max ?? 20;
|
|
33334
|
+
const owner = ownerPubkeys();
|
|
33335
|
+
const channels = await listChannels();
|
|
33336
|
+
const pending = [];
|
|
33337
|
+
for (const ch of channels) {
|
|
33338
|
+
const venue = channelVenue(ch);
|
|
33339
|
+
for (const e of await newChatEvents(ch.id)) pending.push({ e, ch, venue });
|
|
33340
|
+
}
|
|
33341
|
+
pending.sort((a, b) => a.e.created_at - b.e.created_at || (a.e.id < b.e.id ? -1 : a.e.id > b.e.id ? 1 : 0));
|
|
33342
|
+
const deleteTargets = /* @__PURE__ */ new Set();
|
|
33343
|
+
const edits = [];
|
|
33344
|
+
let unsupported = 0;
|
|
33345
|
+
for (const ch of channels) {
|
|
33346
|
+
for (const d of await getPage(ch.id, DELETE_KINDS)) {
|
|
33347
|
+
const t = DELETE_KINDS.includes(d.kind) ? targetOf(d) : null;
|
|
33348
|
+
if (t) deleteTargets.add(t);
|
|
33349
|
+
}
|
|
33350
|
+
}
|
|
33351
|
+
const batch = pending.filter(({ e }) => !deleteTargets.has(e.id)).slice(0, Math.max(0, max));
|
|
33352
|
+
for (const ch of channels) {
|
|
33353
|
+
const mine = batch.filter((b) => b.ch.id === ch.id).map((b) => b.e.created_at);
|
|
33354
|
+
edits.push(...await recentEvents(ch.id, [KIND_EDIT], mine.length ? Math.min(...mine) - LOOKBACK_SEC : void 0));
|
|
33355
|
+
if (dryRun) unsupported += (await getPage(ch.id, UNSUPPORTED_KINDS)).filter((e) => UNSUPPORTED_KINDS.includes(e.kind)).length;
|
|
33356
|
+
}
|
|
33357
|
+
const pubkeys = [...new Set(batch.map(({ e }) => e.pubkey))];
|
|
33358
|
+
const names = pubkeys.length ? await displayNames(pubkeys) : /* @__PURE__ */ new Map();
|
|
33359
|
+
const report = {
|
|
33360
|
+
channels: channels.length,
|
|
33361
|
+
pending: pending.length,
|
|
33362
|
+
inserted: 0,
|
|
33363
|
+
edited: 0,
|
|
33364
|
+
hidden: 0,
|
|
33365
|
+
byVenue: {},
|
|
33366
|
+
...dryRun ? { unsupported } : {}
|
|
33367
|
+
};
|
|
33368
|
+
const userId = dryRun ? 0 : await getDefaultUserId();
|
|
33369
|
+
for (const { e, venue } of batch) {
|
|
33370
|
+
report.byVenue[venue] = (report.byVenue[venue] ?? 0) + 1;
|
|
33371
|
+
if (dryRun) {
|
|
33372
|
+
report.inserted++;
|
|
33373
|
+
continue;
|
|
33374
|
+
}
|
|
33375
|
+
let res;
|
|
33376
|
+
try {
|
|
33377
|
+
res = await insertRawMemory({
|
|
33378
|
+
user_id: userId,
|
|
33379
|
+
agent_platform: "buzz",
|
|
33380
|
+
agent_model: null,
|
|
33381
|
+
role: owner.has(e.pubkey) ? "user" : "assistant",
|
|
33382
|
+
message: chatMessage(e, names),
|
|
33383
|
+
raw_message: e.content,
|
|
33384
|
+
external_uuid: `buzz:${e.id}`,
|
|
33385
|
+
device_name: null,
|
|
33386
|
+
venue,
|
|
33387
|
+
created_at: new Date(e.created_at * 1e3)
|
|
33388
|
+
});
|
|
33389
|
+
} catch (err3) {
|
|
33390
|
+
throw new Error(`buzz:${e.id} \uC800\uC7A5 \uC2E4\uD328: ${err3 instanceof Error ? err3.message : String(err3)}`);
|
|
33391
|
+
}
|
|
33392
|
+
if (res.inserted) report.inserted++;
|
|
33393
|
+
}
|
|
33394
|
+
report.edited = await applyEdits(latestEdits(edits), dryRun);
|
|
33395
|
+
report.hidden = await hideDeleted([...deleteTargets], dryRun);
|
|
33396
|
+
return report;
|
|
33397
|
+
}
|
|
33398
|
+
function parseIngestArgs(argv) {
|
|
33399
|
+
const opts = {};
|
|
33400
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33401
|
+
const a = argv[i];
|
|
33402
|
+
if (a === "--dry-run") opts.dryRun = true;
|
|
33403
|
+
else if (a === "--max") {
|
|
33404
|
+
const v = argv[++i];
|
|
33405
|
+
if (v === void 0 || !/^\d+$/.test(v)) throw new Error("--max: 0 \uC774\uC0C1\uC758 \uC815\uC218");
|
|
33406
|
+
opts.max = Number(v);
|
|
33407
|
+
} else throw new Error(`buzz-ingest: \uBAA8\uB974\uB294 \uC635\uC158 ${a}`);
|
|
33408
|
+
}
|
|
33409
|
+
return opts;
|
|
33410
|
+
}
|
|
33411
|
+
var KIND_CHAT, KIND_EDIT, DELETE_KINDS, UNSUPPORTED_KINDS, PAGE, MAX_PAGES_PER_CHANNEL, LOOKBACK_SEC, HEX64, UUID, CHILD_ENV, BuzzShapeError;
|
|
33412
|
+
var init_buzz_ingest = __esm({
|
|
33413
|
+
"src/auto_save/buzz_ingest.ts"() {
|
|
33414
|
+
"use strict";
|
|
33415
|
+
init_db();
|
|
33416
|
+
init_hot_path();
|
|
33417
|
+
init_users();
|
|
33418
|
+
KIND_CHAT = 9;
|
|
33419
|
+
KIND_EDIT = 40003;
|
|
33420
|
+
DELETE_KINDS = [5, 9005];
|
|
33421
|
+
UNSUPPORTED_KINDS = [40002, 40008, 45001, 45003];
|
|
33422
|
+
PAGE = 200;
|
|
33423
|
+
MAX_PAGES_PER_CHANNEL = 500;
|
|
33424
|
+
LOOKBACK_SEC = 48 * 3600;
|
|
33425
|
+
HEX64 = /^[0-9a-f]{64}$/;
|
|
33426
|
+
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
33427
|
+
CHILD_ENV = /^(PATH|PATHEXT|HOME|USER|LANG|LC_[A-Z]+|TZ|TMPDIR|TEMP|TMP|SSL_CERT_(FILE|DIR)|NODE_EXTRA_CA_CERTS|(HTTPS?|ALL|NO)_PROXY|SYSTEMROOT|WINDIR|COMSPEC|APPDATA|LOCALAPPDATA|USERPROFILE|BUZZ_[A-Z0-9_]+)$/i;
|
|
33428
|
+
BuzzShapeError = class extends Error {
|
|
33429
|
+
};
|
|
33430
|
+
}
|
|
33431
|
+
});
|
|
33432
|
+
|
|
32766
33433
|
// src/migrations/runner.ts
|
|
32767
33434
|
var runner_exports = {};
|
|
32768
33435
|
__export(runner_exports, {
|
|
@@ -47030,325 +47697,10 @@ var StdioServerTransport = class {
|
|
|
47030
47697
|
|
|
47031
47698
|
// src/tools/manage_knowledge.ts
|
|
47032
47699
|
init_db();
|
|
47700
|
+
init_hot_path();
|
|
47701
|
+
init_users();
|
|
47033
47702
|
import * as os3 from "node:os";
|
|
47034
47703
|
|
|
47035
|
-
// src/hot_path.ts
|
|
47036
|
-
init_db();
|
|
47037
|
-
|
|
47038
|
-
// src/auto_save/buzz_envelope.ts
|
|
47039
|
-
var PREAMBLE_BLOCKS = ["agent-instructions", "core-memory"];
|
|
47040
|
-
var HISTORY_OPEN = /^\s*<((?:thread|conversation)-context)(?:\s[^>]*)?>/;
|
|
47041
|
-
var TURN_OPEN = /^\s*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/;
|
|
47042
|
-
var TURN_IN_DROPPED = /(?:^|>)[ \t]*<(?:what-you-were-working-on|buzz-events?|new-message-arrived-while-you-were-working)[\s>]/m;
|
|
47043
|
-
var CONTEXT_OPEN = /^<context>\r?\n/;
|
|
47044
|
-
var CONTEXT_CLOSE = "\n</context>";
|
|
47045
|
-
function isNostrMetaLine(line) {
|
|
47046
|
-
return /^Tags: \[\[".*\]\]\s*$/.test(line) && /[0-9a-f]{64}/.test(line) || /^Parsed: (?:root=[0-9a-f]{64}|mentions=\[.*\([0-9a-f]{64}\))/.test(line);
|
|
47047
|
-
}
|
|
47048
|
-
function skipWhitespace(s, i) {
|
|
47049
|
-
while (i < s.length && /\s/.test(s[i])) i++;
|
|
47050
|
-
return i;
|
|
47051
|
-
}
|
|
47052
|
-
function locateBuzzContext(text) {
|
|
47053
|
-
if (!text.startsWith("<base>")) return CONTEXT_OPEN.test(text.slice(0, 12)) ? { rest: text, pos: 0 } : null;
|
|
47054
|
-
const baseEnd = text.indexOf("</base>");
|
|
47055
|
-
if (baseEnd < 0) return null;
|
|
47056
|
-
const rest = text.slice(baseEnd + "</base>".length);
|
|
47057
|
-
let pos = skipWhitespace(rest, 0);
|
|
47058
|
-
for (; ; ) {
|
|
47059
|
-
const name = PREAMBLE_BLOCKS.find((b) => rest.startsWith(`<${b}>`, pos));
|
|
47060
|
-
if (!name) break;
|
|
47061
|
-
const close = rest.indexOf(`</${name}>`, pos);
|
|
47062
|
-
if (close < 0) return null;
|
|
47063
|
-
pos = skipWhitespace(rest, close + name.length + 3);
|
|
47064
|
-
}
|
|
47065
|
-
return CONTEXT_OPEN.test(rest.slice(pos, pos + 12)) ? { rest, pos } : null;
|
|
47066
|
-
}
|
|
47067
|
-
function cleanBuzzEnvelope(message) {
|
|
47068
|
-
try {
|
|
47069
|
-
const text = message.trimStart();
|
|
47070
|
-
if (!text.startsWith("<base>")) return null;
|
|
47071
|
-
const loc = locateBuzzContext(text);
|
|
47072
|
-
if (!loc) return null;
|
|
47073
|
-
const { rest, pos } = loc;
|
|
47074
|
-
const bodyStart = rest.indexOf("\n", pos) + 1;
|
|
47075
|
-
const contextClose = rest.indexOf(CONTEXT_CLOSE, bodyStart - 1);
|
|
47076
|
-
if (contextClose < 0) return null;
|
|
47077
|
-
const contextBody = rest.slice(bodyStart, contextClose).replace(/\r$/, "");
|
|
47078
|
-
const tail = rest.slice(contextClose + CONTEXT_CLOSE.length);
|
|
47079
|
-
let turnStart = 0;
|
|
47080
|
-
const history = HISTORY_OPEN.exec(tail);
|
|
47081
|
-
if (history) {
|
|
47082
|
-
const closeTag = `</${history[1]}>`;
|
|
47083
|
-
const close = tail.indexOf(closeTag, history[0].length);
|
|
47084
|
-
if (close < 0) return null;
|
|
47085
|
-
turnStart = close + closeTag.length;
|
|
47086
|
-
}
|
|
47087
|
-
if (TURN_IN_DROPPED.test(rest.slice(0, pos)) || TURN_IN_DROPPED.test(tail.slice(0, turnStart))) return null;
|
|
47088
|
-
const turn = tail.slice(turnStart);
|
|
47089
|
-
if (!TURN_OPEN.test(turn)) return null;
|
|
47090
|
-
const turnText = turn.split("\n").filter((line) => !isNostrMetaLine(line)).join("\n").trim();
|
|
47091
|
-
if (!turnText) return null;
|
|
47092
|
-
const cleaned = `<context>
|
|
47093
|
-
${contextBody}
|
|
47094
|
-
</context>
|
|
47095
|
-
|
|
47096
|
-
${turnText}`;
|
|
47097
|
-
if (cleaned.length >= message.length) return null;
|
|
47098
|
-
return cleaned;
|
|
47099
|
-
} catch {
|
|
47100
|
-
return null;
|
|
47101
|
-
}
|
|
47102
|
-
}
|
|
47103
|
-
var EVENT_HEADER = /^(?:Event ID: [0-9a-f]{64}|Kind: \d+|Time: \d{4}-\d{2}-\d{2}T\S+|--- Event \d+ \(.*\) ---|Note: A new message arrived while you were working\..*)\s*$/;
|
|
47104
|
-
function buzzEmbeddingText(message) {
|
|
47105
|
-
try {
|
|
47106
|
-
if (!message.startsWith("<context>\n")) return message;
|
|
47107
|
-
const close = message.indexOf(CONTEXT_CLOSE);
|
|
47108
|
-
if (close < 0) return message;
|
|
47109
|
-
const turn = message.slice(close + CONTEXT_CLOSE.length);
|
|
47110
|
-
if (!TURN_OPEN.test(turn)) return message;
|
|
47111
|
-
const text = turn.split("\n").filter((line) => !EVENT_HEADER.test(line) && !isNostrMetaLine(line)).map(
|
|
47112
|
-
(line) => (
|
|
47113
|
-
// `$` 없이: 끝까지 되짚는 역추적을 막는다 (긴 줄에서 제곱 시간)
|
|
47114
|
-
line.replace(/^From: (.*?) \(npub:.*/, "From: $1").replace(/^Channel: (\S+) \(#[0-9a-f-]+\)/, "Channel: $1")
|
|
47115
|
-
)
|
|
47116
|
-
).join("\n").trim();
|
|
47117
|
-
return text || message;
|
|
47118
|
-
} catch {
|
|
47119
|
-
return message;
|
|
47120
|
-
}
|
|
47121
|
-
}
|
|
47122
|
-
function venueFromBuzzContext(message) {
|
|
47123
|
-
if (!CONTEXT_OPEN.test(message.slice(0, 12))) return null;
|
|
47124
|
-
const end = message.indexOf(CONTEXT_CLOSE);
|
|
47125
|
-
if (end < 0) return null;
|
|
47126
|
-
const lines = message.slice(0, end).split("\n").map((l) => l.replace(/\r$/, ""));
|
|
47127
|
-
const scope = lines.find((l) => l.startsWith("Scope: "))?.slice("Scope: ".length).trim();
|
|
47128
|
-
if (scope !== "thread" && scope !== "channel" && scope !== "dm") return null;
|
|
47129
|
-
if (scope === "dm") return "buzz:dm";
|
|
47130
|
-
const channel = lines.find((l) => l.startsWith("Channel: "))?.trimEnd();
|
|
47131
|
-
const m = channel ? /^Channel: (.+?) \(#[0-9a-f-]{36}\)$/.exec(channel) : null;
|
|
47132
|
-
return m ? `buzz:${m[1]}` : "buzz";
|
|
47133
|
-
}
|
|
47134
|
-
function looksLikeBuzzTurn(message) {
|
|
47135
|
-
const text = message.trimStart();
|
|
47136
|
-
if (text.startsWith("<base>")) return true;
|
|
47137
|
-
if (!CONTEXT_OPEN.test(text.slice(0, 12))) return false;
|
|
47138
|
-
const close = text.indexOf(CONTEXT_CLOSE);
|
|
47139
|
-
return close >= 0 && TURN_OPEN.test(text.slice(close + CONTEXT_CLOSE.length));
|
|
47140
|
-
}
|
|
47141
|
-
function venueFromBuzzMessage(message) {
|
|
47142
|
-
try {
|
|
47143
|
-
const loc = locateBuzzContext(message.trimStart());
|
|
47144
|
-
return loc ? venueFromBuzzContext(loc.rest.slice(loc.pos)) : null;
|
|
47145
|
-
} catch {
|
|
47146
|
-
return null;
|
|
47147
|
-
}
|
|
47148
|
-
}
|
|
47149
|
-
|
|
47150
|
-
// src/auto_save/venue.ts
|
|
47151
|
-
import fs2 from "fs";
|
|
47152
|
-
var INTERACTIVE_ENTRYPOINTS = /* @__PURE__ */ new Set(["cli", "claude-vscode"]);
|
|
47153
|
-
function classifySessionVenue(firstUserText, entrypoint) {
|
|
47154
|
-
if (buzzTurnVenue(firstUserText)) return "buzz";
|
|
47155
|
-
if (entrypoint && INTERACTIVE_ENTRYPOINTS.has(entrypoint)) return "terminal";
|
|
47156
|
-
if (/\bslack\b/i.test(firstUserText.slice(0, 500))) return "slack";
|
|
47157
|
-
if (entrypoint) return "auto";
|
|
47158
|
-
return null;
|
|
47159
|
-
}
|
|
47160
|
-
function buzzTurnVenue(message) {
|
|
47161
|
-
return venueFromBuzzMessage(message) ?? (looksLikeBuzzTurn(message) ? "buzz" : null);
|
|
47162
|
-
}
|
|
47163
|
-
var TAIL_CHUNK = 4 * 1024 * 1024;
|
|
47164
|
-
var TAIL_CAP = 64 * 1024 * 1024;
|
|
47165
|
-
var NEWLINE = 10;
|
|
47166
|
-
function lastBuzzVenueInFile(jsonlPath, uptoBytes, userText) {
|
|
47167
|
-
const fd = fs2.openSync(jsonlPath, "r");
|
|
47168
|
-
try {
|
|
47169
|
-
let end = uptoBytes;
|
|
47170
|
-
let carry = Buffer.alloc(0);
|
|
47171
|
-
while (end > 0 && uptoBytes - end < TAIL_CAP) {
|
|
47172
|
-
const start = Math.max(0, end - TAIL_CHUNK);
|
|
47173
|
-
const chunk = Buffer.allocUnsafe(end - start);
|
|
47174
|
-
fs2.readSync(fd, chunk, 0, chunk.length, start);
|
|
47175
|
-
const buf = carry.length ? Buffer.concat([chunk, carry]) : chunk;
|
|
47176
|
-
const firstNl = start > 0 ? buf.indexOf(NEWLINE) : -1;
|
|
47177
|
-
carry = firstNl >= 0 ? buf.subarray(0, firstNl) : start > 0 ? buf : Buffer.alloc(0);
|
|
47178
|
-
const whole = firstNl >= 0 ? buf.subarray(firstNl + 1) : start > 0 ? Buffer.alloc(0) : buf;
|
|
47179
|
-
const lines = whole.toString("utf-8").split("\n");
|
|
47180
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
47181
|
-
const text = lines[i] ? userText(lines[i]) : null;
|
|
47182
|
-
const venue = text ? buzzTurnVenue(text) : null;
|
|
47183
|
-
if (venue) return venue;
|
|
47184
|
-
}
|
|
47185
|
-
end = start;
|
|
47186
|
-
}
|
|
47187
|
-
return null;
|
|
47188
|
-
} finally {
|
|
47189
|
-
fs2.closeSync(fd);
|
|
47190
|
-
}
|
|
47191
|
-
}
|
|
47192
|
-
|
|
47193
|
-
// src/hot_path.ts
|
|
47194
|
-
var missingColumns = /* @__PURE__ */ new Set();
|
|
47195
|
-
var MISSING_COLUMN_EFFECT = {
|
|
47196
|
-
raw_message: "Buzz \uBD09\uD22C \uC815\uB9AC\uAC00 \uC2DC\uC791\uB429\uB2C8\uB2E4. \uADF8 \uC804\uAE4C\uC9C0\uB294 \uC6D0\uBB38 \uADF8\uB300\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.",
|
|
47197
|
-
venue: "\uB300\uD654 \uC790\uB9AC(venue) \uAE30\uB85D\uC774 \uC2DC\uC791\uB429\uB2C8\uB2E4. \uADF8 \uC804\uAE4C\uC9C0\uB294 venue \uC5C6\uC774 \uC800\uC7A5\uD569\uB2C8\uB2E4."
|
|
47198
|
-
};
|
|
47199
|
-
function missingOptionalColumn(err3, sql, cols) {
|
|
47200
|
-
const e = err3;
|
|
47201
|
-
if (e.code !== "42703") return void 0;
|
|
47202
|
-
const at = Number(e.position);
|
|
47203
|
-
const named = at > 0 ? /^[a-z_]+/.exec(sql.slice(at - 1))?.[0] : void 0;
|
|
47204
|
-
return cols.find(([c]) => named ? c === named : !!e.message?.includes(c))?.[0];
|
|
47205
|
-
}
|
|
47206
|
-
async function insertRawMemory(params) {
|
|
47207
|
-
const {
|
|
47208
|
-
user_id,
|
|
47209
|
-
agent_platform,
|
|
47210
|
-
agent_model,
|
|
47211
|
-
subagent = false,
|
|
47212
|
-
subagent_model = null,
|
|
47213
|
-
subagent_role = null,
|
|
47214
|
-
role,
|
|
47215
|
-
message,
|
|
47216
|
-
is_pinned = false,
|
|
47217
|
-
p_tag_id = null,
|
|
47218
|
-
d_tag = [],
|
|
47219
|
-
embedding = null,
|
|
47220
|
-
external_uuid = null,
|
|
47221
|
-
device_name = null
|
|
47222
|
-
} = params;
|
|
47223
|
-
const embeddingSql = embedding && embedding.length > 0 ? `[${embedding.join(",")}]` : null;
|
|
47224
|
-
const tagProcessed = p_tag_id !== null;
|
|
47225
|
-
const cleaned = role === "user" && !is_pinned && p_tag_id === null && embeddingSql === null ? cleanBuzzEnvelope(message) : null;
|
|
47226
|
-
const venue = params.venue ?? (role === "user" ? buzzTurnVenue(cleaned ?? message) : null);
|
|
47227
|
-
const optional2 = [];
|
|
47228
|
-
if (cleaned !== null) optional2.push(["raw_message", message]);
|
|
47229
|
-
if (venue) optional2.push(["venue", venue]);
|
|
47230
|
-
const buildInsert = (cols2) => {
|
|
47231
|
-
const text = cols2.some(([c]) => c === "raw_message") ? cleaned : message;
|
|
47232
|
-
const sql = `INSERT INTO memory (
|
|
47233
|
-
user_id, agent_platform, agent_model,
|
|
47234
|
-
subagent, subagent_model, subagent_role,
|
|
47235
|
-
role, message,
|
|
47236
|
-
p_tag_id, d_tag, embedding,
|
|
47237
|
-
is_pinned, tag_processed, external_uuid,
|
|
47238
|
-
device_name${cols2.map(([c]) => `, ${c}`).join("")}
|
|
47239
|
-
) VALUES (
|
|
47240
|
-
$1, $2, $3,
|
|
47241
|
-
$4, $5, $6,
|
|
47242
|
-
$7, $8,
|
|
47243
|
-
$9, $10::text[], $11::halfvec,
|
|
47244
|
-
$12, $13, $14,
|
|
47245
|
-
$15${cols2.map((_, i) => `, $${16 + i}`).join("")}
|
|
47246
|
-
)
|
|
47247
|
-
ON CONFLICT (external_uuid) WHERE external_uuid IS NOT NULL
|
|
47248
|
-
DO NOTHING
|
|
47249
|
-
RETURNING id, created_at`;
|
|
47250
|
-
const values = [
|
|
47251
|
-
user_id,
|
|
47252
|
-
agent_platform,
|
|
47253
|
-
agent_model,
|
|
47254
|
-
subagent,
|
|
47255
|
-
subagent_model,
|
|
47256
|
-
subagent_role,
|
|
47257
|
-
role,
|
|
47258
|
-
text,
|
|
47259
|
-
p_tag_id,
|
|
47260
|
-
d_tag,
|
|
47261
|
-
embeddingSql,
|
|
47262
|
-
is_pinned,
|
|
47263
|
-
tagProcessed,
|
|
47264
|
-
external_uuid,
|
|
47265
|
-
device_name,
|
|
47266
|
-
...cols2.map(([, v]) => v)
|
|
47267
|
-
];
|
|
47268
|
-
return { sql, values };
|
|
47269
|
-
};
|
|
47270
|
-
let cols = optional2.filter(([c]) => !missingColumns.has(c));
|
|
47271
|
-
let result;
|
|
47272
|
-
for (; ; ) {
|
|
47273
|
-
const { sql, values } = buildInsert(cols);
|
|
47274
|
-
try {
|
|
47275
|
-
result = await db.query(sql, values);
|
|
47276
|
-
break;
|
|
47277
|
-
} catch (err3) {
|
|
47278
|
-
const missing = missingOptionalColumn(err3, sql, cols);
|
|
47279
|
-
if (!missing) throw err3;
|
|
47280
|
-
missingColumns.add(missing);
|
|
47281
|
-
console.error(
|
|
47282
|
-
`\u26A0\uFE0F [HotPath] memory.${missing} \uCE78\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \`mcp-agents-memory migrate\` \uC2E4\uD589 \uD6C4 \uC774 \uD504\uB85C\uC138\uC2A4\uB97C \uC7AC\uC2DC\uC791\uD574\uC57C ${MISSING_COLUMN_EFFECT[missing]}`
|
|
47283
|
-
);
|
|
47284
|
-
cols = cols.filter(([c]) => c !== missing);
|
|
47285
|
-
}
|
|
47286
|
-
}
|
|
47287
|
-
if (result.rows.length === 0) {
|
|
47288
|
-
const existing = await db.query(
|
|
47289
|
-
`SELECT id, created_at FROM memory WHERE external_uuid = $1 LIMIT 1`,
|
|
47290
|
-
[external_uuid]
|
|
47291
|
-
);
|
|
47292
|
-
if (existing.rows.length > 0) {
|
|
47293
|
-
const row2 = existing.rows[0];
|
|
47294
|
-
return { id: Number(row2.id), created_at: row2.created_at, inserted: false };
|
|
47295
|
-
}
|
|
47296
|
-
throw new Error(`insertRawMemory: ON CONFLICT triggered but no existing row found (external_uuid=${external_uuid})`);
|
|
47297
|
-
}
|
|
47298
|
-
const row = result.rows[0];
|
|
47299
|
-
return { id: Number(row.id), created_at: row.created_at, inserted: true };
|
|
47300
|
-
}
|
|
47301
|
-
|
|
47302
|
-
// src/users.ts
|
|
47303
|
-
init_db();
|
|
47304
|
-
var cache = /* @__PURE__ */ new Map();
|
|
47305
|
-
async function getOrCreateUser(userName) {
|
|
47306
|
-
const cached2 = cache.get(userName);
|
|
47307
|
-
if (cached2 !== void 0) return cached2;
|
|
47308
|
-
const existing = await db.query(
|
|
47309
|
-
`SELECT user_id FROM users WHERE user_name = $1 LIMIT 1`,
|
|
47310
|
-
[userName]
|
|
47311
|
-
);
|
|
47312
|
-
if (existing.rows.length > 0) {
|
|
47313
|
-
const id2 = Number(existing.rows[0].user_id);
|
|
47314
|
-
cache.set(userName, id2);
|
|
47315
|
-
return id2;
|
|
47316
|
-
}
|
|
47317
|
-
const inserted = await db.query(
|
|
47318
|
-
`INSERT INTO users (user_name) VALUES ($1)
|
|
47319
|
-
ON CONFLICT (user_name) DO UPDATE SET updated_at = users.updated_at
|
|
47320
|
-
RETURNING user_id`,
|
|
47321
|
-
[userName]
|
|
47322
|
-
);
|
|
47323
|
-
const id = Number(inserted.rows[0].user_id);
|
|
47324
|
-
cache.set(userName, id);
|
|
47325
|
-
return id;
|
|
47326
|
-
}
|
|
47327
|
-
async function getDefaultUserId() {
|
|
47328
|
-
const name = process.env.USER_NAME ?? "hoon";
|
|
47329
|
-
return getOrCreateUser(name);
|
|
47330
|
-
}
|
|
47331
|
-
async function updateUserProfile(userId, field, value) {
|
|
47332
|
-
if (field === "core_profile") {
|
|
47333
|
-
await db.query(
|
|
47334
|
-
`UPDATE users SET core_profile = $1 WHERE user_id = $2`,
|
|
47335
|
-
[value, userId]
|
|
47336
|
-
);
|
|
47337
|
-
} else {
|
|
47338
|
-
await db.query(
|
|
47339
|
-
`UPDATE users SET sub_profile = $1 WHERE user_id = $2`,
|
|
47340
|
-
[value, userId]
|
|
47341
|
-
);
|
|
47342
|
-
}
|
|
47343
|
-
}
|
|
47344
|
-
async function getUserProfile(userId) {
|
|
47345
|
-
const r = await db.query(
|
|
47346
|
-
`SELECT core_profile, sub_profile FROM users WHERE user_id = $1`,
|
|
47347
|
-
[userId]
|
|
47348
|
-
);
|
|
47349
|
-
return r.rows[0] ?? { core_profile: null, sub_profile: null };
|
|
47350
|
-
}
|
|
47351
|
-
|
|
47352
47704
|
// ../mcp-agents-memory/node_modules/openai/internal/tslib.mjs
|
|
47353
47705
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
47354
47706
|
if (kind === "m")
|
|
@@ -56089,6 +56441,8 @@ async function tagMessage(input) {
|
|
|
56089
56441
|
}
|
|
56090
56442
|
|
|
56091
56443
|
// src/auto_save/opencode_capture.ts
|
|
56444
|
+
init_hot_path();
|
|
56445
|
+
init_users();
|
|
56092
56446
|
import * as fs4 from "node:fs";
|
|
56093
56447
|
import * as path4 from "node:path";
|
|
56094
56448
|
import * as os2 from "node:os";
|
|
@@ -56651,6 +57005,7 @@ ${args.content}` : args.content;
|
|
|
56651
57005
|
|
|
56652
57006
|
// src/tools/search_memory.ts
|
|
56653
57007
|
init_db();
|
|
57008
|
+
init_users();
|
|
56654
57009
|
|
|
56655
57010
|
// src/cold_path/embedder.ts
|
|
56656
57011
|
var MAX_RETRIES = 3;
|
|
@@ -56997,9 +57352,11 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56997
57352
|
|
|
56998
57353
|
// src/tools/manage_project_tags.ts
|
|
56999
57354
|
init_db();
|
|
57355
|
+
init_users();
|
|
57000
57356
|
|
|
57001
57357
|
// src/cold_path/project_alias_promoter.ts
|
|
57002
57358
|
init_db();
|
|
57359
|
+
init_users();
|
|
57003
57360
|
var QUALIFYING_RELATIONS = /* @__PURE__ */ new Set([
|
|
57004
57361
|
"rename",
|
|
57005
57362
|
"alias",
|
|
@@ -58315,7 +58672,9 @@ Actions:
|
|
|
58315
58672
|
}
|
|
58316
58673
|
|
|
58317
58674
|
// src/briefing.ts
|
|
58675
|
+
init_buzz_envelope();
|
|
58318
58676
|
init_db();
|
|
58677
|
+
init_users();
|
|
58319
58678
|
import * as os5 from "node:os";
|
|
58320
58679
|
var RECENT_CURRENT_LIMIT = 8;
|
|
58321
58680
|
var RECENT_OTHERS_LIMIT = 4;
|
|
@@ -58633,9 +58992,13 @@ agent_platform_filter=false.`,
|
|
|
58633
58992
|
}
|
|
58634
58993
|
|
|
58635
58994
|
// src/auto_save/save_message_tool.ts
|
|
58995
|
+
init_hot_path();
|
|
58996
|
+
init_users();
|
|
58636
58997
|
import * as os10 from "node:os";
|
|
58637
58998
|
|
|
58638
58999
|
// src/auto_save/gemini_capture.ts
|
|
59000
|
+
init_hot_path();
|
|
59001
|
+
init_users();
|
|
58639
59002
|
import * as fs5 from "node:fs";
|
|
58640
59003
|
import * as path5 from "node:path";
|
|
58641
59004
|
import * as os6 from "node:os";
|
|
@@ -59020,6 +59383,8 @@ async function captureSessionEnd2() {
|
|
|
59020
59383
|
}
|
|
59021
59384
|
|
|
59022
59385
|
// src/auto_save/grok_capture.ts
|
|
59386
|
+
init_hot_path();
|
|
59387
|
+
init_users();
|
|
59023
59388
|
import * as fs6 from "node:fs";
|
|
59024
59389
|
import * as path6 from "node:path";
|
|
59025
59390
|
import * as os7 from "node:os";
|
|
@@ -59303,6 +59668,8 @@ function isCaptureArmed3() {
|
|
|
59303
59668
|
}
|
|
59304
59669
|
|
|
59305
59670
|
// src/auto_save/antigravity_capture.ts
|
|
59671
|
+
init_hot_path();
|
|
59672
|
+
init_users();
|
|
59306
59673
|
import * as fs7 from "node:fs";
|
|
59307
59674
|
import * as path7 from "node:path";
|
|
59308
59675
|
import * as os8 from "node:os";
|
|
@@ -59605,6 +59972,9 @@ function isCaptureArmed4() {
|
|
|
59605
59972
|
}
|
|
59606
59973
|
|
|
59607
59974
|
// src/auto_save/hermes_capture.ts
|
|
59975
|
+
init_hot_path();
|
|
59976
|
+
init_venue();
|
|
59977
|
+
init_users();
|
|
59608
59978
|
import * as fs8 from "node:fs";
|
|
59609
59979
|
import * as path8 from "node:path";
|
|
59610
59980
|
import * as os9 from "node:os";
|
|
@@ -59975,6 +60345,7 @@ subagent \uCEE8\uD14D\uC2A4\uD2B8\uB77C\uBA74 subagent=true + subagent_model + s
|
|
|
59975
60345
|
|
|
59976
60346
|
// src/tools/task_pin.ts
|
|
59977
60347
|
init_db();
|
|
60348
|
+
init_users();
|
|
59978
60349
|
import * as os11 from "node:os";
|
|
59979
60350
|
var DEVICE_NAME8 = os11.hostname();
|
|
59980
60351
|
var STATUSES = ["pending", "in_progress", "done", "failed"];
|
|
@@ -60125,9 +60496,11 @@ function registerTools(server) {
|
|
|
60125
60496
|
|
|
60126
60497
|
// src/cold_path/worker.ts
|
|
60127
60498
|
init_db();
|
|
60499
|
+
init_buzz_envelope();
|
|
60128
60500
|
|
|
60129
60501
|
// src/cold_path/dtag_promoter.ts
|
|
60130
60502
|
init_db();
|
|
60503
|
+
init_users();
|
|
60131
60504
|
function envInt2(name, fallback) {
|
|
60132
60505
|
const raw = process.env[name];
|
|
60133
60506
|
if (!raw) return fallback;
|
|
@@ -60276,6 +60649,7 @@ async function runDtagPromotion() {
|
|
|
60276
60649
|
|
|
60277
60650
|
// src/librarian.ts
|
|
60278
60651
|
init_db();
|
|
60652
|
+
init_users();
|
|
60279
60653
|
|
|
60280
60654
|
// src/context_budget.ts
|
|
60281
60655
|
var DEFAULT_CTX = 8192;
|
|
@@ -60893,6 +61267,9 @@ async function drainColdPath(maxTicks = 12) {
|
|
|
60893
61267
|
}
|
|
60894
61268
|
|
|
60895
61269
|
// src/auto_save/jsonl_capture.ts
|
|
61270
|
+
init_hot_path();
|
|
61271
|
+
init_venue();
|
|
61272
|
+
init_users();
|
|
60896
61273
|
import * as fs9 from "node:fs";
|
|
60897
61274
|
import * as path9 from "node:path";
|
|
60898
61275
|
import * as os12 from "node:os";
|
|
@@ -61260,6 +61637,8 @@ async function captureSessionEnd6() {
|
|
|
61260
61637
|
}
|
|
61261
61638
|
|
|
61262
61639
|
// src/auto_save/codex_capture.ts
|
|
61640
|
+
init_hot_path();
|
|
61641
|
+
init_users();
|
|
61263
61642
|
import * as fs10 from "node:fs";
|
|
61264
61643
|
import * as path10 from "node:path";
|
|
61265
61644
|
import * as os13 from "node:os";
|
|
@@ -61756,6 +62135,12 @@ Usage:
|
|
|
61756
62135
|
mcp-agents-memory coldpath Run ONLY the cold-path worker as a standalone always-on daemon (no MCP server). For the processing/GPU machine via systemd.
|
|
61757
62136
|
mcp-agents-memory setup Interactive setup \u2014 write config to ~/.config/mcp-agents-memory/.env and run migrations.
|
|
61758
62137
|
mcp-agents-memory migrate Apply any pending DB migrations against the configured database.
|
|
62138
|
+
mcp-agents-memory buzz-ingest [--dry-run] [--max N]
|
|
62139
|
+
(Buzz only) Copy chat messages from the Buzz rooms the CLI identity is a member of
|
|
62140
|
+
into memory, one row per message, via the official \`buzz\` CLI. Oldest first, at most
|
|
62141
|
+
N per run (default 20). Needs BUZZ_RELAY_URL, BUZZ_PRIVATE_KEY and BUZZ_INGEST_OWNER
|
|
62142
|
+
(the memory owner's pubkeys, comma-separated) in the environment of this command only \u2014
|
|
62143
|
+
not in the shared .env; optional BUZZ_CLI.
|
|
61759
62144
|
mcp-agents-memory help Show this message.
|
|
61760
62145
|
|
|
61761
62146
|
Configuration is loaded from (first hit wins):
|
|
@@ -61848,6 +62233,15 @@ async function cli() {
|
|
|
61848
62233
|
await runSetupWizard2();
|
|
61849
62234
|
process.exit(0);
|
|
61850
62235
|
}
|
|
62236
|
+
if (cmd === "buzz-ingest") {
|
|
62237
|
+
const { runBuzzIngest: runBuzzIngest2, parseIngestArgs: parseIngestArgs2 } = await Promise.resolve().then(() => (init_buzz_ingest(), buzz_ingest_exports));
|
|
62238
|
+
const opts = parseIngestArgs2(process.argv.slice(3));
|
|
62239
|
+
await db.connect();
|
|
62240
|
+
const report = await runBuzzIngest2(opts);
|
|
62241
|
+
console.log(JSON.stringify({ dryRun: opts.dryRun ?? false, ...report }));
|
|
62242
|
+
await db.close();
|
|
62243
|
+
process.exit(0);
|
|
62244
|
+
}
|
|
61851
62245
|
if (cmd === "migrate") {
|
|
61852
62246
|
const { runAllMigrations: runAllMigrations2 } = await Promise.resolve().then(() => (init_runner(), runner_exports));
|
|
61853
62247
|
await runAllMigrations2();
|