memory-bank-skill 5.6.2 → 5.7.1

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/cli.js CHANGED
@@ -10,7 +10,7 @@ import { fileURLToPath } from "url";
10
10
  // package.json
11
11
  var package_default = {
12
12
  name: "memory-bank-skill",
13
- version: "5.6.2",
13
+ version: "5.7.1",
14
14
  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",
15
15
  type: "module",
16
16
  main: "dist/plugin.js",
package/dist/plugin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // plugin/memory-bank.ts
3
- import { stat, readFile } from "fs/promises";
3
+ import { stat, readFile, realpath } from "fs/promises";
4
4
  import { execSync } from "child_process";
5
5
  import path from "path";
6
6
  var DEBUG = process.env.MEMORY_BANK_DEBUG === "1";
@@ -753,12 +753,44 @@ ${triggers.join(`
753
753
  },
754
754
  "tool.execute.before": async (input, output) => {
755
755
  const { tool, sessionID } = input;
756
- const isMemoryBankPath = (targetPath) => {
756
+ const isCaseInsensitiveFS = process.platform === "darwin" || process.platform === "win32";
757
+ const normalize = (p) => isCaseInsensitiveFS ? p.toLowerCase() : p;
758
+ let realProjectRoot = null;
759
+ let realMemoryBankDir = null;
760
+ const getRealPaths = async () => {
761
+ if (realProjectRoot === null) {
762
+ try {
763
+ realProjectRoot = normalize(await realpath(projectRoot));
764
+ } catch {
765
+ realProjectRoot = normalize(projectRoot);
766
+ }
767
+ try {
768
+ realMemoryBankDir = normalize(await realpath(path.join(projectRoot, "memory-bank")));
769
+ } catch {
770
+ realMemoryBankDir = normalize(path.join(projectRoot, "memory-bank"));
771
+ }
772
+ }
773
+ return { realProjectRoot, realMemoryBankDir };
774
+ };
775
+ const isMemoryBankPath = async (targetPath) => {
776
+ const { realProjectRoot: rootReal, realMemoryBankDir: mbReal } = await getRealPaths();
757
777
  const absPath = path.isAbsolute(targetPath) ? targetPath : path.resolve(projectRoot, targetPath);
758
- const relativePath = path.relative(projectRoot, absPath);
759
- if (relativePath === ".." || relativePath.startsWith(".." + path.sep))
760
- return false;
761
- return relativePath === "memory-bank" || relativePath.startsWith("memory-bank" + path.sep) || relativePath.startsWith("memory-bank/");
778
+ const lexicalNorm = normalize(absPath);
779
+ const lexicalMBDir = normalize(path.join(projectRoot, "memory-bank"));
780
+ const lexicalMatch = lexicalNorm === lexicalMBDir || lexicalNorm.startsWith(lexicalMBDir + path.sep) || lexicalNorm.startsWith(lexicalMBDir + "/");
781
+ let physicalMatch = false;
782
+ try {
783
+ const resolved = normalize(await realpath(absPath));
784
+ physicalMatch = resolved === mbReal || resolved.startsWith(mbReal + path.sep) || resolved.startsWith(mbReal + "/");
785
+ } catch {
786
+ try {
787
+ const parentResolved = normalize(await realpath(path.dirname(absPath)));
788
+ const targetName = path.basename(absPath);
789
+ const fullResolved = path.join(parentResolved, targetName);
790
+ physicalMatch = fullResolved === mbReal || fullResolved.startsWith(mbReal + path.sep) || fullResolved.startsWith(mbReal + "/");
791
+ } catch {}
792
+ }
793
+ return lexicalMatch || physicalMatch;
762
794
  };
763
795
  const isWriterAllowed = (sid) => {
764
796
  if (writerSessionIDs.has(sid))
@@ -778,36 +810,79 @@ ${triggers.join(`
778
810
  ` + `\u8BF7\u4F7F\u7528 delegate_task \u8C03\u7528 memory-bank-writer agent \u6765\u66F4\u65B0 Memory Bank\u3002
779
811
  ` + `\u793A\u4F8B: delegate_task(subagent_type="memory-bank-writer", load_skills=["memory-bank-writer"], prompt="\u66F4\u65B0...")`);
780
812
  };
781
- if (tool === "Write" || tool === "Edit") {
782
- const targetPath = output.args?.filePath ?? output.args?.path ?? output.args?.filename;
783
- if (!targetPath)
784
- return;
785
- if (!isMemoryBankPath(targetPath))
786
- return;
787
- if (!targetPath.endsWith(".md")) {
788
- blockWrite("only .md files allowed", { targetPath });
813
+ const extractPaths = (toolName, args) => {
814
+ const paths = [];
815
+ const pathArgs = ["filePath", "path", "filename", "file", "dest", "destination", "target"];
816
+ for (const arg of pathArgs) {
817
+ const val = args[arg];
818
+ if (typeof val === "string" && val.trim())
819
+ paths.push(val);
789
820
  }
790
- if (isWriterAllowed(sessionID)) {
791
- log.debug("Writer agent write allowed", { sessionID, tool, targetPath });
821
+ if (toolName === "multiedit" && Array.isArray(args.edits)) {
822
+ for (const edit of args.edits) {
823
+ if (typeof edit === "object" && edit !== null) {
824
+ const e = edit;
825
+ if (typeof e.path === "string")
826
+ paths.push(e.path);
827
+ if (typeof e.filePath === "string")
828
+ paths.push(e.filePath);
829
+ }
830
+ }
831
+ }
832
+ if (toolName === "apply_patch" || toolName === "patch") {
833
+ const patchText = args.patchText ?? args.patch ?? args.diff;
834
+ if (typeof patchText === "string") {
835
+ const gitDiffPattern = /^(?:\+\+\+|---)\s+[ab]\/(.+)$/gm;
836
+ let match;
837
+ while ((match = gitDiffPattern.exec(patchText)) !== null) {
838
+ if (match[1])
839
+ paths.push(match[1]);
840
+ }
841
+ const openCodePattern = /^\*\*\*\s+(?:Add|Update|Delete|Move to)\s+(?:File:\s*)?(.+)$/gm;
842
+ while ((match = openCodePattern.exec(patchText)) !== null) {
843
+ if (match[1])
844
+ paths.push(match[1].trim());
845
+ }
846
+ }
847
+ }
848
+ return [...new Set(paths)];
849
+ };
850
+ const fileWriteTools = ["write", "edit", "multiedit", "apply_patch", "patch"];
851
+ const toolLower = tool.toLowerCase();
852
+ if (fileWriteTools.includes(toolLower)) {
853
+ const targetPaths = extractPaths(toolLower, output.args || {});
854
+ if (targetPaths.length === 0)
792
855
  return;
856
+ for (const targetPath of targetPaths) {
857
+ if (!await isMemoryBankPath(targetPath))
858
+ continue;
859
+ if (!targetPath.toLowerCase().endsWith(".md")) {
860
+ blockWrite("only .md files allowed", { targetPath });
861
+ }
862
+ if (isWriterAllowed(sessionID)) {
863
+ log.debug("Writer agent write allowed", { sessionID, tool, targetPath });
864
+ return;
865
+ }
866
+ blockWrite("not writer agent", {
867
+ targetPath,
868
+ isSubAgent: !!sessionsById.get(sessionID)?.parentID,
869
+ agentName: agentBySessionID.get(sessionID)
870
+ });
793
871
  }
794
- blockWrite("not writer agent", {
795
- targetPath,
796
- isSubAgent: !!sessionsById.get(sessionID)?.parentID,
797
- agentName: agentBySessionID.get(sessionID)
798
- });
799
872
  }
800
873
  if (tool.toLowerCase() === "bash") {
801
874
  const command = output.args?.command;
802
875
  if (!command || typeof command !== "string")
803
876
  return;
804
- if (!/(?:^|[^A-Za-z0-9_-])memory-bank(?:$|[^A-Za-z0-9_-])/.test(command) && !command.startsWith("memory-bank"))
877
+ const cmdToCheck = isCaseInsensitiveFS ? command.toLowerCase() : command;
878
+ const mbPattern = isCaseInsensitiveFS ? /(?:^|[^a-z0-9_.-])memory-bank(?:[\/\\]|$|\s|['"])/ : /(?:^|[^A-Za-z0-9_.-])memory-bank(?:[\/\\]|$|\s|['"])/;
879
+ if (!mbPattern.test(cmdToCheck))
805
880
  return;
806
881
  const hasShellOperators = /[;&|]|\$\(|`/.test(command);
807
882
  if (!hasShellOperators) {
808
883
  const readOnlyPatterns = [
809
- /^\s*(ls|cat|head|tail|less|more|grep|rg|ag|find|tree|wc|file|stat)\b/,
810
- /^\s*git\s+(status|log|diff|show|blame)\b/
884
+ /^\s*(ls|cat|head|tail|less|more|grep|rg|ag|find|tree|wc|file|stat)\b/i,
885
+ /^\s*git\s+(status|log|diff|show|blame)\b/i
811
886
  ];
812
887
  if (readOnlyPatterns.some((p) => p.test(command)))
813
888
  return;
@@ -817,16 +892,16 @@ ${triggers.join(`
817
892
  />>/,
818
893
  /<</,
819
894
  /\|/,
820
- /\btee\b/,
821
- /\bsed\s+-i/,
822
- /\bperl\s+-[ip]/,
823
- /\bcp\b/,
824
- /\bmv\b/,
825
- /\brm\b/,
826
- /\bmkdir\b/,
827
- /\btouch\b/,
828
- /\bgit\s+(add|rm|mv|apply|checkout|restore|reset|clean|stash|commit)\b/,
829
- /\bpython\b.*\bopen\b/
895
+ /\btee\b/i,
896
+ /\bsed\s+-i/i,
897
+ /\bperl\s+-[ip]/i,
898
+ /\bcp\b/i,
899
+ /\bmv\b/i,
900
+ /\brm\b/i,
901
+ /\bmkdir\b/i,
902
+ /\btouch\b/i,
903
+ /\bgit\s+(add|rm|mv|apply|checkout|restore|reset|clean|stash|commit)\b/i,
904
+ /\bpython\b.*\bopen\b/i
830
905
  ];
831
906
  const isWriteOperation = writePatterns.some((p) => p.test(command));
832
907
  if (!isWriteOperation)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-bank-skill",
3
- "version": "5.6.2",
3
+ "version": "5.7.1",
4
4
  "description": "Memory Bank - 项目记忆系统,让 AI 助手在每次对话中都能快速理解项目上下文",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",