@0xmaxma/claude-gateway 1.7.8 → 1.7.10
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.md +11 -3
- package/dist/agent/dreaming/accept.d.ts.map +1 -1
- package/dist/agent/dreaming/accept.js +4 -1
- package/dist/agent/dreaming/accept.js.map +1 -1
- package/dist/agent/dreaming/config.d.ts.map +1 -1
- package/dist/agent/dreaming/config.js +2 -0
- package/dist/agent/dreaming/config.js.map +1 -1
- package/dist/agent/dreaming/reviewer.d.ts.map +1 -1
- package/dist/agent/dreaming/reviewer.js +9 -2
- package/dist/agent/dreaming/reviewer.js.map +1 -1
- package/dist/agent/dreaming/staleness.d.ts +7 -1
- package/dist/agent/dreaming/staleness.d.ts.map +1 -1
- package/dist/agent/dreaming/staleness.js +17 -2
- package/dist/agent/dreaming/staleness.js.map +1 -1
- package/dist/agent/dreaming/types.d.ts +17 -1
- package/dist/agent/dreaming/types.d.ts.map +1 -1
- package/dist/agent/knowledge/archive-db.d.ts +43 -0
- package/dist/agent/knowledge/archive-db.d.ts.map +1 -1
- package/dist/agent/knowledge/archive-db.js +130 -0
- package/dist/agent/knowledge/archive-db.js.map +1 -1
- package/dist/agent/knowledge/config.d.ts +3 -1
- package/dist/agent/knowledge/config.d.ts.map +1 -1
- package/dist/agent/knowledge/config.js +30 -1
- package/dist/agent/knowledge/config.js.map +1 -1
- package/dist/agent/knowledge/index.d.ts +11 -4
- package/dist/agent/knowledge/index.d.ts.map +1 -1
- package/dist/agent/knowledge/index.js +22 -1
- package/dist/agent/knowledge/index.js.map +1 -1
- package/dist/agent/knowledge/indexer.d.ts +0 -7
- package/dist/agent/knowledge/indexer.d.ts.map +1 -1
- package/dist/agent/knowledge/indexer.js +34 -7
- package/dist/agent/knowledge/indexer.js.map +1 -1
- package/dist/agent/knowledge/lifecycle.d.ts +20 -4
- package/dist/agent/knowledge/lifecycle.d.ts.map +1 -1
- package/dist/agent/knowledge/lifecycle.js +33 -4
- package/dist/agent/knowledge/lifecycle.js.map +1 -1
- package/dist/agent/knowledge/reflection.d.ts +114 -0
- package/dist/agent/knowledge/reflection.d.ts.map +1 -0
- package/dist/agent/knowledge/reflection.js +447 -0
- package/dist/agent/knowledge/reflection.js.map +1 -0
- package/dist/agent/knowledge/shared-dedup.d.ts +85 -0
- package/dist/agent/knowledge/shared-dedup.d.ts.map +1 -0
- package/dist/agent/knowledge/shared-dedup.js +187 -0
- package/dist/agent/knowledge/shared-dedup.js.map +1 -0
- package/dist/agent/knowledge/shared-promote.d.ts +82 -7
- package/dist/agent/knowledge/shared-promote.d.ts.map +1 -1
- package/dist/agent/knowledge/shared-promote.js +244 -11
- package/dist/agent/knowledge/shared-promote.js.map +1 -1
- package/dist/agent/knowledge/shared-staleness.d.ts +51 -0
- package/dist/agent/knowledge/shared-staleness.d.ts.map +1 -0
- package/dist/agent/knowledge/shared-staleness.js +149 -0
- package/dist/agent/knowledge/shared-staleness.js.map +1 -0
- package/dist/agent/knowledge/shared-writer.d.ts +19 -0
- package/dist/agent/knowledge/shared-writer.d.ts.map +1 -1
- package/dist/agent/knowledge/shared-writer.js +42 -0
- package/dist/agent/knowledge/shared-writer.js.map +1 -1
- package/dist/agent/knowledge/types.d.ts +24 -0
- package/dist/agent/knowledge/types.d.ts.map +1 -1
- package/dist/agent/runner.d.ts +7 -0
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +106 -16
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/workspace-loader.d.ts +17 -2
- package/dist/agent/workspace-loader.d.ts.map +1 -1
- package/dist/agent/workspace-loader.js +17 -1
- package/dist/agent/workspace-loader.js.map +1 -1
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +2 -1
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/line-webhook-router.d.ts.map +1 -1
- package/dist/api/line-webhook-router.js +7 -15
- package/dist/api/line-webhook-router.js.map +1 -1
- package/dist/api/slack-client.d.ts +25 -2
- package/dist/api/slack-client.d.ts.map +1 -1
- package/dist/api/slack-client.js +102 -0
- package/dist/api/slack-client.js.map +1 -1
- package/dist/api/slack-webhook-router.d.ts +15 -1
- package/dist/api/slack-webhook-router.d.ts.map +1 -1
- package/dist/api/slack-webhook-router.js +128 -1
- package/dist/api/slack-webhook-router.js.map +1 -1
- package/dist/apps/compose-generator.js +7 -4
- package/dist/apps/compose-generator.js.map +1 -1
- package/dist/apps/installer.d.ts +86 -0
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +440 -52
- package/dist/apps/installer.js.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/session/compactor.d.ts +32 -2
- package/dist/session/compactor.d.ts.map +1 -1
- package/dist/session/compactor.js +134 -19
- package/dist/session/compactor.js.map +1 -1
- package/dist/session/process.d.ts +20 -3
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +120 -5
- package/dist/session/process.js.map +1 -1
- package/dist/shared/image-sniff.d.ts +15 -0
- package/dist/shared/image-sniff.d.ts.map +1 -0
- package/dist/shared/image-sniff.js +29 -0
- package/dist/shared/image-sniff.js.map +1 -0
- package/dist/shell/claude-pty-shell.js +146 -27
- package/dist/shell/claude-pty-shell.js.map +1 -1
- package/dist/shell/draft-phantom.d.ts +49 -0
- package/dist/shell/draft-phantom.d.ts.map +1 -0
- package/dist/shell/draft-phantom.js +59 -0
- package/dist/shell/draft-phantom.js.map +1 -0
- package/dist/shell/submit-diag.d.ts +67 -0
- package/dist/shell/submit-diag.d.ts.map +1 -0
- package/dist/shell/submit-diag.js +69 -0
- package/dist/shell/submit-diag.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/mcp/tools/discord/module.ts +24 -17
- package/mcp/tools/memory/archive-reader.test.ts +25 -1
- package/mcp/tools/memory/archive-reader.ts +70 -12
- package/mcp/tools/memory/archive-writer.test.ts +168 -0
- package/mcp/tools/memory/archive-writer.ts +137 -0
- package/mcp/tools/memory/module.test.ts +187 -0
- package/mcp/tools/memory/module.ts +192 -6
- package/mcp/tools/shared/limits.ts +14 -0
- package/mcp/tools/slack/module.ts +66 -4
- package/mcp/tools/telegram/module.ts +11 -3
- package/mcp/tools/telegram/receiver-server.ts +10 -3
- package/mcp/tools/telegram/typing.ts +178 -34
- package/package.json +1 -1
|
@@ -1,29 +1,262 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeIntoNote = mergeIntoNote;
|
|
4
|
+
exports.writeCapped = writeCapped;
|
|
5
|
+
exports.isIndexPointerOnly = isIndexPointerOnly;
|
|
6
|
+
exports.isInstructionShapedName = isInstructionShapedName;
|
|
7
|
+
exports.deriveNameFromContent = deriveNameFromContent;
|
|
3
8
|
exports.makeSharedPromoter = makeSharedPromoter;
|
|
4
|
-
const crypto_1 = require("crypto");
|
|
5
9
|
const shared_writer_1 = require("./shared-writer");
|
|
10
|
+
const shared_dedup_1 = require("./shared-dedup");
|
|
11
|
+
const shared_staleness_1 = require("./shared-staleness");
|
|
6
12
|
const config_1 = require("./config");
|
|
13
|
+
/**
|
|
14
|
+
* Merge a newly-promoted fact into a note's existing content, rather than
|
|
15
|
+
* blindly overwriting it. Deterministic append (no extra LLM call — dreaming
|
|
16
|
+
* already spent its budget proposing the fact); a no-op if the addition is
|
|
17
|
+
* already present verbatim. `relatedNames` (issue #386 part B) adds
|
|
18
|
+
* `[[wikilink]]`s to OTHER near-duplicate notes found alongside the merge
|
|
19
|
+
* target, so the existing (previously unpopulated) `/knowledge/graph`
|
|
20
|
+
* dashboard gets real edges — `wiki.ts` already resolves `[[links]]` into
|
|
21
|
+
* graph edges, no parser change needed.
|
|
22
|
+
*/
|
|
23
|
+
function mergeIntoNote(existing, addition, relatedNames = []) {
|
|
24
|
+
const trimmedAddition = addition.trim();
|
|
25
|
+
// Only link what is not linked yet: a recurring fact that merges into the same
|
|
26
|
+
// note night after night would otherwise stack a duplicate `Related:` line on
|
|
27
|
+
// every pass (issue #398 review).
|
|
28
|
+
const missing = relatedNames.filter((n) => !existing.includes(`[[${n}]]`));
|
|
29
|
+
const links = missing.length ? `\n\nRelated: ${missing.map((n) => `[[${n}]]`).join(' ')}` : '';
|
|
30
|
+
if (!existing.trim())
|
|
31
|
+
return `${trimmedAddition}${links}`;
|
|
32
|
+
// Already recorded verbatim: there is nothing to append — but the note must
|
|
33
|
+
// still gain edges it is missing, or a fact that recurs under a name it
|
|
34
|
+
// already occupies stays a disconnected node forever (issue #398 review).
|
|
35
|
+
if (existing.includes(trimmedAddition))
|
|
36
|
+
return links ? `${existing.trim()}${links}` : existing;
|
|
37
|
+
return `${existing.trim()}\n\n${trimmedAddition}${links}`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write only if the result stays within the same size cap the manual
|
|
41
|
+
* `memory_shared_create`/`_update` tools enforce. Unlike those tools, dreaming
|
|
42
|
+
* has no one to show a "content too large" error to — a note a recurring topic
|
|
43
|
+
* keeps merging into over months has no natural stopping point otherwise, so
|
|
44
|
+
* once a merge would cross the cap the note is left as-is (best-effort: a
|
|
45
|
+
* skipped promotion never fails the local dream, same as any other error here).
|
|
46
|
+
*/
|
|
47
|
+
function writeCapped(cfg, name, content, relatedNames = []) {
|
|
48
|
+
const body = relatedNames.length ? mergeIntoNote('', content, relatedNames) : content;
|
|
49
|
+
if (body.length > shared_writer_1.MAX_SHARED_NOTE_SIZE)
|
|
50
|
+
return false;
|
|
51
|
+
(0, shared_writer_1.writeSharedNote)(cfg, name, body);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
// ── What may be promoted, and under what name (issue #398) ─────────────────
|
|
55
|
+
/** A `MEMORY.md` index bullet: `- [label](target.md) — hook`. */
|
|
56
|
+
const INDEX_POINTER_LINE_RE = /^\s*[-*]\s*\[[^\]]*\]\([^)]*\)\s*(?:[-–—:].*)?$/;
|
|
57
|
+
/**
|
|
58
|
+
* True when the content is nothing but `MEMORY.md` index pointers.
|
|
59
|
+
*
|
|
60
|
+
* The memory-tiering convention writes a fact to its own file AND a one-line
|
|
61
|
+
* pointer into the `MEMORY.md` index. Both land as durable `add`s, so both used
|
|
62
|
+
* to be promoted — and the pointer's links resolve only inside the promoting
|
|
63
|
+
* agent's own workspace, making it dead weight in a shared vault (issue #398:
|
|
64
|
+
* 30 of 40 live notes were pointer-only, with all 32 link targets dangling).
|
|
65
|
+
*
|
|
66
|
+
* The trailing hook text is deliberately NOT rescued into a note of its own: an
|
|
67
|
+
* index hook is written to be read next to the file it points at, so promoting
|
|
68
|
+
* it alone would put a decontextualized fragment in front of every other agent.
|
|
69
|
+
* A dream that proposes the fact itself as prose still promotes normally — only
|
|
70
|
+
* navigation scaffolding is dropped.
|
|
71
|
+
*/
|
|
72
|
+
function isIndexPointerOnly(content) {
|
|
73
|
+
const lines = content
|
|
74
|
+
.split('\n')
|
|
75
|
+
.map((l) => l.trim())
|
|
76
|
+
.filter(Boolean);
|
|
77
|
+
if (lines.length === 0)
|
|
78
|
+
return false;
|
|
79
|
+
return lines.every((l) => INDEX_POINTER_LINE_RE.test(l));
|
|
80
|
+
}
|
|
81
|
+
/** Leading verbs that make a `reason` an edit instruction rather than a topic. */
|
|
82
|
+
const INSTRUCTION_VERB_RE = /^(insert|append|prepend|add|put|place|move|update|replace|remove|delete|keep|group)\b/i;
|
|
83
|
+
/** Anchors an edit instruction points AT — a position or a file, not a subject. */
|
|
84
|
+
const EDIT_ANCHOR_RE = /\b(before|after|above|below|between|index|section|\.md)\b/i;
|
|
85
|
+
/**
|
|
86
|
+
* True when a note name reads as an instruction for editing a file rather than
|
|
87
|
+
* as the name of a fact ("insert after cron config, before the pty_shell
|
|
88
|
+
* section"). `reason` is prompted as free-form justification (`reviewer.ts`) but
|
|
89
|
+
* issue #386 repurposed it as the shared note's identity, so such strings became
|
|
90
|
+
* note names that no future occurrence of the same fact can ever match.
|
|
91
|
+
*
|
|
92
|
+
* Two signals are required — an imperative edit verb AND a positional/file
|
|
93
|
+
* anchor — because either alone is common in legitimate names ("Add-on billing
|
|
94
|
+
* is per seat", "the section header is user-visible").
|
|
95
|
+
*/
|
|
96
|
+
function isInstructionShapedName(name) {
|
|
97
|
+
return INSTRUCTION_VERB_RE.test(name.trim()) && EDIT_ANCHOR_RE.test(name);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A note name derived from the fact itself — the fallback when the proposal has
|
|
101
|
+
* no `topic` and its `reason` reads as an editing instruction.
|
|
102
|
+
*
|
|
103
|
+
* Dropping such a promotion outright (the first cut of issue #398) silently lost
|
|
104
|
+
* genuine facts whose reason merely happened to start with an edit verb, e.g.
|
|
105
|
+
* "Update the deploy section after the API change". Naming from the content
|
|
106
|
+
* keeps the fact; only content with nothing nameable in it is given up on.
|
|
107
|
+
*/
|
|
108
|
+
function deriveNameFromContent(content) {
|
|
109
|
+
const firstSentence = content
|
|
110
|
+
.replace(/^[\s>*-]+/, '')
|
|
111
|
+
.replace(/`+/g, '')
|
|
112
|
+
.split(/(?<=[.!?])\s|\n/)[0]
|
|
113
|
+
?.trim();
|
|
114
|
+
if (!firstSentence)
|
|
115
|
+
return undefined;
|
|
116
|
+
const name = firstSentence.slice(0, 80).trim();
|
|
117
|
+
// Needs real topic words, not just scaffolding, to be a usable identity.
|
|
118
|
+
return (0, shared_dedup_1.significantTokens)(name).size >= 3 ? name : undefined;
|
|
119
|
+
}
|
|
7
120
|
/**
|
|
8
121
|
* Build the per-agent→shared promotion function used after the dreaming applier
|
|
9
122
|
* writes an `add` to local memory (K3↔K4). Returns `undefined` when the shared
|
|
10
123
|
* KB is disabled or in `propose` (dry-run) mode — callers then skip promotion.
|
|
11
124
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
125
|
+
* Note identity is the proposal's `reason` (issue #386) — the SAME freeform
|
|
126
|
+
* namespace `memory_shared_create`/`_update` use, not a content hash. A
|
|
127
|
+
* content-hashed name (the pre-#386 scheme) meant the same recurring fact,
|
|
128
|
+
* reworded slightly by the reviewer each night, hashed differently and was
|
|
129
|
+
* written as a brand-new note every time — this is what created the
|
|
130
|
+
* near-duplicate pileup #386 reports. Naming by `reason` instead means the
|
|
131
|
+
* same recurring fact maps to the same note name across nights, landing as an
|
|
132
|
+
* update. A `reason` that doesn't collide by name is also checked against the
|
|
133
|
+
* shared vault's near-dup search before creating, and merged into the closest
|
|
134
|
+
* match instead of creating a disconnected duplicate when one is found.
|
|
135
|
+
*
|
|
136
|
+
* Concurrency note: the name-collision check, read, and write below are not one
|
|
137
|
+
* atomic operation, so two agents dreaming at the same moment and promoting
|
|
138
|
+
* under the exact same `reason` can race — `shared-writer.ts` already documents
|
|
139
|
+
* that same-file races resolve to last-write-wins, never corruption, and other
|
|
140
|
+
* read-modify-write callers (e.g. `memory_shared_update`) have this same
|
|
141
|
+
* property. Naming by `reason` instead of a content hash makes same-name
|
|
142
|
+
* collisions between different agents more likely than the pre-#386 scheme, but
|
|
143
|
+
* it's the same accepted tradeoff, not a new class of risk.
|
|
18
144
|
*/
|
|
19
|
-
function makeSharedPromoter(
|
|
145
|
+
function makeSharedPromoter(
|
|
146
|
+
// No longer used for NAMING — issue #386 moved note identity off the agent id,
|
|
147
|
+
// and issue #398 moved it to the proposal's `topic` slug (falling back to
|
|
148
|
+
// `reason`, then to the fact itself), so a recurring fact maps to the same
|
|
149
|
+
// shared note whichever agent dreamed it. Still carried because every declined
|
|
150
|
+
// promotion is logged with the agent that proposed it.
|
|
151
|
+
agentId, agentCfg, globalCfg,
|
|
152
|
+
// Promotion can decline for several reasons and used to do so in total silence,
|
|
153
|
+
// which made "why did the shared vault stop growing?" undiagnosable from the
|
|
154
|
+
// outside (issue #398 review). Optional so existing call sites keep working.
|
|
155
|
+
logger) {
|
|
20
156
|
const sharedCfg = (0, config_1.resolveSharedConfig)(agentCfg, globalCfg);
|
|
21
157
|
if (!sharedCfg.enabled || sharedCfg.mode !== 'auto')
|
|
22
158
|
return undefined;
|
|
159
|
+
const skip = (why, data = {}) => {
|
|
160
|
+
logger?.info('shared promotion skipped', { agentId, why, ...data });
|
|
161
|
+
};
|
|
23
162
|
return (p) => {
|
|
24
|
-
const content = p.content ?? '';
|
|
25
|
-
|
|
26
|
-
|
|
163
|
+
const content = (p.content ?? '').trim();
|
|
164
|
+
if (!content)
|
|
165
|
+
return;
|
|
166
|
+
// An index pointer is a per-agent navigation aid, not a shareable fact: its
|
|
167
|
+
// links resolve only inside the promoting agent's own workspace.
|
|
168
|
+
if (isIndexPointerOnly(content)) {
|
|
169
|
+
skip('index-pointer-only', { reason: p.reason });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Identity, best first: an explicit `topic` slug (mirroring the episodic
|
|
173
|
+
// contract), then the free-form `reason`, then the fact itself. A reason that
|
|
174
|
+
// reads as an editing instruction would produce a note name no later
|
|
175
|
+
// occurrence of the same fact could match, so it is passed over — but the
|
|
176
|
+
// fact is still promoted under a content-derived name.
|
|
177
|
+
const explicit = (p.topic ?? '').trim();
|
|
178
|
+
const reason = p.reason.trim();
|
|
179
|
+
const name = explicit ||
|
|
180
|
+
(reason && !isInstructionShapedName(reason) ? reason : deriveNameFromContent(content));
|
|
181
|
+
if (!name) {
|
|
182
|
+
skip('no-usable-name', { reason: p.reason });
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
// A `stale__` twin of THIS name means the GC retired this fact and it has
|
|
187
|
+
// now recurred — the recurrence itself is the promote-back signal. Resolved
|
|
188
|
+
// BEFORE the update/create split because both paths put a live file back at
|
|
189
|
+
// `name`, and once that file exists the GC's own restore refuses forever
|
|
190
|
+
// (`moveNoteFromStale` bails on `sharedNoteExists`). A twin left behind is
|
|
191
|
+
// not inert: retired notes stay indexed and searchable by design (#392), so
|
|
192
|
+
// the same fact would answer every query twice, permanently (issue #398
|
|
193
|
+
// review — the create path handled this, the update path did not).
|
|
194
|
+
const staleTwin = `${shared_staleness_1.STALE_NOTE_PREFIX}${name}`;
|
|
195
|
+
const retired = (0, shared_writer_1.sharedNoteExists)(sharedCfg, staleTwin)
|
|
196
|
+
? ((0, shared_writer_1.readSharedNote)(sharedCfg, staleTwin) ?? '').replace(/^<!--[\s\S]*?-->\s*/, '').trim()
|
|
197
|
+
: '';
|
|
198
|
+
// Only drop the twin once its content is safely in the live note: a write
|
|
199
|
+
// refused by the size cap must leave the retired copy where it is.
|
|
200
|
+
const dropTwinIfWritten = (written) => {
|
|
201
|
+
if (written && retired)
|
|
202
|
+
(0, shared_writer_1.deleteSharedNoteFile)(sharedCfg, staleTwin);
|
|
203
|
+
};
|
|
204
|
+
// Same name recurred: this IS the same fact — update it, never duplicate.
|
|
205
|
+
if ((0, shared_writer_1.sharedNoteExists)(sharedCfg, name)) {
|
|
206
|
+
const existing = (0, shared_writer_1.readSharedNote)(sharedCfg, name) ?? '';
|
|
207
|
+
const withRetired = retired ? mergeIntoNote(existing, retired) : existing;
|
|
208
|
+
const written = writeCapped(sharedCfg, name, mergeIntoNote(withRetired, content));
|
|
209
|
+
if (!written)
|
|
210
|
+
skip('note-size-cap', { reason: p.reason, note: name });
|
|
211
|
+
dropTwinIfWritten(written);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// New name, but the content may already live in another note. FTS is
|
|
215
|
+
// recall only; `filterNearDuplicates` is the precision bar that decides
|
|
216
|
+
// whether an UNATTENDED merge is justified. Below the bar the fact gets
|
|
217
|
+
// its own note — two notes are recoverable, two unrelated facts fused
|
|
218
|
+
// into one are not (issue #398).
|
|
219
|
+
//
|
|
220
|
+
// Retired (`stale__*`) notes are excluded as targets: they are indexed
|
|
221
|
+
// like any other file, and merging a fresh fact into one would write it
|
|
222
|
+
// straight into the set the GC has already moved out of the active vault.
|
|
223
|
+
const seed = (0, shared_dedup_1.buildSeedText)(name, content);
|
|
224
|
+
const candidates = (0, shared_dedup_1.findSimilarSharedNotes)(sharedCfg, seed, 3).filter((c) => !c.name.startsWith(shared_staleness_1.STALE_NOTE_PREFIX));
|
|
225
|
+
// Score against each candidate's FULL body, not the matched chunk: a long
|
|
226
|
+
// note that a recurring topic has merged into spreads the seed across
|
|
227
|
+
// chunks and would score far below its real containment.
|
|
228
|
+
const bodyOf = (c) => (0, shared_writer_1.readSharedNote)(sharedCfg, c.name) ?? '';
|
|
229
|
+
const mergeable = (0, shared_dedup_1.filterNearDuplicates)(seed, candidates, undefined, bodyOf);
|
|
230
|
+
// Wikilinks clear a LOWER bar than merges: a link is an additive "these
|
|
231
|
+
// are related" claim, while a merge asserts they are the same fact and
|
|
232
|
+
// destroys the distinction. Computed for BOTH outcomes — a new note that
|
|
233
|
+
// has related neighbours must still carry its edges, or the graph gains a
|
|
234
|
+
// disconnected node exactly in the 0.25–0.5 band (issue #398 review).
|
|
235
|
+
const linkable = (0, shared_dedup_1.filterNearDuplicates)(seed, candidates, shared_dedup_1.MIN_RELATED_CONTAINMENT, bodyOf);
|
|
236
|
+
if (mergeable.length > 0) {
|
|
237
|
+
const primary = mergeable[0];
|
|
238
|
+
const related = linkable.filter((c) => c.name !== primary.name);
|
|
239
|
+
const existing = (0, shared_writer_1.readSharedNote)(sharedCfg, primary.name) ?? '';
|
|
240
|
+
if (!writeCapped(sharedCfg, primary.name, mergeIntoNote(existing, content, related.map((r) => r.name)))) {
|
|
241
|
+
skip('note-size-cap', { reason: p.reason, note: primary.name });
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
// Creating fresh. Folding a retired twin back in here also stops two files
|
|
246
|
+
// from sharing one `entry_hash`, whose single lifecycle row's `path` would
|
|
247
|
+
// otherwise flip between them on every index pass.
|
|
248
|
+
const body = retired ? mergeIntoNote(retired, content) : content;
|
|
249
|
+
const written = writeCapped(sharedCfg, name, body, linkable.map((r) => r.name));
|
|
250
|
+
if (!written)
|
|
251
|
+
skip('note-size-cap', { reason: p.reason, note: name });
|
|
252
|
+
dropTwinIfWritten(written);
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
// Best-effort — a promotion failure never affects the local dream. It must
|
|
256
|
+
// not be invisible either: a vault that silently stops growing was the
|
|
257
|
+
// undiagnosable failure issue #398 set out to close.
|
|
258
|
+
skip('write-failed', { reason: p.reason, error: err?.message });
|
|
259
|
+
}
|
|
27
260
|
};
|
|
28
261
|
}
|
|
29
262
|
//# sourceMappingURL=shared-promote.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-promote.js","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-promote.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"shared-promote.js","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-promote.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared-KB staleness GC (issue #392 part D) — the shared-vault twin of
|
|
3
|
+
* `dreaming/staleness.ts`'s nightly per-agent GC, extending the SAME
|
|
4
|
+
* `kb_entry_lifecycle` soft-invalidate model to the shared KB, which had none
|
|
5
|
+
* at all (the shared vault's `kb_entry_lifecycle` table existed but was never
|
|
6
|
+
* populated — `indexer.ts` only computed entry blocks for `source: 'memory'`).
|
|
7
|
+
*
|
|
8
|
+
* The unit of identity here is the WHOLE NOTE (`wholeNoteEntryBlock`), not a
|
|
9
|
+
* bullet, so "moving a block" means moving the whole note. A stale note's
|
|
10
|
+
* content is written byte-identical (so its entry_hash — and thus the
|
|
11
|
+
* promote-back feedback loop — survives the move) to a `stale__<name>`
|
|
12
|
+
* sibling note, then the original file is deleted; a note retrieved AFTER
|
|
13
|
+
* being staled is moved back to its original name. This mirrors the personal
|
|
14
|
+
* archive's "decluttering by physical relocation" without merging multiple
|
|
15
|
+
* notes' content together (which would break entry-hash stability).
|
|
16
|
+
*
|
|
17
|
+
* Explicit `supersedes #N`-by-reference detection stays personal-only (issue
|
|
18
|
+
* #392 scope note): shared notes have no visible numeric id, and round 1's
|
|
19
|
+
* write-time merge/near-dup already provides de-facto content supersession.
|
|
20
|
+
* Only TTL/retrieval-based soft-invalidation applies here.
|
|
21
|
+
*/
|
|
22
|
+
import { ArchiveDB } from './archive-db';
|
|
23
|
+
import type { ResolvedKnowledgeSharedCfg } from './types';
|
|
24
|
+
import type { ResolvedStalenessCfg } from '../dreaming/types';
|
|
25
|
+
/** Prefix a staled note's file is moved under (issue #392 part D). */
|
|
26
|
+
export declare const STALE_NOTE_PREFIX = "stale__";
|
|
27
|
+
export interface SharedStalenessResult {
|
|
28
|
+
invalidated: number;
|
|
29
|
+
promoted: number;
|
|
30
|
+
skippedMoves: number;
|
|
31
|
+
foldedLogRows: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Retire a live note: write its content byte-identical (after `comment`, which
|
|
35
|
+
* `wholeNoteEntryBlock` skips when hashing) to `stale__<name>`, then delete the
|
|
36
|
+
* original. Exported so both the TTL-based GC below and the reflection pass
|
|
37
|
+
* (issue #392 part C, merging a note into a cluster's canonical note) share one
|
|
38
|
+
* "move a note out of the active set" primitive. Returns false if the note is
|
|
39
|
+
* missing/empty.
|
|
40
|
+
*/
|
|
41
|
+
export declare function retireSharedNote(cfg: ResolvedKnowledgeSharedCfg, name: string, comment: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Run the shared-KB staleness GC. Never throws; on any error the vault is left
|
|
44
|
+
* as-is. Deterministic given `opts.now`. Mirrors `runStalenessGc`'s shape.
|
|
45
|
+
*/
|
|
46
|
+
export declare function runSharedStalenessGc(cfg: ResolvedKnowledgeSharedCfg, staleCfg: ResolvedStalenessCfg, opts?: {
|
|
47
|
+
now?: number;
|
|
48
|
+
reindex?: (cfg: ResolvedKnowledgeSharedCfg) => void;
|
|
49
|
+
openDb?: (cfg: ResolvedKnowledgeSharedCfg) => ArchiveDB;
|
|
50
|
+
}): SharedStalenessResult;
|
|
51
|
+
//# sourceMappingURL=shared-staleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-staleness.d.ts","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-staleness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAqB,MAAM,cAAc,CAAC;AAM5D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,sEAAsE;AACtE,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AASD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAaxG;AAmCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,0BAA0B,EAC/B,QAAQ,EAAE,oBAAoB,EAC9B,IAAI,CAAC,EAAE;IACL,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACpD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,SAAS,CAAC;CACzD,GACA,qBAAqB,CA2CvB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared-KB staleness GC (issue #392 part D) — the shared-vault twin of
|
|
4
|
+
* `dreaming/staleness.ts`'s nightly per-agent GC, extending the SAME
|
|
5
|
+
* `kb_entry_lifecycle` soft-invalidate model to the shared KB, which had none
|
|
6
|
+
* at all (the shared vault's `kb_entry_lifecycle` table existed but was never
|
|
7
|
+
* populated — `indexer.ts` only computed entry blocks for `source: 'memory'`).
|
|
8
|
+
*
|
|
9
|
+
* The unit of identity here is the WHOLE NOTE (`wholeNoteEntryBlock`), not a
|
|
10
|
+
* bullet, so "moving a block" means moving the whole note. A stale note's
|
|
11
|
+
* content is written byte-identical (so its entry_hash — and thus the
|
|
12
|
+
* promote-back feedback loop — survives the move) to a `stale__<name>`
|
|
13
|
+
* sibling note, then the original file is deleted; a note retrieved AFTER
|
|
14
|
+
* being staled is moved back to its original name. This mirrors the personal
|
|
15
|
+
* archive's "decluttering by physical relocation" without merging multiple
|
|
16
|
+
* notes' content together (which would break entry-hash stability).
|
|
17
|
+
*
|
|
18
|
+
* Explicit `supersedes #N`-by-reference detection stays personal-only (issue
|
|
19
|
+
* #392 scope note): shared notes have no visible numeric id, and round 1's
|
|
20
|
+
* write-time merge/near-dup already provides de-facto content supersession.
|
|
21
|
+
* Only TTL/retrieval-based soft-invalidation applies here.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.STALE_NOTE_PREFIX = void 0;
|
|
25
|
+
exports.retireSharedNote = retireSharedNote;
|
|
26
|
+
exports.runSharedStalenessGc = runSharedStalenessGc;
|
|
27
|
+
const archive_db_1 = require("./archive-db");
|
|
28
|
+
const staleness_1 = require("../dreaming/staleness");
|
|
29
|
+
const indexer_1 = require("./indexer");
|
|
30
|
+
const lifecycle_1 = require("./lifecycle");
|
|
31
|
+
const shared_writer_1 = require("./shared-writer");
|
|
32
|
+
const config_1 = require("./config");
|
|
33
|
+
/** Prefix a staled note's file is moved under (issue #392 part D). */
|
|
34
|
+
exports.STALE_NOTE_PREFIX = 'stale__';
|
|
35
|
+
const ZERO = { invalidated: 0, promoted: 0, skippedMoves: 0, foldedLogRows: 0 };
|
|
36
|
+
/** The note "name" (pre-slug) a lifecycle row's stored path corresponds to. */
|
|
37
|
+
function nameFromPath(relPath) {
|
|
38
|
+
return relPath.replace(/\.md$/i, '');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Retire a live note: write its content byte-identical (after `comment`, which
|
|
42
|
+
* `wholeNoteEntryBlock` skips when hashing) to `stale__<name>`, then delete the
|
|
43
|
+
* original. Exported so both the TTL-based GC below and the reflection pass
|
|
44
|
+
* (issue #392 part C, merging a note into a cluster's canonical note) share one
|
|
45
|
+
* "move a note out of the active set" primitive. Returns false if the note is
|
|
46
|
+
* missing/empty.
|
|
47
|
+
*/
|
|
48
|
+
function retireSharedNote(cfg, name, comment) {
|
|
49
|
+
const content = (0, shared_writer_1.readSharedNote)(cfg, name);
|
|
50
|
+
if (!content || !content.trim())
|
|
51
|
+
return false;
|
|
52
|
+
const block = (0, lifecycle_1.wholeNoteEntryBlock)(content)[0];
|
|
53
|
+
if (!block)
|
|
54
|
+
return false;
|
|
55
|
+
const staleName = `${exports.STALE_NOTE_PREFIX}${name}`;
|
|
56
|
+
(0, shared_writer_1.writeSharedNote)(cfg, staleName, `${comment}\n${block.text}`);
|
|
57
|
+
if ((0, shared_writer_1.deleteSharedNoteFile)(cfg, name))
|
|
58
|
+
return true;
|
|
59
|
+
// A failed delete must not leave a new stale duplicate behind or let callers
|
|
60
|
+
// stamp this active note invalid. Best-effort rollback preserves the invariant
|
|
61
|
+
// that a successful retirement has exactly one physical representation.
|
|
62
|
+
(0, shared_writer_1.deleteSharedNoteFile)(cfg, staleName);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Move a live note to `stale__<name>`, preserving its content byte-identical
|
|
67
|
+
* (after a leading `<!-- staled ... -->` marker line, which `wholeNoteEntryBlock`
|
|
68
|
+
* skips when hashing) so the entry_hash — and therefore the promote-back
|
|
69
|
+
* feedback loop — survives the move. Returns false (skip, don't stamp invalid)
|
|
70
|
+
* if the note is missing/empty or the content no longer matches the block that
|
|
71
|
+
* was scored (moved/edited concurrently).
|
|
72
|
+
*/
|
|
73
|
+
function moveNoteToStale(cfg, r, comment) {
|
|
74
|
+
const name = nameFromPath(r.path);
|
|
75
|
+
const content = (0, shared_writer_1.readSharedNote)(cfg, name);
|
|
76
|
+
if (!content)
|
|
77
|
+
return false;
|
|
78
|
+
const block = (0, lifecycle_1.wholeNoteEntryBlock)(content)[0];
|
|
79
|
+
if (!block || block.entryHash !== r.entryHash)
|
|
80
|
+
return false; // content changed since scoring
|
|
81
|
+
return retireSharedNote(cfg, name, comment);
|
|
82
|
+
}
|
|
83
|
+
/** Move a staled note back to its original name (issue #392 promote-back). */
|
|
84
|
+
function moveNoteFromStale(cfg, r, comment) {
|
|
85
|
+
const staleName = nameFromPath(r.path); // r.path is the stale__<name> source path
|
|
86
|
+
const content = (0, shared_writer_1.readSharedNote)(cfg, staleName);
|
|
87
|
+
if (!content)
|
|
88
|
+
return false;
|
|
89
|
+
const block = (0, lifecycle_1.wholeNoteEntryBlock)(content)[0];
|
|
90
|
+
if (!block || block.entryHash !== r.entryHash)
|
|
91
|
+
return false;
|
|
92
|
+
const originalName = staleName.startsWith(exports.STALE_NOTE_PREFIX) ? staleName.slice(exports.STALE_NOTE_PREFIX.length) : staleName;
|
|
93
|
+
// Don't clobber a brand-new note that was created at the original name while
|
|
94
|
+
// this one sat staled — leave it staled rather than lose the newer note.
|
|
95
|
+
if ((0, shared_writer_1.sharedNoteExists)(cfg, originalName))
|
|
96
|
+
return false;
|
|
97
|
+
(0, shared_writer_1.writeSharedNote)(cfg, originalName, `${comment}\n${block.text}`);
|
|
98
|
+
(0, shared_writer_1.deleteSharedNoteFile)(cfg, staleName);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Run the shared-KB staleness GC. Never throws; on any error the vault is left
|
|
103
|
+
* as-is. Deterministic given `opts.now`. Mirrors `runStalenessGc`'s shape.
|
|
104
|
+
*/
|
|
105
|
+
function runSharedStalenessGc(cfg, staleCfg, opts) {
|
|
106
|
+
if (!staleCfg.enabled)
|
|
107
|
+
return { ...ZERO };
|
|
108
|
+
const now = opts?.now ?? Date.now();
|
|
109
|
+
const reindex = opts?.reindex ?? ((c) => void (0, indexer_1.indexSharedArchive)(c));
|
|
110
|
+
const openDb = opts?.openDb ?? ((c) => archive_db_1.ArchiveDB.forPath((0, config_1.sharedDbPath)(c)));
|
|
111
|
+
const result = { ...ZERO };
|
|
112
|
+
try {
|
|
113
|
+
// Ensure lifecycle rows exist for the current notes (first_seen etc).
|
|
114
|
+
reindex(cfg);
|
|
115
|
+
const db = openDb(cfg);
|
|
116
|
+
if (staleCfg.recordRetrievals)
|
|
117
|
+
result.foldedLogRows = db.aggregateRetrievalLog();
|
|
118
|
+
// Every shared note is lifecycle-eligible (no evergreen/pinned distinction).
|
|
119
|
+
const { invalidate, promote } = (0, staleness_1.decideStaleness)(db.listLifecycle(), staleCfg, now, () => true);
|
|
120
|
+
const date = new Date(now).toISOString().slice(0, 10);
|
|
121
|
+
for (const r of invalidate) {
|
|
122
|
+
const comment = `<!-- staled ${date} (aged out, ${r.retrievalCount} retrievals) -->`;
|
|
123
|
+
if (moveNoteToStale(cfg, r, comment)) {
|
|
124
|
+
db.stampInvalid(r.entryHash, now);
|
|
125
|
+
result.invalidated++;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
result.skippedMoves++;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const r of promote) {
|
|
132
|
+
const comment = `<!-- restored ${date} (retrieved after invalidation) -->`;
|
|
133
|
+
if (moveNoteFromStale(cfg, r, comment)) {
|
|
134
|
+
db.stampInvalid(r.entryHash, null);
|
|
135
|
+
result.promoted++;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
result.skippedMoves++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (result.invalidated + result.promoted > 0)
|
|
142
|
+
reindex(cfg);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
/* best-effort — leave the vault untouched on any error */
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=shared-staleness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-staleness.js","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-staleness.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,25 @@
|
|
|
14
14
|
* escape the notes dir.
|
|
15
15
|
*/
|
|
16
16
|
import type { ResolvedKnowledgeSharedCfg } from './types';
|
|
17
|
+
/**
|
|
18
|
+
* Same cap the Bun-side MCP tools enforce on `memory_shared_create`/`_update`
|
|
19
|
+
* (`MAX_SHARED_NOTE_SIZE` in `mcp/tools/memory/module.ts`) — kept as an
|
|
20
|
+
* independent constant here since the two processes don't share imports
|
|
21
|
+
* (see the cross-runtime note in `shared-dedup.ts`). Keep both values in sync.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MAX_SHARED_NOTE_SIZE: number;
|
|
24
|
+
/** Whether a note already exists at this name (post-`sharedNoteFilename` slugification). */
|
|
25
|
+
export declare function sharedNoteExists(cfg: ResolvedKnowledgeSharedCfg, name: string): boolean;
|
|
26
|
+
/** Full content of a shared note, or null if it does not exist / is unreadable. */
|
|
27
|
+
export declare function readSharedNote(cfg: ResolvedKnowledgeSharedCfg, name: string): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Delete a shared note's file (issue #392 part D — the staleness GC moves a
|
|
30
|
+
* note's content elsewhere, then removes the original). Returns true if a file
|
|
31
|
+
* was actually removed, false if it didn't exist. Best-effort: any other error
|
|
32
|
+
* (permissions, race) is swallowed and reported as false, mirroring the rest of
|
|
33
|
+
* this module's "never throws into the caller's control flow" stance.
|
|
34
|
+
*/
|
|
35
|
+
export declare function deleteSharedNoteFile(cfg: ResolvedKnowledgeSharedCfg, name: string): boolean;
|
|
17
36
|
/** Reduce an arbitrary name to one safe `*.md` path segment (no traversal). */
|
|
18
37
|
export declare function sharedNoteFilename(name: string): string;
|
|
19
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-writer.d.ts","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"shared-writer.d.ts","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAE/C,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,GAAG,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ3F;AAMD,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAqBtG"}
|
|
@@ -48,11 +48,53 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
48
48
|
};
|
|
49
49
|
})();
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.MAX_SHARED_NOTE_SIZE = void 0;
|
|
52
|
+
exports.sharedNoteExists = sharedNoteExists;
|
|
53
|
+
exports.readSharedNote = readSharedNote;
|
|
54
|
+
exports.deleteSharedNoteFile = deleteSharedNoteFile;
|
|
51
55
|
exports.sharedNoteFilename = sharedNoteFilename;
|
|
52
56
|
exports.writeSharedNote = writeSharedNote;
|
|
53
57
|
const fs = __importStar(require("fs"));
|
|
54
58
|
const path = __importStar(require("path"));
|
|
55
59
|
const config_1 = require("./config");
|
|
60
|
+
/**
|
|
61
|
+
* Same cap the Bun-side MCP tools enforce on `memory_shared_create`/`_update`
|
|
62
|
+
* (`MAX_SHARED_NOTE_SIZE` in `mcp/tools/memory/module.ts`) — kept as an
|
|
63
|
+
* independent constant here since the two processes don't share imports
|
|
64
|
+
* (see the cross-runtime note in `shared-dedup.ts`). Keep both values in sync.
|
|
65
|
+
*/
|
|
66
|
+
exports.MAX_SHARED_NOTE_SIZE = 100 * 1024;
|
|
67
|
+
/** Whether a note already exists at this name (post-`sharedNoteFilename` slugification). */
|
|
68
|
+
function sharedNoteExists(cfg, name) {
|
|
69
|
+
return fs.existsSync(path.join((0, config_1.sharedNotesDir)(cfg), sharedNoteFilename(name)));
|
|
70
|
+
}
|
|
71
|
+
/** Full content of a shared note, or null if it does not exist / is unreadable. */
|
|
72
|
+
function readSharedNote(cfg, name) {
|
|
73
|
+
const target = path.join((0, config_1.sharedNotesDir)(cfg), sharedNoteFilename(name));
|
|
74
|
+
try {
|
|
75
|
+
return fs.readFileSync(target, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Delete a shared note's file (issue #392 part D — the staleness GC moves a
|
|
83
|
+
* note's content elsewhere, then removes the original). Returns true if a file
|
|
84
|
+
* was actually removed, false if it didn't exist. Best-effort: any other error
|
|
85
|
+
* (permissions, race) is swallowed and reported as false, mirroring the rest of
|
|
86
|
+
* this module's "never throws into the caller's control flow" stance.
|
|
87
|
+
*/
|
|
88
|
+
function deleteSharedNoteFile(cfg, name) {
|
|
89
|
+
const target = path.join((0, config_1.sharedNotesDir)(cfg), sharedNoteFilename(name));
|
|
90
|
+
try {
|
|
91
|
+
fs.unlinkSync(target);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
56
98
|
// Monotonic per-process counter so concurrent writes within one process still get
|
|
57
99
|
// distinct temp names (combined with pid for cross-process uniqueness).
|
|
58
100
|
let tmpCounter = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-writer.js","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-writer.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG
|
|
1
|
+
{"version":3,"file":"shared-writer.js","sourceRoot":"","sources":["../../../src/agent/knowledge/shared-writer.ts"],"names":[],"mappings":"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"}
|