@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
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AgentMoss CLI — TypeScript version.
|
|
4
|
+
* Supports: init | analyze | server
|
|
5
|
+
*/
|
|
6
|
+
/** 命令模式核心:把一条 shell 命令当 a_next 分析,输出 Deny/Allow(--json 时完整
|
|
7
|
+
* JSON),返回退出码(Allow=0 / Deny=1)。导出供测试直接调用(CLI 分支再 process.exit)。
|
|
8
|
+
* 零文件读写——镜像 Python cli.py 的 _analyze_command。 */
|
|
9
|
+
declare function analyzeRawCommand(command: string, useJson?: boolean): Promise<number>;
|
|
10
|
+
|
|
11
|
+
export { analyzeRawCommand };
|
package/dist/cli.js
CHANGED
|
@@ -1439,6 +1439,7 @@ __export(runtime_config_exports, {
|
|
|
1439
1439
|
getRuntimeConfigPath: () => getRuntimeConfigPath,
|
|
1440
1440
|
getScenarioRules: () => getScenarioRules,
|
|
1441
1441
|
hasRuntimeConfig: () => hasRuntimeConfig,
|
|
1442
|
+
invalidateRuntimeConfigCache: () => invalidateRuntimeConfigCache,
|
|
1442
1443
|
isL2CategoryEnabled: () => isL2CategoryEnabled,
|
|
1443
1444
|
isLayerEnabled: () => isLayerEnabled,
|
|
1444
1445
|
loadRuntimeConfig: () => loadRuntimeConfig,
|
|
@@ -1457,7 +1458,7 @@ __export(runtime_config_exports, {
|
|
|
1457
1458
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1458
1459
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1459
1460
|
});
|
|
1460
|
-
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1461
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3, statSync } from "fs";
|
|
1461
1462
|
import { join as join3 } from "path";
|
|
1462
1463
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1463
1464
|
import { dirname as dirname3 } from "path";
|
|
@@ -1474,6 +1475,7 @@ function saveRuntimeConfig(config) {
|
|
|
1474
1475
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1475
1476
|
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1476
1477
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1478
|
+
invalidateRuntimeConfigCache();
|
|
1477
1479
|
}
|
|
1478
1480
|
function emptyRuntimeConfig() {
|
|
1479
1481
|
return {
|
|
@@ -1487,6 +1489,9 @@ function emptyRuntimeConfig() {
|
|
|
1487
1489
|
scenario_rules: {}
|
|
1488
1490
|
};
|
|
1489
1491
|
}
|
|
1492
|
+
function invalidateRuntimeConfigCache() {
|
|
1493
|
+
runtimeConfigCache = null;
|
|
1494
|
+
}
|
|
1490
1495
|
function loadRuntimeConfig() {
|
|
1491
1496
|
const p = getRuntimeConfigPath();
|
|
1492
1497
|
if (!existsSync4(p)) {
|
|
@@ -1498,9 +1503,14 @@ function loadRuntimeConfig() {
|
|
|
1498
1503
|
return seeded;
|
|
1499
1504
|
}
|
|
1500
1505
|
try {
|
|
1506
|
+
const st = statSync(p);
|
|
1507
|
+
const cacheKey = `${p}|${st.mtimeMs}|${st.size}`;
|
|
1508
|
+
if (runtimeConfigCache && runtimeConfigCache.key === cacheKey) {
|
|
1509
|
+
return runtimeConfigCache.value;
|
|
1510
|
+
}
|
|
1501
1511
|
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1502
1512
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1503
|
-
|
|
1513
|
+
const result = {
|
|
1504
1514
|
version: data.version || 1,
|
|
1505
1515
|
layers: {
|
|
1506
1516
|
L1_heuristic: data.layers?.L1_heuristic ?? true,
|
|
@@ -1514,6 +1524,8 @@ function loadRuntimeConfig() {
|
|
|
1514
1524
|
agent_rules: merged.agent_rules || {},
|
|
1515
1525
|
scenario_rules: merged.scenario_rules || {}
|
|
1516
1526
|
};
|
|
1527
|
+
runtimeConfigCache = { key: cacheKey, value: result };
|
|
1528
|
+
return result;
|
|
1517
1529
|
} catch {
|
|
1518
1530
|
return emptyRuntimeConfig();
|
|
1519
1531
|
}
|
|
@@ -2503,7 +2515,7 @@ function updateScenarioCategoryEnabled(scenarioId, category, enabled) {
|
|
|
2503
2515
|
saveRuntimeConfig(runtime);
|
|
2504
2516
|
return runtime;
|
|
2505
2517
|
}
|
|
2506
|
-
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;
|
|
2518
|
+
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;
|
|
2507
2519
|
var init_runtime_config = __esm({
|
|
2508
2520
|
"src/infra/runtime-config.ts"() {
|
|
2509
2521
|
"use strict";
|
|
@@ -2533,6 +2545,7 @@ var init_runtime_config = __esm({
|
|
|
2533
2545
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2534
2546
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2535
2547
|
};
|
|
2548
|
+
runtimeConfigCache = null;
|
|
2536
2549
|
_AGENTS_DIR_PROD = join3(__dirname4, "agents");
|
|
2537
2550
|
_AGENTS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2538
2551
|
_SCENARIOS_DIR_PROD = join3(__dirname4, "scenarios");
|
|
@@ -2827,6 +2840,56 @@ function isInlineScriptCommand(actionDetail) {
|
|
|
2827
2840
|
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;
|
|
2828
2841
|
return re.test(actionDetail);
|
|
2829
2842
|
}
|
|
2843
|
+
function resolvePathTokens(segment) {
|
|
2844
|
+
const out = [];
|
|
2845
|
+
const low = segment.toLowerCase();
|
|
2846
|
+
for (const m of low.matchAll(HOME_PREFIX_RE)) {
|
|
2847
|
+
const prefix = m[0];
|
|
2848
|
+
const endIdx = (m.index ?? 0) + m[0].length;
|
|
2849
|
+
const tail = low.slice(endIdx);
|
|
2850
|
+
if (!tail || !(tail[0] === "/" || tail[0] === " ")) {
|
|
2851
|
+
out.push([prefix, prefix]);
|
|
2852
|
+
continue;
|
|
2853
|
+
}
|
|
2854
|
+
const token = tail.trim().split(/\s+/)[0] || "";
|
|
2855
|
+
if (!token.startsWith("/")) continue;
|
|
2856
|
+
const cleaned = token.replace(/\/+$/, "").replace(/^['"]|['"]$/g, "");
|
|
2857
|
+
const segments = cleaned.split("/").filter((s) => s && s !== ".");
|
|
2858
|
+
if (!segments.some((s) => s === "..")) continue;
|
|
2859
|
+
let depth = 0;
|
|
2860
|
+
const kept = [];
|
|
2861
|
+
let escaped = false;
|
|
2862
|
+
for (const s of segments) {
|
|
2863
|
+
if (s === "..") {
|
|
2864
|
+
depth -= 1;
|
|
2865
|
+
if (kept.length) kept.pop();
|
|
2866
|
+
if (depth < 0) {
|
|
2867
|
+
escaped = true;
|
|
2868
|
+
depth = 0;
|
|
2869
|
+
}
|
|
2870
|
+
} else {
|
|
2871
|
+
depth += 1;
|
|
2872
|
+
kept.push(s);
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
let resolved = kept.length ? "~/" + kept.join("/") : "~";
|
|
2876
|
+
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";
|
|
2877
|
+
out.push([prefix + token, resolved]);
|
|
2878
|
+
}
|
|
2879
|
+
return out;
|
|
2880
|
+
}
|
|
2881
|
+
function buildPathContext(actionDetail) {
|
|
2882
|
+
if (!PATH_CONTEXT_TRIGGER_RE.test(actionDetail)) return "";
|
|
2883
|
+
const stripped = stripLiteralTextSegments(actionDetail);
|
|
2884
|
+
const lines = [];
|
|
2885
|
+
for (const seg of splitCommandSegments(stripped)) {
|
|
2886
|
+
for (const [raw, lex] of resolvePathTokens(seg)) {
|
|
2887
|
+
lines.push(`- \u547D\u4EE4\u6BB5 \`${seg.trim().slice(0, 60)}\`\uFF1A\`${raw}\` \u8BCD\u6CD5\u89E3\u6790\u4E3A \`${lex}\``);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
if (!lines.length) return "";
|
|
2891
|
+
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";
|
|
2892
|
+
}
|
|
2830
2893
|
function stripLiteralTextSegments(actionDetail) {
|
|
2831
2894
|
const writeScriptExec = />\s*[/~]\S*\.(sh|py|pl|rb)\b/.test(actionDetail) && /(?:&&|\|\||;|\n|\|)\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)/.test(actionDetail);
|
|
2832
2895
|
const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)\b/.test(actionDetail);
|
|
@@ -3353,7 +3416,7 @@ function checkLateralMovement(actionDetail) {
|
|
|
3353
3416
|
}
|
|
3354
3417
|
return null;
|
|
3355
3418
|
}
|
|
3356
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
3419
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, PATH_CONTEXT_TRIGGER_RE, HOME_PREFIX_RE, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
3357
3420
|
var init_heuristic = __esm({
|
|
3358
3421
|
"src/engine/heuristic.ts"() {
|
|
3359
3422
|
"use strict";
|
|
@@ -3381,6 +3444,8 @@ var init_heuristic = __esm({
|
|
|
3381
3444
|
description: c.reason
|
|
3382
3445
|
}));
|
|
3383
3446
|
})();
|
|
3447
|
+
PATH_CONTEXT_TRIGGER_RE = /(?:^|[;&|]\s*)(?:rm|rmdir|unlink|ln|mv|cp|dd|truncate|shred|chmod|chown)\b/i;
|
|
3448
|
+
HOME_PREFIX_RE = /(?:~|~(?=\/)|\$HOME\b|\$\{HOME\}|\/home\/[a-z0-9_.-]+)/gi;
|
|
3384
3449
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
3385
3450
|
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
3386
3451
|
HOME_TARGET_RE = /(?:^|[\s="'($])(?:~|(?:\$home|\$\{home\}))(?:\/(?:\.\*|\*|\.)?)?(?=[\s"';}|&)]|$)/i;
|
|
@@ -5112,7 +5177,7 @@ var init_tracker = __esm({
|
|
|
5112
5177
|
});
|
|
5113
5178
|
|
|
5114
5179
|
// src/engine/script-content-analyzer.ts
|
|
5115
|
-
import { statSync as
|
|
5180
|
+
import { statSync as statSync3, existsSync as existsSync9 } from "fs";
|
|
5116
5181
|
import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
|
|
5117
5182
|
import { homedir as homedir4 } from "os";
|
|
5118
5183
|
function emptyChain() {
|
|
@@ -5226,7 +5291,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5226
5291
|
try {
|
|
5227
5292
|
const resolved = resolvePath2(tok.replace(/^['"]|['"]$/g, ""));
|
|
5228
5293
|
if (existsSync9(resolved)) {
|
|
5229
|
-
const stat =
|
|
5294
|
+
const stat = statSync3(resolved);
|
|
5230
5295
|
if (stat.isFile()) return resolved;
|
|
5231
5296
|
}
|
|
5232
5297
|
} catch {
|
|
@@ -5240,7 +5305,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5240
5305
|
try {
|
|
5241
5306
|
const resolved = resolvePath2(p);
|
|
5242
5307
|
if (existsSync9(resolved)) {
|
|
5243
|
-
const stat =
|
|
5308
|
+
const stat = statSync3(resolved);
|
|
5244
5309
|
if (stat.isFile()) return resolved;
|
|
5245
5310
|
}
|
|
5246
5311
|
} catch {
|
|
@@ -5256,7 +5321,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5256
5321
|
try {
|
|
5257
5322
|
resolved = resolvePath2(p);
|
|
5258
5323
|
if (existsSync9(resolved)) {
|
|
5259
|
-
const stat =
|
|
5324
|
+
const stat = statSync3(resolved);
|
|
5260
5325
|
if (stat.isFile()) return resolved;
|
|
5261
5326
|
}
|
|
5262
5327
|
} catch {
|
|
@@ -5733,7 +5798,7 @@ async function runLLMAnalysis(input, previous) {
|
|
|
5733
5798
|
} else {
|
|
5734
5799
|
scriptAnalysis = analyzeScriptContent(input.aNext.actionType, input.aNext.actionDetail);
|
|
5735
5800
|
}
|
|
5736
|
-
const prompt = buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, previous.skipL3Hints ?? "", scriptChainText);
|
|
5801
|
+
const prompt = buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, previous.skipL3Hints ?? "", scriptChainText, previous.pathContext ?? "");
|
|
5737
5802
|
logPrompt(prompt, input.aNext, previous.llmLogPath);
|
|
5738
5803
|
const result = await analyzeWithLLM(prompt, config);
|
|
5739
5804
|
if (llmCache.size >= LLM_CACHE_MAX) {
|
|
@@ -5757,7 +5822,7 @@ ${prompt}
|
|
|
5757
5822
|
console.warn("[AgentMoss] Failed to write LLM prompt to log:", e);
|
|
5758
5823
|
}
|
|
5759
5824
|
}
|
|
5760
|
-
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "") {
|
|
5825
|
+
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "", pathContext = "") {
|
|
5761
5826
|
const skillsText = formatSkillsForPrompt(matchedSkills);
|
|
5762
5827
|
const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
|
|
5763
5828
|
const promptHistoryText = formatPromptHistory(input.promptHistory);
|
|
@@ -5765,7 +5830,7 @@ function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis,
|
|
|
5765
5830
|
const hintsText = formatHints(previous);
|
|
5766
5831
|
const securityJudgeTemplate = templates["security_judge"];
|
|
5767
5832
|
if (securityJudgeTemplate) {
|
|
5768
|
-
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("}}", "}");
|
|
5833
|
+
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("}}", "}");
|
|
5769
5834
|
}
|
|
5770
5835
|
console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
|
|
5771
5836
|
return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
|
|
@@ -8186,6 +8251,21 @@ async function runAnalysis(input) {
|
|
|
8186
8251
|
if ((effectiveResult.riskLevel === "high" || effectiveResult.riskLevel === "critical") && (!skipInlineFileAccess || isCredentialPath)) {
|
|
8187
8252
|
return effectiveResult;
|
|
8188
8253
|
}
|
|
8254
|
+
} else {
|
|
8255
|
+
if (isInlineScriptCmd || isLiteralTextCmd) {
|
|
8256
|
+
const inlineJudgment = analyzeInlineScript(input.aNext.actionDetail);
|
|
8257
|
+
if (inlineJudgment.actionable && !inlineJudgment.allowed) {
|
|
8258
|
+
return {
|
|
8259
|
+
allowed: false,
|
|
8260
|
+
reason: inlineJudgment.reason,
|
|
8261
|
+
riskLevel: inlineJudgment.riskLevel,
|
|
8262
|
+
riskType: inlineJudgment.riskType,
|
|
8263
|
+
confidence: 90,
|
|
8264
|
+
source: "logic_rule",
|
|
8265
|
+
violatedLayers: ["L2.1"]
|
|
8266
|
+
};
|
|
8267
|
+
}
|
|
8268
|
+
}
|
|
8189
8269
|
}
|
|
8190
8270
|
if (isLogicRulesEnabled()) {
|
|
8191
8271
|
const formalSessions = [];
|
|
@@ -8287,12 +8367,14 @@ async function runAnalysis(input) {
|
|
|
8287
8367
|
}
|
|
8288
8368
|
let llmResult;
|
|
8289
8369
|
try {
|
|
8370
|
+
const pathContext = buildPathContext(input.aNext.actionDetail);
|
|
8290
8371
|
llmResult = await runLLMAnalysis(input, {
|
|
8291
8372
|
heuristic: heuristicResult,
|
|
8292
8373
|
logic: logicResult,
|
|
8293
8374
|
skipL3Hints,
|
|
8294
8375
|
scriptChain: scriptChain ?? void 0,
|
|
8295
|
-
llmLogPath: input.llmLogPath
|
|
8376
|
+
llmLogPath: input.llmLogPath,
|
|
8377
|
+
pathContext
|
|
8296
8378
|
});
|
|
8297
8379
|
} catch (e) {
|
|
8298
8380
|
const { getLLMFailMode: getLLMFailMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -10174,10 +10256,14 @@ function printHelp() {
|
|
|
10174
10256
|
|
|
10175
10257
|
Commands:
|
|
10176
10258
|
init Generate input.json template
|
|
10177
|
-
analyze <input>
|
|
10259
|
+
analyze <input> Analyze an input JSON file, or a raw shell command string
|
|
10260
|
+
e.g. agent-moss analyze "cat ~/.ssh/id_rsa" \u2192 prints Deny/Allow
|
|
10178
10261
|
server Start HTTP API server
|
|
10179
10262
|
install Install systemd service for AgentMoss
|
|
10180
10263
|
|
|
10264
|
+
Analyze options:
|
|
10265
|
+
--json Command mode: print the full JSON result instead of plain Deny/Allow
|
|
10266
|
+
|
|
10181
10267
|
Server options:
|
|
10182
10268
|
--host <host> Listen host (default: 127.0.0.1)
|
|
10183
10269
|
--port <port> Listen port (default: 9090, 0=auto assign)
|
|
@@ -10186,6 +10272,22 @@ Install options:
|
|
|
10186
10272
|
--enable Enable service on boot (systemctl enable)
|
|
10187
10273
|
`);
|
|
10188
10274
|
}
|
|
10275
|
+
async function analyzeRawCommand(command, useJson = false) {
|
|
10276
|
+
const { runAnalysis: runAnalysis2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
|
|
10277
|
+
const result = await runAnalysis2({
|
|
10278
|
+
sessionId: "cli-command",
|
|
10279
|
+
promptSession: "",
|
|
10280
|
+
actionHistory: [],
|
|
10281
|
+
aNext: { actionType: "bash", actionDetail: command },
|
|
10282
|
+
reason: "",
|
|
10283
|
+
osType: process.platform === "win32" ? "windows" : "linux",
|
|
10284
|
+
cwd: process.cwd(),
|
|
10285
|
+
agentId: ""
|
|
10286
|
+
});
|
|
10287
|
+
if (useJson) console.log(JSON.stringify(result, null, 2));
|
|
10288
|
+
else console.log(result.allowed ? "Allow" : "Deny");
|
|
10289
|
+
return result.allowed ? 0 : 1;
|
|
10290
|
+
}
|
|
10189
10291
|
async function main() {
|
|
10190
10292
|
const args = process.argv.slice(2);
|
|
10191
10293
|
const command = args[0];
|
|
@@ -10211,14 +10313,33 @@ async function main() {
|
|
|
10211
10313
|
break;
|
|
10212
10314
|
}
|
|
10213
10315
|
case "analyze": {
|
|
10214
|
-
|
|
10215
|
-
|
|
10316
|
+
const target = args[1];
|
|
10317
|
+
if (!target) {
|
|
10318
|
+
console.error('Usage: agent-moss analyze <input.json | "shell command">');
|
|
10216
10319
|
process.exit(1);
|
|
10217
10320
|
}
|
|
10218
10321
|
const fs7 = await import("fs");
|
|
10219
10322
|
const path6 = await import("path");
|
|
10220
10323
|
const { runAnalysis: runAnalysis2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
|
|
10221
|
-
const
|
|
10324
|
+
const useJson = args.includes("--json");
|
|
10325
|
+
const osType = process.platform === "win32" ? "windows" : "linux";
|
|
10326
|
+
const isFile = fs7.existsSync(target) && fs7.statSync(target).isFile();
|
|
10327
|
+
if (!isFile) {
|
|
10328
|
+
if (fs7.existsSync(target)) {
|
|
10329
|
+
console.error(`\u9519\u8BEF: \u4E0D\u662F\u6587\u4EF6: ${target}`);
|
|
10330
|
+
process.exit(2);
|
|
10331
|
+
}
|
|
10332
|
+
if (/\.(json|ya?ml|toml)$/i.test(target)) {
|
|
10333
|
+
console.error(`\u9519\u8BEF: \u6587\u4EF6\u4E0D\u5B58\u5728: ${target}`);
|
|
10334
|
+
process.exit(2);
|
|
10335
|
+
}
|
|
10336
|
+
if (!target.trim()) {
|
|
10337
|
+
console.error("\u9519\u8BEF: \u8F93\u5165\u4E3A\u7A7A\uFF08\u8BF7\u7ED9 JSON \u6587\u4EF6\u8DEF\u5F84\u6216 shell \u547D\u4EE4\uFF09");
|
|
10338
|
+
process.exit(2);
|
|
10339
|
+
}
|
|
10340
|
+
process.exit(await analyzeRawCommand(target, useJson));
|
|
10341
|
+
}
|
|
10342
|
+
const filePath = path6.resolve(target);
|
|
10222
10343
|
const data = JSON.parse(fs7.readFileSync(filePath, "utf-8"));
|
|
10223
10344
|
const result = await runAnalysis2({
|
|
10224
10345
|
sessionId: data.session_id || "unknown",
|
|
@@ -10430,6 +10551,9 @@ if (isMain) {
|
|
|
10430
10551
|
process.exit(1);
|
|
10431
10552
|
});
|
|
10432
10553
|
}
|
|
10554
|
+
export {
|
|
10555
|
+
analyzeRawCommand
|
|
10556
|
+
};
|
|
10433
10557
|
//! 顺序即 fail-closed 短路优先级:verify 逐个执行,首个返回违规的性质成为
|
|
10434
10558
|
//! first_violation,后续不再评估。调整顺序影响判定归属,须与 Python
|
|
10435
10559
|
//! properties.py ALL_PROPERTIES 保持一致并双端测试确认。
|