oc-tweaks 0.10.0 → 0.11.0
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/dist/index.js +82 -40
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -63,10 +63,12 @@ async function loadJsonConfig(path, defaults) {
|
|
|
63
63
|
var DEFAULT_CONFIG = {
|
|
64
64
|
compaction: {},
|
|
65
65
|
autoMemory: {
|
|
66
|
+
enabled: false,
|
|
66
67
|
autoWrite: "notify",
|
|
67
68
|
maxBytesPerFile: 32768,
|
|
68
69
|
maxWritesPerSession: 5,
|
|
69
|
-
summaryTokenBudget: 4000
|
|
70
|
+
summaryTokenBudget: 4000,
|
|
71
|
+
maxDiffLines: 500
|
|
70
72
|
},
|
|
71
73
|
backgroundSubagent: {},
|
|
72
74
|
leaderboard: {},
|
|
@@ -148,6 +150,75 @@ function buildSystemInjection(entries, opts) {
|
|
|
148
150
|
`);
|
|
149
151
|
}
|
|
150
152
|
|
|
153
|
+
// src/plugins/auto-memory/recall.ts
|
|
154
|
+
import { readFile } from "node:fs/promises";
|
|
155
|
+
|
|
156
|
+
// src/plugins/auto-memory/sanitize.ts
|
|
157
|
+
function wrapAsUntrusted(id, body) {
|
|
158
|
+
return `<untrusted_memory id="${id}">
|
|
159
|
+
${body}
|
|
160
|
+
</untrusted_memory>`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/plugins/auto-memory/recall.ts
|
|
164
|
+
var DEFAULT_MAX_BYTES_PER_FILE = 32768;
|
|
165
|
+
var TRUNCATION_MARKER = "<!-- truncated -->";
|
|
166
|
+
var NO_MATCH_SENTINEL_ID = "__none__";
|
|
167
|
+
var NO_MATCH_SENTINEL_CONTENT = "<!-- recall:no-match -->";
|
|
168
|
+
function truncateBytes(body, maxBytes) {
|
|
169
|
+
const buf = Buffer.from(body, "utf8");
|
|
170
|
+
if (buf.byteLength <= maxBytes)
|
|
171
|
+
return body;
|
|
172
|
+
return buf.subarray(0, maxBytes).toString("utf8") + ` ${TRUNCATION_MARKER}`;
|
|
173
|
+
}
|
|
174
|
+
function fireOnHit(id, cb) {
|
|
175
|
+
if (!cb)
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
const r = cb(id);
|
|
179
|
+
if (r && typeof r.catch === "function") {
|
|
180
|
+
r.catch((err) => {
|
|
181
|
+
console.error("[recall] onHit (async) failed:", err);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.error("[recall] onHit (sync) failed:", err);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function recallMemory(query, registry, opts = {}) {
|
|
189
|
+
const maxBytes = opts.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE;
|
|
190
|
+
if (query.length === 0) {
|
|
191
|
+
return [{ id: NO_MATCH_SENTINEL_ID, content: NO_MATCH_SENTINEL_CONTENT }];
|
|
192
|
+
}
|
|
193
|
+
const typeCandidates = opts.filterType ? registry.filter((e) => e.meta.type === opts.filterType) : registry;
|
|
194
|
+
const candidates = opts.filterTags?.length ? typeCandidates.filter((entry) => {
|
|
195
|
+
const tags = entry.meta.tags;
|
|
196
|
+
return !tags || tags.some((tag) => opts.filterTags?.includes(tag));
|
|
197
|
+
}) : typeCandidates;
|
|
198
|
+
const hits = [];
|
|
199
|
+
for (const entry of candidates) {
|
|
200
|
+
let body;
|
|
201
|
+
try {
|
|
202
|
+
body = await readFile(entry.absPath, "utf8");
|
|
203
|
+
} catch {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (!body.includes(query))
|
|
207
|
+
continue;
|
|
208
|
+
const truncated = truncateBytes(body, maxBytes);
|
|
209
|
+
const id = entry.meta.id || entry.absPath;
|
|
210
|
+
hits.push({
|
|
211
|
+
id,
|
|
212
|
+
content: wrapAsUntrusted(id, truncated)
|
|
213
|
+
});
|
|
214
|
+
fireOnHit(id, opts.onHit);
|
|
215
|
+
}
|
|
216
|
+
if (hits.length === 0) {
|
|
217
|
+
return [{ id: NO_MATCH_SENTINEL_ID, content: NO_MATCH_SENTINEL_CONTENT }];
|
|
218
|
+
}
|
|
219
|
+
return hits;
|
|
220
|
+
}
|
|
221
|
+
|
|
151
222
|
// src/plugins/auto-memory/registry.ts
|
|
152
223
|
import { closeSync, openSync, readdirSync, readSync } from "node:fs";
|
|
153
224
|
import { join } from "node:path";
|
|
@@ -455,53 +526,24 @@ var autoMemoryPlugin = async ({ directory }) => {
|
|
|
455
526
|
return;
|
|
456
527
|
await ensureAutoMemoryInfra(home, projectMemoryDir);
|
|
457
528
|
const entries = scanMemoryRoots(globalMemoryDir, projectMemoryDir);
|
|
529
|
+
const recalled = await recallMemory("", entries, {
|
|
530
|
+
onHit: (id) => {
|
|
531
|
+
process.stderr.write(`T9-onHit: ${id}
|
|
532
|
+
`);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
458
535
|
const injection = buildMemoryInjection(entries, config.autoMemory.summaryTokenBudget ?? 4000);
|
|
536
|
+
const recallInjection = recalled.map((result) => result.content).join(`
|
|
537
|
+
`);
|
|
459
538
|
const summaryPathHints = buildSummaryPathHints(entries);
|
|
460
539
|
output.system.push(buildMemoryGuide({
|
|
461
540
|
globalMemoryDir,
|
|
462
541
|
projectMemoryDir,
|
|
463
542
|
entries,
|
|
464
|
-
injection,
|
|
543
|
+
injection: [injection, recallInjection].filter(Boolean).join(`
|
|
544
|
+
`),
|
|
465
545
|
summaryPathHints
|
|
466
546
|
}));
|
|
467
|
-
}),
|
|
468
|
-
"experimental.session.compacting": safeHook("auto-memory:compacting", async (_input, output) => {
|
|
469
|
-
const config = await loadOcTweaksConfig();
|
|
470
|
-
if (!config || config.autoMemory?.enabled !== true)
|
|
471
|
-
return;
|
|
472
|
-
await ensureAutoMemoryInfra(home, projectMemoryDir);
|
|
473
|
-
output.context.push(`## \uD83D\uDCBE Memory Checkpoint
|
|
474
|
-
|
|
475
|
-
核心问题:**如果明天开一个全新会话,本轮对话中有哪些信息会让你希望已经记录下来?**
|
|
476
|
-
|
|
477
|
-
有 → 标记保存。没有 → 标记 none。
|
|
478
|
-
|
|
479
|
-
### 值得保存
|
|
480
|
-
- 用户表达的偏好、纠正、或明确要求记住的内容
|
|
481
|
-
- 架构决策、设计约束、技术选型及其理由
|
|
482
|
-
- 反复出现问题的根因与解决方案
|
|
483
|
-
- 工作流、工具链、沟通风格等跨会话有价值的模式
|
|
484
|
-
|
|
485
|
-
### 不要保存
|
|
486
|
-
- 本次对话的临时细节(具体报错、一次性调试步骤)
|
|
487
|
-
- AGENTS.md / CLAUDE.md 中已有的内容
|
|
488
|
-
- 未验证的猜测
|
|
489
|
-
- 机密信息(密码、API key 等)
|
|
490
|
-
|
|
491
|
-
每次 compaction 最多标记 1-2 条,宁缺毋滥。
|
|
492
|
-
|
|
493
|
-
有内容:
|
|
494
|
-
\`\`\`
|
|
495
|
-
[MEMORY: 文件名.md]
|
|
496
|
-
简洁 bullet points,保持原意
|
|
497
|
-
\`\`\`
|
|
498
|
-
|
|
499
|
-
无内容:\`[MEMORY: none]\` 并附一句理由说明为何无需保存
|
|
500
|
-
|
|
501
|
-
### Memory 路径
|
|
502
|
-
- 全局:\`${globalMemoryDir}/\`
|
|
503
|
-
- 项目:\`${projectMemoryDir}/\`
|
|
504
|
-
`);
|
|
505
547
|
})
|
|
506
548
|
};
|
|
507
549
|
};
|