@kenhkl/agent-moss 0.11.4 → 0.12.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/cli.js +231 -364
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +196 -329
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/l1_rules.json +821 -0
- package/dist/rules/l2_rules.json +82 -0
- package/dist/rules/l3_rules.json +245 -0
- package/dist/server.js +217 -350
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -564,8 +564,70 @@ var init_inline_analyzer = __esm({
|
|
|
564
564
|
}
|
|
565
565
|
});
|
|
566
566
|
|
|
567
|
+
// src/infra/rules-loader.ts
|
|
568
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
569
|
+
import { resolve, dirname } from "path";
|
|
570
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
571
|
+
function findRulesFile(name) {
|
|
572
|
+
for (const dir of RULES_DIR_CANDS) {
|
|
573
|
+
const p = resolve(dir, name);
|
|
574
|
+
if (existsSync(p)) return p;
|
|
575
|
+
}
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
function loadJson(name) {
|
|
579
|
+
const p = findRulesFile(name);
|
|
580
|
+
if (!p) return {};
|
|
581
|
+
try {
|
|
582
|
+
return JSON.parse(readFileSync2(p, "utf-8")) || {};
|
|
583
|
+
} catch {
|
|
584
|
+
return {};
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function loadL1() {
|
|
588
|
+
return loadJson("l1_rules.json");
|
|
589
|
+
}
|
|
590
|
+
function loadL2() {
|
|
591
|
+
return loadJson("l2_rules.json");
|
|
592
|
+
}
|
|
593
|
+
function loadL3() {
|
|
594
|
+
return loadJson("l3_rules.json");
|
|
595
|
+
}
|
|
596
|
+
var __filename2, __dirname2, RULES_DIR_CANDS;
|
|
597
|
+
var init_rules_loader = __esm({
|
|
598
|
+
"src/infra/rules-loader.ts"() {
|
|
599
|
+
"use strict";
|
|
600
|
+
init_esm_shims();
|
|
601
|
+
__filename2 = fileURLToPath3(import.meta.url);
|
|
602
|
+
__dirname2 = dirname(__filename2);
|
|
603
|
+
RULES_DIR_CANDS = (() => {
|
|
604
|
+
const cands = [
|
|
605
|
+
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
606
|
+
resolve(__dirname2, "../rules"),
|
|
607
|
+
resolve(__dirname2, "rules"),
|
|
608
|
+
// dev src: __dirname=ts/src/infra/ → ts/src/infra/../../../agent_moss/rules = 仓库根 agent_moss/rules
|
|
609
|
+
resolve(__dirname2, "../../../agent_moss/rules"),
|
|
610
|
+
// dist 但 __dirname 指向 dist/engine 再往上两级的仓库根 agent_moss/rules
|
|
611
|
+
resolve(__dirname2, "../../../../agent_moss/rules"),
|
|
612
|
+
// 相对当前工作目录的仓库根(兜底,兼容以仓库根为 cwd 运行)
|
|
613
|
+
resolve(process.cwd(), "agent_moss/rules")
|
|
614
|
+
];
|
|
615
|
+
return cands.filter((c) => existsSync(c));
|
|
616
|
+
})();
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
|
|
567
620
|
// src/engine/logic-rules.ts
|
|
568
621
|
import * as fs2 from "fs";
|
|
622
|
+
function _loadSensitivePathScope(scope) {
|
|
623
|
+
const sps = loadL1().sensitive_path_access || [];
|
|
624
|
+
return sps.filter((sp) => sp.scope === scope).map((sp) => ({
|
|
625
|
+
path: sp.path,
|
|
626
|
+
riskLevel: sp.risk_level,
|
|
627
|
+
desc: sp.desc,
|
|
628
|
+
credential: sp.deny_mode === "deny_both" ? true : void 0
|
|
629
|
+
}));
|
|
630
|
+
}
|
|
569
631
|
function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
|
|
570
632
|
if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
|
|
571
633
|
if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
|
|
@@ -927,57 +989,10 @@ var init_logic_rules = __esm({
|
|
|
927
989
|
"use strict";
|
|
928
990
|
init_esm_shims();
|
|
929
991
|
init_inline_analyzer();
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
{ path: "/etc/passwd", riskLevel: "high", desc: "\u7CFB\u7EDF\u7528\u6237\u6587\u4EF6" },
|
|
935
|
-
{ path: "/etc/sudoers", riskLevel: "critical", desc: "sudo \u914D\u7F6E", credential: true },
|
|
936
|
-
// 系统配置(仅拦截写入)
|
|
937
|
-
{ path: "/etc/hosts", riskLevel: "medium", desc: "DNS \u89E3\u6790\u914D\u7F6E" },
|
|
938
|
-
{ path: "/etc/crontab", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1" },
|
|
939
|
-
{ path: "/etc/cron.d/", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55\uFF08\u62C6\u5206\u5F0F crontab\uFF09" },
|
|
940
|
-
{ path: "/var/spool/cron/", riskLevel: "high", desc: "\u7528\u6237\u7EA7\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55" },
|
|
941
|
-
{ path: "/etc/systemd/", riskLevel: "high", desc: "systemd \u670D\u52A1\u914D\u7F6E" },
|
|
942
|
-
{ path: "/etc/ssh/sshd_config", riskLevel: "high", desc: "SSH \u670D\u52A1\u914D\u7F6E" },
|
|
943
|
-
{ path: "/etc/pam.d/", riskLevel: "high", desc: "PAM \u53EF\u63D2\u62D4\u8BA4\u8BC1\u6A21\u5757\u914D\u7F6E" },
|
|
944
|
-
// 危险目录(仅拦截写入)
|
|
945
|
-
{ path: "/boot/", riskLevel: "critical", desc: "\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55" },
|
|
946
|
-
{ path: "/proc/sys/", riskLevel: "high", desc: "\u5185\u6838\u53C2\u6570" },
|
|
947
|
-
{ path: "/sys/", riskLevel: "high", desc: "sysfs \u5185\u6838\u63A5\u53E3" },
|
|
948
|
-
// 设备文件(/dev/null、/dev/zero、/dev/urandom 已移除,误报率极高)
|
|
949
|
-
{ path: "/dev/random", riskLevel: "high", desc: "\u963B\u585E\u5F0F\u968F\u673A\u6570\u8BBE\u5907\uFF08\u8BFB\u53D6\u8017\u5C3D\u71B5\u6C60\uFF09" },
|
|
950
|
-
{ path: "/dev/mem", riskLevel: "critical", desc: "\u7269\u7406\u5185\u5B58\u8BBF\u95EE\u8BBE\u5907\uFF08\u8BFB\u5199\u5747\u5371\u9669\uFF09", credential: true },
|
|
951
|
-
{ path: "/dev/kmsg", riskLevel: "high", desc: "\u5185\u6838\u6D88\u606F\u7F13\u51B2\u533A" },
|
|
952
|
-
// SSH 主机私钥
|
|
953
|
-
// SSH 主机私钥(排除 .pub 公钥变体,对齐 Python .ssh/id_rsa(?!\.pub) 范式)
|
|
954
|
-
{ path: "/etc/ssh/ssh_host_rsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A RSA \u79C1\u94A5", credential: true },
|
|
955
|
-
{ path: "/etc/ssh/ssh_host_ed25519_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A Ed25519 \u79C1\u94A5", credential: true },
|
|
956
|
-
{ path: "/etc/ssh/ssh_host_ecdsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A ECDSA \u79C1\u94A5", credential: true },
|
|
957
|
-
// Nginx 配置(仅拦截写入,对齐 Python linux.py sensitive_paths)
|
|
958
|
-
{ path: "/etc/nginx/nginx.conf", riskLevel: "high", desc: "Nginx \u4E3B\u914D\u7F6E" },
|
|
959
|
-
{ path: "/etc/nginx/conf.d/", riskLevel: "high", desc: "Nginx \u5B50\u914D\u7F6E\u76EE\u5F55" },
|
|
960
|
-
{ path: "/etc/nginx/sites-enabled/", riskLevel: "high", desc: "Nginx \u542F\u7528\u7AD9\u70B9\u914D\u7F6E\u76EE\u5F55" }
|
|
961
|
-
];
|
|
962
|
-
HOME_SENSITIVE_PATHS = [
|
|
963
|
-
{ path: ".ssh/id_rsa", riskLevel: "critical", desc: "SSH \u79C1\u94A5", credential: true },
|
|
964
|
-
{ path: ".ssh/id_ed25519", riskLevel: "critical", desc: "SSH \u79C1\u94A5 (ed25519)", credential: true },
|
|
965
|
-
{ path: ".ssh/authorized_keys", riskLevel: "high", desc: "SSH \u6388\u6743\u5BC6\u94A5" },
|
|
966
|
-
// 持久化与命令劫持(仅拦截写入)
|
|
967
|
-
{ path: ".bashrc", riskLevel: "high", desc: "\u7528\u6237 Shell \u521D\u59CB\u5316\u811A\u672C" },
|
|
968
|
-
{ path: ".bash_profile", riskLevel: "high", desc: "\u7528\u6237 Shell \u767B\u5F55\u811A\u672C" },
|
|
969
|
-
{ path: ".profile", riskLevel: "high", desc: "\u7528\u6237\u901A\u7528\u767B\u5F55\u811A\u672C" },
|
|
970
|
-
{ path: ".aws/credentials", riskLevel: "critical", desc: "AWS \u51ED\u8BC1", credential: true },
|
|
971
|
-
{ path: ".gitconfig", riskLevel: "medium", desc: "Git \u914D\u7F6E" },
|
|
972
|
-
{ path: ".gnupg", riskLevel: "high", desc: "GPG \u5BC6\u94A5\u76EE\u5F55" }
|
|
973
|
-
];
|
|
974
|
-
CREDENTIAL_PATHS = [
|
|
975
|
-
{ path: "credentials.yml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
976
|
-
{ path: "credentials.yaml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
977
|
-
{ path: "secrets.yml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
978
|
-
{ path: "secrets.yaml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
979
|
-
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
980
|
-
];
|
|
992
|
+
init_rules_loader();
|
|
993
|
+
ROOT_SENSITIVE_PATHS = _loadSensitivePathScope("root");
|
|
994
|
+
HOME_SENSITIVE_PATHS = _loadSensitivePathScope("home");
|
|
995
|
+
CREDENTIAL_PATHS = _loadSensitivePathScope("credential").map(({ path: path3, riskLevel, desc }) => ({ path: path3, riskLevel, desc, credential: true }));
|
|
981
996
|
NON_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
982
997
|
"ask_user_question",
|
|
983
998
|
"glob",
|
|
@@ -1105,34 +1120,22 @@ var init_logic_rules = __esm({
|
|
|
1105
1120
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
1106
1121
|
READ_KEYWORDS = ["read", "\u8BFB\u53D6", "cat", "head", "tail", "less", "more", "view", "\u67E5\u770B", "open", "\u6253\u5F00", "load", "\u52A0\u8F7D", "grep", "search", "\u641C\u7D22", "find", "\u67E5\u627E"];
|
|
1107
1122
|
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
1108
|
-
PASSWORD_MODIFY_PATTERNS =
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
INTENT_DEVIATION_PATTERNS = [
|
|
1125
|
-
{
|
|
1126
|
-
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
1127
|
-
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
|
|
1128
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
1129
|
-
},
|
|
1130
|
-
{
|
|
1131
|
-
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
1132
|
-
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
1133
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
1134
|
-
}
|
|
1135
|
-
];
|
|
1123
|
+
PASSWORD_MODIFY_PATTERNS = (() => {
|
|
1124
|
+
const pats = loadL2().password_modify_consent || [];
|
|
1125
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1126
|
+
})();
|
|
1127
|
+
USER_DELETION_PATTERNS = (() => {
|
|
1128
|
+
const pats = loadL2().user_deletion_consent || [];
|
|
1129
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1130
|
+
})();
|
|
1131
|
+
INTENT_DEVIATION_PATTERNS = (() => {
|
|
1132
|
+
const pats = loadL2().intent_consistency || [];
|
|
1133
|
+
return pats.map((p) => ({
|
|
1134
|
+
intentKeywords: p.intent_keywords,
|
|
1135
|
+
dangerousActions: p.dangerous_actions,
|
|
1136
|
+
reason: p.reason
|
|
1137
|
+
}));
|
|
1138
|
+
})();
|
|
1136
1139
|
INLINE_SCRIPT_RE = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
1137
1140
|
DIR_TRAVERSAL_KW = [
|
|
1138
1141
|
"os.listdir",
|
|
@@ -1150,21 +1153,21 @@ var init_logic_rules = __esm({
|
|
|
1150
1153
|
});
|
|
1151
1154
|
|
|
1152
1155
|
// src/engine/skill-loader.ts
|
|
1153
|
-
import { readFileSync as
|
|
1154
|
-
import { resolve, dirname } from "path";
|
|
1155
|
-
import { fileURLToPath as
|
|
1156
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
|
|
1157
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
1158
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1156
1159
|
function loadAllSkills() {
|
|
1157
1160
|
if (cachedSkills) return cachedSkills;
|
|
1158
1161
|
cachedSkills = {};
|
|
1159
|
-
const dir =
|
|
1160
|
-
if (!
|
|
1162
|
+
const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
|
|
1163
|
+
if (!existsSync3(dir)) {
|
|
1161
1164
|
console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
|
|
1162
1165
|
return cachedSkills;
|
|
1163
1166
|
}
|
|
1164
1167
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
|
|
1165
1168
|
for (const f of files) {
|
|
1166
1169
|
const name = f.replace(".md", "");
|
|
1167
|
-
cachedSkills[name] =
|
|
1170
|
+
cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
|
|
1168
1171
|
}
|
|
1169
1172
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1170
1173
|
return cachedSkills;
|
|
@@ -1218,32 +1221,27 @@ function formatSkillsForPrompt(skills) {
|
|
|
1218
1221
|
${s.skillContent}`
|
|
1219
1222
|
).join("\n\n---\n\n");
|
|
1220
1223
|
}
|
|
1221
|
-
var
|
|
1224
|
+
var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
|
|
1222
1225
|
var init_skill_loader = __esm({
|
|
1223
1226
|
"src/engine/skill-loader.ts"() {
|
|
1224
1227
|
"use strict";
|
|
1225
1228
|
init_esm_shims();
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
"skill_installation_guard": ["skill", "plugin", "\u63D2\u4EF6", "extension", "\u6269\u5C55", "install skill", "\u5B89\u88C5\u63D2\u4EF6", "\u5B89\u88C5\u6280\u80FD", "marketplace", "\u5546\u5E97"],
|
|
1243
|
-
"supply_chain_guard": ["dependency", "\u4F9D\u8D56", "package", "\u5305", "npm install", "pip install", "requirements", "import", "library", "\u5E93", "registry", "\u4ED3\u5E93", "supply", "\u4F9B\u5E94\u94FE", "typosquatting"],
|
|
1244
|
-
"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"],
|
|
1245
|
-
"indirect_access_guard": ["listdir", "os.walk", "os.scandir", "glob.glob", "glob.iglob", "pathlib", "iterdir", "rglob", "scandir", "os.listdir", "\u76EE\u5F55\u904D\u5386", "traversal"]
|
|
1246
|
-
};
|
|
1229
|
+
init_rules_loader();
|
|
1230
|
+
__filename3 = fileURLToPath4(import.meta.url);
|
|
1231
|
+
__dirname3 = dirname2(__filename3);
|
|
1232
|
+
SKILLS_DIR = resolve2(__dirname3, "../skills");
|
|
1233
|
+
SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
|
|
1234
|
+
SKILL_KEYWORD_MAP = (() => {
|
|
1235
|
+
const map = {};
|
|
1236
|
+
const cats = loadL3();
|
|
1237
|
+
for (const cat of Object.values(cats)) {
|
|
1238
|
+
if (!cat || typeof cat !== "object") continue;
|
|
1239
|
+
for (const [skillId, keywords] of Object.entries(cat)) {
|
|
1240
|
+
map[skillId] = keywords;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
return map;
|
|
1244
|
+
})();
|
|
1247
1245
|
cachedSkills = null;
|
|
1248
1246
|
}
|
|
1249
1247
|
});
|
|
@@ -1295,10 +1293,10 @@ __export(runtime_config_exports, {
|
|
|
1295
1293
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1296
1294
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1297
1295
|
});
|
|
1298
|
-
import { readFileSync as
|
|
1296
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1299
1297
|
import { join as join2 } from "path";
|
|
1300
|
-
import { fileURLToPath as
|
|
1301
|
-
import { dirname as
|
|
1298
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1299
|
+
import { dirname as dirname3 } from "path";
|
|
1302
1300
|
function runtimeDir() {
|
|
1303
1301
|
return getRuntimeConfigDir();
|
|
1304
1302
|
}
|
|
@@ -1310,7 +1308,7 @@ function getRuntimeConfigPath() {
|
|
|
1310
1308
|
function saveRuntimeConfig(config) {
|
|
1311
1309
|
const p = getRuntimeConfigPath();
|
|
1312
1310
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1313
|
-
if (dir && !
|
|
1311
|
+
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1314
1312
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1315
1313
|
}
|
|
1316
1314
|
function emptyRuntimeConfig() {
|
|
@@ -1325,7 +1323,7 @@ function emptyRuntimeConfig() {
|
|
|
1325
1323
|
}
|
|
1326
1324
|
function loadRuntimeConfig() {
|
|
1327
1325
|
const p = getRuntimeConfigPath();
|
|
1328
|
-
if (!
|
|
1326
|
+
if (!existsSync4(p)) {
|
|
1329
1327
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
1330
1328
|
try {
|
|
1331
1329
|
saveRuntimeConfig(seeded);
|
|
@@ -1334,7 +1332,7 @@ function loadRuntimeConfig() {
|
|
|
1334
1332
|
return seeded;
|
|
1335
1333
|
}
|
|
1336
1334
|
try {
|
|
1337
|
-
const data = JSON.parse(
|
|
1335
|
+
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1338
1336
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1339
1337
|
return {
|
|
1340
1338
|
version: data.version || 1,
|
|
@@ -1402,9 +1400,9 @@ function getEnabledL2SensitivePaths(runtime) {
|
|
|
1402
1400
|
}
|
|
1403
1401
|
function hasRuntimeConfig() {
|
|
1404
1402
|
const p = getRuntimeConfigPath();
|
|
1405
|
-
if (!
|
|
1403
|
+
if (!existsSync4(p)) return false;
|
|
1406
1404
|
try {
|
|
1407
|
-
JSON.parse(
|
|
1405
|
+
JSON.parse(readFileSync4(p, "utf-8"));
|
|
1408
1406
|
return true;
|
|
1409
1407
|
} catch {
|
|
1410
1408
|
return false;
|
|
@@ -1583,8 +1581,8 @@ function _l3SkillsToRules() {
|
|
|
1583
1581
|
}
|
|
1584
1582
|
function _agentRulesToDefaults() {
|
|
1585
1583
|
const out = {};
|
|
1586
|
-
const agentsDir =
|
|
1587
|
-
if (!
|
|
1584
|
+
const agentsDir = existsSync4(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync4(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
1585
|
+
if (!existsSync4(agentsDir)) return out;
|
|
1588
1586
|
let entries;
|
|
1589
1587
|
try {
|
|
1590
1588
|
entries = readdirSync3(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -1593,10 +1591,10 @@ function _agentRulesToDefaults() {
|
|
|
1593
1591
|
}
|
|
1594
1592
|
for (const agentId of entries) {
|
|
1595
1593
|
const rulesFile = join2(agentsDir, agentId, "rules.json");
|
|
1596
|
-
if (!
|
|
1594
|
+
if (!existsSync4(rulesFile)) continue;
|
|
1597
1595
|
let data;
|
|
1598
1596
|
try {
|
|
1599
|
-
data = JSON.parse(
|
|
1597
|
+
data = JSON.parse(readFileSync4(rulesFile, "utf-8"));
|
|
1600
1598
|
} catch {
|
|
1601
1599
|
continue;
|
|
1602
1600
|
}
|
|
@@ -1675,6 +1673,9 @@ function generateSourceDefaults() {
|
|
|
1675
1673
|
agent_rules: _agentRulesToDefaults()
|
|
1676
1674
|
};
|
|
1677
1675
|
}
|
|
1676
|
+
function normalizePatternForFingerprint(pattern) {
|
|
1677
|
+
return pattern.replace(/\\\//g, "/");
|
|
1678
|
+
}
|
|
1678
1679
|
function _ruleFingerprint(rule) {
|
|
1679
1680
|
if (rule.intent_keywords && rule.intent_keywords.length || rule.dangerous_actions && rule.dangerous_actions.length) {
|
|
1680
1681
|
return JSON.stringify([
|
|
@@ -1682,8 +1683,8 @@ function _ruleFingerprint(rule) {
|
|
|
1682
1683
|
[...rule.dangerous_actions || []].sort()
|
|
1683
1684
|
]);
|
|
1684
1685
|
}
|
|
1685
|
-
if (rule.path) return JSON.stringify([rule.path]);
|
|
1686
|
-
if (rule.pattern) return JSON.stringify([rule.pattern]);
|
|
1686
|
+
if (rule.path) return JSON.stringify([normalizePatternForFingerprint(rule.path)]);
|
|
1687
|
+
if (rule.pattern) return JSON.stringify([normalizePatternForFingerprint(rule.pattern)]);
|
|
1687
1688
|
if (rule.keyword) return JSON.stringify([rule.keyword, rule.lang || ""]);
|
|
1688
1689
|
if (rule.value) return JSON.stringify([rule.value]);
|
|
1689
1690
|
return JSON.stringify([rule.id || ""]);
|
|
@@ -2034,7 +2035,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2034
2035
|
skills.splice(idx, 1);
|
|
2035
2036
|
const skillPath = join2(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2036
2037
|
try {
|
|
2037
|
-
if (
|
|
2038
|
+
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2038
2039
|
} catch {
|
|
2039
2040
|
}
|
|
2040
2041
|
saveRuntimeConfig(runtime);
|
|
@@ -2148,7 +2149,7 @@ function updateAgentCategoryEnabled(agentId, category, enabled) {
|
|
|
2148
2149
|
saveRuntimeConfig(runtime);
|
|
2149
2150
|
return runtime;
|
|
2150
2151
|
}
|
|
2151
|
-
var
|
|
2152
|
+
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DENY_MODE_LABELS, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, SKILL_ID_RE;
|
|
2152
2153
|
var init_runtime_config = __esm({
|
|
2153
2154
|
"src/infra/runtime-config.ts"() {
|
|
2154
2155
|
"use strict";
|
|
@@ -2157,7 +2158,7 @@ var init_runtime_config = __esm({
|
|
|
2157
2158
|
init_heuristic();
|
|
2158
2159
|
init_logic_rules();
|
|
2159
2160
|
init_skill_loader();
|
|
2160
|
-
|
|
2161
|
+
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2161
2162
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2162
2163
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2163
2164
|
RUNTIME_CONFIG_PATH = join2(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
@@ -2171,19 +2172,19 @@ var init_runtime_config = __esm({
|
|
|
2171
2172
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2172
2173
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2173
2174
|
};
|
|
2174
|
-
_AGENTS_DIR_PROD = join2(
|
|
2175
|
-
_AGENTS_DIR_DEV = join2(
|
|
2175
|
+
_AGENTS_DIR_PROD = join2(__dirname4, "agents");
|
|
2176
|
+
_AGENTS_DIR_DEV = join2(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2176
2177
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2177
2178
|
}
|
|
2178
2179
|
});
|
|
2179
2180
|
|
|
2180
2181
|
// src/agents/index.ts
|
|
2181
|
-
import { readFileSync as
|
|
2182
|
-
import { resolve as
|
|
2183
|
-
import { fileURLToPath as
|
|
2182
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
|
|
2183
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
2184
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
2184
2185
|
function resolveAgentsDir() {
|
|
2185
|
-
if (
|
|
2186
|
-
if (
|
|
2186
|
+
if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
2187
|
+
if (existsSync5(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
2187
2188
|
return AGENTS_DIR_PROD;
|
|
2188
2189
|
}
|
|
2189
2190
|
function getAgentExtensions(agentId) {
|
|
@@ -2199,13 +2200,13 @@ function getAgentExtensions(agentId) {
|
|
|
2199
2200
|
}
|
|
2200
2201
|
if (ext === null) {
|
|
2201
2202
|
const agentsDir = resolveAgentsDir();
|
|
2202
|
-
const rulesFile =
|
|
2203
|
-
if (!
|
|
2203
|
+
const rulesFile = resolve3(agentsDir, agentId, "rules.json");
|
|
2204
|
+
if (!existsSync5(rulesFile)) {
|
|
2204
2205
|
cache.set(agentId, null);
|
|
2205
2206
|
return null;
|
|
2206
2207
|
}
|
|
2207
2208
|
try {
|
|
2208
|
-
const raw =
|
|
2209
|
+
const raw = readFileSync5(rulesFile, "utf-8");
|
|
2209
2210
|
ext = JSON.parse(raw);
|
|
2210
2211
|
if (!ext.agent_id) {
|
|
2211
2212
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
@@ -2224,15 +2225,15 @@ function getAgentExtensions(agentId) {
|
|
|
2224
2225
|
);
|
|
2225
2226
|
return ext;
|
|
2226
2227
|
}
|
|
2227
|
-
var
|
|
2228
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
2228
2229
|
var init_agents = __esm({
|
|
2229
2230
|
"src/agents/index.ts"() {
|
|
2230
2231
|
"use strict";
|
|
2231
2232
|
init_esm_shims();
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
AGENTS_DIR_PROD =
|
|
2235
|
-
AGENTS_DIR_DEV_FALLBACK =
|
|
2233
|
+
__filename4 = fileURLToPath6(import.meta.url);
|
|
2234
|
+
__dirname5 = dirname4(__filename4);
|
|
2235
|
+
AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
|
|
2236
|
+
AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
|
|
2236
2237
|
cache = /* @__PURE__ */ new Map();
|
|
2237
2238
|
}
|
|
2238
2239
|
});
|
|
@@ -2292,7 +2293,7 @@ function runHeuristicCheck(input) {
|
|
|
2292
2293
|
}
|
|
2293
2294
|
}
|
|
2294
2295
|
}
|
|
2295
|
-
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
2296
|
+
const injectionText = isSearchActionType(input.aNext.actionType) ? `${input.aNext.actionType} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase() : `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
2296
2297
|
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
2297
2298
|
if (injectionHits.length > 0) {
|
|
2298
2299
|
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
@@ -2419,6 +2420,10 @@ function severityRank(s) {
|
|
|
2419
2420
|
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
2420
2421
|
return ranks[s] || 0;
|
|
2421
2422
|
}
|
|
2423
|
+
function isSearchActionType(actionType) {
|
|
2424
|
+
const at = actionType.toLowerCase();
|
|
2425
|
+
return SEARCH_ACTION_PREFIXES.some((p) => at.startsWith(p)) || ["websearch", "web_search", "search", "query"].includes(at);
|
|
2426
|
+
}
|
|
2422
2427
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2423
2428
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2424
2429
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
@@ -2686,172 +2691,34 @@ function checkLateralMovement(actionDetail) {
|
|
|
2686
2691
|
}
|
|
2687
2692
|
return null;
|
|
2688
2693
|
}
|
|
2689
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES;
|
|
2694
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES;
|
|
2690
2695
|
var init_heuristic = __esm({
|
|
2691
2696
|
"src/engine/heuristic.ts"() {
|
|
2692
2697
|
"use strict";
|
|
2693
2698
|
init_esm_shims();
|
|
2694
2699
|
init_config();
|
|
2695
2700
|
init_agents();
|
|
2701
|
+
init_rules_loader();
|
|
2696
2702
|
init_logic_rules();
|
|
2697
|
-
INJECTION_KEYWORDS =
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
2715
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
2716
|
-
// ---- Command Injection ----
|
|
2717
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
2718
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
2719
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
2720
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
2721
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
2722
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
2723
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
2724
|
-
// ---- Social Engineering ----
|
|
2725
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
2726
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
2727
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
2728
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
2729
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
2730
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
2731
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
2732
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
2733
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
2734
|
-
// ---- XSS ----
|
|
2735
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
2736
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
2737
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
2738
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
2739
|
-
// ---- Fake Boundaries ----
|
|
2740
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
2741
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
2742
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
2743
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
2744
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
2745
|
-
// ---- Developer Mode ----
|
|
2746
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
2747
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
2748
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
2749
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
2750
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
2751
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
2752
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
2753
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
2754
|
-
];
|
|
2755
|
-
DANGEROUS_PATTERNS = [
|
|
2756
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
2757
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
2758
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/(?!\w)/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)", riskType: "script_execution" },
|
|
2759
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
2760
|
-
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
2761
|
-
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var(?!\/tmp)|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55", riskType: "script_execution" },
|
|
2762
|
-
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
2763
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)", riskType: "script_execution" },
|
|
2764
|
-
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
2765
|
-
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)", riskType: "script_execution" },
|
|
2766
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
2767
|
-
{ pattern: /dd\s+if=\/dev\/zero.*\bof\s*=\s*\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55 (dd if=/dev/zero of=/\u7CFB\u7EDF\u76EE\u5F55)", riskType: "script_execution" },
|
|
2768
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
2769
|
-
{ pattern: /mkfs\.\w+\s+\/dev\/(sd|hd|nvme|vd|loop|mapper|md|dm)\S+/i, severity: "critical", description: "\u683C\u5F0F\u5316\u5757\u8BBE\u5907 (mkfs /dev/\u5757\u8BBE\u5907)", riskType: "script_execution" },
|
|
2770
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
2771
|
-
// --- Critical: remote code execution ---
|
|
2772
|
-
// curl|bash 优先匹配 user_rules(high/sensitive_action),见下方 UserRuleMatcher 段;
|
|
2773
|
-
// 非 bash 的 curl|sh/zsh/dash 走 CommandPatternScanner critical。两条分流由
|
|
2774
|
-
// runHeuristicCheck 的规则顺序保证(bash 在前 high,其余 fall-through 到 critical)。
|
|
2775
|
-
{ pattern: /curl\s+.*\|\s*bash/i, severity: "high", description: "curl pipe bash \u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2776
|
-
{ pattern: /curl\s+.*\|\s*(sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2777
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2778
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
2779
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "high", description: "base64 \u89E3\u7801\u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2780
|
-
// --- Critical: reverse shell ---
|
|
2781
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
2782
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
2783
|
-
// --- Critical: sensitive file access ---
|
|
2784
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
2785
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
2786
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
2787
|
-
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
2788
|
-
// --- Critical: privilege escalation / container escape ---
|
|
2789
|
-
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038", riskType: "privilege_escalation" },
|
|
2790
|
-
// --- Critical: dangerous permissions / ownership (提权 / 权限敞口) ---
|
|
2791
|
-
// 修正「只拦 777、xx7 漏放」的缺口:
|
|
2792
|
-
// 1) 八进制末位 7:other 位含写+执行敞口(chmod 777/647/007/4777 等);644/755/1700 不命中
|
|
2793
|
-
// 2) 八进制 setuid/setgid 位:首位 4(setuid)/2(setgid) 的 4 位八进制(chmod 4755/2755)
|
|
2794
|
-
// 3) 符号 setuid/setgid:chmod u+s / g+s / a+s
|
|
2795
|
-
// 普通权限修改(chmod 644)不在此列——L2 read_before_write 已豁免 chmod/chown(不写内容),
|
|
2796
|
-
// 危险形态在此 L1 专门拦,以「提权」正确理由拦截,不再靠 RBW 误打误撞。
|
|
2797
|
-
{ pattern: /chmod\s+[0-7]{0,3}7\b/i, severity: "critical", description: "\u5371\u9669\u6743\u9650\u8BBE\u7F6E (chmod ...7, other \u4F4D\u542B\u5199+\u6267\u884C\u655E\u53E3)", riskType: "privilege_escalation" },
|
|
2798
|
-
{ pattern: /chmod\s+[24][0-7]{3}\b/i, severity: "critical", description: "setuid/setgid \u4F4D\u8BBE\u7F6E (chmod 4xxx/2xxx, \u63D0\u6743)", riskType: "privilege_escalation" },
|
|
2799
|
-
{ pattern: /chmod\s+[ugoa]\+s\b/i, severity: "critical", description: "\u7B26\u53F7 setuid/setgid \u8BBE\u7F6E (chmod u+s/g+s/a+s, \u63D0\u6743)", riskType: "privilege_escalation" },
|
|
2800
|
-
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005", riskType: "script_execution" },
|
|
2801
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
2802
|
-
{ pattern: /sudo\s+(rm|chmod|chown|dd|mkfs|format|iptables|crontab|passwd|userdel|useradd|groupdel)\b/i, severity: "high", description: "\u63D0\u6743\u6267\u884C\u9AD8\u5371\u547D\u4EE4 (sudo + \u5371\u9669\u64CD\u4F5C)", riskType: "privilege_escalation" },
|
|
2803
|
-
// --- High: system config overwrite ---
|
|
2804
|
-
// > /etc/ 重定向覆盖:对齐 Python CommandPatternScanner `>\s*/etc/`(不兼容引号路径),
|
|
2805
|
-
// 引号包裹的重定向目标(cat > '/etc/ssh/sshd_config')走 checkSensitivePath 敏感路径 high。
|
|
2806
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
2807
|
-
{ pattern: />\s*\/boot\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55", riskType: "file_access" },
|
|
2808
|
-
// 注:/proc/ 重定向覆盖走 checkSensitivePath 的 high(内核参数 /proc/sys/),此处不拦 /proc/ 避免遮蔽(对齐 Python)。
|
|
2809
|
-
// --- High: download script + execute risk ---
|
|
2810
|
-
// curl -X POST 外传敏感信息(对齐 Python linux.py: curl POST env/key/token)
|
|
2811
|
-
{ pattern: /curl\s+.*-X\s+POST.*\b(env|environment|secret|key|token|password)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 curl POST \u5916\u4F20\u53EF\u80FD\u5305\u542B\u654F\u611F\u4FE1\u606F\u7684\u8BF7\u6C42", riskType: "data_exfiltration" },
|
|
2812
|
-
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730", riskType: "script_execution" },
|
|
2813
|
-
{ pattern: /(?:curl|wget)\s+\S+.*\b(?:chmod|chown)\s+\+x\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u540E\u4FEE\u6539\u53EF\u6267\u884C\u6743\u9650\uFF0C\u5B58\u5728\u8FDC\u7A0B\u4EE3\u7801\u6267\u884C\u98CE\u9669", riskType: "script_execution" },
|
|
2814
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
2815
|
-
// --- High: package manager pipe-to-shell ---
|
|
2816
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
2817
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
2818
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
2819
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
2820
|
-
{ pattern: /git\s+push\s+.*--force/i, severity: "medium", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)\uFF0C\u53EF\u80FD\u8986\u76D6\u8FDC\u7A0B\u63D0\u4EA4\u5386\u53F2", riskType: "script_execution" },
|
|
2821
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
2822
|
-
{ pattern: /\bnmap\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF (nmap)\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
2823
|
-
{ pattern: /\b(masscan|zmap|unicornscan)\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF\u5DE5\u5177\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
2824
|
-
// --- Medium: credential export ---
|
|
2825
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
2826
|
-
// --- High: shell rc file append (persistence) ---
|
|
2827
|
-
// 两条规则:第一条匹配 ~ 与 /home/<user>/ 形态;第二条按文件名兜底,
|
|
2828
|
-
// 覆盖非标准 home 路径(如鸿蒙 /storage/Users/currentUser/.bashrc、
|
|
2829
|
-
// /root/.bashrc),避免按 home 前缀枚举导致漏检持久化后门。
|
|
2830
|
-
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
2831
|
-
{ pattern: />>\s*\S*\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)\b/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
2832
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
2833
|
-
{ pattern: />\s*\/dev\/(sd|hd|nvme|vd|loop|mem|kmsg|port|zero|random|urandom|full|core)/i, severity: "high", description: "\u91CD\u5B9A\u5411\u5199\u5165\u8BBE\u5907\u6587\u4EF6", riskType: "file_access" },
|
|
2834
|
-
// --- High: non-interactive password modification ---
|
|
2835
|
-
{ pattern: /\|\s*passwd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7BA1\u9053\u65B9\u5F0F\u8C03\u7528 passwd\uFF08\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\uFF09", riskType: "script_execution" },
|
|
2836
|
-
{ pattern: /\bpasswd\s+--stdin\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 passwd --stdin \u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u8F93\u5165", riskType: "script_execution" },
|
|
2837
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
2838
|
-
{ pattern: /\b(newusers|lnewusers)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 newusers/lnewusers \u6279\u91CF\u7528\u6237\u6DFB\u52A0\u547D\u4EE4", riskType: "script_execution" },
|
|
2839
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*d\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u5BC6\u7801\u64CD\u4F5C (passwd -d)", riskType: "script_execution" },
|
|
2840
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*l\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u9501\u5B9A\u7528\u6237\u8D26\u6237\u64CD\u4F5C (passwd -l)", riskType: "script_execution" },
|
|
2841
|
-
// --- High: non-interactive password modification (extended) ---
|
|
2842
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
2843
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
2844
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
2845
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
2846
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
2847
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
2848
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
2849
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
2850
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
2851
|
-
// --- High: generic command -p parameter password setting ---
|
|
2852
|
-
{ pattern: /\b(useradd|luseradd|groupadd|usermod|lusermod|groupmod|lgroupmod)\b[^&|;]*?\s-p\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 -p \u53C2\u6570\u8BBE\u7F6E\u6216\u4FEE\u6539\u5BC6\u7801 (useradd/usermod/groupmod)", riskType: "script_execution" }
|
|
2853
|
-
];
|
|
2703
|
+
INJECTION_KEYWORDS = (() => {
|
|
2704
|
+
const kws = loadL1().injection_detection || [];
|
|
2705
|
+
return kws.map((k) => ({
|
|
2706
|
+
keyword: k.keyword,
|
|
2707
|
+
riskLevel: k.risk_level,
|
|
2708
|
+
lang: k.lang || "en"
|
|
2709
|
+
}));
|
|
2710
|
+
})();
|
|
2711
|
+
DANGEROUS_PATTERNS = (() => {
|
|
2712
|
+
const cmds = loadL1().dangerous_commands || [];
|
|
2713
|
+
return cmds.map((c) => ({
|
|
2714
|
+
pattern: new RegExp(c.pattern, "i"),
|
|
2715
|
+
severity: c.risk_level,
|
|
2716
|
+
riskType: c.risk_type,
|
|
2717
|
+
description: c.reason
|
|
2718
|
+
}));
|
|
2719
|
+
})();
|
|
2854
2720
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
2721
|
+
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
2855
2722
|
}
|
|
2856
2723
|
});
|
|
2857
2724
|
|
|
@@ -2864,16 +2731,16 @@ __export(token_stats_exports, {
|
|
|
2864
2731
|
recordTokenUsage: () => recordTokenUsage,
|
|
2865
2732
|
resetTokenStats: () => resetTokenStats
|
|
2866
2733
|
});
|
|
2867
|
-
import { readFileSync as
|
|
2734
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
2868
2735
|
function getStatsPath() {
|
|
2869
2736
|
const envPath = process.env[ENV_STATS_PATH];
|
|
2870
2737
|
if (envPath) return envPath;
|
|
2871
2738
|
return getTokenStatsPath();
|
|
2872
2739
|
}
|
|
2873
2740
|
function loadAllRecords(statsPath) {
|
|
2874
|
-
if (!
|
|
2741
|
+
if (!existsSync8(statsPath)) return [];
|
|
2875
2742
|
try {
|
|
2876
|
-
const data = JSON.parse(
|
|
2743
|
+
const data = JSON.parse(readFileSync9(statsPath, "utf-8"));
|
|
2877
2744
|
if (Array.isArray(data)) return data;
|
|
2878
2745
|
if (data && Array.isArray(data.records)) return data.records;
|
|
2879
2746
|
return [];
|
|
@@ -2884,7 +2751,7 @@ function loadAllRecords(statsPath) {
|
|
|
2884
2751
|
function saveRecords(statsPath, records) {
|
|
2885
2752
|
try {
|
|
2886
2753
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
2887
|
-
if (dir && !
|
|
2754
|
+
if (dir && !existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
2888
2755
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
2889
2756
|
} catch (e) {
|
|
2890
2757
|
}
|
|
@@ -3006,7 +2873,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
3006
2873
|
}
|
|
3007
2874
|
function resetTokenStats() {
|
|
3008
2875
|
const statsPath = getStatsPath();
|
|
3009
|
-
if (
|
|
2876
|
+
if (existsSync8(statsPath)) {
|
|
3010
2877
|
try {
|
|
3011
2878
|
unlinkSync2(statsPath);
|
|
3012
2879
|
} catch {
|
|
@@ -3037,28 +2904,28 @@ init_skill_loader();
|
|
|
3037
2904
|
|
|
3038
2905
|
// src/engine/template-loader.ts
|
|
3039
2906
|
init_esm_shims();
|
|
3040
|
-
import { readFileSync as
|
|
3041
|
-
import { resolve as
|
|
3042
|
-
import { fileURLToPath as
|
|
3043
|
-
var
|
|
3044
|
-
var
|
|
3045
|
-
var TEMPLATES_DIR =
|
|
3046
|
-
var TEMPLATES_DIR_FALLBACK =
|
|
2907
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
2908
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
2909
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
2910
|
+
var __filename5 = fileURLToPath7(import.meta.url);
|
|
2911
|
+
var __dirname6 = dirname5(__filename5);
|
|
2912
|
+
var TEMPLATES_DIR = resolve4(__dirname6, "../templates");
|
|
2913
|
+
var TEMPLATES_DIR_FALLBACK = resolve4(__dirname6, "../../../agent_moss/templates");
|
|
3047
2914
|
var TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
3048
2915
|
var cachedTemplates = null;
|
|
3049
2916
|
function loadTemplates() {
|
|
3050
2917
|
if (cachedTemplates) return cachedTemplates;
|
|
3051
2918
|
cachedTemplates = {};
|
|
3052
|
-
const dir =
|
|
3053
|
-
if (!
|
|
2919
|
+
const dir = existsSync6(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
|
|
2920
|
+
if (!existsSync6(dir)) {
|
|
3054
2921
|
console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
|
|
3055
2922
|
return cachedTemplates;
|
|
3056
2923
|
}
|
|
3057
2924
|
for (const file of TEMPLATE_FILES) {
|
|
3058
|
-
const filePath =
|
|
3059
|
-
if (
|
|
2925
|
+
const filePath = resolve4(dir, file);
|
|
2926
|
+
if (existsSync6(filePath)) {
|
|
3060
2927
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
3061
|
-
cachedTemplates[key] =
|
|
2928
|
+
cachedTemplates[key] = readFileSync6(filePath, "utf-8");
|
|
3062
2929
|
}
|
|
3063
2930
|
}
|
|
3064
2931
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
@@ -3067,8 +2934,8 @@ function loadTemplates() {
|
|
|
3067
2934
|
|
|
3068
2935
|
// src/engine/script-analyzer.ts
|
|
3069
2936
|
init_esm_shims();
|
|
3070
|
-
import { readFileSync as
|
|
3071
|
-
import { resolve as
|
|
2937
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
2938
|
+
import { resolve as resolve5, join as join3 } from "path";
|
|
3072
2939
|
var SUSPICIOUS_PATTERNS = [
|
|
3073
2940
|
// Network exfiltration (curl/wget POST in scripts is almost never legitimate)
|
|
3074
2941
|
{ name: "curl POST", pattern: /curl\s+(.*\s)?-X\s+POST/i },
|
|
@@ -3201,8 +3068,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
3201
3068
|
}
|
|
3202
3069
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
3203
3070
|
try {
|
|
3204
|
-
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) :
|
|
3205
|
-
const raw =
|
|
3071
|
+
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve5(scriptPath);
|
|
3072
|
+
const raw = readFileSync7(expandedPath, "utf-8");
|
|
3206
3073
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
3207
3074
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
3208
3075
|
} catch (e) {
|
|
@@ -3256,8 +3123,8 @@ ${result.scriptContent}
|
|
|
3256
3123
|
init_esm_shims();
|
|
3257
3124
|
init_heuristic();
|
|
3258
3125
|
init_logic_rules();
|
|
3259
|
-
import { readFileSync as
|
|
3260
|
-
import { resolve as
|
|
3126
|
+
import { readFileSync as readFileSync8, statSync, existsSync as existsSync7 } from "fs";
|
|
3127
|
+
import { resolve as resolve6, join as join4, isAbsolute, dirname as dirname6 } from "path";
|
|
3261
3128
|
import { homedir as homedir2 } from "os";
|
|
3262
3129
|
function emptyChain() {
|
|
3263
3130
|
return {
|
|
@@ -3486,7 +3353,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
3486
3353
|
let resolved;
|
|
3487
3354
|
try {
|
|
3488
3355
|
resolved = resolvePath(p);
|
|
3489
|
-
if (
|
|
3356
|
+
if (existsSync7(resolved)) {
|
|
3490
3357
|
const stat = statSync(resolved);
|
|
3491
3358
|
if (stat.isFile()) return resolved;
|
|
3492
3359
|
}
|
|
@@ -3500,18 +3367,18 @@ function resolvePath(p) {
|
|
|
3500
3367
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
3501
3368
|
expanded = join4(homedir2(), expanded.slice(1));
|
|
3502
3369
|
}
|
|
3503
|
-
return
|
|
3370
|
+
return resolve6(expanded);
|
|
3504
3371
|
}
|
|
3505
3372
|
function readScriptContent2(scriptPath, maxFileSize = 2 * 1024 * 1024) {
|
|
3506
3373
|
try {
|
|
3507
3374
|
const path3 = resolvePath(scriptPath);
|
|
3508
|
-
if (!
|
|
3375
|
+
if (!existsSync7(path3)) return { content: "", lineCount: 0, fileSize: 0, error: `\u811A\u672C\u4E0D\u5B58\u5728: ${scriptPath}` };
|
|
3509
3376
|
const stat = statSync(path3);
|
|
3510
3377
|
if (!stat.isFile()) return { content: "", lineCount: 0, fileSize: 0, error: `\u4E0D\u662F\u6587\u4EF6: ${scriptPath}` };
|
|
3511
3378
|
if (stat.size > maxFileSize) {
|
|
3512
3379
|
return { content: "", lineCount: 0, fileSize: stat.size, error: `\u811A\u672C\u6587\u4EF6\u8FC7\u5927 (${stat.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6` };
|
|
3513
3380
|
}
|
|
3514
|
-
const content =
|
|
3381
|
+
const content = readFileSync8(path3, "utf-8");
|
|
3515
3382
|
const lineCount = content ? content.split("\n").length : 0;
|
|
3516
3383
|
return { content, lineCount, fileSize: stat.size, error: "" };
|
|
3517
3384
|
} catch (e) {
|
|
@@ -3530,7 +3397,7 @@ function extractChildScriptPaths(content, baseDir) {
|
|
|
3530
3397
|
if (pathStr.includes("/dev/") || pathStr.startsWith("|") || pathStr.startsWith(";")) continue;
|
|
3531
3398
|
const full = isAbsolute(pathStr) ? pathStr : join4(baseDir, pathStr);
|
|
3532
3399
|
const resolved = resolvePath(full);
|
|
3533
|
-
if (
|
|
3400
|
+
if (existsSync7(resolved)) {
|
|
3534
3401
|
try {
|
|
3535
3402
|
if (statSync(resolved).isFile() && !paths.includes(resolved)) paths.push(resolved);
|
|
3536
3403
|
} catch {
|
|
@@ -3545,7 +3412,7 @@ function resolveScriptChain(entryPath, input, maxDepth = 3, maxFileSize = 2 * 10
|
|
|
3545
3412
|
const result = emptyChain();
|
|
3546
3413
|
result.entryPath = entryPath;
|
|
3547
3414
|
const entry = resolvePath(entryPath);
|
|
3548
|
-
const baseDir =
|
|
3415
|
+
const baseDir = existsSync7(entry) ? dirname6(entry) : input.cwd || process.cwd();
|
|
3549
3416
|
resolveRecursive({
|
|
3550
3417
|
path: entry,
|
|
3551
3418
|
depth: 0,
|
|
@@ -3620,7 +3487,7 @@ function resolveRecursive(ctx) {
|
|
|
3620
3487
|
maxTotalSize,
|
|
3621
3488
|
visited,
|
|
3622
3489
|
result,
|
|
3623
|
-
baseDir:
|
|
3490
|
+
baseDir: dirname6(resolvePath(childPath)),
|
|
3624
3491
|
input
|
|
3625
3492
|
});
|
|
3626
3493
|
if (result.hasCritical) return;
|
|
@@ -3973,7 +3840,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
3973
3840
|
}
|
|
3974
3841
|
if (attempt < maxRetries) {
|
|
3975
3842
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
3976
|
-
await new Promise((
|
|
3843
|
+
await new Promise((resolve7) => setTimeout(resolve7, retryCfg.retryInterval * 1e3));
|
|
3977
3844
|
} else {
|
|
3978
3845
|
clearTimeout(totalTimeoutTimer);
|
|
3979
3846
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|