mcp-agents-memory 0.9.18 → 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 +975 -348
- package/build/migrations/029_venue.js +26000 -0
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -1675,15 +1675,15 @@ var require_pg_connection_string = __commonJS({
|
|
|
1675
1675
|
if (config2.sslcert || config2.sslkey || config2.sslrootcert || config2.sslmode) {
|
|
1676
1676
|
config2.ssl = {};
|
|
1677
1677
|
}
|
|
1678
|
-
const
|
|
1678
|
+
const fs14 = config2.sslcert || config2.sslkey || config2.sslrootcert ? __require("fs") : null;
|
|
1679
1679
|
if (config2.sslcert) {
|
|
1680
|
-
config2.ssl.cert =
|
|
1680
|
+
config2.ssl.cert = fs14.readFileSync(config2.sslcert).toString();
|
|
1681
1681
|
}
|
|
1682
1682
|
if (config2.sslkey) {
|
|
1683
|
-
config2.ssl.key =
|
|
1683
|
+
config2.ssl.key = fs14.readFileSync(config2.sslkey).toString();
|
|
1684
1684
|
}
|
|
1685
1685
|
if (config2.sslrootcert) {
|
|
1686
|
-
config2.ssl.ca =
|
|
1686
|
+
config2.ssl.ca = fs14.readFileSync(config2.sslrootcert).toString();
|
|
1687
1687
|
}
|
|
1688
1688
|
if (options.useLibpqCompat && config2.uselibpqcompat) {
|
|
1689
1689
|
throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
|
|
@@ -3620,15 +3620,15 @@ var require_lib = __commonJS({
|
|
|
3620
3620
|
"../mcp-agents-memory/node_modules/pgpass/lib/index.js"(exports, module) {
|
|
3621
3621
|
"use strict";
|
|
3622
3622
|
var path13 = __require("path");
|
|
3623
|
-
var
|
|
3623
|
+
var fs14 = __require("fs");
|
|
3624
3624
|
var helper = require_helper();
|
|
3625
3625
|
module.exports = function(connInfo, cb) {
|
|
3626
3626
|
var file = helper.getFileName();
|
|
3627
|
-
|
|
3627
|
+
fs14.stat(file, function(err3, stat) {
|
|
3628
3628
|
if (err3 || !helper.usePgPass(stat, file)) {
|
|
3629
3629
|
return cb(void 0);
|
|
3630
3630
|
}
|
|
3631
|
-
var st =
|
|
3631
|
+
var st = fs14.createReadStream(file);
|
|
3632
3632
|
helper.getPassword(connInfo, st, cb);
|
|
3633
3633
|
});
|
|
3634
3634
|
};
|
|
@@ -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;
|
|
@@ -18203,8 +18203,8 @@ var require_SFTP = __commonJS({
|
|
|
18203
18203
|
"../mcp-agents-memory/node_modules/ssh2/lib/protocol/SFTP.js"(exports, module) {
|
|
18204
18204
|
"use strict";
|
|
18205
18205
|
var EventEmitter = __require("events");
|
|
18206
|
-
var
|
|
18207
|
-
var { constants } =
|
|
18206
|
+
var fs14 = __require("fs");
|
|
18207
|
+
var { constants } = fs14;
|
|
18208
18208
|
var {
|
|
18209
18209
|
Readable: ReadableStream2,
|
|
18210
18210
|
Writable: WritableStream
|
|
@@ -18633,12 +18633,12 @@ var require_SFTP = __commonJS({
|
|
|
18633
18633
|
fastGet(remotePath, localPath, opts, cb) {
|
|
18634
18634
|
if (this.server)
|
|
18635
18635
|
throw new Error("Client-only method called in server mode");
|
|
18636
|
-
fastXfer(this,
|
|
18636
|
+
fastXfer(this, fs14, remotePath, localPath, opts, cb);
|
|
18637
18637
|
}
|
|
18638
18638
|
fastPut(localPath, remotePath, opts, cb) {
|
|
18639
18639
|
if (this.server)
|
|
18640
18640
|
throw new Error("Client-only method called in server mode");
|
|
18641
|
-
fastXfer(
|
|
18641
|
+
fastXfer(fs14, this, localPath, remotePath, opts, cb);
|
|
18642
18642
|
}
|
|
18643
18643
|
readFile(path13, options, callback_) {
|
|
18644
18644
|
if (this.server)
|
|
@@ -19899,13 +19899,13 @@ var require_SFTP = __commonJS({
|
|
|
19899
19899
|
if (--left === 0)
|
|
19900
19900
|
cb(err3);
|
|
19901
19901
|
};
|
|
19902
|
-
if (srcHandle && (src ===
|
|
19902
|
+
if (srcHandle && (src === fs14 || src.outgoing.state === "open"))
|
|
19903
19903
|
++left;
|
|
19904
|
-
if (dstHandle && (dst ===
|
|
19904
|
+
if (dstHandle && (dst === fs14 || dst.outgoing.state === "open"))
|
|
19905
19905
|
++left;
|
|
19906
|
-
if (srcHandle && (src ===
|
|
19906
|
+
if (srcHandle && (src === fs14 || src.outgoing.state === "open"))
|
|
19907
19907
|
src.close(srcHandle, cbfinal);
|
|
19908
|
-
if (dstHandle && (dst ===
|
|
19908
|
+
if (dstHandle && (dst === fs14 || dst.outgoing.state === "open"))
|
|
19909
19909
|
dst.close(dstHandle, cbfinal);
|
|
19910
19910
|
} else {
|
|
19911
19911
|
cb(err3);
|
|
@@ -19921,7 +19921,7 @@ var require_SFTP = __commonJS({
|
|
|
19921
19921
|
tryStat(null, { size: fileSize });
|
|
19922
19922
|
function tryStat(err4, attrs) {
|
|
19923
19923
|
if (err4) {
|
|
19924
|
-
if (src !==
|
|
19924
|
+
if (src !== fs14) {
|
|
19925
19925
|
src.stat(srcPath, (err_, attrs_) => {
|
|
19926
19926
|
if (err_)
|
|
19927
19927
|
return onerror(err4);
|
|
@@ -25485,7 +25485,7 @@ var require_package2 = __commonJS({
|
|
|
25485
25485
|
// ../mcp-agents-memory/node_modules/dotenv/lib/main.js
|
|
25486
25486
|
var require_main = __commonJS({
|
|
25487
25487
|
"../mcp-agents-memory/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
25488
|
-
var
|
|
25488
|
+
var fs14 = __require("fs");
|
|
25489
25489
|
var path13 = __require("path");
|
|
25490
25490
|
var os14 = __require("os");
|
|
25491
25491
|
var crypto3 = __require("crypto");
|
|
@@ -25594,7 +25594,7 @@ var require_main = __commonJS({
|
|
|
25594
25594
|
if (options && options.path && options.path.length > 0) {
|
|
25595
25595
|
if (Array.isArray(options.path)) {
|
|
25596
25596
|
for (const filepath of options.path) {
|
|
25597
|
-
if (
|
|
25597
|
+
if (fs14.existsSync(filepath)) {
|
|
25598
25598
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
25599
25599
|
}
|
|
25600
25600
|
}
|
|
@@ -25604,7 +25604,7 @@ var require_main = __commonJS({
|
|
|
25604
25604
|
} else {
|
|
25605
25605
|
possibleVaultPath = path13.resolve(process.cwd(), ".env.vault");
|
|
25606
25606
|
}
|
|
25607
|
-
if (
|
|
25607
|
+
if (fs14.existsSync(possibleVaultPath)) {
|
|
25608
25608
|
return possibleVaultPath;
|
|
25609
25609
|
}
|
|
25610
25610
|
return null;
|
|
@@ -25653,7 +25653,7 @@ var require_main = __commonJS({
|
|
|
25653
25653
|
const parsedAll = {};
|
|
25654
25654
|
for (const path14 of optionPaths) {
|
|
25655
25655
|
try {
|
|
25656
|
-
const parsed = DotenvModule.parse(
|
|
25656
|
+
const parsed = DotenvModule.parse(fs14.readFileSync(path14, { encoding }));
|
|
25657
25657
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
25658
25658
|
} catch (e) {
|
|
25659
25659
|
if (debug) {
|
|
@@ -32726,12 +32726,12 @@ var require_dist2 = __commonJS({
|
|
|
32726
32726
|
throw new Error(`Unknown format "${name}"`);
|
|
32727
32727
|
return f;
|
|
32728
32728
|
};
|
|
32729
|
-
function addFormats(ajv, list,
|
|
32729
|
+
function addFormats(ajv, list, fs14, exportName) {
|
|
32730
32730
|
var _a3;
|
|
32731
32731
|
var _b;
|
|
32732
32732
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
32733
32733
|
for (const f of list)
|
|
32734
|
-
ajv.addFormat(f,
|
|
32734
|
+
ajv.addFormat(f, fs14[f]);
|
|
32735
32735
|
}
|
|
32736
32736
|
module.exports = exports = formatsPlugin;
|
|
32737
32737
|
Object.defineProperty(exports, "__esModule", { value: 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, {
|
|
@@ -32770,12 +33437,12 @@ __export(runner_exports, {
|
|
|
32770
33437
|
runAllMigrations: () => runAllMigrations
|
|
32771
33438
|
});
|
|
32772
33439
|
import { spawn } from "child_process";
|
|
32773
|
-
import
|
|
33440
|
+
import fs12 from "fs";
|
|
32774
33441
|
import path12 from "path";
|
|
32775
33442
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
32776
33443
|
function listMigrationFiles() {
|
|
32777
|
-
if (!
|
|
32778
|
-
return
|
|
33444
|
+
if (!fs12.existsSync(migrationsDir)) return [];
|
|
33445
|
+
return fs12.readdirSync(migrationsDir).filter((f) => MIGRATION_FILE_RE.test(f)).sort();
|
|
32779
33446
|
}
|
|
32780
33447
|
function runOne(file) {
|
|
32781
33448
|
return new Promise((resolve, reject) => {
|
|
@@ -32808,7 +33475,7 @@ var init_runner = __esm({
|
|
|
32808
33475
|
"src/migrations/runner.ts"() {
|
|
32809
33476
|
"use strict";
|
|
32810
33477
|
__dirname4 = path12.dirname(fileURLToPath4(import.meta.url));
|
|
32811
|
-
migrationsDir =
|
|
33478
|
+
migrationsDir = fs12.existsSync(path12.join(__dirname4, "migrations")) ? path12.join(__dirname4, "migrations") : __dirname4;
|
|
32812
33479
|
MIGRATION_FILE_RE = /^\d{3}_.+\.js$/;
|
|
32813
33480
|
}
|
|
32814
33481
|
});
|
|
@@ -47030,231 +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 cleanBuzzEnvelope(message) {
|
|
47053
|
-
try {
|
|
47054
|
-
const text = message.trimStart();
|
|
47055
|
-
if (!text.startsWith("<base>")) return null;
|
|
47056
|
-
const baseEnd = text.indexOf("</base>");
|
|
47057
|
-
if (baseEnd < 0) return null;
|
|
47058
|
-
const rest = text.slice(baseEnd + "</base>".length);
|
|
47059
|
-
let pos = skipWhitespace(rest, 0);
|
|
47060
|
-
for (; ; ) {
|
|
47061
|
-
const name = PREAMBLE_BLOCKS.find((b) => rest.startsWith(`<${b}>`, pos));
|
|
47062
|
-
if (!name) break;
|
|
47063
|
-
const close = rest.indexOf(`</${name}>`, pos);
|
|
47064
|
-
if (close < 0) return null;
|
|
47065
|
-
pos = skipWhitespace(rest, close + name.length + 3);
|
|
47066
|
-
}
|
|
47067
|
-
if (!CONTEXT_OPEN.test(rest.slice(pos, pos + 12))) return null;
|
|
47068
|
-
const bodyStart = rest.indexOf("\n", pos) + 1;
|
|
47069
|
-
const contextClose = rest.indexOf(CONTEXT_CLOSE, bodyStart - 1);
|
|
47070
|
-
if (contextClose < 0) return null;
|
|
47071
|
-
const contextBody = rest.slice(bodyStart, contextClose).replace(/\r$/, "");
|
|
47072
|
-
const tail = rest.slice(contextClose + CONTEXT_CLOSE.length);
|
|
47073
|
-
let turnStart = 0;
|
|
47074
|
-
const history = HISTORY_OPEN.exec(tail);
|
|
47075
|
-
if (history) {
|
|
47076
|
-
const closeTag = `</${history[1]}>`;
|
|
47077
|
-
const close = tail.indexOf(closeTag, history[0].length);
|
|
47078
|
-
if (close < 0) return null;
|
|
47079
|
-
turnStart = close + closeTag.length;
|
|
47080
|
-
}
|
|
47081
|
-
if (TURN_IN_DROPPED.test(rest.slice(0, pos)) || TURN_IN_DROPPED.test(tail.slice(0, turnStart))) return null;
|
|
47082
|
-
const turn = tail.slice(turnStart);
|
|
47083
|
-
if (!TURN_OPEN.test(turn)) return null;
|
|
47084
|
-
const turnText = turn.split("\n").filter((line) => !isNostrMetaLine(line)).join("\n").trim();
|
|
47085
|
-
if (!turnText) return null;
|
|
47086
|
-
const cleaned = `<context>
|
|
47087
|
-
${contextBody}
|
|
47088
|
-
</context>
|
|
47089
|
-
|
|
47090
|
-
${turnText}`;
|
|
47091
|
-
if (cleaned.length >= message.length) return null;
|
|
47092
|
-
return cleaned;
|
|
47093
|
-
} catch {
|
|
47094
|
-
return null;
|
|
47095
|
-
}
|
|
47096
|
-
}
|
|
47097
|
-
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*$/;
|
|
47098
|
-
function buzzEmbeddingText(message) {
|
|
47099
|
-
try {
|
|
47100
|
-
if (!message.startsWith("<context>\n")) return message;
|
|
47101
|
-
const close = message.indexOf(CONTEXT_CLOSE);
|
|
47102
|
-
if (close < 0) return message;
|
|
47103
|
-
const turn = message.slice(close + CONTEXT_CLOSE.length);
|
|
47104
|
-
if (!TURN_OPEN.test(turn)) return message;
|
|
47105
|
-
const text = turn.split("\n").filter((line) => !EVENT_HEADER.test(line) && !isNostrMetaLine(line)).map(
|
|
47106
|
-
(line) => (
|
|
47107
|
-
// `$` 없이: 끝까지 되짚는 역추적을 막는다 (긴 줄에서 제곱 시간)
|
|
47108
|
-
line.replace(/^From: (.*?) \(npub:.*/, "From: $1").replace(/^Channel: (\S+) \(#[0-9a-f-]+\)/, "Channel: $1")
|
|
47109
|
-
)
|
|
47110
|
-
).join("\n").trim();
|
|
47111
|
-
return text || message;
|
|
47112
|
-
} catch {
|
|
47113
|
-
return message;
|
|
47114
|
-
}
|
|
47115
|
-
}
|
|
47116
|
-
|
|
47117
|
-
// src/hot_path.ts
|
|
47118
|
-
var rawMessageColumnMissing = false;
|
|
47119
|
-
async function insertRawMemory(params) {
|
|
47120
|
-
const {
|
|
47121
|
-
user_id,
|
|
47122
|
-
agent_platform,
|
|
47123
|
-
agent_model,
|
|
47124
|
-
subagent = false,
|
|
47125
|
-
subagent_model = null,
|
|
47126
|
-
subagent_role = null,
|
|
47127
|
-
role,
|
|
47128
|
-
message,
|
|
47129
|
-
is_pinned = false,
|
|
47130
|
-
p_tag_id = null,
|
|
47131
|
-
d_tag = [],
|
|
47132
|
-
embedding = null,
|
|
47133
|
-
external_uuid = null,
|
|
47134
|
-
device_name = null
|
|
47135
|
-
} = params;
|
|
47136
|
-
const embeddingSql = embedding && embedding.length > 0 ? `[${embedding.join(",")}]` : null;
|
|
47137
|
-
const tagProcessed = p_tag_id !== null;
|
|
47138
|
-
const cleaned = role === "user" && !is_pinned && p_tag_id === null && embeddingSql === null ? cleanBuzzEnvelope(message) : null;
|
|
47139
|
-
const insert = (text, raw) => db.query(
|
|
47140
|
-
`INSERT INTO memory (
|
|
47141
|
-
user_id, agent_platform, agent_model,
|
|
47142
|
-
subagent, subagent_model, subagent_role,
|
|
47143
|
-
role, message,
|
|
47144
|
-
p_tag_id, d_tag, embedding,
|
|
47145
|
-
is_pinned, tag_processed, external_uuid,
|
|
47146
|
-
device_name${raw !== null ? ", raw_message" : ""}
|
|
47147
|
-
) VALUES (
|
|
47148
|
-
$1, $2, $3,
|
|
47149
|
-
$4, $5, $6,
|
|
47150
|
-
$7, $8,
|
|
47151
|
-
$9, $10::text[], $11::halfvec,
|
|
47152
|
-
$12, $13, $14,
|
|
47153
|
-
$15${raw !== null ? ", $16" : ""}
|
|
47154
|
-
)
|
|
47155
|
-
ON CONFLICT (external_uuid) WHERE external_uuid IS NOT NULL
|
|
47156
|
-
DO NOTHING
|
|
47157
|
-
RETURNING id, created_at`,
|
|
47158
|
-
[
|
|
47159
|
-
user_id,
|
|
47160
|
-
agent_platform,
|
|
47161
|
-
agent_model,
|
|
47162
|
-
subagent,
|
|
47163
|
-
subagent_model,
|
|
47164
|
-
subagent_role,
|
|
47165
|
-
role,
|
|
47166
|
-
text,
|
|
47167
|
-
p_tag_id,
|
|
47168
|
-
d_tag,
|
|
47169
|
-
embeddingSql,
|
|
47170
|
-
is_pinned,
|
|
47171
|
-
tagProcessed,
|
|
47172
|
-
external_uuid,
|
|
47173
|
-
device_name,
|
|
47174
|
-
...raw !== null ? [raw] : []
|
|
47175
|
-
]
|
|
47176
|
-
);
|
|
47177
|
-
let result;
|
|
47178
|
-
if (cleaned !== null && !rawMessageColumnMissing) {
|
|
47179
|
-
try {
|
|
47180
|
-
result = await insert(cleaned, message);
|
|
47181
|
-
} catch (err3) {
|
|
47182
|
-
const e = err3;
|
|
47183
|
-
if (e.code !== "42703" || !e.message?.includes("raw_message")) throw err3;
|
|
47184
|
-
rawMessageColumnMissing = true;
|
|
47185
|
-
console.error(
|
|
47186
|
-
"\u26A0\uFE0F [HotPath] memory.raw_message \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 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."
|
|
47187
|
-
);
|
|
47188
|
-
result = await insert(message, null);
|
|
47189
|
-
}
|
|
47190
|
-
} else {
|
|
47191
|
-
result = await insert(message, null);
|
|
47192
|
-
}
|
|
47193
|
-
if (result.rows.length === 0) {
|
|
47194
|
-
const existing = await db.query(
|
|
47195
|
-
`SELECT id, created_at FROM memory WHERE external_uuid = $1 LIMIT 1`,
|
|
47196
|
-
[external_uuid]
|
|
47197
|
-
);
|
|
47198
|
-
if (existing.rows.length > 0) {
|
|
47199
|
-
const row2 = existing.rows[0];
|
|
47200
|
-
return { id: Number(row2.id), created_at: row2.created_at, inserted: false };
|
|
47201
|
-
}
|
|
47202
|
-
throw new Error(`insertRawMemory: ON CONFLICT triggered but no existing row found (external_uuid=${external_uuid})`);
|
|
47203
|
-
}
|
|
47204
|
-
const row = result.rows[0];
|
|
47205
|
-
return { id: Number(row.id), created_at: row.created_at, inserted: true };
|
|
47206
|
-
}
|
|
47207
|
-
|
|
47208
|
-
// src/users.ts
|
|
47209
|
-
init_db();
|
|
47210
|
-
var cache = /* @__PURE__ */ new Map();
|
|
47211
|
-
async function getOrCreateUser(userName) {
|
|
47212
|
-
const cached2 = cache.get(userName);
|
|
47213
|
-
if (cached2 !== void 0) return cached2;
|
|
47214
|
-
const existing = await db.query(
|
|
47215
|
-
`SELECT user_id FROM users WHERE user_name = $1 LIMIT 1`,
|
|
47216
|
-
[userName]
|
|
47217
|
-
);
|
|
47218
|
-
if (existing.rows.length > 0) {
|
|
47219
|
-
const id2 = Number(existing.rows[0].user_id);
|
|
47220
|
-
cache.set(userName, id2);
|
|
47221
|
-
return id2;
|
|
47222
|
-
}
|
|
47223
|
-
const inserted = await db.query(
|
|
47224
|
-
`INSERT INTO users (user_name) VALUES ($1)
|
|
47225
|
-
ON CONFLICT (user_name) DO UPDATE SET updated_at = users.updated_at
|
|
47226
|
-
RETURNING user_id`,
|
|
47227
|
-
[userName]
|
|
47228
|
-
);
|
|
47229
|
-
const id = Number(inserted.rows[0].user_id);
|
|
47230
|
-
cache.set(userName, id);
|
|
47231
|
-
return id;
|
|
47232
|
-
}
|
|
47233
|
-
async function getDefaultUserId() {
|
|
47234
|
-
const name = process.env.USER_NAME ?? "hoon";
|
|
47235
|
-
return getOrCreateUser(name);
|
|
47236
|
-
}
|
|
47237
|
-
async function updateUserProfile(userId, field, value) {
|
|
47238
|
-
if (field === "core_profile") {
|
|
47239
|
-
await db.query(
|
|
47240
|
-
`UPDATE users SET core_profile = $1 WHERE user_id = $2`,
|
|
47241
|
-
[value, userId]
|
|
47242
|
-
);
|
|
47243
|
-
} else {
|
|
47244
|
-
await db.query(
|
|
47245
|
-
`UPDATE users SET sub_profile = $1 WHERE user_id = $2`,
|
|
47246
|
-
[value, userId]
|
|
47247
|
-
);
|
|
47248
|
-
}
|
|
47249
|
-
}
|
|
47250
|
-
async function getUserProfile(userId) {
|
|
47251
|
-
const r = await db.query(
|
|
47252
|
-
`SELECT core_profile, sub_profile FROM users WHERE user_id = $1`,
|
|
47253
|
-
[userId]
|
|
47254
|
-
);
|
|
47255
|
-
return r.rows[0] ?? { core_profile: null, sub_profile: null };
|
|
47256
|
-
}
|
|
47257
|
-
|
|
47258
47704
|
// ../mcp-agents-memory/node_modules/openai/internal/tslib.mjs
|
|
47259
47705
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
47260
47706
|
if (kind === "m")
|
|
@@ -55635,7 +56081,7 @@ async function generateEmbedding(text) {
|
|
|
55635
56081
|
init_db();
|
|
55636
56082
|
|
|
55637
56083
|
// src/cold_path/jev_judge.ts
|
|
55638
|
-
import
|
|
56084
|
+
import fs3 from "fs";
|
|
55639
56085
|
var API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
55640
56086
|
var MODEL = "jev-latest";
|
|
55641
56087
|
var TYPESAFE_KEY_PATH = "/home/admin_3alab/.config/typesafe/api_key";
|
|
@@ -55661,7 +56107,7 @@ function loadJevApiKey() {
|
|
|
55661
56107
|
const fromEnv = process.env.TYPESAFE_API_KEY?.trim();
|
|
55662
56108
|
if (fromEnv) return fromEnv;
|
|
55663
56109
|
try {
|
|
55664
|
-
return
|
|
56110
|
+
return fs3.readFileSync(TYPESAFE_KEY_PATH, "utf8").trim() || null;
|
|
55665
56111
|
} catch {
|
|
55666
56112
|
return null;
|
|
55667
56113
|
}
|
|
@@ -55995,7 +56441,9 @@ async function tagMessage(input) {
|
|
|
55995
56441
|
}
|
|
55996
56442
|
|
|
55997
56443
|
// src/auto_save/opencode_capture.ts
|
|
55998
|
-
|
|
56444
|
+
init_hot_path();
|
|
56445
|
+
init_users();
|
|
56446
|
+
import * as fs4 from "node:fs";
|
|
55999
56447
|
import * as path4 from "node:path";
|
|
56000
56448
|
import * as os2 from "node:os";
|
|
56001
56449
|
var DEVICE_NAME = os2.hostname();
|
|
@@ -56191,7 +56639,7 @@ async function captureSessionStart(_cwd) {
|
|
|
56191
56639
|
_state = null;
|
|
56192
56640
|
_consecutiveFailures = 0;
|
|
56193
56641
|
const dbPath = resolveDbPath();
|
|
56194
|
-
if (!dbPath || !
|
|
56642
|
+
if (!dbPath || !fs4.existsSync(dbPath)) return;
|
|
56195
56643
|
const DatabaseSync = await loadSqlite();
|
|
56196
56644
|
if (!DatabaseSync) {
|
|
56197
56645
|
console.error(
|
|
@@ -56557,6 +57005,7 @@ ${args.content}` : args.content;
|
|
|
56557
57005
|
|
|
56558
57006
|
// src/tools/search_memory.ts
|
|
56559
57007
|
init_db();
|
|
57008
|
+
init_users();
|
|
56560
57009
|
|
|
56561
57010
|
// src/cold_path/embedder.ts
|
|
56562
57011
|
var MAX_RETRIES = 3;
|
|
@@ -56590,6 +57039,30 @@ function vectorToHalfvecSql(embedding) {
|
|
|
56590
57039
|
|
|
56591
57040
|
// src/tools/search_memory.ts
|
|
56592
57041
|
import os4 from "node:os";
|
|
57042
|
+
|
|
57043
|
+
// src/memory_columns.ts
|
|
57044
|
+
init_db();
|
|
57045
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
57046
|
+
async function hasMemoryColumn(column) {
|
|
57047
|
+
const c = cache2.get(column);
|
|
57048
|
+
if (c && (c.exists || Date.now() - c.checkedAt < 5 * 60 * 1e3)) return c.exists;
|
|
57049
|
+
let exists = false;
|
|
57050
|
+
try {
|
|
57051
|
+
const r = await db.query(
|
|
57052
|
+
// 쿼리가 search_path로 찾는 바로 그 memory 테이블 기준
|
|
57053
|
+
`SELECT 1 FROM pg_attribute
|
|
57054
|
+
WHERE attrelid = to_regclass('memory') AND attname = $1 AND NOT attisdropped LIMIT 1`,
|
|
57055
|
+
[column]
|
|
57056
|
+
);
|
|
57057
|
+
exists = r.rows.length > 0;
|
|
57058
|
+
} catch {
|
|
57059
|
+
exists = false;
|
|
57060
|
+
}
|
|
57061
|
+
cache2.set(column, { exists, checkedAt: Date.now() });
|
|
57062
|
+
return exists;
|
|
57063
|
+
}
|
|
57064
|
+
|
|
57065
|
+
// src/tools/search_memory.ts
|
|
56593
57066
|
var DEFAULT_LIMIT = 10;
|
|
56594
57067
|
var DEFAULT_FALLBACK_THRESHOLD = 0.3;
|
|
56595
57068
|
function parseDateRange(s) {
|
|
@@ -56664,7 +57137,10 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56664
57137
|
"\uAE30\uAE30 \uD55C\uC815. 'global'(\uAE30\uBCF8): \uC804 \uAE30\uAE30 \uAC80\uC0C9(\uB113\uAC8C). 'local': \uD604\uC7AC \uAE30\uAE30(hostname)\uB85C \uD55C\uC815(\uC774\uC5B4\uBC1B\uAE30\uC6A9, \uC881\uAC8C). zero-config \u2014 \uC11C\uBC84\uAC00 hostname \uC790\uB3D9 \uD574\uC11D."
|
|
56665
57138
|
),
|
|
56666
57139
|
limit: external_exports.number().int().min(1).max(50).optional().describe(`\uCD5C\uB300 \uACB0\uACFC \uC218 (default ${DEFAULT_LIMIT})`),
|
|
56667
|
-
include_archived: external_exports.boolean().optional().describe("archived \uBA54\uBAA8\uB9AC\uB3C4 \uD3EC\uD568 (default false)")
|
|
57140
|
+
include_archived: external_exports.boolean().optional().describe("archived \uBA54\uBAA8\uB9AC\uB3C4 \uD3EC\uD568 (default false)"),
|
|
57141
|
+
venue: external_exports.string().optional().describe(
|
|
57142
|
+
"\uB300\uD654\uAC00 \uC624\uAC04 \uC790\uB9AC\uB85C \uD55C\uC815. 'buzz'(\uBC84\uC988 \uC804\uCCB4) / 'buzz:<\uCC44\uB110>'(\uADF8 \uCC44\uB110, \uC608: buzz:DevRoom) / 'buzz:dm' / 'terminal'(\uC0AC\uB78C\uACFC 1:1) / 'slack' / 'auto'. \uACB0\uACFC\uB9C8\uB2E4 venue\uAC00 \uBD99\uC5B4 \uB098\uC628\uB2E4."
|
|
57143
|
+
)
|
|
56668
57144
|
}
|
|
56669
57145
|
},
|
|
56670
57146
|
async (args) => {
|
|
@@ -56717,6 +57193,13 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56717
57193
|
filters.push(`(m.device_name = $${p++} OR m.is_pinned = TRUE)`);
|
|
56718
57194
|
params.push(localDevice);
|
|
56719
57195
|
}
|
|
57196
|
+
const withVenue = await hasMemoryColumn("venue");
|
|
57197
|
+
const venueSel = withVenue ? ", m.venue" : "";
|
|
57198
|
+
const venueFilter = (n) => args.venue.includes(":") ? `lower(m.venue) = lower($${n})` : `(lower(m.venue) = lower($${n}) OR lower(m.venue) LIKE lower($${n}) || ':%')`;
|
|
57199
|
+
if (args.venue && withVenue) {
|
|
57200
|
+
filters.push(venueFilter(p++));
|
|
57201
|
+
params.push(args.venue);
|
|
57202
|
+
}
|
|
56720
57203
|
const whereSql = filters.join(" AND ");
|
|
56721
57204
|
let used = "recency";
|
|
56722
57205
|
let topSimilarity = void 0;
|
|
@@ -56731,7 +57214,7 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56731
57214
|
params.push(limit2);
|
|
56732
57215
|
const r = await db.query(
|
|
56733
57216
|
`SELECT m.id, m.role, m.message, m.agent_platform, m.agent_model, m.device_name,
|
|
56734
|
-
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at,
|
|
57217
|
+
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at${venueSel},
|
|
56735
57218
|
1 - (m.embedding <=> $${vecParam}::halfvec) AS similarity
|
|
56736
57219
|
FROM memory m
|
|
56737
57220
|
LEFT JOIN project_tags pt ON pt.id = canonical_project_tag_id(m.p_tag_id)
|
|
@@ -56752,6 +57235,7 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56752
57235
|
d_tag: row.d_tag ?? [],
|
|
56753
57236
|
is_pinned: row.is_pinned,
|
|
56754
57237
|
created_at: row.created_at,
|
|
57238
|
+
venue: row.venue ?? null,
|
|
56755
57239
|
similarity: Number(row.similarity)
|
|
56756
57240
|
}));
|
|
56757
57241
|
if (rows.length > 0) {
|
|
@@ -56787,12 +57271,16 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56787
57271
|
ilikeFilters.push(`(m.device_name = $${q++} OR m.is_pinned = TRUE)`);
|
|
56788
57272
|
ilikeParams.push(localDevice);
|
|
56789
57273
|
}
|
|
57274
|
+
if (args.venue && withVenue) {
|
|
57275
|
+
ilikeFilters.push(venueFilter(q++));
|
|
57276
|
+
ilikeParams.push(args.venue);
|
|
57277
|
+
}
|
|
56790
57278
|
ilikeFilters.push(`m.message ILIKE $${q++}`);
|
|
56791
57279
|
ilikeParams.push(`%${args.query}%`);
|
|
56792
57280
|
ilikeParams.push(limit2);
|
|
56793
57281
|
const r = await db.query(
|
|
56794
57282
|
`SELECT m.id, m.role, m.message, m.agent_platform, m.agent_model, m.device_name,
|
|
56795
|
-
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at
|
|
57283
|
+
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at${venueSel}
|
|
56796
57284
|
FROM memory m
|
|
56797
57285
|
LEFT JOIN project_tags pt ON pt.id = canonical_project_tag_id(m.p_tag_id)
|
|
56798
57286
|
WHERE ${ilikeFilters.join(" AND ")}
|
|
@@ -56811,7 +57299,8 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56811
57299
|
p_tag_name: row.p_tag_name,
|
|
56812
57300
|
d_tag: row.d_tag ?? [],
|
|
56813
57301
|
is_pinned: row.is_pinned,
|
|
56814
|
-
created_at: row.created_at
|
|
57302
|
+
created_at: row.created_at,
|
|
57303
|
+
venue: row.venue ?? null
|
|
56815
57304
|
}));
|
|
56816
57305
|
used = "ilike";
|
|
56817
57306
|
topSimilarity = void 0;
|
|
@@ -56821,7 +57310,7 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56821
57310
|
params.push(limit2);
|
|
56822
57311
|
const r = await db.query(
|
|
56823
57312
|
`SELECT m.id, m.role, m.message, m.agent_platform, m.agent_model, m.device_name,
|
|
56824
|
-
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at
|
|
57313
|
+
pt.name AS p_tag_name, m.d_tag, m.is_pinned, m.created_at${venueSel}
|
|
56825
57314
|
FROM memory m
|
|
56826
57315
|
LEFT JOIN project_tags pt ON pt.id = canonical_project_tag_id(m.p_tag_id)
|
|
56827
57316
|
WHERE ${whereSql}
|
|
@@ -56839,7 +57328,8 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56839
57328
|
p_tag_name: row.p_tag_name,
|
|
56840
57329
|
d_tag: row.d_tag ?? [],
|
|
56841
57330
|
is_pinned: row.is_pinned,
|
|
56842
|
-
created_at: row.created_at
|
|
57331
|
+
created_at: row.created_at,
|
|
57332
|
+
venue: row.venue ?? null
|
|
56843
57333
|
}));
|
|
56844
57334
|
used = "recency";
|
|
56845
57335
|
}
|
|
@@ -56851,6 +57341,7 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56851
57341
|
threshold: used === "ilike" ? threshold : void 0,
|
|
56852
57342
|
top_similarity: topSimilarity,
|
|
56853
57343
|
count: rows.length,
|
|
57344
|
+
...args.venue && !withVenue ? { note: "\uC774 DB\uC5D4 \uC544\uC9C1 venue \uCE78\uC774 \uC5C6\uC5B4(migration 029 \uC804) venue \uD544\uD130\uB97C \uC801\uC6A9\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4." } : {},
|
|
56854
57345
|
results: rows
|
|
56855
57346
|
}, null, 2)
|
|
56856
57347
|
}]
|
|
@@ -56861,9 +57352,11 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
56861
57352
|
|
|
56862
57353
|
// src/tools/manage_project_tags.ts
|
|
56863
57354
|
init_db();
|
|
57355
|
+
init_users();
|
|
56864
57356
|
|
|
56865
57357
|
// src/cold_path/project_alias_promoter.ts
|
|
56866
57358
|
init_db();
|
|
57359
|
+
init_users();
|
|
56867
57360
|
var QUALIFYING_RELATIONS = /* @__PURE__ */ new Set([
|
|
56868
57361
|
"rename",
|
|
56869
57362
|
"alias",
|
|
@@ -58179,7 +58672,9 @@ Actions:
|
|
|
58179
58672
|
}
|
|
58180
58673
|
|
|
58181
58674
|
// src/briefing.ts
|
|
58675
|
+
init_buzz_envelope();
|
|
58182
58676
|
init_db();
|
|
58677
|
+
init_users();
|
|
58183
58678
|
import * as os5 from "node:os";
|
|
58184
58679
|
var RECENT_CURRENT_LIMIT = 8;
|
|
58185
58680
|
var RECENT_OTHERS_LIMIT = 4;
|
|
@@ -58192,6 +58687,7 @@ var PINNED_LIMIT = 10;
|
|
|
58192
58687
|
var INJECT_PINNED_LIMIT = 5;
|
|
58193
58688
|
var BRIEF_MAX_CHARS = Number(process.env.BRIEF_MAX_CHARS ?? 8e3);
|
|
58194
58689
|
async function collectBrief(opts = {}) {
|
|
58690
|
+
const venueSel = await hasMemoryColumn("venue") ? ", venue" : "";
|
|
58195
58691
|
const userId = opts.userId ?? await getDefaultUserId();
|
|
58196
58692
|
const shortTermDays = opts.shortTermDays ?? Number(process.env.SHORT_TERM_DAYS ?? 3);
|
|
58197
58693
|
const currentPlatform = opts.currentPlatform ?? null;
|
|
@@ -58202,7 +58698,7 @@ async function collectBrief(opts = {}) {
|
|
|
58202
58698
|
);
|
|
58203
58699
|
const user = u.rows[0] ?? { user_name: "unknown", core_profile: null, sub_profile: null };
|
|
58204
58700
|
const pinnedMsgs = await db.query(
|
|
58205
|
-
`SELECT role, agent_platform, device_name, message, created_at
|
|
58701
|
+
`SELECT role, agent_platform, device_name, message, created_at${venueSel}
|
|
58206
58702
|
FROM memory
|
|
58207
58703
|
WHERE user_id = $1
|
|
58208
58704
|
AND is_active = TRUE
|
|
@@ -58230,7 +58726,7 @@ async function collectBrief(opts = {}) {
|
|
|
58230
58726
|
let recentOthers = [];
|
|
58231
58727
|
if (currentPlatform) {
|
|
58232
58728
|
const currentMsgs = await db.query(
|
|
58233
|
-
`SELECT role, agent_platform, device_name, message, created_at
|
|
58729
|
+
`SELECT role, agent_platform, device_name, message, created_at${venueSel}
|
|
58234
58730
|
FROM memory
|
|
58235
58731
|
WHERE user_id = $1
|
|
58236
58732
|
AND is_active = TRUE
|
|
@@ -58245,7 +58741,7 @@ async function collectBrief(opts = {}) {
|
|
|
58245
58741
|
);
|
|
58246
58742
|
recentCurrent = currentMsgs.rows.reverse().map(rowToMsg);
|
|
58247
58743
|
const othersMsgs = await db.query(
|
|
58248
|
-
`SELECT role, agent_platform, device_name, message, created_at
|
|
58744
|
+
`SELECT role, agent_platform, device_name, message, created_at${venueSel}
|
|
58249
58745
|
FROM memory
|
|
58250
58746
|
WHERE user_id = $1
|
|
58251
58747
|
AND is_active = TRUE
|
|
@@ -58260,7 +58756,7 @@ async function collectBrief(opts = {}) {
|
|
|
58260
58756
|
recentOthers = othersMsgs.rows.reverse().map(rowToMsg);
|
|
58261
58757
|
} else {
|
|
58262
58758
|
const msgs = await db.query(
|
|
58263
|
-
`SELECT role, agent_platform, device_name, message, created_at
|
|
58759
|
+
`SELECT role, agent_platform, device_name, message, created_at${venueSel}
|
|
58264
58760
|
FROM memory
|
|
58265
58761
|
WHERE user_id = $1
|
|
58266
58762
|
AND is_active = TRUE
|
|
@@ -58307,11 +58803,15 @@ async function collectBrief(opts = {}) {
|
|
|
58307
58803
|
};
|
|
58308
58804
|
}
|
|
58309
58805
|
function rowToMsg(r) {
|
|
58806
|
+
const raw = String(r.message ?? "");
|
|
58807
|
+
const buzz = buzzEmbeddingText(raw);
|
|
58808
|
+
const text = buzz === raw ? raw : buzz.split("\n").filter((l) => !/^<\/?[a-z-]+(\s[^>]*)?>\s*$/.test(l)).join(" ").replace(/\s+/g, " ").trim();
|
|
58310
58809
|
return {
|
|
58311
58810
|
role: r.role,
|
|
58312
58811
|
agent_platform: r.agent_platform,
|
|
58313
58812
|
device_name: r.device_name ?? null,
|
|
58314
|
-
|
|
58813
|
+
venue: r.venue ?? null,
|
|
58814
|
+
preview: text.slice(0, MAX_PREVIEW_STORE),
|
|
58315
58815
|
created_at: r.created_at
|
|
58316
58816
|
};
|
|
58317
58817
|
}
|
|
@@ -58441,7 +58941,8 @@ function fitSection(heading, lines, budget) {
|
|
|
58441
58941
|
function formatMsgLine(m, showPlatform, maxPreview = PREVIEW_COMPACT) {
|
|
58442
58942
|
const dt = m.created_at?.toISOString?.().slice(11, 16) ?? "";
|
|
58443
58943
|
const device = m.device_name ? `@${m.device_name} ` : "";
|
|
58444
|
-
const
|
|
58944
|
+
const venue = m.venue ? `${m.venue} ` : "";
|
|
58945
|
+
const platformTag = (showPlatform ? `${m.agent_platform} ${device}` : device) + venue;
|
|
58445
58946
|
const truncated = m.preview.length > maxPreview;
|
|
58446
58947
|
const text = truncated ? m.preview.slice(0, maxPreview) : m.preview;
|
|
58447
58948
|
return `- [${dt} ${platformTag}${m.role}] ${text}${truncated ? "\u2026" : ""}`;
|
|
@@ -58491,10 +58992,14 @@ agent_platform_filter=false.`,
|
|
|
58491
58992
|
}
|
|
58492
58993
|
|
|
58493
58994
|
// src/auto_save/save_message_tool.ts
|
|
58995
|
+
init_hot_path();
|
|
58996
|
+
init_users();
|
|
58494
58997
|
import * as os10 from "node:os";
|
|
58495
58998
|
|
|
58496
58999
|
// src/auto_save/gemini_capture.ts
|
|
58497
|
-
|
|
59000
|
+
init_hot_path();
|
|
59001
|
+
init_users();
|
|
59002
|
+
import * as fs5 from "node:fs";
|
|
58498
59003
|
import * as path5 from "node:path";
|
|
58499
59004
|
import * as os6 from "node:os";
|
|
58500
59005
|
import * as crypto2 from "node:crypto";
|
|
@@ -58520,12 +59025,12 @@ function deriveChatsDirCandidates(cwd) {
|
|
|
58520
59025
|
path5.join(GEMINI_TMP_ROOT, cwdHash, "chats"),
|
|
58521
59026
|
path5.join(GEMINI_TMP_ROOT, path5.basename(cwd), "chats")
|
|
58522
59027
|
];
|
|
58523
|
-
return candidates.filter((d) =>
|
|
59028
|
+
return candidates.filter((d) => fs5.existsSync(d));
|
|
58524
59029
|
}
|
|
58525
59030
|
async function readSessionFile(filePath) {
|
|
58526
59031
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
58527
59032
|
try {
|
|
58528
|
-
const raw =
|
|
59033
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
58529
59034
|
if (!raw.trim()) return null;
|
|
58530
59035
|
return JSON.parse(raw);
|
|
58531
59036
|
} catch {
|
|
@@ -58615,23 +59120,23 @@ async function flushJsonFile(filePath, fileState, contentSeen) {
|
|
|
58615
59120
|
return { inserted, skipped, dedup };
|
|
58616
59121
|
}
|
|
58617
59122
|
async function flushJsonlFile(filePath, fileState, contentSeen) {
|
|
58618
|
-
if (!
|
|
59123
|
+
if (!fs5.existsSync(filePath)) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
58619
59124
|
let stat;
|
|
58620
59125
|
try {
|
|
58621
|
-
stat =
|
|
59126
|
+
stat = fs5.statSync(filePath);
|
|
58622
59127
|
} catch {
|
|
58623
59128
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
58624
59129
|
}
|
|
58625
59130
|
if (stat.size <= fileState.cursor) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
58626
59131
|
const length = stat.size - fileState.cursor;
|
|
58627
|
-
const fd =
|
|
59132
|
+
const fd = fs5.openSync(filePath, "r");
|
|
58628
59133
|
let raw;
|
|
58629
59134
|
try {
|
|
58630
59135
|
const buf = Buffer.alloc(length);
|
|
58631
|
-
|
|
59136
|
+
fs5.readSync(fd, buf, 0, length, fileState.cursor);
|
|
58632
59137
|
raw = buf.toString("utf-8");
|
|
58633
59138
|
} finally {
|
|
58634
|
-
|
|
59139
|
+
fs5.closeSync(fd);
|
|
58635
59140
|
}
|
|
58636
59141
|
const lastNl = raw.lastIndexOf("\n");
|
|
58637
59142
|
if (lastNl === -1) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
@@ -58702,10 +59207,10 @@ async function flushAllFiles() {
|
|
|
58702
59207
|
let totalI = 0, totalS = 0, totalD = 0;
|
|
58703
59208
|
const contentSeen = /* @__PURE__ */ new Set();
|
|
58704
59209
|
for (const dir of _state2.chatsDirs) {
|
|
58705
|
-
if (!
|
|
59210
|
+
if (!fs5.existsSync(dir)) continue;
|
|
58706
59211
|
let entries;
|
|
58707
59212
|
try {
|
|
58708
|
-
entries =
|
|
59213
|
+
entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
58709
59214
|
} catch {
|
|
58710
59215
|
continue;
|
|
58711
59216
|
}
|
|
@@ -58770,7 +59275,7 @@ function captureSessionStart2(cwd) {
|
|
|
58770
59275
|
for (const dir of chatsDirs) {
|
|
58771
59276
|
let entries;
|
|
58772
59277
|
try {
|
|
58773
|
-
entries =
|
|
59278
|
+
entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
58774
59279
|
} catch {
|
|
58775
59280
|
continue;
|
|
58776
59281
|
}
|
|
@@ -58786,21 +59291,21 @@ function captureSessionStart2(cwd) {
|
|
|
58786
59291
|
if (format === "json") {
|
|
58787
59292
|
let session = null;
|
|
58788
59293
|
try {
|
|
58789
|
-
session = JSON.parse(
|
|
59294
|
+
session = JSON.parse(fs5.readFileSync(filePath, "utf-8"));
|
|
58790
59295
|
} catch {
|
|
58791
59296
|
}
|
|
58792
59297
|
cursor = session && Array.isArray(session.messages) ? session.messages.length : 0;
|
|
58793
59298
|
if (session?.sessionId) realSessionId = session.sessionId;
|
|
58794
59299
|
} else {
|
|
58795
59300
|
try {
|
|
58796
|
-
cursor =
|
|
59301
|
+
cursor = fs5.statSync(filePath).size;
|
|
58797
59302
|
} catch {
|
|
58798
59303
|
}
|
|
58799
59304
|
try {
|
|
58800
|
-
const fd =
|
|
59305
|
+
const fd = fs5.openSync(filePath, "r");
|
|
58801
59306
|
const buf = Buffer.alloc(512);
|
|
58802
|
-
const n =
|
|
58803
|
-
|
|
59307
|
+
const n = fs5.readSync(fd, buf, 0, 512, 0);
|
|
59308
|
+
fs5.closeSync(fd);
|
|
58804
59309
|
const firstLine = buf.slice(0, n).toString("utf-8").split("\n")[0].trim();
|
|
58805
59310
|
const header = JSON.parse(firstLine);
|
|
58806
59311
|
if (typeof header.sessionId === "string" && header.sessionId) {
|
|
@@ -58823,7 +59328,7 @@ function armDirWatchers() {
|
|
|
58823
59328
|
if (_watchers.length > 0) return;
|
|
58824
59329
|
for (const dir of _state2.chatsDirs) {
|
|
58825
59330
|
try {
|
|
58826
|
-
const w =
|
|
59331
|
+
const w = fs5.watch(dir, (_evt, filename) => {
|
|
58827
59332
|
if (filename && !filename.endsWith(".json") && !filename.endsWith(".jsonl")) return;
|
|
58828
59333
|
scheduleFlush();
|
|
58829
59334
|
});
|
|
@@ -58878,7 +59383,9 @@ async function captureSessionEnd2() {
|
|
|
58878
59383
|
}
|
|
58879
59384
|
|
|
58880
59385
|
// src/auto_save/grok_capture.ts
|
|
58881
|
-
|
|
59386
|
+
init_hot_path();
|
|
59387
|
+
init_users();
|
|
59388
|
+
import * as fs6 from "node:fs";
|
|
58882
59389
|
import * as path6 from "node:path";
|
|
58883
59390
|
import * as os7 from "node:os";
|
|
58884
59391
|
var DEVICE_NAME4 = os7.hostname();
|
|
@@ -58899,7 +59406,7 @@ function extractSessionId(filePath) {
|
|
|
58899
59406
|
}
|
|
58900
59407
|
function countCompleteLines(filePath) {
|
|
58901
59408
|
try {
|
|
58902
|
-
const content =
|
|
59409
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
58903
59410
|
let n = 0;
|
|
58904
59411
|
for (let i = 0; i < content.length; i++) if (content[i] === "\n") n++;
|
|
58905
59412
|
return n;
|
|
@@ -58908,13 +59415,13 @@ function countCompleteLines(filePath) {
|
|
|
58908
59415
|
}
|
|
58909
59416
|
}
|
|
58910
59417
|
function* walkChatHistories(root) {
|
|
58911
|
-
if (!
|
|
59418
|
+
if (!fs6.existsSync(root)) return;
|
|
58912
59419
|
const stack = [root];
|
|
58913
59420
|
while (stack.length) {
|
|
58914
59421
|
const dir = stack.pop();
|
|
58915
59422
|
let entries;
|
|
58916
59423
|
try {
|
|
58917
|
-
entries =
|
|
59424
|
+
entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
58918
59425
|
} catch {
|
|
58919
59426
|
continue;
|
|
58920
59427
|
}
|
|
@@ -58929,7 +59436,7 @@ function* walkChatHistories(root) {
|
|
|
58929
59436
|
}
|
|
58930
59437
|
}
|
|
58931
59438
|
function captureSessionStart3(_cwd) {
|
|
58932
|
-
const rootExists =
|
|
59439
|
+
const rootExists = fs6.existsSync(SESSIONS_ROOT);
|
|
58933
59440
|
_state3 = {
|
|
58934
59441
|
rootExists,
|
|
58935
59442
|
files: /* @__PURE__ */ new Map()
|
|
@@ -58941,7 +59448,7 @@ function captureSessionStart3(_cwd) {
|
|
|
58941
59448
|
for (const filePath of walkChatHistories(SESSIONS_ROOT)) {
|
|
58942
59449
|
let stat;
|
|
58943
59450
|
try {
|
|
58944
|
-
stat =
|
|
59451
|
+
stat = fs6.statSync(filePath);
|
|
58945
59452
|
} catch {
|
|
58946
59453
|
continue;
|
|
58947
59454
|
}
|
|
@@ -58992,14 +59499,14 @@ function parseEntry(line, lineIndex) {
|
|
|
58992
59499
|
async function flushDeltaForFile2(filePath, fileState) {
|
|
58993
59500
|
let stat;
|
|
58994
59501
|
try {
|
|
58995
|
-
stat =
|
|
59502
|
+
stat = fs6.statSync(filePath);
|
|
58996
59503
|
} catch {
|
|
58997
59504
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
58998
59505
|
}
|
|
58999
59506
|
if (stat.size === fileState.lastSize) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
59000
59507
|
let content;
|
|
59001
59508
|
try {
|
|
59002
|
-
content =
|
|
59509
|
+
content = fs6.readFileSync(filePath, "utf-8");
|
|
59003
59510
|
} catch {
|
|
59004
59511
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
59005
59512
|
}
|
|
@@ -59046,7 +59553,7 @@ async function flushAllFiles2() {
|
|
|
59046
59553
|
if (!fileState) {
|
|
59047
59554
|
let stat = null;
|
|
59048
59555
|
try {
|
|
59049
|
-
stat =
|
|
59556
|
+
stat = fs6.statSync(filePath);
|
|
59050
59557
|
} catch {
|
|
59051
59558
|
}
|
|
59052
59559
|
const fileBirthMs = stat ? stat.birthtimeMs || stat.ctimeMs : SERVER_START_MS;
|
|
@@ -59106,7 +59613,7 @@ function armDirWatcher() {
|
|
|
59106
59613
|
if (!_state3 || !_state3.rootExists) return;
|
|
59107
59614
|
if (_watcher) return;
|
|
59108
59615
|
try {
|
|
59109
|
-
_watcher =
|
|
59616
|
+
_watcher = fs6.watch(SESSIONS_ROOT, { recursive: true }, (_evt, filename) => {
|
|
59110
59617
|
if (!filename) return;
|
|
59111
59618
|
if (path6.basename(filename) !== CHAT_FILE) return;
|
|
59112
59619
|
scheduleFlush2();
|
|
@@ -59161,7 +59668,9 @@ function isCaptureArmed3() {
|
|
|
59161
59668
|
}
|
|
59162
59669
|
|
|
59163
59670
|
// src/auto_save/antigravity_capture.ts
|
|
59164
|
-
|
|
59671
|
+
init_hot_path();
|
|
59672
|
+
init_users();
|
|
59673
|
+
import * as fs7 from "node:fs";
|
|
59165
59674
|
import * as path7 from "node:path";
|
|
59166
59675
|
import * as os8 from "node:os";
|
|
59167
59676
|
var DEVICE_NAME5 = os8.hostname();
|
|
@@ -59186,7 +59695,7 @@ function extractSid(filePath) {
|
|
|
59186
59695
|
}
|
|
59187
59696
|
function countCompleteLines2(filePath) {
|
|
59188
59697
|
try {
|
|
59189
|
-
const content =
|
|
59698
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
59190
59699
|
let n = 0;
|
|
59191
59700
|
for (let i = 0; i < content.length; i++) if (content[i] === "\n") n++;
|
|
59192
59701
|
return n;
|
|
@@ -59195,13 +59704,13 @@ function countCompleteLines2(filePath) {
|
|
|
59195
59704
|
}
|
|
59196
59705
|
}
|
|
59197
59706
|
function* walkTranscripts(root) {
|
|
59198
|
-
if (!
|
|
59707
|
+
if (!fs7.existsSync(root)) return;
|
|
59199
59708
|
const stack = [root];
|
|
59200
59709
|
while (stack.length) {
|
|
59201
59710
|
const dir = stack.pop();
|
|
59202
59711
|
let entries;
|
|
59203
59712
|
try {
|
|
59204
|
-
entries =
|
|
59713
|
+
entries = fs7.readdirSync(dir, { withFileTypes: true });
|
|
59205
59714
|
} catch {
|
|
59206
59715
|
continue;
|
|
59207
59716
|
}
|
|
@@ -59223,7 +59732,7 @@ function* walkAllTranscripts() {
|
|
|
59223
59732
|
}
|
|
59224
59733
|
}
|
|
59225
59734
|
function captureSessionStart4(_cwd) {
|
|
59226
|
-
const rootExists = ROOTS.some((r) =>
|
|
59735
|
+
const rootExists = ROOTS.some((r) => fs7.existsSync(r.dir));
|
|
59227
59736
|
_state4 = {
|
|
59228
59737
|
rootExists,
|
|
59229
59738
|
files: /* @__PURE__ */ new Map()
|
|
@@ -59235,7 +59744,7 @@ function captureSessionStart4(_cwd) {
|
|
|
59235
59744
|
for (const { filePath, platform } of walkAllTranscripts()) {
|
|
59236
59745
|
let stat;
|
|
59237
59746
|
try {
|
|
59238
|
-
stat =
|
|
59747
|
+
stat = fs7.statSync(filePath);
|
|
59239
59748
|
} catch {
|
|
59240
59749
|
continue;
|
|
59241
59750
|
}
|
|
@@ -59248,7 +59757,7 @@ function captureSessionStart4(_cwd) {
|
|
|
59248
59757
|
});
|
|
59249
59758
|
count++;
|
|
59250
59759
|
}
|
|
59251
|
-
const liveRoots = ROOTS.filter((r) =>
|
|
59760
|
+
const liveRoots = ROOTS.filter((r) => fs7.existsSync(r.dir)).map((r) => r.platform);
|
|
59252
59761
|
console.error(`\u{1F4DD} [Antigravity] capture armed: ${count} transcript(s) across [${liveRoots.join(", ")}]`);
|
|
59253
59762
|
armDirWatcher2();
|
|
59254
59763
|
}
|
|
@@ -59286,14 +59795,14 @@ function parseEntry2(line) {
|
|
|
59286
59795
|
async function flushDeltaForFile3(filePath, fileState) {
|
|
59287
59796
|
let stat;
|
|
59288
59797
|
try {
|
|
59289
|
-
stat =
|
|
59798
|
+
stat = fs7.statSync(filePath);
|
|
59290
59799
|
} catch {
|
|
59291
59800
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
59292
59801
|
}
|
|
59293
59802
|
if (stat.size === fileState.lastSize) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
59294
59803
|
let content;
|
|
59295
59804
|
try {
|
|
59296
|
-
content =
|
|
59805
|
+
content = fs7.readFileSync(filePath, "utf-8");
|
|
59297
59806
|
} catch {
|
|
59298
59807
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
59299
59808
|
}
|
|
@@ -59342,7 +59851,7 @@ async function flushAllFiles3() {
|
|
|
59342
59851
|
if (!fileState) {
|
|
59343
59852
|
let stat = null;
|
|
59344
59853
|
try {
|
|
59345
|
-
stat =
|
|
59854
|
+
stat = fs7.statSync(filePath);
|
|
59346
59855
|
} catch {
|
|
59347
59856
|
}
|
|
59348
59857
|
const fileBirthMs = stat ? stat.birthtimeMs || stat.ctimeMs : SERVER_START_MS2;
|
|
@@ -59404,9 +59913,9 @@ function armDirWatcher2() {
|
|
|
59404
59913
|
if (!_state4 || !_state4.rootExists) return;
|
|
59405
59914
|
if (_watchers2.length) return;
|
|
59406
59915
|
for (const { dir } of ROOTS) {
|
|
59407
|
-
if (!
|
|
59916
|
+
if (!fs7.existsSync(dir)) continue;
|
|
59408
59917
|
try {
|
|
59409
|
-
const w =
|
|
59918
|
+
const w = fs7.watch(dir, { recursive: true }, (_evt, filename) => {
|
|
59410
59919
|
if (!filename) return;
|
|
59411
59920
|
if (path7.basename(filename) !== CHAT_FILE2) return;
|
|
59412
59921
|
scheduleFlush3();
|
|
@@ -59463,7 +59972,10 @@ function isCaptureArmed4() {
|
|
|
59463
59972
|
}
|
|
59464
59973
|
|
|
59465
59974
|
// src/auto_save/hermes_capture.ts
|
|
59466
|
-
|
|
59975
|
+
init_hot_path();
|
|
59976
|
+
init_venue();
|
|
59977
|
+
init_users();
|
|
59978
|
+
import * as fs8 from "node:fs";
|
|
59467
59979
|
import * as path8 from "node:path";
|
|
59468
59980
|
import * as os9 from "node:os";
|
|
59469
59981
|
var DEVICE_NAME6 = os9.hostname();
|
|
@@ -59519,8 +60031,44 @@ function parseNewRows(db2, afterId) {
|
|
|
59519
60031
|
}
|
|
59520
60032
|
return { rows, maxId };
|
|
59521
60033
|
}
|
|
59522
|
-
function
|
|
59523
|
-
if (
|
|
60034
|
+
function lookupSource(db2, sessionId, cache3) {
|
|
60035
|
+
if (cache3.has(sessionId)) return cache3.get(sessionId);
|
|
60036
|
+
let source = null;
|
|
60037
|
+
try {
|
|
60038
|
+
const row = db2.prepare(`SELECT source FROM sessions WHERE id = ? LIMIT 1`).get(sessionId);
|
|
60039
|
+
source = row?.source ?? null;
|
|
60040
|
+
} catch {
|
|
60041
|
+
source = null;
|
|
60042
|
+
}
|
|
60043
|
+
cache3.set(sessionId, source);
|
|
60044
|
+
return source;
|
|
60045
|
+
}
|
|
60046
|
+
var SOURCE_VENUE = { slack: "slack", cli: "terminal", subagent: "subagent", cron: "auto" };
|
|
60047
|
+
function rowVenue(db2, row, state) {
|
|
60048
|
+
const source = lookupSource(db2, row.sessionId, state.sourceCache);
|
|
60049
|
+
if (source !== "acp") return source ? SOURCE_VENUE[source] ?? null : null;
|
|
60050
|
+
const own = row.role === "user" ? buzzTurnVenue(row.message) : null;
|
|
60051
|
+
if (own) {
|
|
60052
|
+
state.buzzVenue.set(row.sessionId, own);
|
|
60053
|
+
return own;
|
|
60054
|
+
}
|
|
60055
|
+
if (!state.buzzVenue.has(row.sessionId)) {
|
|
60056
|
+
let seeded = null;
|
|
60057
|
+
try {
|
|
60058
|
+
const prev = db2.prepare(`SELECT content FROM messages WHERE session_id = ? AND id < ? AND role = 'user' ORDER BY id DESC LIMIT 20`).all(row.sessionId, row.id);
|
|
60059
|
+
for (const p of prev) {
|
|
60060
|
+
seeded = p.content ? buzzTurnVenue(p.content) : null;
|
|
60061
|
+
if (seeded) break;
|
|
60062
|
+
}
|
|
60063
|
+
} catch {
|
|
60064
|
+
seeded = null;
|
|
60065
|
+
}
|
|
60066
|
+
state.buzzVenue.set(row.sessionId, seeded);
|
|
60067
|
+
}
|
|
60068
|
+
return state.buzzVenue.get(row.sessionId) ?? null;
|
|
60069
|
+
}
|
|
60070
|
+
function lookupModel(db2, sessionId, cache3) {
|
|
60071
|
+
if (cache3.has(sessionId)) return cache3.get(sessionId);
|
|
59524
60072
|
let model = null;
|
|
59525
60073
|
try {
|
|
59526
60074
|
const row = db2.prepare(`SELECT model FROM sessions WHERE id = ? LIMIT 1`).get(sessionId);
|
|
@@ -59528,7 +60076,7 @@ function lookupModel(db2, sessionId, cache2) {
|
|
|
59528
60076
|
} catch {
|
|
59529
60077
|
model = null;
|
|
59530
60078
|
}
|
|
59531
|
-
|
|
60079
|
+
cache3.set(sessionId, model);
|
|
59532
60080
|
return model;
|
|
59533
60081
|
}
|
|
59534
60082
|
function isCaptureArmed5() {
|
|
@@ -59541,7 +60089,7 @@ async function captureSessionStart5(_cwd) {
|
|
|
59541
60089
|
}
|
|
59542
60090
|
_state5 = null;
|
|
59543
60091
|
_consecutiveOpenFailures = 0;
|
|
59544
|
-
if (!
|
|
60092
|
+
if (!fs8.existsSync(STATE_DB)) return;
|
|
59545
60093
|
const DatabaseSync = await loadSqlite2();
|
|
59546
60094
|
if (!DatabaseSync) {
|
|
59547
60095
|
console.error(
|
|
@@ -59573,7 +60121,7 @@ async function captureSessionStart5(_cwd) {
|
|
|
59573
60121
|
db2.close();
|
|
59574
60122
|
} catch {
|
|
59575
60123
|
}
|
|
59576
|
-
_state5 = { cursor: maxId, modelCache: /* @__PURE__ */ new Map() };
|
|
60124
|
+
_state5 = { cursor: maxId, modelCache: /* @__PURE__ */ new Map(), sourceCache: /* @__PURE__ */ new Map(), buzzVenue: /* @__PURE__ */ new Map(), venueByRow: /* @__PURE__ */ new Map() };
|
|
59577
60125
|
console.error(`\u{1F4DD} [Hermes] capture armed: cursor=${maxId} (live-from-now)`);
|
|
59578
60126
|
if (_pollTimer5) clearInterval(_pollTimer5);
|
|
59579
60127
|
_pollTimer5 = setInterval(() => {
|
|
@@ -59612,6 +60160,15 @@ async function flush2() {
|
|
|
59612
60160
|
const userId = await getDefaultUserId();
|
|
59613
60161
|
for (const r of rows) {
|
|
59614
60162
|
const agentModel = r.role === "user" ? null : lookupModel(db2, r.sessionId, _state5.modelCache) ?? "unknown";
|
|
60163
|
+
let venue = _state5.venueByRow.get(r.id);
|
|
60164
|
+
if (venue === void 0) {
|
|
60165
|
+
try {
|
|
60166
|
+
venue = rowVenue(db2, r, _state5);
|
|
60167
|
+
} catch {
|
|
60168
|
+
venue = null;
|
|
60169
|
+
}
|
|
60170
|
+
_state5.venueByRow.set(r.id, venue);
|
|
60171
|
+
}
|
|
59615
60172
|
try {
|
|
59616
60173
|
const res = await insertRawMemory({
|
|
59617
60174
|
user_id: userId,
|
|
@@ -59620,8 +60177,10 @@ async function flush2() {
|
|
|
59620
60177
|
role: r.role,
|
|
59621
60178
|
message: r.message,
|
|
59622
60179
|
external_uuid: `hermes:${r.id}`,
|
|
59623
|
-
device_name: DEVICE_NAME6
|
|
60180
|
+
device_name: DEVICE_NAME6,
|
|
60181
|
+
venue
|
|
59624
60182
|
});
|
|
60183
|
+
_state5.venueByRow.delete(r.id);
|
|
59625
60184
|
if (res.inserted) inserted++;
|
|
59626
60185
|
else dedup++;
|
|
59627
60186
|
} catch (err3) {
|
|
@@ -59786,6 +60345,7 @@ subagent \uCEE8\uD14D\uC2A4\uD2B8\uB77C\uBA74 subagent=true + subagent_model + s
|
|
|
59786
60345
|
|
|
59787
60346
|
// src/tools/task_pin.ts
|
|
59788
60347
|
init_db();
|
|
60348
|
+
init_users();
|
|
59789
60349
|
import * as os11 from "node:os";
|
|
59790
60350
|
var DEVICE_NAME8 = os11.hostname();
|
|
59791
60351
|
var STATUSES = ["pending", "in_progress", "done", "failed"];
|
|
@@ -59936,9 +60496,11 @@ function registerTools(server) {
|
|
|
59936
60496
|
|
|
59937
60497
|
// src/cold_path/worker.ts
|
|
59938
60498
|
init_db();
|
|
60499
|
+
init_buzz_envelope();
|
|
59939
60500
|
|
|
59940
60501
|
// src/cold_path/dtag_promoter.ts
|
|
59941
60502
|
init_db();
|
|
60503
|
+
init_users();
|
|
59942
60504
|
function envInt2(name, fallback) {
|
|
59943
60505
|
const raw = process.env[name];
|
|
59944
60506
|
if (!raw) return fallback;
|
|
@@ -60087,6 +60649,7 @@ async function runDtagPromotion() {
|
|
|
60087
60649
|
|
|
60088
60650
|
// src/librarian.ts
|
|
60089
60651
|
init_db();
|
|
60652
|
+
init_users();
|
|
60090
60653
|
|
|
60091
60654
|
// src/context_budget.ts
|
|
60092
60655
|
var DEFAULT_CTX = 8192;
|
|
@@ -60704,7 +61267,10 @@ async function drainColdPath(maxTicks = 12) {
|
|
|
60704
61267
|
}
|
|
60705
61268
|
|
|
60706
61269
|
// src/auto_save/jsonl_capture.ts
|
|
60707
|
-
|
|
61270
|
+
init_hot_path();
|
|
61271
|
+
init_venue();
|
|
61272
|
+
init_users();
|
|
61273
|
+
import * as fs9 from "node:fs";
|
|
60708
61274
|
import * as path9 from "node:path";
|
|
60709
61275
|
import * as os12 from "node:os";
|
|
60710
61276
|
var CLIENT_PLATFORM2 = "claude-code";
|
|
@@ -60723,12 +61289,12 @@ function findProjectDir(cwd) {
|
|
|
60723
61289
|
const slug = cwdToSlug(cwd);
|
|
60724
61290
|
const slugPath = path9.join(PROJECTS_ROOT, slug);
|
|
60725
61291
|
try {
|
|
60726
|
-
if (
|
|
61292
|
+
if (fs9.statSync(slugPath).isDirectory()) return slugPath;
|
|
60727
61293
|
} catch {
|
|
60728
61294
|
}
|
|
60729
61295
|
let subdirs;
|
|
60730
61296
|
try {
|
|
60731
|
-
subdirs =
|
|
61297
|
+
subdirs = fs9.readdirSync(PROJECTS_ROOT, { withFileTypes: true });
|
|
60732
61298
|
} catch {
|
|
60733
61299
|
return null;
|
|
60734
61300
|
}
|
|
@@ -60737,7 +61303,7 @@ function findProjectDir(cwd) {
|
|
|
60737
61303
|
const dirPath = path9.join(PROJECTS_ROOT, subdir.name);
|
|
60738
61304
|
let files;
|
|
60739
61305
|
try {
|
|
60740
|
-
files =
|
|
61306
|
+
files = fs9.readdirSync(dirPath, { withFileTypes: true });
|
|
60741
61307
|
} catch {
|
|
60742
61308
|
continue;
|
|
60743
61309
|
}
|
|
@@ -60752,13 +61318,13 @@ function findProjectDir(cwd) {
|
|
|
60752
61318
|
function readCwdFromJsonl(jsonlPath) {
|
|
60753
61319
|
let fd;
|
|
60754
61320
|
try {
|
|
60755
|
-
fd =
|
|
61321
|
+
fd = fs9.openSync(jsonlPath, "r");
|
|
60756
61322
|
} catch {
|
|
60757
61323
|
return null;
|
|
60758
61324
|
}
|
|
60759
61325
|
try {
|
|
60760
61326
|
const buf = Buffer.alloc(2048);
|
|
60761
|
-
const bytesRead =
|
|
61327
|
+
const bytesRead = fs9.readSync(fd, buf, 0, 2048, 0);
|
|
60762
61328
|
const raw = buf.slice(0, bytesRead).toString("utf-8");
|
|
60763
61329
|
for (const line of raw.split("\n")) {
|
|
60764
61330
|
if (!line.trim()) continue;
|
|
@@ -60770,7 +61336,7 @@ function readCwdFromJsonl(jsonlPath) {
|
|
|
60770
61336
|
}
|
|
60771
61337
|
return null;
|
|
60772
61338
|
} finally {
|
|
60773
|
-
|
|
61339
|
+
fs9.closeSync(fd);
|
|
60774
61340
|
}
|
|
60775
61341
|
}
|
|
60776
61342
|
function captureSessionStart6(cwd) {
|
|
@@ -60800,7 +61366,7 @@ function _tryArm(cwd, attempt) {
|
|
|
60800
61366
|
_state6.projectDir = projectDir;
|
|
60801
61367
|
let entries;
|
|
60802
61368
|
try {
|
|
60803
|
-
entries =
|
|
61369
|
+
entries = fs9.readdirSync(projectDir, { withFileTypes: true });
|
|
60804
61370
|
} catch {
|
|
60805
61371
|
return;
|
|
60806
61372
|
}
|
|
@@ -60809,7 +61375,7 @@ function _tryArm(cwd, attempt) {
|
|
|
60809
61375
|
const jsonlPath = path9.join(projectDir, entry.name);
|
|
60810
61376
|
let stat;
|
|
60811
61377
|
try {
|
|
60812
|
-
stat =
|
|
61378
|
+
stat = fs9.statSync(jsonlPath);
|
|
60813
61379
|
} catch {
|
|
60814
61380
|
continue;
|
|
60815
61381
|
}
|
|
@@ -60855,27 +61421,48 @@ function parseEntry3(line) {
|
|
|
60855
61421
|
uuid: entry.uuid ?? `${entry.timestamp ?? ""}-${Math.random()}`,
|
|
60856
61422
|
role: entry.type,
|
|
60857
61423
|
message: messageText,
|
|
60858
|
-
agent_model
|
|
61424
|
+
agent_model,
|
|
61425
|
+
entrypoint: typeof entry.entrypoint === "string" ? entry.entrypoint : void 0
|
|
60859
61426
|
};
|
|
60860
61427
|
}
|
|
61428
|
+
var HEAD_SCAN_BYTES = 2 * 1024 * 1024;
|
|
61429
|
+
function sessionVenueKind(jsonlPath) {
|
|
61430
|
+
const fd = fs9.openSync(jsonlPath, "r");
|
|
61431
|
+
try {
|
|
61432
|
+
const size = fs9.fstatSync(fd).size;
|
|
61433
|
+
const buf = Buffer.allocUnsafe(Math.min(HEAD_SCAN_BYTES, size));
|
|
61434
|
+
fs9.readSync(fd, buf, 0, buf.length, 0);
|
|
61435
|
+
for (const line of buf.toString("utf-8").split("\n")) {
|
|
61436
|
+
const parsed = line.trim() ? parseEntry3(line) : null;
|
|
61437
|
+
if (parsed?.role === "user") return classifySessionVenue(parsed.message, parsed.entrypoint);
|
|
61438
|
+
}
|
|
61439
|
+
return size >= HEAD_SCAN_BYTES ? null : void 0;
|
|
61440
|
+
} finally {
|
|
61441
|
+
fs9.closeSync(fd);
|
|
61442
|
+
}
|
|
61443
|
+
}
|
|
61444
|
+
var userTextOf = (line) => {
|
|
61445
|
+
const parsed = parseEntry3(line);
|
|
61446
|
+
return parsed?.role === "user" ? parsed.message : null;
|
|
61447
|
+
};
|
|
60861
61448
|
async function flushDeltaForFile4(jsonlPath, fileState) {
|
|
60862
|
-
if (!
|
|
61449
|
+
if (!fs9.existsSync(jsonlPath)) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60863
61450
|
let stat;
|
|
60864
61451
|
try {
|
|
60865
|
-
stat =
|
|
61452
|
+
stat = fs9.statSync(jsonlPath);
|
|
60866
61453
|
} catch {
|
|
60867
61454
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60868
61455
|
}
|
|
60869
61456
|
if (stat.size <= fileState.cursorBytes) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60870
61457
|
const length = stat.size - fileState.cursorBytes;
|
|
60871
|
-
const fd =
|
|
61458
|
+
const fd = fs9.openSync(jsonlPath, "r");
|
|
60872
61459
|
let raw;
|
|
60873
61460
|
try {
|
|
60874
61461
|
const buf = Buffer.alloc(length);
|
|
60875
|
-
|
|
61462
|
+
fs9.readSync(fd, buf, 0, length, fileState.cursorBytes);
|
|
60876
61463
|
raw = buf.toString("utf-8");
|
|
60877
61464
|
} finally {
|
|
60878
|
-
|
|
61465
|
+
fs9.closeSync(fd);
|
|
60879
61466
|
}
|
|
60880
61467
|
const lastNl = raw.lastIndexOf("\n");
|
|
60881
61468
|
if (lastNl === -1) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
@@ -60884,6 +61471,14 @@ async function flushDeltaForFile4(jsonlPath, fileState) {
|
|
|
60884
61471
|
const newCursor = fileState.cursorBytes + advanceBy;
|
|
60885
61472
|
const lines = parsable.split("\n");
|
|
60886
61473
|
const userId = await getDefaultUserId();
|
|
61474
|
+
if (fileState.venueKind === void 0) {
|
|
61475
|
+
try {
|
|
61476
|
+
fileState.venueKind = sessionVenueKind(jsonlPath);
|
|
61477
|
+
} catch {
|
|
61478
|
+
fileState.venueKind = null;
|
|
61479
|
+
}
|
|
61480
|
+
}
|
|
61481
|
+
const deltaStart = fileState.cursorBytes;
|
|
60887
61482
|
let inserted = 0, skipped = 0, dedup = 0;
|
|
60888
61483
|
for (const line of lines) {
|
|
60889
61484
|
const trimmed = line.trim();
|
|
@@ -60900,6 +61495,20 @@ async function flushDeltaForFile4(jsonlPath, fileState) {
|
|
|
60900
61495
|
}
|
|
60901
61496
|
fileState.contentSeen.add(ck);
|
|
60902
61497
|
const externalUuid = `claude-code:${fileState.sessionId}:${parsed.uuid}`;
|
|
61498
|
+
let venue = fileState.venueKind ?? null;
|
|
61499
|
+
if (fileState.venueKind === "buzz") {
|
|
61500
|
+
const own = parsed.role === "user" ? buzzTurnVenue(parsed.message) : null;
|
|
61501
|
+
if (own) {
|
|
61502
|
+
fileState.buzzVenue = own;
|
|
61503
|
+
} else if (fileState.buzzVenue === void 0) {
|
|
61504
|
+
try {
|
|
61505
|
+
fileState.buzzVenue = lastBuzzVenueInFile(jsonlPath, deltaStart, userTextOf);
|
|
61506
|
+
} catch {
|
|
61507
|
+
fileState.buzzVenue = null;
|
|
61508
|
+
}
|
|
61509
|
+
}
|
|
61510
|
+
venue = own ?? fileState.buzzVenue ?? "buzz";
|
|
61511
|
+
}
|
|
60903
61512
|
const agentModel = parsed.role === "user" ? null : parsed.agent_model ?? "unknown";
|
|
60904
61513
|
try {
|
|
60905
61514
|
const result = await insertRawMemory({
|
|
@@ -60909,7 +61518,8 @@ async function flushDeltaForFile4(jsonlPath, fileState) {
|
|
|
60909
61518
|
role: parsed.role,
|
|
60910
61519
|
message: parsed.message,
|
|
60911
61520
|
external_uuid: externalUuid,
|
|
60912
|
-
device_name: DEVICE_NAME9
|
|
61521
|
+
device_name: DEVICE_NAME9,
|
|
61522
|
+
venue
|
|
60913
61523
|
});
|
|
60914
61524
|
if (result.inserted) inserted++;
|
|
60915
61525
|
else dedup++;
|
|
@@ -60924,10 +61534,10 @@ async function flushDeltaForFile4(jsonlPath, fileState) {
|
|
|
60924
61534
|
async function flushAllFiles4() {
|
|
60925
61535
|
if (!_state6 || !_state6.projectDir) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60926
61536
|
const projectDir = _state6.projectDir;
|
|
60927
|
-
if (!
|
|
61537
|
+
if (!fs9.existsSync(projectDir)) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60928
61538
|
let entries;
|
|
60929
61539
|
try {
|
|
60930
|
-
entries =
|
|
61540
|
+
entries = fs9.readdirSync(projectDir, { withFileTypes: true });
|
|
60931
61541
|
} catch {
|
|
60932
61542
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
60933
61543
|
}
|
|
@@ -60983,7 +61593,7 @@ function armDirWatcher3() {
|
|
|
60983
61593
|
if (!_state6 || !_state6.projectDir) return;
|
|
60984
61594
|
if (_watcher2) return;
|
|
60985
61595
|
try {
|
|
60986
|
-
_watcher2 =
|
|
61596
|
+
_watcher2 = fs9.watch(_state6.projectDir, (_eventType, filename) => {
|
|
60987
61597
|
if (filename && !filename.endsWith(".jsonl")) return;
|
|
60988
61598
|
scheduleFlush4();
|
|
60989
61599
|
});
|
|
@@ -61027,7 +61637,9 @@ async function captureSessionEnd6() {
|
|
|
61027
61637
|
}
|
|
61028
61638
|
|
|
61029
61639
|
// src/auto_save/codex_capture.ts
|
|
61030
|
-
|
|
61640
|
+
init_hot_path();
|
|
61641
|
+
init_users();
|
|
61642
|
+
import * as fs10 from "node:fs";
|
|
61031
61643
|
import * as path10 from "node:path";
|
|
61032
61644
|
import * as os13 from "node:os";
|
|
61033
61645
|
import { spawnSync } from "node:child_process";
|
|
@@ -61075,13 +61687,13 @@ function extractSessionId2(filename) {
|
|
|
61075
61687
|
return m ? m[1] : null;
|
|
61076
61688
|
}
|
|
61077
61689
|
function* walkRollouts(root) {
|
|
61078
|
-
if (!
|
|
61690
|
+
if (!fs10.existsSync(root)) return;
|
|
61079
61691
|
const stack = [root];
|
|
61080
61692
|
while (stack.length) {
|
|
61081
61693
|
const dir = stack.pop();
|
|
61082
61694
|
let entries;
|
|
61083
61695
|
try {
|
|
61084
|
-
entries =
|
|
61696
|
+
entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
61085
61697
|
} catch {
|
|
61086
61698
|
continue;
|
|
61087
61699
|
}
|
|
@@ -61096,7 +61708,7 @@ function* walkRollouts(root) {
|
|
|
61096
61708
|
}
|
|
61097
61709
|
}
|
|
61098
61710
|
function captureSessionStart7(_cwd) {
|
|
61099
|
-
const rootExists =
|
|
61711
|
+
const rootExists = fs10.existsSync(SESSIONS_ROOT2);
|
|
61100
61712
|
_state7 = {
|
|
61101
61713
|
rootExists,
|
|
61102
61714
|
files: /* @__PURE__ */ new Map()
|
|
@@ -61108,7 +61720,7 @@ function captureSessionStart7(_cwd) {
|
|
|
61108
61720
|
for (const filePath of walkRollouts(SESSIONS_ROOT2)) {
|
|
61109
61721
|
let stat;
|
|
61110
61722
|
try {
|
|
61111
|
-
stat =
|
|
61723
|
+
stat = fs10.statSync(filePath);
|
|
61112
61724
|
} catch {
|
|
61113
61725
|
continue;
|
|
61114
61726
|
}
|
|
@@ -61162,23 +61774,23 @@ function extractModelFromTurnContext(line) {
|
|
|
61162
61774
|
}
|
|
61163
61775
|
}
|
|
61164
61776
|
async function flushDeltaForFile5(filePath, fileState) {
|
|
61165
|
-
if (!
|
|
61777
|
+
if (!fs10.existsSync(filePath)) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
61166
61778
|
let stat;
|
|
61167
61779
|
try {
|
|
61168
|
-
stat =
|
|
61780
|
+
stat = fs10.statSync(filePath);
|
|
61169
61781
|
} catch {
|
|
61170
61782
|
return { inserted: 0, skipped: 0, dedup: 0 };
|
|
61171
61783
|
}
|
|
61172
61784
|
if (stat.size <= fileState.cursorBytes) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
61173
61785
|
const length = stat.size - fileState.cursorBytes;
|
|
61174
|
-
const fd =
|
|
61786
|
+
const fd = fs10.openSync(filePath, "r");
|
|
61175
61787
|
let raw;
|
|
61176
61788
|
try {
|
|
61177
61789
|
const buf = Buffer.alloc(length);
|
|
61178
|
-
|
|
61790
|
+
fs10.readSync(fd, buf, 0, length, fileState.cursorBytes);
|
|
61179
61791
|
raw = buf.toString("utf-8");
|
|
61180
61792
|
} finally {
|
|
61181
|
-
|
|
61793
|
+
fs10.closeSync(fd);
|
|
61182
61794
|
}
|
|
61183
61795
|
const lastNl = raw.lastIndexOf("\n");
|
|
61184
61796
|
if (lastNl === -1) return { inserted: 0, skipped: 0, dedup: 0 };
|
|
@@ -61242,7 +61854,7 @@ async function flushAllFiles5() {
|
|
|
61242
61854
|
if (!sessionId) continue;
|
|
61243
61855
|
let stat = null;
|
|
61244
61856
|
try {
|
|
61245
|
-
stat =
|
|
61857
|
+
stat = fs10.statSync(filePath);
|
|
61246
61858
|
} catch {
|
|
61247
61859
|
}
|
|
61248
61860
|
const fileBirthMs = stat ? stat.birthtimeMs || stat.ctimeMs : SERVER_START_MS3;
|
|
@@ -61302,7 +61914,7 @@ function armDirWatcher4() {
|
|
|
61302
61914
|
if (!_state7 || !_state7.rootExists) return;
|
|
61303
61915
|
if (_watcher3) return;
|
|
61304
61916
|
try {
|
|
61305
|
-
_watcher3 =
|
|
61917
|
+
_watcher3 = fs10.watch(SESSIONS_ROOT2, { recursive: true }, (_evt, filename) => {
|
|
61306
61918
|
if (!filename) return;
|
|
61307
61919
|
const base = path10.basename(filename);
|
|
61308
61920
|
if (!base.startsWith("rollout-") || !base.endsWith(".jsonl")) return;
|
|
@@ -61355,16 +61967,16 @@ async function captureSessionEnd7() {
|
|
|
61355
61967
|
}
|
|
61356
61968
|
|
|
61357
61969
|
// src/version.ts
|
|
61358
|
-
import
|
|
61970
|
+
import fs11 from "fs";
|
|
61359
61971
|
import path11 from "path";
|
|
61360
61972
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
61361
61973
|
var __dirname3 = path11.dirname(fileURLToPath3(import.meta.url));
|
|
61362
61974
|
var packageJsonPath = path11.resolve(__dirname3, "..", "package.json");
|
|
61363
|
-
var packageJson = JSON.parse(
|
|
61975
|
+
var packageJson = JSON.parse(fs11.readFileSync(packageJsonPath, "utf8"));
|
|
61364
61976
|
var PACKAGE_VERSION2 = packageJson.version || "0.0.0";
|
|
61365
61977
|
|
|
61366
61978
|
// src/index.ts
|
|
61367
|
-
import
|
|
61979
|
+
import fs13 from "fs";
|
|
61368
61980
|
var BRIEF_DB_TIMEOUT_MS = 5e3;
|
|
61369
61981
|
var INSTRUCTIONS_MAX_CHARS = Number(process.env.INSTRUCTIONS_MAX_CHARS ?? 1900);
|
|
61370
61982
|
var INSTRUCTIONS_SEP = "\n\n---\n\n";
|
|
@@ -61523,6 +62135,12 @@ Usage:
|
|
|
61523
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.
|
|
61524
62136
|
mcp-agents-memory setup Interactive setup \u2014 write config to ~/.config/mcp-agents-memory/.env and run migrations.
|
|
61525
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.
|
|
61526
62144
|
mcp-agents-memory help Show this message.
|
|
61527
62145
|
|
|
61528
62146
|
Configuration is loaded from (first hit wins):
|
|
@@ -61561,7 +62179,7 @@ async function runMcpServer() {
|
|
|
61561
62179
|
if (process.env.SSH_ENABLED === "true" && !process.env.SSH_KEY_PATH) {
|
|
61562
62180
|
throw new Error("\u274C SSH_KEY_PATH is required when SSH is enabled");
|
|
61563
62181
|
}
|
|
61564
|
-
if (process.env.SSH_KEY_PATH && !
|
|
62182
|
+
if (process.env.SSH_KEY_PATH && !fs13.existsSync(process.env.SSH_KEY_PATH)) {
|
|
61565
62183
|
console.error(`\u26A0\uFE0F [WARNING] SSH key not found at: ${process.env.SSH_KEY_PATH}`);
|
|
61566
62184
|
}
|
|
61567
62185
|
try {
|
|
@@ -61615,6 +62233,15 @@ async function cli() {
|
|
|
61615
62233
|
await runSetupWizard2();
|
|
61616
62234
|
process.exit(0);
|
|
61617
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
|
+
}
|
|
61618
62245
|
if (cmd === "migrate") {
|
|
61619
62246
|
const { runAllMigrations: runAllMigrations2 } = await Promise.resolve().then(() => (init_runner(), runner_exports));
|
|
61620
62247
|
await runAllMigrations2();
|