memory-bank-skill 7.4.0 → 7.4.2
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 +2 -2
- package/dist/cli.js +1 -17
- package/dist/plugin.js +80 -43
- package/package.json +1 -1
- package/skills/memory-bank/references/writer.md +27 -0
package/README.md
CHANGED
|
@@ -180,5 +180,5 @@ service=memory-bank Plugin initialized (unified) {"projectRoot":"..."}
|
|
|
180
180
|
|
|
181
181
|
## 版本
|
|
182
182
|
|
|
183
|
-
- **版本**: 7.4.
|
|
184
|
-
- **主要更新**:
|
|
183
|
+
- **版本**: 7.4.1
|
|
184
|
+
- **主要更新**: Writing guideline 改为 post-write advisory — 写入后建议参考规范检查,per-turn 去重
|
package/dist/cli.js
CHANGED
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
-
var __defProp = Object.defineProperty;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
3
|
var __require = import.meta.require;
|
|
20
4
|
|
|
21
5
|
// src/cli.ts
|
|
@@ -27,7 +11,7 @@ import { fileURLToPath } from "url";
|
|
|
27
11
|
// package.json
|
|
28
12
|
var package_default = {
|
|
29
13
|
name: "memory-bank-skill",
|
|
30
|
-
version: "7.4.
|
|
14
|
+
version: "7.4.2",
|
|
31
15
|
description: "Memory Bank - \u9879\u76EE\u8BB0\u5FC6\u7CFB\u7EDF\uFF0C\u8BA9 AI \u52A9\u624B\u5728\u6BCF\u6B21\u5BF9\u8BDD\u4E2D\u90FD\u80FD\u5FEB\u901F\u7406\u89E3\u9879\u76EE\u4E0A\u4E0B\u6587",
|
|
32
16
|
type: "module",
|
|
33
17
|
main: "dist/plugin.js",
|
package/dist/plugin.js
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
2
|
var __require = import.meta.require;
|
|
19
3
|
|
|
20
4
|
// plugin/memory-bank.ts
|
|
21
5
|
import { stat, readFile, access, realpath } from "fs/promises";
|
|
6
|
+
import { realpathSync } from "fs";
|
|
22
7
|
import { execSync } from "child_process";
|
|
23
8
|
import path from "path";
|
|
24
9
|
var DEBUG = process.env.MEMORY_BANK_DEBUG === "1";
|
|
@@ -374,7 +359,7 @@ function getMessageGatingState(gatingKey, sessionId, projectRoot) {
|
|
|
374
359
|
meta.pendingDocFirstSatisfied = false;
|
|
375
360
|
}
|
|
376
361
|
}
|
|
377
|
-
state = { readFiles: new Set, contextSatisfied: false, warnedThisMessage: false, docFirstSatisfied: inheritDocFirst, docFirstWarned: false };
|
|
362
|
+
state = { readFiles: new Set, contextSatisfied: false, warnedThisMessage: false, docFirstSatisfied: inheritDocFirst, docFirstWarned: false, writingGuideInjected: false };
|
|
378
363
|
messageGatingStates.set(gatingKey, state);
|
|
379
364
|
if (messageGatingStates.size > 100) {
|
|
380
365
|
const first = messageGatingStates.keys().next().value;
|
|
@@ -398,12 +383,63 @@ var FALLBACK_ANCHORS = [
|
|
|
398
383
|
];
|
|
399
384
|
function canonicalizeRelPath(rawPath, projectRoot) {
|
|
400
385
|
const abs = path.isAbsolute(rawPath) ? rawPath : path.resolve(projectRoot, rawPath);
|
|
401
|
-
|
|
402
|
-
if (rel.startsWith(".."))
|
|
403
|
-
|
|
386
|
+
let rel = path.relative(projectRoot, abs);
|
|
387
|
+
if (rel.startsWith("..")) {
|
|
388
|
+
try {
|
|
389
|
+
const realAbs = realpathSync(abs);
|
|
390
|
+
const realRoot = realpathSync(projectRoot);
|
|
391
|
+
rel = path.relative(realRoot, realAbs);
|
|
392
|
+
if (rel.startsWith(".."))
|
|
393
|
+
return "";
|
|
394
|
+
} catch {
|
|
395
|
+
return "";
|
|
396
|
+
}
|
|
397
|
+
}
|
|
404
398
|
const posix = rel.replace(/\\/g, "/");
|
|
405
399
|
return process.platform === "darwin" || process.platform === "win32" ? posix.toLowerCase() : posix;
|
|
406
400
|
}
|
|
401
|
+
function stripQuotedContent(cmd) {
|
|
402
|
+
let result = "";
|
|
403
|
+
let inSingle = false;
|
|
404
|
+
let inDouble = false;
|
|
405
|
+
for (let i = 0;i < cmd.length; i++) {
|
|
406
|
+
const ch = cmd[i];
|
|
407
|
+
if (inSingle) {
|
|
408
|
+
if (ch === "'")
|
|
409
|
+
inSingle = false;
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (inDouble) {
|
|
413
|
+
if (ch === "\\" && i + 1 < cmd.length) {
|
|
414
|
+
i++;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (ch === '"')
|
|
418
|
+
inDouble = false;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (ch === "'") {
|
|
422
|
+
inSingle = true;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (ch === '"') {
|
|
426
|
+
inDouble = true;
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
result += ch;
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
var BASH_REDIRECT_PATTERNS = [
|
|
434
|
+
/(?<![0-9&])>(?![&>])\s*\S/,
|
|
435
|
+
/(?<![0-9&])>>\s*\S/,
|
|
436
|
+
/\|\s*tee\s/,
|
|
437
|
+
/\bsed\s+(-[^-]*)?-i/,
|
|
438
|
+
/\bperl\s+(-[^-]*)?-[pi]/
|
|
439
|
+
];
|
|
440
|
+
function hasBashRedirectOutsideQuotes(cmd) {
|
|
441
|
+
return BASH_REDIRECT_PATTERNS.some((p) => p.test(stripQuotedContent(cmd)));
|
|
442
|
+
}
|
|
407
443
|
function isAnchorPath(canonicalPath) {
|
|
408
444
|
return ANCHOR_PATH_PATTERNS.some((p) => p.test(canonicalPath));
|
|
409
445
|
}
|
|
@@ -1061,17 +1097,7 @@ ${triggers.join(`
|
|
|
1061
1097
|
if (anchorState.recovery?.required) {
|
|
1062
1098
|
const writeToolsForRecovery = ["write", "edit", "multiedit", "apply_patch", "patch"];
|
|
1063
1099
|
const isWriteTool = writeToolsForRecovery.includes(toolLowerForRecovery);
|
|
1064
|
-
const isBashWrite = toolLowerForRecovery === "bash" && (
|
|
1065
|
-
const cmd = output.args?.command || "";
|
|
1066
|
-
const bashWritePatterns = [
|
|
1067
|
-
/(?<![0-9&])>(?![&>])\s*\S/,
|
|
1068
|
-
/(?<![0-9&])>>\s*\S/,
|
|
1069
|
-
/\|\s*tee\s/,
|
|
1070
|
-
/\bsed\s+(-[^-]*)?-i/,
|
|
1071
|
-
/\bperl\s+(-[^-]*)?-[pi]/
|
|
1072
|
-
];
|
|
1073
|
-
return bashWritePatterns.some((p) => p.test(cmd));
|
|
1074
|
-
})();
|
|
1100
|
+
const isBashWrite = toolLowerForRecovery === "bash" && hasBashRedirectOutsideQuotes(output.args?.command || "");
|
|
1075
1101
|
if (isWriteTool || isBashWrite) {
|
|
1076
1102
|
const riskLevel = isWriteTool ? assessWriteRisk(toolLowerForRecovery, output.args || {}, projectRoot) : "medium";
|
|
1077
1103
|
if (riskLevel !== "low") {
|
|
@@ -1229,13 +1255,6 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1229
1255
|
}
|
|
1230
1256
|
if (toolLower2 === "bash" && !gatingState.contextSatisfied) {
|
|
1231
1257
|
const command = output.args?.command || "";
|
|
1232
|
-
const bashWritePatterns = [
|
|
1233
|
-
/(?<![0-9&])>(?![&>])\s*\S/,
|
|
1234
|
-
/(?<![0-9&])>>\s*\S/,
|
|
1235
|
-
/\|\s*tee\s/,
|
|
1236
|
-
/\bsed\s+(-[^-]*)?-i/,
|
|
1237
|
-
/\bperl\s+(-[^-]*)?-[pi]/
|
|
1238
|
-
];
|
|
1239
1258
|
const bashSensitivePatterns = [
|
|
1240
1259
|
/package\.json/i,
|
|
1241
1260
|
/\.env/i,
|
|
@@ -1247,7 +1266,7 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1247
1266
|
/\.github\/workflows/i,
|
|
1248
1267
|
/infra\//i
|
|
1249
1268
|
];
|
|
1250
|
-
const isLikelyWrite =
|
|
1269
|
+
const isLikelyWrite = hasBashRedirectOutsideQuotes(command);
|
|
1251
1270
|
const isSensitiveTarget = bashSensitivePatterns.some((p) => p.test(command));
|
|
1252
1271
|
if (isLikelyWrite) {
|
|
1253
1272
|
const riskLevel = isSensitiveTarget ? "high" : "medium";
|
|
@@ -1375,7 +1394,16 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1375
1394
|
}
|
|
1376
1395
|
}
|
|
1377
1396
|
}
|
|
1378
|
-
async function injectWritingGuideline(sid) {
|
|
1397
|
+
async function injectWritingGuideline(sid, writtenPaths) {
|
|
1398
|
+
const meta = getSessionMeta(sid, projectRoot);
|
|
1399
|
+
const messageKey = meta.lastUserMessageKey || "default";
|
|
1400
|
+
const gatingKey = `${sid}::${messageKey}`;
|
|
1401
|
+
const gatingState = getMessageGatingState(gatingKey, sid, projectRoot);
|
|
1402
|
+
if (gatingState.writingGuideInjected)
|
|
1403
|
+
return;
|
|
1404
|
+
gatingState.writingGuideInjected = true;
|
|
1405
|
+
const pathList = writtenPaths.map((p) => `- ${p}`).join(`
|
|
1406
|
+
`);
|
|
1379
1407
|
client.session.prompt({
|
|
1380
1408
|
path: { id: sid },
|
|
1381
1409
|
body: {
|
|
@@ -1385,8 +1413,13 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1385
1413
|
type: "text",
|
|
1386
1414
|
text: `## [Memory Bank Writing Guide]
|
|
1387
1415
|
|
|
1388
|
-
` + `\
|
|
1389
|
-
|
|
1416
|
+
` + `\u5DF2\u68C0\u6D4B\u5230 memory-bank/ \u5199\u5165\uFF1A
|
|
1417
|
+
${pathList}
|
|
1418
|
+
|
|
1419
|
+
` + `\u5EFA\u8BAE\u53C2\u8003\u5199\u5165\u89C4\u8303\u786E\u8BA4\u5185\u5BB9\u662F\u5426\u9700\u8981\u8C03\u6574\uFF1A
|
|
1420
|
+
` + `read({ filePath: "~/.config/opencode/skills/memory-bank/references/writer.md" })
|
|
1421
|
+
|
|
1422
|
+
` + `\u5982\u9700\u4FEE\u6B63\u8BF7\u76F4\u63A5\u4FEE\u6539\uFF0C\u7136\u540E\u7EE7\u7EED\u539F\u672C\u7684\u4EFB\u52A1\u3002`
|
|
1390
1423
|
}]
|
|
1391
1424
|
}
|
|
1392
1425
|
}).catch((err) => log.error("Failed to send writing guideline:", String(err)));
|
|
@@ -1439,6 +1472,7 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1439
1472
|
const targetPaths = extractPaths(toolLower, output.args || {});
|
|
1440
1473
|
if (targetPaths.length === 0)
|
|
1441
1474
|
return;
|
|
1475
|
+
const mbWrittenPaths = [];
|
|
1442
1476
|
for (const targetPath of targetPaths) {
|
|
1443
1477
|
if (!await isMemoryBankPath(targetPath))
|
|
1444
1478
|
continue;
|
|
@@ -1447,10 +1481,13 @@ Or call: proxy_task({ subagent_type: "memory-reader", ... })`);
|
|
|
1447
1481
|
throw new Error(`[Memory Bank Guard] memory-bank/ \u4E0B\u53EA\u5141\u8BB8\u5199\u5165 .md \u6587\u4EF6\u3002
|
|
1448
1482
|
` + `\u76EE\u6807\u6587\u4EF6: ${targetPath}`);
|
|
1449
1483
|
}
|
|
1450
|
-
|
|
1484
|
+
mbWrittenPaths.push(targetPath);
|
|
1451
1485
|
markDocFirstSatisfied(sessionID);
|
|
1452
1486
|
log.debug("Memory Bank write allowed", { sessionID, tool, targetPath });
|
|
1453
1487
|
}
|
|
1488
|
+
if (mbWrittenPaths.length > 0) {
|
|
1489
|
+
await injectWritingGuideline(sessionID, mbWrittenPaths);
|
|
1490
|
+
}
|
|
1454
1491
|
}
|
|
1455
1492
|
if (tool.toLowerCase() === "bash") {
|
|
1456
1493
|
const command = output.args?.command;
|
package/package.json
CHANGED
|
@@ -284,6 +284,33 @@ USER_BLOCK 将保持不变。
|
|
|
284
284
|
| Decision Highlights | 新增决策时追加(保持 10-20 条以内) |
|
|
285
285
|
| Routing Rules | 仅在 details/ 结构变化时更新 |
|
|
286
286
|
|
|
287
|
+
### MEMORY.md 膨胀控制
|
|
288
|
+
|
|
289
|
+
MEMORY.md 是单入口索引,必须保持精简。按行数控制膨胀:
|
|
290
|
+
|
|
291
|
+
| 行数 | 动作 |
|
|
292
|
+
|------|------|
|
|
293
|
+
| ≤ 120 行 | 正常维护 |
|
|
294
|
+
| 120 - 200 行 | 审查:Decision Highlights 超 15 条归档旧条目到 details/patterns.md,Quick Answers 超 8 条删过期项 |
|
|
295
|
+
| > 200 行 | 强制分区:膨胀区块提取到 details/,MEMORY.md 只留摘要 + 指针 |
|
|
296
|
+
|
|
297
|
+
**分区操作**(> 200 行时):
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
1. 识别膨胀区块(通常是 Decision Highlights 或 Routing Rules)
|
|
301
|
+
2. 提取到 details/:
|
|
302
|
+
- Decision Highlights 旧条目 → details/patterns.md
|
|
303
|
+
- Routing Rules 过多 → details/routing-extended.md
|
|
304
|
+
- Quick Answers 过多 → details/faq.md
|
|
305
|
+
3. MEMORY.md 保留:
|
|
306
|
+
- 最近 5-8 条 Decision Highlights
|
|
307
|
+
- 核心 Routing Rules(通用 + 高频项目特定)
|
|
308
|
+
- 3-5 条最高频 Quick Answers
|
|
309
|
+
4. 添加指针:「完整历史见 details/patterns.md」
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**原则**:MEMORY.md 是路由器不是数据库,超过一屏能扫完的量就该分区。
|
|
313
|
+
|
|
287
314
|
### 详情文件写入
|
|
288
315
|
|
|
289
316
|
```
|