@kenhkl/agent-moss 0.15.2 → 0.15.5
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.d.ts +10 -0
- package/dist/cli.js +140 -16
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +94 -12
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/l1_rules.json +58 -15
- package/dist/rules/mc_rules.json +2 -30
- package/dist/rules/user_rules.json +2 -71
- package/dist/scenarios/__pycache__/__init__.cpython-311.pyc +0 -0
- package/dist/server.js +94 -12
- package/dist/server.js.map +1 -1
- package/dist/skills/script_execution_guard.md +14 -9
- package/dist/templates/security_judge_template.txt +7 -1
- package/package.json +2 -2
|
@@ -1434,6 +1434,7 @@ __export(runtime_config_exports, {
|
|
|
1434
1434
|
getRuntimeConfigPath: () => getRuntimeConfigPath,
|
|
1435
1435
|
getScenarioRules: () => getScenarioRules,
|
|
1436
1436
|
hasRuntimeConfig: () => hasRuntimeConfig,
|
|
1437
|
+
invalidateRuntimeConfigCache: () => invalidateRuntimeConfigCache,
|
|
1437
1438
|
isL2CategoryEnabled: () => isL2CategoryEnabled,
|
|
1438
1439
|
isLayerEnabled: () => isLayerEnabled,
|
|
1439
1440
|
loadRuntimeConfig: () => loadRuntimeConfig,
|
|
@@ -1452,7 +1453,7 @@ __export(runtime_config_exports, {
|
|
|
1452
1453
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1453
1454
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1454
1455
|
});
|
|
1455
|
-
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1456
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3, statSync } from "fs";
|
|
1456
1457
|
import { join as join3 } from "path";
|
|
1457
1458
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1458
1459
|
import { dirname as dirname3 } from "path";
|
|
@@ -1469,6 +1470,7 @@ function saveRuntimeConfig(config) {
|
|
|
1469
1470
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1470
1471
|
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1471
1472
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1473
|
+
invalidateRuntimeConfigCache();
|
|
1472
1474
|
}
|
|
1473
1475
|
function emptyRuntimeConfig() {
|
|
1474
1476
|
return {
|
|
@@ -1482,6 +1484,9 @@ function emptyRuntimeConfig() {
|
|
|
1482
1484
|
scenario_rules: {}
|
|
1483
1485
|
};
|
|
1484
1486
|
}
|
|
1487
|
+
function invalidateRuntimeConfigCache() {
|
|
1488
|
+
runtimeConfigCache = null;
|
|
1489
|
+
}
|
|
1485
1490
|
function loadRuntimeConfig() {
|
|
1486
1491
|
const p = getRuntimeConfigPath();
|
|
1487
1492
|
if (!existsSync4(p)) {
|
|
@@ -1493,9 +1498,14 @@ function loadRuntimeConfig() {
|
|
|
1493
1498
|
return seeded;
|
|
1494
1499
|
}
|
|
1495
1500
|
try {
|
|
1501
|
+
const st = statSync(p);
|
|
1502
|
+
const cacheKey = `${p}|${st.mtimeMs}|${st.size}`;
|
|
1503
|
+
if (runtimeConfigCache && runtimeConfigCache.key === cacheKey) {
|
|
1504
|
+
return runtimeConfigCache.value;
|
|
1505
|
+
}
|
|
1496
1506
|
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1497
1507
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1498
|
-
|
|
1508
|
+
const result = {
|
|
1499
1509
|
version: data.version || 1,
|
|
1500
1510
|
layers: {
|
|
1501
1511
|
L1_heuristic: data.layers?.L1_heuristic ?? true,
|
|
@@ -1509,6 +1519,8 @@ function loadRuntimeConfig() {
|
|
|
1509
1519
|
agent_rules: merged.agent_rules || {},
|
|
1510
1520
|
scenario_rules: merged.scenario_rules || {}
|
|
1511
1521
|
};
|
|
1522
|
+
runtimeConfigCache = { key: cacheKey, value: result };
|
|
1523
|
+
return result;
|
|
1512
1524
|
} catch {
|
|
1513
1525
|
return emptyRuntimeConfig();
|
|
1514
1526
|
}
|
|
@@ -2498,7 +2510,7 @@ function updateScenarioCategoryEnabled(scenarioId, category, enabled) {
|
|
|
2498
2510
|
saveRuntimeConfig(runtime);
|
|
2499
2511
|
return runtime;
|
|
2500
2512
|
}
|
|
2501
|
-
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DEFAULT_LAYERS, DENY_MODE_LABELS, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, _SCENARIOS_DIR_PROD, _SCENARIOS_DIR_DEV, SKILL_ID_RE;
|
|
2513
|
+
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DEFAULT_LAYERS, DENY_MODE_LABELS, runtimeConfigCache, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, _SCENARIOS_DIR_PROD, _SCENARIOS_DIR_DEV, SKILL_ID_RE;
|
|
2502
2514
|
var init_runtime_config = __esm({
|
|
2503
2515
|
"src/infra/runtime-config.ts"() {
|
|
2504
2516
|
"use strict";
|
|
@@ -2528,6 +2540,7 @@ var init_runtime_config = __esm({
|
|
|
2528
2540
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2529
2541
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2530
2542
|
};
|
|
2543
|
+
runtimeConfigCache = null;
|
|
2531
2544
|
_AGENTS_DIR_PROD = join3(__dirname4, "agents");
|
|
2532
2545
|
_AGENTS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2533
2546
|
_SCENARIOS_DIR_PROD = join3(__dirname4, "scenarios");
|
|
@@ -2822,6 +2835,56 @@ function isInlineScriptCommand(actionDetail) {
|
|
|
2822
2835
|
const re = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
2823
2836
|
return re.test(actionDetail);
|
|
2824
2837
|
}
|
|
2838
|
+
function resolvePathTokens(segment) {
|
|
2839
|
+
const out = [];
|
|
2840
|
+
const low = segment.toLowerCase();
|
|
2841
|
+
for (const m of low.matchAll(HOME_PREFIX_RE)) {
|
|
2842
|
+
const prefix = m[0];
|
|
2843
|
+
const endIdx = (m.index ?? 0) + m[0].length;
|
|
2844
|
+
const tail = low.slice(endIdx);
|
|
2845
|
+
if (!tail || !(tail[0] === "/" || tail[0] === " ")) {
|
|
2846
|
+
out.push([prefix, prefix]);
|
|
2847
|
+
continue;
|
|
2848
|
+
}
|
|
2849
|
+
const token = tail.trim().split(/\s+/)[0] || "";
|
|
2850
|
+
if (!token.startsWith("/")) continue;
|
|
2851
|
+
const cleaned = token.replace(/\/+$/, "").replace(/^['"]|['"]$/g, "");
|
|
2852
|
+
const segments = cleaned.split("/").filter((s) => s && s !== ".");
|
|
2853
|
+
if (!segments.some((s) => s === "..")) continue;
|
|
2854
|
+
let depth = 0;
|
|
2855
|
+
const kept = [];
|
|
2856
|
+
let escaped = false;
|
|
2857
|
+
for (const s of segments) {
|
|
2858
|
+
if (s === "..") {
|
|
2859
|
+
depth -= 1;
|
|
2860
|
+
if (kept.length) kept.pop();
|
|
2861
|
+
if (depth < 0) {
|
|
2862
|
+
escaped = true;
|
|
2863
|
+
depth = 0;
|
|
2864
|
+
}
|
|
2865
|
+
} else {
|
|
2866
|
+
depth += 1;
|
|
2867
|
+
kept.push(s);
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
let resolved = kept.length ? "~/" + kept.join("/") : "~";
|
|
2871
|
+
if (escaped) resolved += "\uFF08\u26A0\uFE0F .. \u5F39\u6808\u8D85\u51FA\u4E3B\u76EE\u5F55\u6839\uFF0C\u5B9E\u9645\u76EE\u6807\u5728\u4E3B\u76EE\u5F55\u4E4B\u5916\uFF09";
|
|
2872
|
+
out.push([prefix + token, resolved]);
|
|
2873
|
+
}
|
|
2874
|
+
return out;
|
|
2875
|
+
}
|
|
2876
|
+
function buildPathContext(actionDetail) {
|
|
2877
|
+
if (!PATH_CONTEXT_TRIGGER_RE.test(actionDetail)) return "";
|
|
2878
|
+
const stripped = stripLiteralTextSegments(actionDetail);
|
|
2879
|
+
const lines = [];
|
|
2880
|
+
for (const seg of splitCommandSegments(stripped)) {
|
|
2881
|
+
for (const [raw, lex] of resolvePathTokens(seg)) {
|
|
2882
|
+
lines.push(`- \u547D\u4EE4\u6BB5 \`${seg.trim().slice(0, 60)}\`\uFF1A\`${raw}\` \u8BCD\u6CD5\u89E3\u6790\u4E3A \`${lex}\``);
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
if (!lines.length) return "";
|
|
2886
|
+
return "## \u8DEF\u5F84\u89E3\u6790\u4E8B\u5B9E\uFF08\u8BCD\u6CD5\u5206\u6790\uFF0C\u786E\u5B9A\u6027\u7ED3\u8BBA\uFF09\n" + lines.join("\n") + "\n\n## \u8FD0\u884C\u65F6\u672A\u9A8C\u8BC1\uFF08\u4F9B\u53C2\u8003\uFF0C\u975E\u4E8B\u5B9E\uFF09\n- \u5206\u6790\u5668\u4E0D\u8BFB\u6587\u4EF6\u7CFB\u7EDF\uFF1A\u65E0\u6CD5\u786E\u8BA4\u8DEF\u5F84\u4E2D\u7684\u4E2D\u95F4\u76EE\u5F55\u662F\u5426\u4E3A\u7B26\u53F7\u94FE\u63A5\uFF1B\u82E5\u4E2D\u95F4\u6BB5\u5728\u6267\u884C\u65F6\u662F\uFF08\u6216\u88AB\u66FF\u6362\u4E3A\uFF09\u6307\u5411\u4E3B\u76EE\u5F55\u5916\u7684\u8F6F\u94FE\uFF0C\u5B9E\u9645\u64CD\u4F5C\u76EE\u6807\u53EF\u80FD\u968F\u4E4B\u6539\u53D8\u3002\u8BCD\u6CD5\u89E3\u6790\u7ED3\u679C\u57FA\u4E8E\u6807\u51C6\u8DEF\u5F84\u8BED\u4E49\uFF0C\u4E0D\u5E94\u56E0\u731C\u6D4B\u300C\u89E3\u6790\u4F9D\u8D56\u67D0\u6BB5\u662F\u5426\u5B58\u5728\u300D\u800C\u5426\u5B9A\u5B83\u3002";
|
|
2887
|
+
}
|
|
2825
2888
|
function stripLiteralTextSegments(actionDetail) {
|
|
2826
2889
|
const writeScriptExec = />\s*[/~]\S*\.(sh|py|pl|rb)\b/.test(actionDetail) && /(?:&&|\|\||;|\n|\|)\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)/.test(actionDetail);
|
|
2827
2890
|
const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)\b/.test(actionDetail);
|
|
@@ -3348,7 +3411,7 @@ function checkLateralMovement(actionDetail) {
|
|
|
3348
3411
|
}
|
|
3349
3412
|
return null;
|
|
3350
3413
|
}
|
|
3351
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
3414
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, PATH_CONTEXT_TRIGGER_RE, HOME_PREFIX_RE, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
3352
3415
|
var init_heuristic = __esm({
|
|
3353
3416
|
"src/engine/heuristic.ts"() {
|
|
3354
3417
|
"use strict";
|
|
@@ -3376,6 +3439,8 @@ var init_heuristic = __esm({
|
|
|
3376
3439
|
description: c.reason
|
|
3377
3440
|
}));
|
|
3378
3441
|
})();
|
|
3442
|
+
PATH_CONTEXT_TRIGGER_RE = /(?:^|[;&|]\s*)(?:rm|rmdir|unlink|ln|mv|cp|dd|truncate|shred|chmod|chown)\b/i;
|
|
3443
|
+
HOME_PREFIX_RE = /(?:~|~(?=\/)|\$HOME\b|\$\{HOME\}|\/home\/[a-z0-9_.-]+)/gi;
|
|
3379
3444
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
3380
3445
|
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
3381
3446
|
HOME_TARGET_RE = /(?:^|[\s="'($])(?:~|(?:\$home|\$\{home\}))(?:\/(?:\.\*|\*|\.)?)?(?=[\s"';}|&)]|$)/i;
|
|
@@ -3791,7 +3856,7 @@ init_esm_shims();
|
|
|
3791
3856
|
init_heuristic();
|
|
3792
3857
|
init_logic_rules();
|
|
3793
3858
|
init_inline_analyzer();
|
|
3794
|
-
import { statSync as
|
|
3859
|
+
import { statSync as statSync3, existsSync as existsSync9 } from "fs";
|
|
3795
3860
|
import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
|
|
3796
3861
|
import { homedir as homedir4 } from "os";
|
|
3797
3862
|
|
|
@@ -5452,7 +5517,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5452
5517
|
try {
|
|
5453
5518
|
const resolved = resolvePath2(tok.replace(/^['"]|['"]$/g, ""));
|
|
5454
5519
|
if (existsSync9(resolved)) {
|
|
5455
|
-
const stat =
|
|
5520
|
+
const stat = statSync3(resolved);
|
|
5456
5521
|
if (stat.isFile()) return resolved;
|
|
5457
5522
|
}
|
|
5458
5523
|
} catch {
|
|
@@ -5466,7 +5531,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5466
5531
|
try {
|
|
5467
5532
|
const resolved = resolvePath2(p);
|
|
5468
5533
|
if (existsSync9(resolved)) {
|
|
5469
|
-
const stat =
|
|
5534
|
+
const stat = statSync3(resolved);
|
|
5470
5535
|
if (stat.isFile()) return resolved;
|
|
5471
5536
|
}
|
|
5472
5537
|
} catch {
|
|
@@ -5482,7 +5547,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5482
5547
|
try {
|
|
5483
5548
|
resolved = resolvePath2(p);
|
|
5484
5549
|
if (existsSync9(resolved)) {
|
|
5485
|
-
const stat =
|
|
5550
|
+
const stat = statSync3(resolved);
|
|
5486
5551
|
if (stat.isFile()) return resolved;
|
|
5487
5552
|
}
|
|
5488
5553
|
} catch {
|
|
@@ -5693,7 +5758,7 @@ async function runLLMAnalysis(input, previous) {
|
|
|
5693
5758
|
} else {
|
|
5694
5759
|
scriptAnalysis = analyzeScriptContent(input.aNext.actionType, input.aNext.actionDetail);
|
|
5695
5760
|
}
|
|
5696
|
-
const prompt = buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, previous.skipL3Hints ?? "", scriptChainText);
|
|
5761
|
+
const prompt = buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, previous.skipL3Hints ?? "", scriptChainText, previous.pathContext ?? "");
|
|
5697
5762
|
logPrompt(prompt, input.aNext, previous.llmLogPath);
|
|
5698
5763
|
const result = await analyzeWithLLM(prompt, config);
|
|
5699
5764
|
if (llmCache.size >= LLM_CACHE_MAX) {
|
|
@@ -5717,7 +5782,7 @@ ${prompt}
|
|
|
5717
5782
|
console.warn("[AgentMoss] Failed to write LLM prompt to log:", e);
|
|
5718
5783
|
}
|
|
5719
5784
|
}
|
|
5720
|
-
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "") {
|
|
5785
|
+
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "", pathContext = "") {
|
|
5721
5786
|
const skillsText = formatSkillsForPrompt(matchedSkills);
|
|
5722
5787
|
const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
|
|
5723
5788
|
const promptHistoryText = formatPromptHistory(input.promptHistory);
|
|
@@ -5725,7 +5790,7 @@ function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis,
|
|
|
5725
5790
|
const hintsText = formatHints(previous);
|
|
5726
5791
|
const securityJudgeTemplate = templates["security_judge"];
|
|
5727
5792
|
if (securityJudgeTemplate) {
|
|
5728
|
-
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{prompt_history_text}", promptHistoryText).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("{skip_l3_hints}", skipL3Hints).replaceAll("{{", "{").replaceAll("}}", "}");
|
|
5793
|
+
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{prompt_history_text}", promptHistoryText).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("{skip_l3_hints}", skipL3Hints).replaceAll("{path_context}", pathContext || "\uFF08\u672C\u547D\u4EE4\u65E0\u4E3B\u76EE\u5F55\u76F8\u5173\u8DEF\u5F84\u6BB5\uFF0C\u4E0D\u9002\u7528\uFF09").replaceAll("{{", "{").replaceAll("}}", "}");
|
|
5729
5794
|
}
|
|
5730
5795
|
console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
|
|
5731
5796
|
return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
|
|
@@ -7609,6 +7674,21 @@ async function runAnalysis(input) {
|
|
|
7609
7674
|
if ((effectiveResult.riskLevel === "high" || effectiveResult.riskLevel === "critical") && (!skipInlineFileAccess || isCredentialPath)) {
|
|
7610
7675
|
return effectiveResult;
|
|
7611
7676
|
}
|
|
7677
|
+
} else {
|
|
7678
|
+
if (isInlineScriptCmd || isLiteralTextCmd) {
|
|
7679
|
+
const inlineJudgment = analyzeInlineScript(input.aNext.actionDetail);
|
|
7680
|
+
if (inlineJudgment.actionable && !inlineJudgment.allowed) {
|
|
7681
|
+
return {
|
|
7682
|
+
allowed: false,
|
|
7683
|
+
reason: inlineJudgment.reason,
|
|
7684
|
+
riskLevel: inlineJudgment.riskLevel,
|
|
7685
|
+
riskType: inlineJudgment.riskType,
|
|
7686
|
+
confidence: 90,
|
|
7687
|
+
source: "logic_rule",
|
|
7688
|
+
violatedLayers: ["L2.1"]
|
|
7689
|
+
};
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7612
7692
|
}
|
|
7613
7693
|
if (isLogicRulesEnabled()) {
|
|
7614
7694
|
const formalSessions = [];
|
|
@@ -7710,12 +7790,14 @@ async function runAnalysis(input) {
|
|
|
7710
7790
|
}
|
|
7711
7791
|
let llmResult;
|
|
7712
7792
|
try {
|
|
7793
|
+
const pathContext = buildPathContext(input.aNext.actionDetail);
|
|
7713
7794
|
llmResult = await runLLMAnalysis(input, {
|
|
7714
7795
|
heuristic: heuristicResult,
|
|
7715
7796
|
logic: logicResult,
|
|
7716
7797
|
skipL3Hints,
|
|
7717
7798
|
scriptChain: scriptChain ?? void 0,
|
|
7718
|
-
llmLogPath: input.llmLogPath
|
|
7799
|
+
llmLogPath: input.llmLogPath,
|
|
7800
|
+
pathContext
|
|
7719
7801
|
});
|
|
7720
7802
|
} catch (e) {
|
|
7721
7803
|
const { getLLMFailMode: getLLMFailMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|