@kenhkl/agent-moss 0.7.4 → 0.7.6

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
@@ -747,16 +747,17 @@ import { fileURLToPath as fileURLToPath2 } from "url";
747
747
  function loadAllSkills() {
748
748
  if (cachedSkills) return cachedSkills;
749
749
  cachedSkills = {};
750
- if (!existsSync2(SKILLS_DIR)) {
751
- console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR);
750
+ const dir = existsSync2(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
751
+ if (!existsSync2(dir)) {
752
+ console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
752
753
  return cachedSkills;
753
754
  }
754
- const files = readdirSync(SKILLS_DIR).filter((f) => f.endsWith(".md"));
755
+ const files = readdirSync(dir).filter((f) => f.endsWith(".md"));
755
756
  for (const f of files) {
756
757
  const name = f.replace(".md", "");
757
- cachedSkills[name] = readFileSync(resolve(SKILLS_DIR, f), "utf-8");
758
+ cachedSkills[name] = readFileSync(resolve(dir, f), "utf-8");
758
759
  }
759
- console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills`);
760
+ console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
760
761
  return cachedSkills;
761
762
  }
762
763
  function matchSkills(actionType, actionDetail, reason, maxSkills = 3) {
@@ -808,14 +809,15 @@ function formatSkillsForPrompt(skills) {
808
809
  ${s.skillContent}`
809
810
  ).join("\n\n---\n\n");
810
811
  }
811
- var __filename2, __dirname2, SKILLS_DIR, SKILL_KEYWORD_MAP, cachedSkills;
812
+ var __filename2, __dirname2, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
812
813
  var init_skill_loader = __esm({
813
814
  "src/engine/skill-loader.ts"() {
814
815
  "use strict";
815
816
  init_esm_shims();
816
817
  __filename2 = fileURLToPath2(import.meta.url);
817
818
  __dirname2 = dirname(__filename2);
818
- SKILLS_DIR = resolve(__dirname2, "../../agent_moss/skills");
819
+ SKILLS_DIR = resolve(__dirname2, "../skills");
820
+ SKILLS_DIR_FALLBACK = resolve(__dirname2, "../../agent_moss/skills");
819
821
  SKILL_KEYWORD_MAP = {
820
822
  "file_access_guard": ["file", "\u6587\u4EF6", "path", "\u8DEF\u5F84", "read", "write", "cat", "open", "access", "\u8BBF\u95EE", "\u8BFB\u5199", "copy", "cp", "mv", "move"],
821
823
  "script_execution_guard": ["command", "shell", "bash", "exec", "execute", "\u6267\u884C", "\u547D\u4EE4", "script", "\u811A\u672C", "run", "\u8FD0\u884C", "subprocess", "system", "eval", "compile", "\u5B89\u88C5", "install", "pip", "npm"],
@@ -825,7 +827,9 @@ var init_skill_loader = __esm({
825
827
  "general_tool_risk_guard": ["tool", "\u5DE5\u5177", "api", "invoke", "\u8C03\u7528", "function", "\u51FD\u6570"],
826
828
  "lateral_movement_guard": ["ssh", "scp", "ftp", "sftp", "rdp", "vnc", "telnet", "\u5185\u7F51", "\u6A2A\u5411", "tunnel", "\u4EE3\u7406", "proxy", "port", "\u7AEF\u53E3", "scan", "\u626B\u63CF", "ping", "traceroute", "nslookup"],
827
829
  "persistence_backdoor_guard": ["cron", "crontab", "\u5B9A\u65F6", "scheduled", "startup", "\u542F\u52A8\u9879", "service", "\u670D\u52A1", "daemon", "\u5B88\u62A4", "registry", "\u6CE8\u518C\u8868", "backdoor", "\u540E\u95E8", "persist", "\u6301\u4E45\u5316", "authorized_keys", "bashrc", "zshrc", "profile", ".rc", "shell config", "shell \u914D\u7F6E"],
828
- "resource_exhaustion_guard": ["fork", "bomb", "\u70B8\u5F39", "memory", "\u5185\u5B58", "disk", "\u78C1\u76D8", "cpu", "process", "\u8FDB\u7A0B", "dd", "while true", "\u65E0\u9650\u5FAA\u73AF", "\u8017\u5C3D", "exhaust", "\u8D44\u6E90"],
830
+ // 注意:避免裸 'memory'/'内存'/'dd'——会误命中 memory-addMemory(写记忆工具,
831
+ // 'dd' 是 'addMemory' 的子串)等无害操作。用组合词/命令前缀精准匹配攻击场景。
832
+ "resource_exhaustion_guard": ["fork", "bomb", "\u70B8\u5F39", "memory bomb", "oom", "out of memory", "\u5185\u5B58\u6EA2\u51FA", "\u5185\u5B58\u8017\u5C3D", "\u5185\u5B58\u6CC4\u6F0F", "disk", "\u78C1\u76D8", "cpu", "process", "\u8FDB\u7A0B", "dd if=", "/dev/zero", "/dev/null", "yes >", "while true", "\u65E0\u9650\u5FAA\u73AF", "\u8017\u5C3D", "exhaust", "\u8D44\u6E90"],
829
833
  "skill_installation_guard": ["skill", "plugin", "\u63D2\u4EF6", "extension", "\u6269\u5C55", "install skill", "\u5B89\u88C5\u63D2\u4EF6", "\u5B89\u88C5\u6280\u80FD", "marketplace", "\u5546\u5E97"],
830
834
  "supply_chain_guard": ["dependency", "\u4F9D\u8D56", "package", "\u5305", "npm install", "pip install", "requirements", "import", "library", "\u5E93", "registry", "\u4ED3\u5E93", "supply", "\u4F9B\u5E94\u94FE", "typosquatting"],
831
835
  "intent_deviation_guard": ["rm", "del", "delete", "remove", "\u5220\u9664", "format", "\u683C\u5F0F\u5316", "drop", "truncate", "\u6E05\u7A7A", "wipe", "\u64E6\u9664", "\u91CD\u7F6E", "reset", "sudo", "root", "admin", "\u7BA1\u7406\u5458", "privilege", "\u63D0\u6743"]
@@ -841,28 +845,30 @@ import { fileURLToPath as fileURLToPath3 } from "url";
841
845
  function loadTemplates() {
842
846
  if (cachedTemplates) return cachedTemplates;
843
847
  cachedTemplates = {};
844
- if (!existsSync3(TEMPLATES_DIR)) {
845
- console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR);
848
+ const dir = existsSync3(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
849
+ if (!existsSync3(dir)) {
850
+ console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
846
851
  return cachedTemplates;
847
852
  }
848
853
  for (const file of TEMPLATE_FILES) {
849
- const filePath = resolve2(TEMPLATES_DIR, file);
854
+ const filePath = resolve2(dir, file);
850
855
  if (existsSync3(filePath)) {
851
856
  const key = file.replace(".txt", "").replace("_template", "");
852
857
  cachedTemplates[key] = readFileSync2(filePath, "utf-8");
853
858
  }
854
859
  }
855
- console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates`);
860
+ console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
856
861
  return cachedTemplates;
857
862
  }
858
- var __filename3, __dirname3, TEMPLATES_DIR, TEMPLATE_FILES, cachedTemplates;
863
+ var __filename3, __dirname3, TEMPLATES_DIR, TEMPLATES_DIR_FALLBACK, TEMPLATE_FILES, cachedTemplates;
859
864
  var init_template_loader = __esm({
860
865
  "src/engine/template-loader.ts"() {
861
866
  "use strict";
862
867
  init_esm_shims();
863
868
  __filename3 = fileURLToPath3(import.meta.url);
864
869
  __dirname3 = dirname2(__filename3);
865
- TEMPLATES_DIR = resolve2(__dirname3, "../../agent_moss/templates");
870
+ TEMPLATES_DIR = resolve2(__dirname3, "../templates");
871
+ TEMPLATES_DIR_FALLBACK = resolve2(__dirname3, "../../agent_moss/templates");
866
872
  TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
867
873
  cachedTemplates = null;
868
874
  }
@@ -1100,13 +1106,14 @@ async function runLLMAnalysis(input, previous) {
1100
1106
  function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis) {
1101
1107
  const skillsText = formatSkillsForPrompt(matchedSkills);
1102
1108
  const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
1103
- const templateName = previous.heuristic || previous.logic ? "prompt2" : "prompt1";
1104
- const baseTemplate = templates[templateName] || templates["prompt1"] || "";
1105
1109
  const scriptAnalysisText = scriptAnalysis ? formatScriptAnalysisForPrompt(scriptAnalysis) : "";
1106
1110
  const hintsText = formatHints(previous);
1107
- return `${baseTemplate}
1108
-
1109
- ## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
1111
+ const securityJudgeTemplate = templates["security_judge"];
1112
+ if (securityJudgeTemplate) {
1113
+ return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{action_history}", historyStr).replaceAll("{action_type}", input.aNext.actionType).replaceAll("{action_detail}", input.aNext.actionDetail).replaceAll("{reason}", input.reason || "\u672A\u8BF4\u660E").replaceAll("{skills_text}", skillsText).replaceAll("{hints_text}", hintsText).replaceAll("{script_analysis_text}", scriptAnalysisText).replaceAll("{{", "{").replaceAll("}}", "}");
1114
+ }
1115
+ console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
1116
+ return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
1110
1117
  - \u4F1A\u8BDD ID: ${input.sessionId}
1111
1118
  - \u7528\u6237\u4EFB\u52A1: ${input.promptSession || "\u672A\u6307\u5B9A"}
1112
1119
  - \u64CD\u4F5C\u7CFB\u7EDF: ${input.osType}
@@ -1128,8 +1135,7 @@ ${scriptAnalysisText ? `
1128
1135
  ## \u811A\u672C\u5185\u5BB9\u5206\u6790
1129
1136
  ${scriptAnalysisText}` : ""}
1130
1137
 
1131
- \u8BF7\u6839\u636E\u4EE5\u4E0A\u4FE1\u606F\uFF0C\u5BF9\u5373\u5C06\u6267\u884C\u7684\u64CD\u4F5C\u8FDB\u884C\u5B89\u5168\u5224\u65AD\u3002\u4F60\u5FC5\u987B\u8F93\u51FA\u4E25\u683C\u7684 JSON \u683C\u5F0F\uFF0C
1132
- \u4E0D\u8981\u5305\u542B\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3001\u6CE8\u91CA\u6216 markdown \u6807\u8BB0\u3002
1138
+ \u8BF7\u6839\u636E\u4EE5\u4E0A\u4FE1\u606F\uFF0C\u5BF9\u5373\u5C06\u6267\u884C\u7684\u64CD\u4F5C\u8FDB\u884C\u5B89\u5168\u5224\u65AD\u3002\u524D\u7F6E\u68C0\u6D4B\u4E3A low/medium \u4E14\u6709\u5408\u7406\u6267\u884C\u7406\u7531\u65F6\u5E94\u5F53\u5141\u8BB8\u3002\u4F60\u5FC5\u987B\u8F93\u51FA\u4E25\u683C\u7684 JSON \u683C\u5F0F\uFF0C\u4E0D\u8981\u5305\u542B\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3001\u6CE8\u91CA\u6216 markdown \u6807\u8BB0\u3002
1133
1139
 
1134
1140
  \u8F93\u51FA\u683C\u5F0F:
1135
1141
  {"allowed": true/false, "reason": "\u5224\u65AD\u7406\u7531", "riskLevel": "low|medium|high|critical", "riskType": "\u98CE\u9669\u7C7B\u578B", "confidence": 0-100}`;
@@ -1176,7 +1182,9 @@ async function analyzeWithLLM(prompt, config) {
1176
1182
  temperature: config.temperature || 0.1,
1177
1183
  max_tokens: config.maxTokens || 1024,
1178
1184
  messages: [
1179
- { role: "system", content: "\u4F60\u662F\u4E00\u4E2A AI Agent \u5B89\u5168\u5BA1\u8BA1\u4E13\u5BB6\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u5206\u6790\u5373\u5C06\u6267\u884C\u7684\u547D\u4EE4\u662F\u5426\u5B89\u5168\u3002\u4F60\u5FC5\u987B\u53EA\u8F93\u51FA\u7EAF JSON\uFF0C\u4E0D\u8981\u5305\u542B\u4EFB\u4F55 markdown \u6807\u8BB0\u3001\u4EE3\u7801\u5757\u6216\u5176\u4ED6\u6587\u5B57\u3002" },
1185
+ // security_judge 模板自带角色定义与判断规则,system 仅做输出格式约束,
1186
+ // 避免与模板里的"你是 xiaoO Audit Agent 安全审计员"角色定义冲突(对齐 Python:无独立 system)。
1187
+ { role: "system", content: "\u53EA\u8F93\u51FA\u7EAF JSON\uFF0C\u4E0D\u8981\u5305\u542B markdown \u6807\u8BB0\u3001\u4EE3\u7801\u5757\u6216\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002" },
1180
1188
  { role: "user", content: prompt }
1181
1189
  ]
1182
1190
  });
@@ -1322,8 +1330,9 @@ async function runAnalysis(input) {
1322
1330
  }
1323
1331
  const logicResult = isLogicRulesEnabled() ? runLogicCheck(input) : null;
1324
1332
  if (logicResult && !logicResult.allowed) {
1333
+ const isCredentialPath = logicResult.riskType === "sensitive_path_access" && (logicResult.riskLevel === "high" || logicResult.riskLevel === "critical");
1325
1334
  const skipInlineFileAccess = isInlineScriptCmd && logicResult.riskType === "sensitive_path_access";
1326
- if (!skipInlineFileAccess) {
1335
+ if (!skipInlineFileAccess || isCredentialPath) {
1327
1336
  return logicResult;
1328
1337
  }
1329
1338
  }