mcp-agents-memory 0.9.32 → 0.9.34
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 +11 -1
- package/build/index.js +293 -161
- package/package.json +9 -2
package/README.ko.md
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
| 컬럼 | 설명 |
|
|
59
59
|
|---|---|
|
|
60
60
|
| `user_id` | 사용자 식별 |
|
|
61
|
-
| `agent_platform` | claude-code / codex /
|
|
61
|
+
| `agent_platform` | **수집·실행 경로**. 세션 캡처면 그 실행 환경(claude-code / codex-acp / hermes / grok-cli …), 버즈 게시 원문을 직접 수집한 행이면 `buzz` |
|
|
62
62
|
| `agent_model` | opus-4-7 / gemini-3-pro / gpt-5.5 등 |
|
|
63
63
|
| `subagent` | yes / no (1-level만 추적) |
|
|
64
64
|
| `subagent_model` / `subagent_role` | sub일 때 채움. role은 free-form (lowercase normalize) |
|
|
@@ -69,8 +69,18 @@
|
|
|
69
69
|
| `embedding` | `vector(3072)` — text-embedding-3-large |
|
|
70
70
|
| `is_active` / `archived_at` | soft delete (무손실 보존) |
|
|
71
71
|
| `is_pinned` | `manage_knowledge`로 강제 기억된 row, archive 면제 |
|
|
72
|
+
| `venue` | **대화 공간**. `buzz:<채널>` / `buzz:dm` / `terminal`(사람과 1:1) / `slack` / `auto` / `subagent`. 알 수 없으면 NULL |
|
|
73
|
+
| `device_name` | **캡처 장비** — 그 행을 적은 프로세스의 hostname(`os.hostname()`). 글을 쓴 사람의 기기가 **아니다**. 버즈 원문 수집 행은 의도적으로 NULL |
|
|
74
|
+
| `external_uuid` | 중복 방지 키. 버즈 원문 수집본은 `buzz:<event id>` 접두라 **수집 경로 표식으로도 쓰인다** |
|
|
72
75
|
| `created_at` / `updated_at` | |
|
|
73
76
|
|
|
77
|
+
> **`venue` 와 `agent_platform` 에 둘 다 `buzz` 가 보이는 이유** — 뜻이 다른 두 칸이다.
|
|
78
|
+
> 같은 버즈 채널 대화라도 **어디서 말했나**(`venue=buzz:<채널>`)와 **어느 경로로 저장됐나**가 따로다:
|
|
79
|
+
> 버즈에 게시된 원문을 수집기가 직접 가져오면 `agent_platform=buzz`, 그 글을 받은 에이전트 세션
|
|
80
|
+
> 로그에서 캡처되면 `agent_platform=codex-acp` 처럼 그 실행 환경이 들어간다. 그래서 한 발화가
|
|
81
|
+
> 두 경로로 각각 남을 수 있고, 두 칸은 서로 대체되지 않는다.
|
|
82
|
+
> ⚠️ `agent_platform=buzz` 행의 '실행 환경'은 **미상**이다 — 그 값은 실행 환경이 아니라 수집 경로다.
|
|
83
|
+
|
|
74
84
|
**`user` 테이블** — Librarian이 memory에서 핵심 정보 promote
|
|
75
85
|
|
|
76
86
|
| 컬럼 | 설명 |
|
package/build/index.js
CHANGED
|
@@ -32909,7 +32909,7 @@ function venueFromBuzzContext(message) {
|
|
|
32909
32909
|
if (scope !== "thread" && scope !== "channel" && scope !== "dm") return null;
|
|
32910
32910
|
if (scope === "dm") return "buzz:dm";
|
|
32911
32911
|
const channel = lines.find((l) => l.startsWith("Channel: "))?.trimEnd();
|
|
32912
|
-
const m = channel ?
|
|
32912
|
+
const m = channel ? CHANNEL_LINE.exec(channel) : null;
|
|
32913
32913
|
return m ? `buzz:${m[1]}` : "buzz";
|
|
32914
32914
|
}
|
|
32915
32915
|
function looksLikeBuzzTurn(message) {
|
|
@@ -32919,15 +32919,46 @@ function looksLikeBuzzTurn(message) {
|
|
|
32919
32919
|
const close = text.indexOf(CONTEXT_CLOSE);
|
|
32920
32920
|
return close >= 0 && TURN_OPEN.test(text.slice(close + CONTEXT_CLOSE.length));
|
|
32921
32921
|
}
|
|
32922
|
+
function venueFromBuzzEvent(text) {
|
|
32923
|
+
const open = EVENT_ONLY_OPEN.exec(text);
|
|
32924
|
+
if (!open) return null;
|
|
32925
|
+
const lines = text.split("\n").map((l) => l.replace(/\r$/, "").trimEnd());
|
|
32926
|
+
const firstContent = lines.findIndex((l) => EVENT_CONTENT_LINE.test(l));
|
|
32927
|
+
let events;
|
|
32928
|
+
if (open[1] === "buzz-event") {
|
|
32929
|
+
events = [lines];
|
|
32930
|
+
} else {
|
|
32931
|
+
const starts = lines.flatMap((l, i) => EVENT_BOUNDARY.test(l) ? [i] : []);
|
|
32932
|
+
if (!starts.length || firstContent >= 0 && starts[0] > firstContent) return null;
|
|
32933
|
+
events = starts.map((from, k) => lines.slice(from, starts[k + 1] ?? lines.length));
|
|
32934
|
+
}
|
|
32935
|
+
const names = /* @__PURE__ */ new Set();
|
|
32936
|
+
for (const event of events) {
|
|
32937
|
+
const head = event.slice(0, EVENT_HEADER_LINES);
|
|
32938
|
+
const end = head.findIndex((l) => EVENT_CONTENT_LINE.test(l));
|
|
32939
|
+
if (end < 0) return null;
|
|
32940
|
+
const own = /* @__PURE__ */ new Set();
|
|
32941
|
+
for (const line of head.slice(0, end)) {
|
|
32942
|
+
const m = CHANNEL_LINE.exec(line);
|
|
32943
|
+
if (m) own.add(m[1]);
|
|
32944
|
+
}
|
|
32945
|
+
if (own.size !== 1) return null;
|
|
32946
|
+
for (const name2 of own) names.add(name2);
|
|
32947
|
+
}
|
|
32948
|
+
if (names.size !== 1) return null;
|
|
32949
|
+
const [name] = names;
|
|
32950
|
+
return name === "DM" ? "buzz:dm" : `buzz:${name}`;
|
|
32951
|
+
}
|
|
32922
32952
|
function venueFromBuzzMessage(message) {
|
|
32923
32953
|
try {
|
|
32924
|
-
const
|
|
32925
|
-
|
|
32954
|
+
const text = message.trimStart();
|
|
32955
|
+
const loc = locateBuzzContext(text);
|
|
32956
|
+
return loc ? venueFromBuzzContext(loc.rest.slice(loc.pos)) : venueFromBuzzEvent(text);
|
|
32926
32957
|
} catch {
|
|
32927
32958
|
return null;
|
|
32928
32959
|
}
|
|
32929
32960
|
}
|
|
32930
|
-
var PREAMBLE_BLOCKS, HISTORY_OPEN, TURN_OPEN, TURN_IN_DROPPED, TURN_LINE, CONTEXT_OPEN, BUZZ_SCOPE, BUZZ_CHANNEL, CONTEXT_CLOSE, QUOTE_ENTRY, EVENT_HEADER, WRAPPER_LINE, EVENT_LABEL, IDENTIFIER_ONLY;
|
|
32961
|
+
var PREAMBLE_BLOCKS, HISTORY_OPEN, TURN_OPEN, TURN_IN_DROPPED, TURN_LINE, CONTEXT_OPEN, BUZZ_SCOPE, BUZZ_CHANNEL, CONTEXT_CLOSE, CHANNEL_LINE, EVENT_ONLY_OPEN, EVENT_CONTENT_LINE, EVENT_BOUNDARY, EVENT_HEADER_LINES, QUOTE_ENTRY, EVENT_HEADER, WRAPPER_LINE, EVENT_LABEL, IDENTIFIER_ONLY;
|
|
32931
32962
|
var init_buzz_envelope = __esm({
|
|
32932
32963
|
"src/auto_save/buzz_envelope.ts"() {
|
|
32933
32964
|
"use strict";
|
|
@@ -32940,6 +32971,11 @@ var init_buzz_envelope = __esm({
|
|
|
32940
32971
|
BUZZ_SCOPE = /^Scope: (?:thread|channel|dm)\r?\n/;
|
|
32941
32972
|
BUZZ_CHANNEL = /(?:^|\n)Channel: .+ \(#[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\)\r?(?=\n|$)/;
|
|
32942
32973
|
CONTEXT_CLOSE = "\n</context>";
|
|
32974
|
+
CHANNEL_LINE = /^Channel: (.+?) \(#[0-9a-f-]{36}\)$/;
|
|
32975
|
+
EVENT_ONLY_OPEN = /^<(buzz-events?)[\s>]/;
|
|
32976
|
+
EVENT_CONTENT_LINE = /^Content: /;
|
|
32977
|
+
EVENT_BOUNDARY = /^--- Event \d+ \(.*\) ---$/;
|
|
32978
|
+
EVENT_HEADER_LINES = 12;
|
|
32943
32979
|
QUOTE_ENTRY = /^\[(\d+)\] (?:([0-9a-f]{64})|.*? \(([0-9a-f]{64})\)) \((\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?(?:Z|[+-]\d\d:\d\d))\): ?/;
|
|
32944
32980
|
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*$/;
|
|
32945
32981
|
WRAPPER_LINE = /^<\/?[a-z-]+(\s[^>]*)?>\s*$/;
|
|
@@ -43028,6 +43064,220 @@ OUTPUT strict JSON object: { "verdict": "project" | "generic" | "unsure", "reaso
|
|
|
43028
43064
|
}
|
|
43029
43065
|
});
|
|
43030
43066
|
|
|
43067
|
+
// src/cold_path/tagger_core.ts
|
|
43068
|
+
function agentCandidateLine(c) {
|
|
43069
|
+
if (!c || !c.project_name) return "";
|
|
43070
|
+
const why = c.reason ? ` \u2014 ${c.reason}` : "";
|
|
43071
|
+
const refs = c.evidence_refs?.length ? ` [evidence: ${c.evidence_refs.join(", ")}]` : "";
|
|
43072
|
+
return `agent candidate (a proposal from the agent that had this conversation \u2014 NOT a decision; verify against the list): ${c.project_name}${why}${refs}
|
|
43073
|
+
`;
|
|
43074
|
+
}
|
|
43075
|
+
function buildUserPrompt(input, candidates, registry2 = false, hint) {
|
|
43076
|
+
if (registry2) {
|
|
43077
|
+
const hintLine = hint && input.venue ? `${registryHintLine(input.venue, hint)}
|
|
43078
|
+
` : "";
|
|
43079
|
+
return `registry (the ONLY allowed p_tag values \u2014 pick exactly one name, or null if none clearly fits; never invent a name, never use NEW:):
|
|
43080
|
+
${registryCandidateLines(candidates)}
|
|
43081
|
+
${hintLine}${agentCandidateLine(input.agentCandidate)}role=${input.role}
|
|
43082
|
+
message: ${input.message}`;
|
|
43083
|
+
}
|
|
43084
|
+
const candList = candidates.length > 0 ? candidates.map((c) => c.name).join(", ") : "(none)";
|
|
43085
|
+
return `candidates: ${candList}
|
|
43086
|
+
${agentCandidateLine(input.agentCandidate)}role=${input.role}
|
|
43087
|
+
message: ${input.message}`;
|
|
43088
|
+
}
|
|
43089
|
+
function registrySchema(candidates) {
|
|
43090
|
+
return {
|
|
43091
|
+
type: "object",
|
|
43092
|
+
properties: {
|
|
43093
|
+
p_tag: { anyOf: [{ type: "string", enum: candidates.map((c) => c.name) }, { type: "null" }] },
|
|
43094
|
+
d_tag: { type: "array", items: { type: "string" }, maxItems: 5 }
|
|
43095
|
+
},
|
|
43096
|
+
required: ["p_tag", "d_tag"],
|
|
43097
|
+
additionalProperties: false
|
|
43098
|
+
};
|
|
43099
|
+
}
|
|
43100
|
+
async function resolveRegistryAnswer(raw, candidates, ports, trace) {
|
|
43101
|
+
const answer = parsePTagAnswer(raw);
|
|
43102
|
+
if (trace) trace.parser_result = answer.type;
|
|
43103
|
+
let canonicalId = null;
|
|
43104
|
+
if (answer.type === "name") {
|
|
43105
|
+
canonicalId = await ports.resolveCanonical(answer.slug, { maxDepth: REGISTRY_ALIAS_MAX_DEPTH });
|
|
43106
|
+
}
|
|
43107
|
+
const verdict = registryVerdict(answer, canonicalId, new Set(candidates.map((c) => c.id)));
|
|
43108
|
+
if (verdict.accept == null && verdict.reason !== "no_answer") {
|
|
43109
|
+
console.error(`\u26A0\uFE0F [Tagger] \uBA85\uBD80 \uBAA8\uB4DC: "${String(raw)}" \uBC1B\uC9C0 \uC54A\uC74C (${verdict.reason}). p_tag NULL.`);
|
|
43110
|
+
}
|
|
43111
|
+
if (trace) {
|
|
43112
|
+
trace.decision_reason = verdict.accept != null ? "resolved_existing" : verdict.reason === "no_answer" ? "no_answer" : "null_no_match";
|
|
43113
|
+
}
|
|
43114
|
+
return verdict.accept;
|
|
43115
|
+
}
|
|
43116
|
+
async function runTagger(input, ports, trace) {
|
|
43117
|
+
const { rows: candidates, registry: registry2 } = await ports.listCandidates();
|
|
43118
|
+
const hint = registry2 && input.venue ? (await ports.listHints()).get(input.venue) : void 0;
|
|
43119
|
+
const userPrompt = buildUserPrompt(input, candidates, registry2, hint);
|
|
43120
|
+
if (trace) {
|
|
43121
|
+
trace.assembled_prompt = userPrompt;
|
|
43122
|
+
trace.registry_mode = registry2;
|
|
43123
|
+
trace.candidate_count = candidates.length;
|
|
43124
|
+
trace.fallback_attempted = false;
|
|
43125
|
+
trace.fallback_used = false;
|
|
43126
|
+
trace.jev_applied = false;
|
|
43127
|
+
trace.persistence_action = "none";
|
|
43128
|
+
}
|
|
43129
|
+
const isLocal = ports.isLocalProvider();
|
|
43130
|
+
let raw;
|
|
43131
|
+
if (isLocal) {
|
|
43132
|
+
try {
|
|
43133
|
+
raw = await ports.callPrimary({
|
|
43134
|
+
system: ports.systemPrompt,
|
|
43135
|
+
user: userPrompt,
|
|
43136
|
+
responseFormat: "json",
|
|
43137
|
+
jsonSchema: registry2 ? registrySchema(candidates) : TAGGER_SCHEMA,
|
|
43138
|
+
enableThinking: false
|
|
43139
|
+
// thinking off — 태거는 단순 매핑 작업. thinking 켜면 reasoning이 모든 토큰 소비해 content 비어버림.
|
|
43140
|
+
// jsonSchema → llama.cpp grammar로 <think> bleed 차단 (Qwen3 bug #20345).
|
|
43141
|
+
});
|
|
43142
|
+
} catch (err3) {
|
|
43143
|
+
if (!ports.fallbackEnabled()) throw err3;
|
|
43144
|
+
console.warn(`\u26A0\uFE0F [Tagger] Local model \uC2E4\uD328, grok fallback: ${err3.message?.slice(0, 80)}`);
|
|
43145
|
+
if (trace) trace.fallback_attempted = true;
|
|
43146
|
+
try {
|
|
43147
|
+
raw = await ports.callFallback({
|
|
43148
|
+
system: ports.systemPrompt,
|
|
43149
|
+
user: userPrompt,
|
|
43150
|
+
responseFormat: "json"
|
|
43151
|
+
});
|
|
43152
|
+
} catch (fbErr) {
|
|
43153
|
+
if (trace) trace.fallback_error = fbErr.message;
|
|
43154
|
+
throw fbErr;
|
|
43155
|
+
}
|
|
43156
|
+
if (trace) trace.fallback_used = true;
|
|
43157
|
+
}
|
|
43158
|
+
} else {
|
|
43159
|
+
raw = await ports.callPrimary({
|
|
43160
|
+
system: ports.systemPrompt,
|
|
43161
|
+
user: userPrompt,
|
|
43162
|
+
responseFormat: "json"
|
|
43163
|
+
});
|
|
43164
|
+
}
|
|
43165
|
+
if (trace) trace.raw_model_output = raw;
|
|
43166
|
+
let parsed;
|
|
43167
|
+
try {
|
|
43168
|
+
parsed = JSON.parse(raw);
|
|
43169
|
+
} catch {
|
|
43170
|
+
throw new Error(`Tagger returned invalid JSON: ${raw.slice(0, 200)}`);
|
|
43171
|
+
}
|
|
43172
|
+
if (trace) trace.model_raw_p_tag = parsed.p_tag ?? null;
|
|
43173
|
+
const qwenProposedNewTag = typeof parsed.p_tag === "string" && parsed.p_tag.startsWith("NEW:");
|
|
43174
|
+
if (!qwenProposedNewTag) {
|
|
43175
|
+
const jev = await ports.judgeJev({
|
|
43176
|
+
message: input.message,
|
|
43177
|
+
role: input.role,
|
|
43178
|
+
agent_platform: input.agent_platform,
|
|
43179
|
+
agent_model: input.agent_model,
|
|
43180
|
+
candidates
|
|
43181
|
+
});
|
|
43182
|
+
if (jev !== null && ports.applyJev(jev)) {
|
|
43183
|
+
parsed.p_tag = jev.choice;
|
|
43184
|
+
if (trace) trace.jev_applied = true;
|
|
43185
|
+
}
|
|
43186
|
+
}
|
|
43187
|
+
if (trace) trace.effective_p_tag = parsed.p_tag ?? null;
|
|
43188
|
+
let p_tag_id = null;
|
|
43189
|
+
let newly_created_p_tag_name;
|
|
43190
|
+
if (registry2) {
|
|
43191
|
+
p_tag_id = await resolveRegistryAnswer(parsed.p_tag, candidates, ports, trace);
|
|
43192
|
+
} else if (parsed.p_tag && typeof parsed.p_tag === "string") {
|
|
43193
|
+
if (parsed.p_tag.startsWith("NEW:")) {
|
|
43194
|
+
const newName = parsed.p_tag.slice(4).trim();
|
|
43195
|
+
if (newName && await ports.isBlockedNewName(newName)) {
|
|
43196
|
+
console.error(`\u26A0\uFE0F [Tagger] "${newName}"\uC740(\uB294) \uC0C8 \uD0DC\uADF8 \uC81C\uC548\uC5D0\uC11C \uC0AC\uB78C\uC758 \uACB0\uC815\uC744 \uAE30\uB2E4\uB9AC\uAC70\uB098 \uBC18\uB824\uB41C \uC774\uB984\uC774\uB77C \uB9CC\uB4E4\uC9C0 \uC54A\uC74C. p_tag NULL.`);
|
|
43197
|
+
if (trace) {
|
|
43198
|
+
trace.decision_reason = "blocked_by_policy";
|
|
43199
|
+
trace.proposed_name = newName;
|
|
43200
|
+
}
|
|
43201
|
+
} else if (newName) {
|
|
43202
|
+
if (ports.getOrCreateTag) {
|
|
43203
|
+
p_tag_id = await ports.getOrCreateTag(newName);
|
|
43204
|
+
newly_created_p_tag_name = newName;
|
|
43205
|
+
if (trace) {
|
|
43206
|
+
trace.decision_reason = "new_created_or_existing";
|
|
43207
|
+
trace.proposed_name = newName;
|
|
43208
|
+
trace.persistence_action = "created_or_existing";
|
|
43209
|
+
}
|
|
43210
|
+
} else {
|
|
43211
|
+
if (trace) {
|
|
43212
|
+
trace.decision_reason = "new_proposal_no_persist";
|
|
43213
|
+
trace.proposed_name = newName;
|
|
43214
|
+
trace.persistence_action = "skipped_no_port";
|
|
43215
|
+
}
|
|
43216
|
+
}
|
|
43217
|
+
}
|
|
43218
|
+
} else {
|
|
43219
|
+
const slug = parsed.p_tag.toLowerCase().trim();
|
|
43220
|
+
const candidateSlugs = new Set(candidates.map((c) => c.name.toLowerCase()));
|
|
43221
|
+
if (candidateSlugs.has(slug)) {
|
|
43222
|
+
p_tag_id = ports.getOrCreateTag ? await ports.getOrCreateTag(parsed.p_tag) : await ports.resolveCanonical(slug);
|
|
43223
|
+
if (trace) {
|
|
43224
|
+
trace.decision_reason = "resolved_existing";
|
|
43225
|
+
trace.persistence_action = ports.getOrCreateTag ? "created_or_existing" : "none";
|
|
43226
|
+
}
|
|
43227
|
+
} else {
|
|
43228
|
+
const aliasId = await ports.resolveCanonical(slug);
|
|
43229
|
+
if (aliasId != null) {
|
|
43230
|
+
p_tag_id = aliasId;
|
|
43231
|
+
if (trace) trace.decision_reason = "resolved_existing";
|
|
43232
|
+
} else {
|
|
43233
|
+
console.error(`\u26A0\uFE0F [Tagger] \uD6C4\uBCF4 \uC678 \uC774\uB984 "${parsed.p_tag}" \uAC70\uBD80 (NEW: prefix \uC5C6\uC74C). p_tag NULL \uBC18\uD658.`);
|
|
43234
|
+
p_tag_id = null;
|
|
43235
|
+
if (trace) trace.decision_reason = "rejected_not_candidate";
|
|
43236
|
+
}
|
|
43237
|
+
}
|
|
43238
|
+
}
|
|
43239
|
+
} else if (trace) {
|
|
43240
|
+
trace.decision_reason = "no_answer";
|
|
43241
|
+
}
|
|
43242
|
+
const d_tag = Array.isArray(parsed.d_tag) ? parsed.d_tag.filter((t) => typeof t === "string").map((t) => t.toLowerCase().trim()).filter((t) => t.length > 0 && t.length <= 50).slice(0, 5) : [];
|
|
43243
|
+
return {
|
|
43244
|
+
p_tag_id,
|
|
43245
|
+
d_tag,
|
|
43246
|
+
newly_created_p_tag_name
|
|
43247
|
+
};
|
|
43248
|
+
}
|
|
43249
|
+
var TAGGER_SCHEMA, GENERIC_TAGGER_PROMPT, REGISTRY_ALIAS_MAX_DEPTH;
|
|
43250
|
+
var init_tagger_core = __esm({
|
|
43251
|
+
"src/cold_path/tagger_core.ts"() {
|
|
43252
|
+
"use strict";
|
|
43253
|
+
init_project_registry();
|
|
43254
|
+
TAGGER_SCHEMA = {
|
|
43255
|
+
type: "object",
|
|
43256
|
+
properties: {
|
|
43257
|
+
p_tag: { type: ["string", "null"] },
|
|
43258
|
+
d_tag: { type: "array", items: { type: "string" }, maxItems: 5 }
|
|
43259
|
+
},
|
|
43260
|
+
required: ["p_tag", "d_tag"],
|
|
43261
|
+
additionalProperties: false
|
|
43262
|
+
};
|
|
43263
|
+
GENERIC_TAGGER_PROMPT = `Tagger for a user's long-term memory across AI agents.
|
|
43264
|
+
|
|
43265
|
+
OUTPUT (strict JSON):
|
|
43266
|
+
{ "p_tag": "<existing-name>" | "NEW:<slug>" | null, "d_tag": ["<kw>", ...] }
|
|
43267
|
+
|
|
43268
|
+
p_tag: ONE project tag. Prefer matching a name from the candidate list below;
|
|
43269
|
+
map obvious synonyms to an existing candidate. Use "NEW:<slug>" only when the
|
|
43270
|
+
message is clearly about a project absent from the list. null when the message
|
|
43271
|
+
is too short or generic to project-tag.
|
|
43272
|
+
|
|
43273
|
+
d_tag: 0-3 short lowercase hyphenated keywords about the topic. Skip if no signal.
|
|
43274
|
+
|
|
43275
|
+
ROLE: input includes role='user' or role='assistant'. For role='assistant',
|
|
43276
|
+
tag the topic; do not treat the reply as a fact about the user.`;
|
|
43277
|
+
REGISTRY_ALIAS_MAX_DEPTH = 20;
|
|
43278
|
+
}
|
|
43279
|
+
});
|
|
43280
|
+
|
|
43031
43281
|
// src/cold_path/tagger.ts
|
|
43032
43282
|
function candidateSelectionConfig() {
|
|
43033
43283
|
const configuredStrategy = process.env.TAGGER_CANDIDATE_STRATEGY?.trim().toLowerCase();
|
|
@@ -43117,20 +43367,6 @@ async function listChannelHints() {
|
|
|
43117
43367
|
_hintCache = { map, expires: now + CANDIDATE_CACHE_TTL_MS };
|
|
43118
43368
|
return map;
|
|
43119
43369
|
}
|
|
43120
|
-
function buildUserPrompt(input, candidates, registry2 = false, hint) {
|
|
43121
|
-
if (registry2) {
|
|
43122
|
-
const hintLine = hint && input.venue ? `${registryHintLine(input.venue, hint)}
|
|
43123
|
-
` : "";
|
|
43124
|
-
return `registry (the ONLY allowed p_tag values \u2014 pick exactly one name, or null if none clearly fits; never invent a name, never use NEW:):
|
|
43125
|
-
${registryCandidateLines(candidates)}
|
|
43126
|
-
${hintLine}role=${input.role}
|
|
43127
|
-
message: ${input.message}`;
|
|
43128
|
-
}
|
|
43129
|
-
const candList = candidates.length > 0 ? candidates.map((c) => c.name).join(", ") : "(none)";
|
|
43130
|
-
return `candidates: ${candList}
|
|
43131
|
-
role=${input.role}
|
|
43132
|
-
message: ${input.message}`;
|
|
43133
|
-
}
|
|
43134
43370
|
async function getOrCreateProjectTag(name) {
|
|
43135
43371
|
const slug = name.toLowerCase().trim();
|
|
43136
43372
|
if (!slug) throw new Error("Empty p_tag name");
|
|
@@ -43154,136 +43390,51 @@ async function getOrCreateProjectTag(name) {
|
|
|
43154
43390
|
invalidateCandidateCache();
|
|
43155
43391
|
return Number(inserted.rows[0].id);
|
|
43156
43392
|
}
|
|
43157
|
-
function
|
|
43158
|
-
|
|
43159
|
-
type: "object",
|
|
43160
|
-
properties: {
|
|
43161
|
-
p_tag: { anyOf: [{ type: "string", enum: candidates.map((c) => c.name) }, { type: "null" }] },
|
|
43162
|
-
d_tag: { type: "array", items: { type: "string" }, maxItems: 5 }
|
|
43163
|
-
},
|
|
43164
|
-
required: ["p_tag", "d_tag"],
|
|
43165
|
-
additionalProperties: false
|
|
43166
|
-
};
|
|
43167
|
-
}
|
|
43168
|
-
async function resolveRegistryAnswer(raw, candidates) {
|
|
43169
|
-
const answer = parsePTagAnswer(raw);
|
|
43170
|
-
let canonicalId = null;
|
|
43171
|
-
if (answer.type === "name") {
|
|
43393
|
+
async function resolveCanonicalId(name, opts) {
|
|
43394
|
+
if (opts?.maxDepth != null) {
|
|
43172
43395
|
const chain = await db.query(
|
|
43173
43396
|
`WITH RECURSIVE chain AS (
|
|
43174
43397
|
SELECT id, alias_of, 0 AS depth FROM project_tags WHERE name = $1
|
|
43175
43398
|
UNION ALL
|
|
43176
43399
|
SELECT pt.id, pt.alias_of, c.depth + 1 FROM project_tags pt JOIN chain c ON pt.id = c.alias_of
|
|
43177
|
-
WHERE c.depth <
|
|
43400
|
+
WHERE c.depth < ${opts.maxDepth}
|
|
43178
43401
|
)
|
|
43179
43402
|
SELECT id FROM chain WHERE alias_of IS NULL LIMIT 1`,
|
|
43180
|
-
[
|
|
43403
|
+
[name]
|
|
43181
43404
|
);
|
|
43182
|
-
|
|
43183
|
-
}
|
|
43184
|
-
const verdict = registryVerdict(answer, canonicalId, new Set(candidates.map((c) => c.id)));
|
|
43185
|
-
if (verdict.accept == null && verdict.reason !== "no_answer") {
|
|
43186
|
-
console.error(`\u26A0\uFE0F [Tagger] \uBA85\uBD80 \uBAA8\uB4DC: "${String(raw)}" \uBC1B\uC9C0 \uC54A\uC74C (${verdict.reason}). p_tag NULL.`);
|
|
43405
|
+
return chain.rows.length > 0 ? Number(chain.rows[0].id) : null;
|
|
43187
43406
|
}
|
|
43188
|
-
|
|
43407
|
+
const aliasCheck = await db.query(
|
|
43408
|
+
`WITH RECURSIVE chain AS (
|
|
43409
|
+
SELECT id, alias_of FROM project_tags WHERE name = $1
|
|
43410
|
+
UNION ALL
|
|
43411
|
+
SELECT pt.id, pt.alias_of FROM project_tags pt JOIN chain c ON pt.id = c.alias_of
|
|
43412
|
+
)
|
|
43413
|
+
SELECT id FROM chain WHERE alias_of IS NULL LIMIT 1`,
|
|
43414
|
+
[name]
|
|
43415
|
+
);
|
|
43416
|
+
return aliasCheck.rows.length > 0 ? Number(aliasCheck.rows[0].id) : null;
|
|
43189
43417
|
}
|
|
43190
|
-
|
|
43191
|
-
const { rows: candidates, registry: registry2 } = await listProjectTagCandidates();
|
|
43192
|
-
const hint = registry2 && input.venue ? (await listChannelHints()).get(input.venue) : void 0;
|
|
43193
|
-
const userPrompt = buildUserPrompt(input, candidates, registry2, hint);
|
|
43194
|
-
const isLocal = ROLE_REGISTRY.tagger.provider === "local";
|
|
43195
|
-
let raw;
|
|
43196
|
-
if (isLocal) {
|
|
43197
|
-
try {
|
|
43198
|
-
raw = await callRole("tagger", {
|
|
43199
|
-
system: SYSTEM_PROMPT,
|
|
43200
|
-
user: userPrompt,
|
|
43201
|
-
responseFormat: "json",
|
|
43202
|
-
jsonSchema: registry2 ? registrySchema(candidates) : TAGGER_SCHEMA,
|
|
43203
|
-
enableThinking: false
|
|
43204
|
-
// thinking off — 태거는 단순 매핑 작업. thinking 켜면 reasoning이 모든 토큰 소비해 content 비어버림.
|
|
43205
|
-
// jsonSchema → llama.cpp grammar로 <think> bleed 차단 (Qwen3 bug #20345).
|
|
43206
|
-
});
|
|
43207
|
-
} catch (err3) {
|
|
43208
|
-
if (!localFallbackEnabled()) throw err3;
|
|
43209
|
-
console.warn(`\u26A0\uFE0F [Tagger] Local model \uC2E4\uD328, grok fallback: ${err3.message?.slice(0, 80)}`);
|
|
43210
|
-
raw = await callSpec(GROK_FALLBACK_SPEC, {
|
|
43211
|
-
system: SYSTEM_PROMPT,
|
|
43212
|
-
user: userPrompt,
|
|
43213
|
-
responseFormat: "json"
|
|
43214
|
-
});
|
|
43215
|
-
}
|
|
43216
|
-
} else {
|
|
43217
|
-
raw = await callRole("tagger", {
|
|
43218
|
-
system: SYSTEM_PROMPT,
|
|
43219
|
-
user: userPrompt,
|
|
43220
|
-
responseFormat: "json"
|
|
43221
|
-
});
|
|
43222
|
-
}
|
|
43223
|
-
let parsed;
|
|
43224
|
-
try {
|
|
43225
|
-
parsed = JSON.parse(raw);
|
|
43226
|
-
} catch {
|
|
43227
|
-
throw new Error(`Tagger returned invalid JSON: ${raw.slice(0, 200)}`);
|
|
43228
|
-
}
|
|
43229
|
-
const qwenProposedNewTag = typeof parsed.p_tag === "string" && parsed.p_tag.startsWith("NEW:");
|
|
43230
|
-
if (!qwenProposedNewTag) {
|
|
43231
|
-
const jev = await judgeProjectTag({
|
|
43232
|
-
message: input.message,
|
|
43233
|
-
role: input.role,
|
|
43234
|
-
agent_platform: input.agent_platform,
|
|
43235
|
-
agent_model: input.agent_model,
|
|
43236
|
-
candidates
|
|
43237
|
-
});
|
|
43238
|
-
if (jev !== null && shouldApplyJevJudgment(jev)) {
|
|
43239
|
-
parsed.p_tag = jev.choice;
|
|
43240
|
-
}
|
|
43241
|
-
}
|
|
43242
|
-
let p_tag_id = null;
|
|
43243
|
-
let newly_created_p_tag_name;
|
|
43244
|
-
if (registry2) {
|
|
43245
|
-
p_tag_id = await resolveRegistryAnswer(parsed.p_tag, candidates);
|
|
43246
|
-
} else if (parsed.p_tag && typeof parsed.p_tag === "string") {
|
|
43247
|
-
if (parsed.p_tag.startsWith("NEW:")) {
|
|
43248
|
-
const newName = parsed.p_tag.slice(4).trim();
|
|
43249
|
-
if (newName && await isBlockedNewTagName(newName)) {
|
|
43250
|
-
console.error(`\u26A0\uFE0F [Tagger] "${newName}"\uC740(\uB294) \uC0C8 \uD0DC\uADF8 \uC81C\uC548\uC5D0\uC11C \uC0AC\uB78C\uC758 \uACB0\uC815\uC744 \uAE30\uB2E4\uB9AC\uAC70\uB098 \uBC18\uB824\uB41C \uC774\uB984\uC774\uB77C \uB9CC\uB4E4\uC9C0 \uC54A\uC74C. p_tag NULL.`);
|
|
43251
|
-
} else if (newName) {
|
|
43252
|
-
p_tag_id = await getOrCreateProjectTag(newName);
|
|
43253
|
-
newly_created_p_tag_name = newName;
|
|
43254
|
-
}
|
|
43255
|
-
} else {
|
|
43256
|
-
const slug = parsed.p_tag.toLowerCase().trim();
|
|
43257
|
-
const candidateSlugs = new Set(candidates.map((c) => c.name.toLowerCase()));
|
|
43258
|
-
if (candidateSlugs.has(slug)) {
|
|
43259
|
-
p_tag_id = await getOrCreateProjectTag(parsed.p_tag);
|
|
43260
|
-
} else {
|
|
43261
|
-
const aliasCheck = await db.query(
|
|
43262
|
-
`WITH RECURSIVE chain AS (
|
|
43263
|
-
SELECT id, alias_of FROM project_tags WHERE name = $1
|
|
43264
|
-
UNION ALL
|
|
43265
|
-
SELECT pt.id, pt.alias_of FROM project_tags pt JOIN chain c ON pt.id = c.alias_of
|
|
43266
|
-
)
|
|
43267
|
-
SELECT id FROM chain WHERE alias_of IS NULL LIMIT 1`,
|
|
43268
|
-
[slug]
|
|
43269
|
-
);
|
|
43270
|
-
if (aliasCheck.rows.length > 0) {
|
|
43271
|
-
p_tag_id = Number(aliasCheck.rows[0].id);
|
|
43272
|
-
} else {
|
|
43273
|
-
console.error(`\u26A0\uFE0F [Tagger] \uD6C4\uBCF4 \uC678 \uC774\uB984 "${parsed.p_tag}" \uAC70\uBD80 (NEW: prefix \uC5C6\uC74C). p_tag NULL \uBC18\uD658.`);
|
|
43274
|
-
p_tag_id = null;
|
|
43275
|
-
}
|
|
43276
|
-
}
|
|
43277
|
-
}
|
|
43278
|
-
}
|
|
43279
|
-
const d_tag = Array.isArray(parsed.d_tag) ? parsed.d_tag.filter((t) => typeof t === "string").map((t) => t.toLowerCase().trim()).filter((t) => t.length > 0 && t.length <= 50).slice(0, 5) : [];
|
|
43418
|
+
function operationalPorts() {
|
|
43280
43419
|
return {
|
|
43281
|
-
|
|
43282
|
-
|
|
43283
|
-
|
|
43420
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
43421
|
+
isLocalProvider: () => ROLE_REGISTRY.tagger.provider === "local",
|
|
43422
|
+
fallbackEnabled: localFallbackEnabled,
|
|
43423
|
+
callPrimary: (opts) => callRole("tagger", opts),
|
|
43424
|
+
callFallback: (opts) => callSpec(GROK_FALLBACK_SPEC, opts),
|
|
43425
|
+
judgeJev: (i) => judgeProjectTag(i),
|
|
43426
|
+
applyJev: (j) => shouldApplyJevJudgment(j),
|
|
43427
|
+
listCandidates: listProjectTagCandidates,
|
|
43428
|
+
listHints: listChannelHints,
|
|
43429
|
+
resolveCanonical: resolveCanonicalId,
|
|
43430
|
+
isBlockedNewName: isBlockedNewTagName,
|
|
43431
|
+
getOrCreateTag: getOrCreateProjectTag
|
|
43284
43432
|
};
|
|
43285
43433
|
}
|
|
43286
|
-
|
|
43434
|
+
async function tagMessage(input) {
|
|
43435
|
+
return runTagger(input, operationalPorts());
|
|
43436
|
+
}
|
|
43437
|
+
var GROK_FALLBACK_SPEC, localFallbackEnabled, _candidateCache, REGISTRY_CANDIDATE_LIMIT, CANDIDATE_CACHE_TTL_MS, _hintCache, SYSTEM_PROMPT;
|
|
43287
43438
|
var init_tagger = __esm({
|
|
43288
43439
|
"src/cold_path/tagger.ts"() {
|
|
43289
43440
|
"use strict";
|
|
@@ -43293,35 +43444,13 @@ var init_tagger = __esm({
|
|
|
43293
43444
|
init_prompts();
|
|
43294
43445
|
init_dtag_promoter();
|
|
43295
43446
|
init_project_registry();
|
|
43447
|
+
init_tagger_core();
|
|
43296
43448
|
GROK_FALLBACK_SPEC = { provider: "xai", model_name: "grok-4-1-fast-non-reasoning" };
|
|
43297
43449
|
localFallbackEnabled = () => process.env.LOCAL_GROK_FALLBACK !== "false";
|
|
43298
43450
|
_candidateCache = null;
|
|
43299
43451
|
REGISTRY_CANDIDATE_LIMIT = 60;
|
|
43300
43452
|
CANDIDATE_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
43301
43453
|
_hintCache = null;
|
|
43302
|
-
TAGGER_SCHEMA = {
|
|
43303
|
-
type: "object",
|
|
43304
|
-
properties: {
|
|
43305
|
-
p_tag: { type: ["string", "null"] },
|
|
43306
|
-
d_tag: { type: "array", items: { type: "string" }, maxItems: 5 }
|
|
43307
|
-
},
|
|
43308
|
-
required: ["p_tag", "d_tag"],
|
|
43309
|
-
additionalProperties: false
|
|
43310
|
-
};
|
|
43311
|
-
GENERIC_TAGGER_PROMPT = `Tagger for a user's long-term memory across AI agents.
|
|
43312
|
-
|
|
43313
|
-
OUTPUT (strict JSON):
|
|
43314
|
-
{ "p_tag": "<existing-name>" | "NEW:<slug>" | null, "d_tag": ["<kw>", ...] }
|
|
43315
|
-
|
|
43316
|
-
p_tag: ONE project tag. Prefer matching a name from the candidate list below;
|
|
43317
|
-
map obvious synonyms to an existing candidate. Use "NEW:<slug>" only when the
|
|
43318
|
-
message is clearly about a project absent from the list. null when the message
|
|
43319
|
-
is too short or generic to project-tag.
|
|
43320
|
-
|
|
43321
|
-
d_tag: 0-3 short lowercase hyphenated keywords about the topic. Skip if no signal.
|
|
43322
|
-
|
|
43323
|
-
ROLE: input includes role='user' or role='assistant'. For role='assistant',
|
|
43324
|
-
tag the topic; do not treat the reply as a fact about the user.`;
|
|
43325
43454
|
SYSTEM_PROMPT = getPrompt("tagger", GENERIC_TAGGER_PROMPT);
|
|
43326
43455
|
}
|
|
43327
43456
|
});
|
|
@@ -59307,15 +59436,15 @@ date_range \uC778\uC2DD \uD615\uC2DD:
|
|
|
59307
59436
|
date_range: external_exports.string().optional().describe("\uAE30\uAC04 \uD55C\uC815 (today / last_week / last_month / 7_days_ago / YYYY-MM-DD)"),
|
|
59308
59437
|
role: external_exports.enum(["user", "assistant"]).optional().describe("\uBC1C\uD654\uC790 \uD55C\uC815 (\uC0DD\uB7B5 \uC2DC \uB458 \uB2E4)"),
|
|
59309
59438
|
agent_platform: external_exports.string().optional().describe(
|
|
59310
|
-
"
|
|
59439
|
+
"**\uC218\uC9D1\xB7\uC2E4\uD589 \uACBD\uB85C** \uD55C\uC815 (\uC608: 'claude-code', 'gemini-cli-mcp-client'). 'buzz' \uB294 \uBC84\uC988 \uAC8C\uC2DC \uC6D0\uBB38\uC744 \uC9C1\uC811 \uC218\uC9D1\uD55C \uD589\uC774\uB2E4 \u2014 \uC2E4\uD589 \uD658\uACBD\uC774 \uC544\uB2C8\uB77C \uC218\uC9D1 \uACBD\uB85C\uC774\uACE0, \uADF8 \uD589\uC758 \uC2E4\uD589 \uD658\uACBD\uC740 \uBBF8\uC0C1\uC774\uB2E4. **\uB300\uD654 \uACF5\uAC04\uC73C\uB85C \uC881\uD788\uB824\uBA74 \uC774 \uCE78\uC774 \uC544\uB2C8\uB77C venue \uB97C \uC4F4\uB2E4.** \uC0DD\uB7B5 \uB610\uB294 '*' \uC774\uBA74 cross-platform(\uC804 \uD50C\uB7AB\uD3FC)."
|
|
59311
59440
|
),
|
|
59312
59441
|
device_scope: external_exports.enum(["local", "global"]).optional().describe(
|
|
59313
|
-
"\
|
|
59442
|
+
"**\uCEA1\uCC98 \uC7A5\uBE44** \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. \uC8FC\uC758: device_name \uC740 \uADF8 \uD589\uC744 \uC801\uC740 \uD504\uB85C\uC138\uC2A4\uC758 \uAE30\uACC4\uC774\uACE0 \uAE00\uC744 \uC4F4 \uC0AC\uB78C\uC758 \uAE30\uAE30\uAC00 \uC544\uB2C8\uB2E4. \uBC84\uC988 \uC6D0\uBB38 \uC218\uC9D1 \uD589\uC740 NULL \uC774\uB77C 'local' \uC5D0 \uC548 \uAC78\uB9B0\uB2E4 \u2014 \uB2E8 **pinned(\uAC15\uC81C\uAE30\uC5B5) \uD589\uC740 device_name \uC774 NULL \uC774\uC5B4\uB3C4 'local' \uC5D0 \uD3EC\uD568**\uB41C\uB2E4(\uAC15\uC81C\uAE30\uC5B5\uC740 \uB9E5\uB77D \uBD88\uBB38 \uB178\uCD9C)."
|
|
59314
59443
|
),
|
|
59315
59444
|
limit: external_exports.number().int().min(1).max(50).optional().describe(`\uCD5C\uB300 \uACB0\uACFC \uC218 (default ${DEFAULT_LIMIT})`),
|
|
59316
59445
|
include_archived: external_exports.boolean().optional().describe("archived \uBA54\uBAA8\uB9AC\uB3C4 \uD3EC\uD568 (default false)"),
|
|
59317
59446
|
venue: external_exports.string().optional().describe(
|
|
59318
|
-
"
|
|
59447
|
+
"**\uB300\uD654 \uACF5\uAC04**(\uC5B4\uB514\uC11C \uB9D0\uD588\uB098)\uC73C\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. \uAC19\uC740 \uACF5\uAC04\uC758 \uB300\uD654\uAC00 \uC218\uC9D1 \uACBD\uB85C(agent_platform)\uB294 \uC5EC\uB7EC \uC885\uB958\uC77C \uC218 \uC788\uB2E4."
|
|
59319
59448
|
)
|
|
59320
59449
|
}
|
|
59321
59450
|
},
|
|
@@ -63734,6 +63863,7 @@ async function maybeRunLibrarian() {
|
|
|
63734
63863
|
}
|
|
63735
63864
|
var COLDPATH_ADVISORY_LOCK_KEY = 4242000017;
|
|
63736
63865
|
var lockClient = null;
|
|
63866
|
+
var ownedColdPath = false;
|
|
63737
63867
|
async function acquireColdPathLock() {
|
|
63738
63868
|
if (lockClient) return true;
|
|
63739
63869
|
const client2 = await db.getClient();
|
|
@@ -63741,6 +63871,7 @@ async function acquireColdPathLock() {
|
|
|
63741
63871
|
const res = await client2.query("SELECT pg_try_advisory_lock($1) AS got", [COLDPATH_ADVISORY_LOCK_KEY]);
|
|
63742
63872
|
if (res.rows[0]?.got === true) {
|
|
63743
63873
|
lockClient = client2;
|
|
63874
|
+
ownedColdPath = true;
|
|
63744
63875
|
return true;
|
|
63745
63876
|
}
|
|
63746
63877
|
client2.release();
|
|
@@ -63812,6 +63943,7 @@ function stopColdPathWorker() {
|
|
|
63812
63943
|
console.error("\u{1F535} [ColdPath] stopped");
|
|
63813
63944
|
}
|
|
63814
63945
|
async function drainColdPath(maxTicks = 12) {
|
|
63946
|
+
if (!ownedColdPath) return 0;
|
|
63815
63947
|
let waitCount = 0;
|
|
63816
63948
|
while (running && waitCount < 30) {
|
|
63817
63949
|
await new Promise((r) => setTimeout(r, 100));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-agents-memory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.34",
|
|
4
4
|
"description": "Long-term memory for AI agents with provenance tracking",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,14 @@
|
|
|
32
32
|
"check:alias-evidence": "esbuild scripts/check_alias_evidence.ts --bundle --platform=node --format=esm --outfile=node_modules/.cache/mcp-agents-memory/check_alias_evidence.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_alias_evidence.mjs",
|
|
33
33
|
"check:retag": "esbuild scripts/check_ptag_retag.ts --bundle --platform=node --format=esm --outfile=node_modules/.cache/mcp-agents-memory/check_ptag_retag.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_ptag_retag.mjs",
|
|
34
34
|
"check:coldpath-gate": "esbuild scripts/check_coldpath_gate.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_coldpath_gate.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_coldpath_gate.mjs",
|
|
35
|
-
"check:codex-arm": "esbuild scripts/check_codex_arm.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_codex_arm.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_codex_arm.mjs"
|
|
35
|
+
"check:codex-arm": "esbuild scripts/check_codex_arm.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_codex_arm.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_codex_arm.mjs",
|
|
36
|
+
"check:coldpath-drain": "esbuild scripts/check_coldpath_drain.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_coldpath_drain.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_coldpath_drain.mjs",
|
|
37
|
+
"check:tagger-core": "esbuild scripts/check_tagger_core_equivalence.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_tagger_core_equivalence.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_tagger_core_equivalence.mjs",
|
|
38
|
+
"check:tagger-nodb": "esbuild scripts/check_tagger_core_nodb.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_tagger_core_nodb.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_tagger_core_nodb.mjs",
|
|
39
|
+
"eval:tagging": "esbuild scripts/eval_tagging_runner.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/eval_tagging_runner.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/eval_tagging_runner.mjs",
|
|
40
|
+
"check:eval-runner": "esbuild scripts/check_eval_runner.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_eval_runner.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_eval_runner.mjs",
|
|
41
|
+
"eval:candidates": "esbuild scripts/eval_candidate_generator.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/eval_candidate_generator.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/eval_candidate_generator.mjs",
|
|
42
|
+
"check:candidates": "esbuild scripts/check_candidate_generator.ts --bundle --platform=node --format=esm --packages=external --outfile=node_modules/.cache/mcp-agents-memory/check_candidate_generator.mjs --log-level=warning && node node_modules/.cache/mcp-agents-memory/check_candidate_generator.mjs"
|
|
36
43
|
},
|
|
37
44
|
"keywords": [
|
|
38
45
|
"mcp",
|