@kenhkl/agent-moss 0.16.12 → 0.16.13
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/README.md +3 -0
- package/dist/cli.js +213 -65
- package/dist/data/agent_moss.service +4 -0
- package/dist/engine/coordinator.js +134 -25
- package/dist/server.js +213 -65
- package/dist/static/index.html +26 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,9 @@ const result = await resp.json();
|
|
|
105
105
|
| `AGENT_MOSS_DISABLE_HEURISTIC` | 设为 `1` 禁用层1 特征匹配 | 未设置 |
|
|
106
106
|
| `AGENT_MOSS_DISABLE_LOGIC_RULES` | 设为 `1` 禁用层2 逻辑规则 | 未设置 |
|
|
107
107
|
| `AGENT_MOSS_CUSTOM_RULES` | 自定义规则 JSON 数组 | `[]` |
|
|
108
|
+
| `AGENT_MOSS_RULES_MODE` | 规则来源模式:`hot`(默认)/ `cold`(冷启动:启动时读规则目录并冻结,runtime/Console 不参与)/ `builtin`(仅内置)。非法值按 builtin fail-safe | 未设置(hot)|
|
|
109
|
+
| `AGENT_MOSS_RULES_BUILTIN_ONLY` | 设为 `1` = builtin(仅内置)| 未设置 |
|
|
110
|
+
| `AGENT_MOSS_DISABLE_RULE_HOT_RELOAD` | 设为 `1` = cold(禁用 runtime/Console 热加载,但启动时仍读规则目录)| 未设置 |
|
|
108
111
|
|
|
109
112
|
### 自定义规则
|
|
110
113
|
|
package/dist/cli.js
CHANGED
|
@@ -488,6 +488,52 @@ var init_runtime_config_bridge = __esm({
|
|
|
488
488
|
}
|
|
489
489
|
});
|
|
490
490
|
|
|
491
|
+
// src/infra/rules-mode.ts
|
|
492
|
+
function truthy(name) {
|
|
493
|
+
return TRUTHY.has((process.env[name] || "").trim().toLowerCase());
|
|
494
|
+
}
|
|
495
|
+
function getRulesMode() {
|
|
496
|
+
if (cached !== null) return cached;
|
|
497
|
+
const raw = (process.env[ENV_RULES_MODE] || "").trim().toLowerCase();
|
|
498
|
+
if (raw) {
|
|
499
|
+
if (VALID_MODES.has(raw)) {
|
|
500
|
+
cached = raw;
|
|
501
|
+
} else {
|
|
502
|
+
console.error(
|
|
503
|
+
`[AgentMoss] ${ENV_RULES_MODE}=${JSON.stringify(raw)} \u975E\u6CD5\uFF08\u53EA\u652F\u6301 hot / cold / builtin\uFF09\uFF1B\u4E3A\u5B89\u5168\u8D77\u89C1\u6309 builtin\uFF08\u4EC5\u5185\u7F6E\u89C4\u5219\uFF09\u5904\u7406`
|
|
504
|
+
);
|
|
505
|
+
cached = "builtin";
|
|
506
|
+
}
|
|
507
|
+
return cached;
|
|
508
|
+
}
|
|
509
|
+
if (truthy(ENV_RULES_BUILTIN_ONLY)) cached = "builtin";
|
|
510
|
+
else if (truthy(ENV_DISABLE_RULE_HOT_RELOAD)) cached = "cold";
|
|
511
|
+
else cached = "hot";
|
|
512
|
+
return cached;
|
|
513
|
+
}
|
|
514
|
+
function isHotReloadEnabled() {
|
|
515
|
+
return getRulesMode() === "hot";
|
|
516
|
+
}
|
|
517
|
+
function isRuntimeConfigDisabled() {
|
|
518
|
+
return getRulesMode() !== "hot";
|
|
519
|
+
}
|
|
520
|
+
function isBuiltinOnly() {
|
|
521
|
+
return getRulesMode() === "builtin";
|
|
522
|
+
}
|
|
523
|
+
var ENV_RULES_MODE, ENV_RULES_BUILTIN_ONLY, ENV_DISABLE_RULE_HOT_RELOAD, TRUTHY, VALID_MODES, cached;
|
|
524
|
+
var init_rules_mode = __esm({
|
|
525
|
+
"src/infra/rules-mode.ts"() {
|
|
526
|
+
"use strict";
|
|
527
|
+
init_esm_shims();
|
|
528
|
+
ENV_RULES_MODE = "AGENT_MOSS_RULES_MODE";
|
|
529
|
+
ENV_RULES_BUILTIN_ONLY = "AGENT_MOSS_RULES_BUILTIN_ONLY";
|
|
530
|
+
ENV_DISABLE_RULE_HOT_RELOAD = "AGENT_MOSS_DISABLE_RULE_HOT_RELOAD";
|
|
531
|
+
TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
532
|
+
VALID_MODES = /* @__PURE__ */ new Set(["hot", "cold", "builtin"]);
|
|
533
|
+
cached = null;
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
|
|
491
537
|
// src/infra/rules-loader.ts
|
|
492
538
|
import { readFileSync as readFileSync2, existsSync, readdirSync, statSync } from "fs";
|
|
493
539
|
import { resolve, dirname, join as join2 } from "path";
|
|
@@ -501,6 +547,7 @@ function parseDirEnv(envName) {
|
|
|
501
547
|
return raw.split(/[,;]/).map((s) => s.trim()).filter(Boolean).map((s) => resolve(s));
|
|
502
548
|
}
|
|
503
549
|
function rulesDirs() {
|
|
550
|
+
if (isBuiltinOnly()) return [];
|
|
504
551
|
const dirs = [];
|
|
505
552
|
for (const env of RULES_DIR_ENVS) dirs.push(...parseDirEnv(env));
|
|
506
553
|
dirs.push(resolve(dataRootDir(), "rules"));
|
|
@@ -517,10 +564,16 @@ function resolveRulesFile(name) {
|
|
|
517
564
|
return findRulesFile(name);
|
|
518
565
|
}
|
|
519
566
|
function loadJson(name) {
|
|
567
|
+
if (!isHotReloadEnabled()) {
|
|
568
|
+
const cached2 = frozenJsonCache.get(name);
|
|
569
|
+
if (cached2 !== void 0) return cached2;
|
|
570
|
+
}
|
|
520
571
|
const p = findRulesFile(name);
|
|
521
572
|
if (!p) return {};
|
|
522
573
|
try {
|
|
523
|
-
|
|
574
|
+
const parsed = JSON.parse(readFileSync2(p, "utf-8")) || {};
|
|
575
|
+
if (!isHotReloadEnabled()) frozenJsonCache.set(name, parsed);
|
|
576
|
+
return parsed;
|
|
524
577
|
} catch {
|
|
525
578
|
return {};
|
|
526
579
|
}
|
|
@@ -845,6 +898,7 @@ function scanRuleDirs() {
|
|
|
845
898
|
return { override, extra, loaded, ignored };
|
|
846
899
|
}
|
|
847
900
|
function rulesCached() {
|
|
901
|
+
if (!isHotReloadEnabled() && _RULES_CACHE) return _RULES_CACHE;
|
|
848
902
|
const dirs = rulesDirs();
|
|
849
903
|
const sig = RULES_DIR_ENVS.map((e) => `${e}=${process.env[e] || ""}`).join("|") + "|" + dirs.join("|");
|
|
850
904
|
const files = [];
|
|
@@ -880,9 +934,11 @@ function identicalToBuiltin(override) {
|
|
|
880
934
|
return Object.keys(override).length > 0;
|
|
881
935
|
}
|
|
882
936
|
function loadOverrideRules() {
|
|
937
|
+
if (isBuiltinOnly()) return {};
|
|
883
938
|
return rulesCached().override;
|
|
884
939
|
}
|
|
885
940
|
function loadExtraRules() {
|
|
941
|
+
if (isBuiltinOnly()) return {};
|
|
886
942
|
return rulesCached().extra;
|
|
887
943
|
}
|
|
888
944
|
function ruleFilesLoaded() {
|
|
@@ -891,12 +947,13 @@ function ruleFilesLoaded() {
|
|
|
891
947
|
function ignoredRuleFiles() {
|
|
892
948
|
return rulesCached().ignored;
|
|
893
949
|
}
|
|
894
|
-
var __filename2, __dirname2, OVERRIDE_FILENAME, EXTRA_FILENAME, RULES_DIR_ENVS, RULES_DIR_CANDS, SCENARIO_LIST_KEYS, EXTRA_CATEGORIES, STRUCT_KEYS, EXTRA_FLAT_FIELD, _RULES_CACHE, warnedIgnored;
|
|
950
|
+
var __filename2, __dirname2, OVERRIDE_FILENAME, EXTRA_FILENAME, RULES_DIR_ENVS, RULES_DIR_CANDS, frozenJsonCache, SCENARIO_LIST_KEYS, EXTRA_CATEGORIES, STRUCT_KEYS, EXTRA_FLAT_FIELD, _RULES_CACHE, warnedIgnored;
|
|
895
951
|
var init_rules_loader = __esm({
|
|
896
952
|
"src/infra/rules-loader.ts"() {
|
|
897
953
|
"use strict";
|
|
898
954
|
init_esm_shims();
|
|
899
955
|
init_paths();
|
|
956
|
+
init_rules_mode();
|
|
900
957
|
init_runtime_config_bridge();
|
|
901
958
|
__filename2 = fileURLToPath2(import.meta.url);
|
|
902
959
|
__dirname2 = dirname(__filename2);
|
|
@@ -919,6 +976,7 @@ var init_rules_loader = __esm({
|
|
|
919
976
|
];
|
|
920
977
|
return cands.filter((c) => existsSync(c));
|
|
921
978
|
})();
|
|
979
|
+
frozenJsonCache = /* @__PURE__ */ new Map();
|
|
922
980
|
SCENARIO_LIST_KEYS = ["extra_command_patterns", "extra_injection_keywords", "extra_sensitive_paths"];
|
|
923
981
|
EXTRA_CATEGORIES = {
|
|
924
982
|
dangerous_commands: ["pattern"],
|
|
@@ -2001,6 +2059,7 @@ function userSkillsDir() {
|
|
|
2001
2059
|
return resolve3(getDataRoot(), "agent_moss_skills");
|
|
2002
2060
|
}
|
|
2003
2061
|
function runtimeCustomSkillKeywords() {
|
|
2062
|
+
if (isRuntimeConfigDisabled()) return {};
|
|
2004
2063
|
try {
|
|
2005
2064
|
const rt = runtimeConfigBridge.current?.loadRuntimeConfig?.();
|
|
2006
2065
|
if (!rt) return {};
|
|
@@ -2018,6 +2077,7 @@ function runtimeCustomSkillKeywords() {
|
|
|
2018
2077
|
}
|
|
2019
2078
|
}
|
|
2020
2079
|
function loadUserSkill(name) {
|
|
2080
|
+
if (isRuntimeConfigDisabled()) return "";
|
|
2021
2081
|
if (userSkillCache[name] !== void 0) return userSkillCache[name];
|
|
2022
2082
|
try {
|
|
2023
2083
|
const p = resolve3(userSkillsDir(), `${name}.md`);
|
|
@@ -2086,6 +2146,7 @@ var init_skill_loader = __esm({
|
|
|
2086
2146
|
init_esm_shims();
|
|
2087
2147
|
init_rules_loader();
|
|
2088
2148
|
init_paths();
|
|
2149
|
+
init_rules_mode();
|
|
2089
2150
|
init_asset_dir();
|
|
2090
2151
|
init_runtime_config_bridge();
|
|
2091
2152
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
@@ -2146,6 +2207,7 @@ __export(runtime_config_exports, {
|
|
|
2146
2207
|
getEnabledScenarioExtensions: () => getEnabledScenarioExtensions,
|
|
2147
2208
|
getEnvOverrides: () => getEnvOverrides,
|
|
2148
2209
|
getProfileOrDetect: () => getProfileOrDetect,
|
|
2210
|
+
getRuleSourceFingerprint: () => getRuleSourceFingerprint,
|
|
2149
2211
|
getRuntimeConfigPath: () => getRuntimeConfigPath,
|
|
2150
2212
|
getScenarioRules: () => getScenarioRules,
|
|
2151
2213
|
hasRuntimeConfig: () => hasRuntimeConfig,
|
|
@@ -2180,7 +2242,22 @@ function getRuntimeConfigPath() {
|
|
|
2180
2242
|
if (envPath) return envPath;
|
|
2181
2243
|
return RUNTIME_CONFIG_PATH;
|
|
2182
2244
|
}
|
|
2245
|
+
function getRuleSourceFingerprint() {
|
|
2246
|
+
if (isRuntimeConfigDisabled()) return `mode:${getRulesMode()}`;
|
|
2247
|
+
const p = getRuntimeConfigPath();
|
|
2248
|
+
try {
|
|
2249
|
+
const st = statSync2(p);
|
|
2250
|
+
return `${p}|${st.mtimeMs}|${st.size}`;
|
|
2251
|
+
} catch {
|
|
2252
|
+
return `${p}|absent`;
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2183
2255
|
function saveRuntimeConfig(config) {
|
|
2256
|
+
if (isRuntimeConfigDisabled()) {
|
|
2257
|
+
throw new Error(
|
|
2258
|
+
`\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF1A\u4FEE\u6539\u89C4\u5219\u4E0D\u4F1A\u751F\u6548\uFF0C\u8BF7\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u5E76\u91CD\u542F\u670D\u52A1\u3002`
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2184
2261
|
const p = getRuntimeConfigPath();
|
|
2185
2262
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
2186
2263
|
if (dir && !existsSync5(dir)) mkdirSync(dir, { recursive: true });
|
|
@@ -2204,6 +2281,18 @@ function invalidateRuntimeConfigCache() {
|
|
|
2204
2281
|
hasRuntimeConfigCache.clear();
|
|
2205
2282
|
}
|
|
2206
2283
|
function loadRuntimeConfig() {
|
|
2284
|
+
if (isRuntimeConfigDisabled()) {
|
|
2285
|
+
return {
|
|
2286
|
+
version: 1,
|
|
2287
|
+
layers: { ...DEFAULT_LAYERS },
|
|
2288
|
+
L1_rules: {},
|
|
2289
|
+
L2_rules: {},
|
|
2290
|
+
L3_skills: {},
|
|
2291
|
+
L2_2: {},
|
|
2292
|
+
agent_rules: {},
|
|
2293
|
+
scenario_rules: {}
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2207
2296
|
const p = getRuntimeConfigPath();
|
|
2208
2297
|
if (!existsSync5(p)) {
|
|
2209
2298
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
@@ -2250,6 +2339,7 @@ function loadRuntimeConfig() {
|
|
|
2250
2339
|
function isLayerEnabled(layerKey) {
|
|
2251
2340
|
const disableKey = LAYER_DISABLE_ENV[layerKey];
|
|
2252
2341
|
if (disableKey && process.env[disableKey] === "1") return false;
|
|
2342
|
+
if (isRuntimeConfigDisabled()) return true;
|
|
2253
2343
|
const runtime = loadRuntimeConfig();
|
|
2254
2344
|
const layers = runtime.layers || {};
|
|
2255
2345
|
if (layerKey in layers) return !!layers[layerKey];
|
|
@@ -2350,6 +2440,7 @@ function getEnabledL2SensitivePaths(runtime, osType) {
|
|
|
2350
2440
|
});
|
|
2351
2441
|
}
|
|
2352
2442
|
function hasRuntimeConfig() {
|
|
2443
|
+
if (isRuntimeConfigDisabled()) return false;
|
|
2353
2444
|
const p = getRuntimeConfigPath();
|
|
2354
2445
|
let key;
|
|
2355
2446
|
try {
|
|
@@ -2358,8 +2449,8 @@ function hasRuntimeConfig() {
|
|
|
2358
2449
|
} catch {
|
|
2359
2450
|
return false;
|
|
2360
2451
|
}
|
|
2361
|
-
const
|
|
2362
|
-
if (
|
|
2452
|
+
const cached2 = hasRuntimeConfigCache.get(key);
|
|
2453
|
+
if (cached2 !== void 0) return cached2;
|
|
2363
2454
|
let ok = false;
|
|
2364
2455
|
try {
|
|
2365
2456
|
JSON.parse(readFileSync4(p, "utf-8"));
|
|
@@ -3239,6 +3330,11 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
3239
3330
|
}
|
|
3240
3331
|
function addCustomSkill(skillId, category, keywords, content) {
|
|
3241
3332
|
_validateSkillId(skillId);
|
|
3333
|
+
if (isRuntimeConfigDisabled()) {
|
|
3334
|
+
throw new Error(
|
|
3335
|
+
`\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF0C\u4E0D\u5141\u8BB8\u65B0\u589E\u81EA\u5B9A\u4E49 skill\u3002`
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3242
3338
|
const runtime = loadRuntimeConfig();
|
|
3243
3339
|
const skillsDir = join3(getRuntimeConfigDir(), "agent_moss_skills");
|
|
3244
3340
|
try {
|
|
@@ -3465,6 +3561,7 @@ var init_runtime_config = __esm({
|
|
|
3465
3561
|
init_skill_loader();
|
|
3466
3562
|
init_rules_loader();
|
|
3467
3563
|
init_runtime_config_bridge();
|
|
3564
|
+
init_rules_mode();
|
|
3468
3565
|
__dirname4 = dirname3(fileURLToPath4(import.meta.url));
|
|
3469
3566
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
3470
3567
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
@@ -3536,6 +3633,7 @@ __export(config_exports, {
|
|
|
3536
3633
|
isPolicyGenEnabled: () => isPolicyGenEnabled,
|
|
3537
3634
|
isPolicySaveEnabled: () => isPolicySaveEnabled,
|
|
3538
3635
|
probeLLMConnection: () => probeLLMConnection,
|
|
3636
|
+
reloadCustomRules: () => reloadCustomRules,
|
|
3539
3637
|
updateLLMConfig: () => updateLLMConfig,
|
|
3540
3638
|
userRuleVariantPattern: () => userRuleVariantPattern,
|
|
3541
3639
|
wildcardToRegExp: () => wildcardToRegExp
|
|
@@ -3616,17 +3714,19 @@ function wildcardToRegExp(pattern) {
|
|
|
3616
3714
|
}
|
|
3617
3715
|
function loadCustomRules() {
|
|
3618
3716
|
const rules = [];
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3717
|
+
if (!isBuiltinOnly()) {
|
|
3718
|
+
try {
|
|
3719
|
+
const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
|
|
3720
|
+
if (raw) {
|
|
3721
|
+
const parsed = JSON.parse(raw);
|
|
3722
|
+
if (Array.isArray(parsed)) {
|
|
3723
|
+
for (const r of parsed) {
|
|
3724
|
+
if (r && r.pattern && r.action) rules.push({ pattern: r.pattern, action: r.action, severity: r.severity || "high" });
|
|
3725
|
+
}
|
|
3626
3726
|
}
|
|
3627
3727
|
}
|
|
3728
|
+
} catch {
|
|
3628
3729
|
}
|
|
3629
|
-
} catch {
|
|
3630
3730
|
}
|
|
3631
3731
|
for (const rulesPath of USER_RULES_PATHS) {
|
|
3632
3732
|
try {
|
|
@@ -3655,6 +3755,9 @@ function userRuleVariantPattern(pattern) {
|
|
|
3655
3755
|
}
|
|
3656
3756
|
return null;
|
|
3657
3757
|
}
|
|
3758
|
+
function reloadCustomRules() {
|
|
3759
|
+
customRules = loadCustomRules();
|
|
3760
|
+
}
|
|
3658
3761
|
function getLLMConfig() {
|
|
3659
3762
|
return llmConfig;
|
|
3660
3763
|
}
|
|
@@ -3742,6 +3845,7 @@ function layerEnabledOrDefault(key) {
|
|
|
3742
3845
|
}
|
|
3743
3846
|
}
|
|
3744
3847
|
function isBrainEnabled() {
|
|
3848
|
+
if (isRuntimeConfigDisabled()) return false;
|
|
3745
3849
|
return getAgentMossSetting("AGENT_MOSS_BRAIN_ENABLED", "") === "1";
|
|
3746
3850
|
}
|
|
3747
3851
|
function getAgentMossSetting(key, def = "") {
|
|
@@ -3783,6 +3887,7 @@ var init_config = __esm({
|
|
|
3783
3887
|
init_esm_shims();
|
|
3784
3888
|
init_paths();
|
|
3785
3889
|
init_runtime_config();
|
|
3890
|
+
init_rules_mode();
|
|
3786
3891
|
__configModuleDir = (() => {
|
|
3787
3892
|
try {
|
|
3788
3893
|
return path2.dirname(fileURLToPath5(import.meta.url));
|
|
@@ -3839,7 +3944,9 @@ function resolveAgentsDir() {
|
|
|
3839
3944
|
}
|
|
3840
3945
|
function getAgentExtensions(agentId) {
|
|
3841
3946
|
if (!agentId) return null;
|
|
3842
|
-
|
|
3947
|
+
const fp = getRuleSourceFingerprint();
|
|
3948
|
+
const cached2 = cache.get(agentId);
|
|
3949
|
+
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
3843
3950
|
let ext = null;
|
|
3844
3951
|
try {
|
|
3845
3952
|
if (hasRuntimeConfig()) {
|
|
@@ -3851,7 +3958,7 @@ function getAgentExtensions(agentId) {
|
|
|
3851
3958
|
const agentsDir = resolveAgentsDir();
|
|
3852
3959
|
const rulesFile = resolve4(agentsDir, agentId, "rules.json");
|
|
3853
3960
|
if (!existsSync6(rulesFile)) {
|
|
3854
|
-
cache.set(agentId, null);
|
|
3961
|
+
cache.set(agentId, { fp, ext: null });
|
|
3855
3962
|
return null;
|
|
3856
3963
|
}
|
|
3857
3964
|
try {
|
|
@@ -3859,16 +3966,16 @@ function getAgentExtensions(agentId) {
|
|
|
3859
3966
|
ext = JSON.parse(raw);
|
|
3860
3967
|
if (!ext.agent_id) {
|
|
3861
3968
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
3862
|
-
cache.set(agentId, null);
|
|
3969
|
+
cache.set(agentId, { fp, ext: null });
|
|
3863
3970
|
return null;
|
|
3864
3971
|
}
|
|
3865
3972
|
} catch (e) {
|
|
3866
3973
|
console.error(`[AgentMoss agents] \u52A0\u8F7D agent ${agentId} rules.json \u5931\u8D25:`, e.message);
|
|
3867
|
-
cache.set(agentId, null);
|
|
3974
|
+
cache.set(agentId, { fp, ext: null });
|
|
3868
3975
|
return null;
|
|
3869
3976
|
}
|
|
3870
3977
|
}
|
|
3871
|
-
cache.set(agentId, ext);
|
|
3978
|
+
cache.set(agentId, { fp, ext });
|
|
3872
3979
|
console.error(
|
|
3873
3980
|
`[AgentMoss agents] \u52A0\u8F7D agent ${agentId} \u5B9A\u5236\u89C4\u5219: ${ext.extra_command_patterns?.length ?? 0} cmd patterns, ${ext.extra_injection_keywords?.length ?? 0} injection keywords, ${ext.extra_sensitive_paths?.length ?? 0} sensitive paths, ${ext.builtin_safe_skills?.length ?? 0} builtin safe skills, ${ext.builtin_safe_action_types?.length ?? 0} builtin safe action types`
|
|
3874
3981
|
);
|
|
@@ -3914,7 +4021,9 @@ function resolveScenariosDir() {
|
|
|
3914
4021
|
}
|
|
3915
4022
|
function getScenarioExtensions(scenarioId) {
|
|
3916
4023
|
if (!scenarioId) return null;
|
|
3917
|
-
|
|
4024
|
+
const fp = getRuleSourceFingerprint();
|
|
4025
|
+
const cached2 = cache2.get(scenarioId);
|
|
4026
|
+
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
3918
4027
|
let ext = null;
|
|
3919
4028
|
let overrideHit = null;
|
|
3920
4029
|
try {
|
|
@@ -3938,7 +4047,7 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3938
4047
|
);
|
|
3939
4048
|
}
|
|
3940
4049
|
if (!existsSync7(rulesFile)) {
|
|
3941
|
-
cache2.set(scenarioId, null);
|
|
4050
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3942
4051
|
return null;
|
|
3943
4052
|
}
|
|
3944
4053
|
try {
|
|
@@ -3947,7 +4056,7 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3947
4056
|
const id = data.scenario_id || data.agent_id || "";
|
|
3948
4057
|
if (!id) {
|
|
3949
4058
|
console.warn(`[AgentMoss scenarios] rules.json \u7F3A\u5C11 scenario_id \u5B57\u6BB5: ${rulesFile}`);
|
|
3950
|
-
cache2.set(scenarioId, null);
|
|
4059
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3951
4060
|
return null;
|
|
3952
4061
|
}
|
|
3953
4062
|
ext = {
|
|
@@ -3962,11 +4071,11 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3962
4071
|
};
|
|
3963
4072
|
} catch (e) {
|
|
3964
4073
|
console.error(`[AgentMoss scenarios] \u52A0\u8F7D\u573A\u666F ${scenarioId} rules.json \u5931\u8D25:`, e.message);
|
|
3965
|
-
cache2.set(scenarioId, null);
|
|
4074
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3966
4075
|
return null;
|
|
3967
4076
|
}
|
|
3968
4077
|
}
|
|
3969
|
-
cache2.set(scenarioId, ext);
|
|
4078
|
+
cache2.set(scenarioId, { fp, ext });
|
|
3970
4079
|
console.error(
|
|
3971
4080
|
`[AgentMoss scenarios] \u52A0\u8F7D\u573A\u666F ${scenarioId} \u5B9A\u5236\u89C4\u5219: ${ext.extra_command_patterns?.length ?? 0} cmd patterns, ${ext.extra_injection_keywords?.length ?? 0} injection keywords, ${ext.extra_sensitive_paths?.length ?? 0} sensitive paths`
|
|
3972
4081
|
);
|
|
@@ -7320,10 +7429,10 @@ async function runLLMAnalysis(input, previous) {
|
|
|
7320
7429
|
const config = input.llmConfig?.apiKey ? { ...globalConfig, ...input.llmConfig } : globalConfig;
|
|
7321
7430
|
const rawDetail = input.aNext.actionDetail.replace(/^terminal-\w+:\s*command=([^,]+).*/, "$1").trim();
|
|
7322
7431
|
const cacheKey = `${input.aNext.actionType}:${rawDetail || input.aNext.actionDetail}`;
|
|
7323
|
-
const
|
|
7324
|
-
if (
|
|
7432
|
+
const cached2 = llmCache.get(cacheKey);
|
|
7433
|
+
if (cached2) {
|
|
7325
7434
|
console.log("[AgentMoss] LLM cache hit");
|
|
7326
|
-
return
|
|
7435
|
+
return cached2;
|
|
7327
7436
|
}
|
|
7328
7437
|
const matchedSkills = matchSkills(input.aNext.actionType, input.aNext.actionDetail, input.reason);
|
|
7329
7438
|
const templates = loadTemplates();
|
|
@@ -11073,12 +11182,12 @@ async function analyzeInner(input, mossLog) {
|
|
|
11073
11182
|
}
|
|
11074
11183
|
const cache3 = getDefaultCache();
|
|
11075
11184
|
mossLog.startStep("step2_cache_lookup");
|
|
11076
|
-
const
|
|
11077
|
-
if (
|
|
11185
|
+
const cached2 = cache3.get(input.sessionId, input.promptSession);
|
|
11186
|
+
if (cached2 !== null) {
|
|
11078
11187
|
mossLog.endStep("step2_cache_lookup", "\u7F13\u5B58\u547D\u4E2D");
|
|
11079
|
-
savePolicyToFile(input.sessionId,
|
|
11080
|
-
const res = allowResult(
|
|
11081
|
-
mossLog.logResult("Allow", res.reason,
|
|
11188
|
+
savePolicyToFile(input.sessionId, cached2);
|
|
11189
|
+
const res = allowResult(cached2, judgment);
|
|
11190
|
+
mossLog.logResult("Allow", res.reason, cached2);
|
|
11082
11191
|
return res;
|
|
11083
11192
|
}
|
|
11084
11193
|
if (!isPolicyGenEnabled()) {
|
|
@@ -11931,9 +12040,23 @@ function authMiddleware() {
|
|
|
11931
12040
|
await next();
|
|
11932
12041
|
};
|
|
11933
12042
|
}
|
|
12043
|
+
function displayRuntimeConfig() {
|
|
12044
|
+
return isRuntimeConfigDisabled() ? generateSourceDefaults() : loadRuntimeConfig();
|
|
12045
|
+
}
|
|
12046
|
+
function builtinOnlyReadOnlyMiddleware() {
|
|
12047
|
+
return async (c, next) => {
|
|
12048
|
+
if (isRuntimeConfigDisabled() && !["GET", "HEAD", "OPTIONS"].includes(c.req.method)) {
|
|
12049
|
+
return c.json({
|
|
12050
|
+
detail: `\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF1AConsole \u53EA\u8BFB\uFF0C\u4FEE\u6539\u4E0D\u4F1A\u4FDD\u5B58\u3002\u8BF7\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u5E76\u91CD\u542F\u670D\u52A1\u540E\u518D\u6539\u89C4\u5219\u3002`
|
|
12051
|
+
}, 403);
|
|
12052
|
+
}
|
|
12053
|
+
await next();
|
|
12054
|
+
};
|
|
12055
|
+
}
|
|
11934
12056
|
function createConsoleRouter() {
|
|
11935
12057
|
const console2 = new Hono();
|
|
11936
12058
|
console2.use("/api/*", authMiddleware());
|
|
12059
|
+
console2.use("/api/*", builtinOnlyReadOnlyMiddleware());
|
|
11937
12060
|
const serveIndex = (c) => {
|
|
11938
12061
|
const indexFile = join15(STATIC_DIR, "index.html");
|
|
11939
12062
|
if (existsSync18(indexFile)) {
|
|
@@ -11944,8 +12067,8 @@ function createConsoleRouter() {
|
|
|
11944
12067
|
console2.get("/", serveIndex);
|
|
11945
12068
|
console2.get("", serveIndex);
|
|
11946
12069
|
console2.get("/api/layers", (c) => {
|
|
11947
|
-
const rc =
|
|
11948
|
-
return c.json({ layers: rc.layers, env_overrides: getEnvOverrides() });
|
|
12070
|
+
const rc = displayRuntimeConfig();
|
|
12071
|
+
return c.json({ layers: rc.layers, env_overrides: getEnvOverrides(), builtin_only: isBuiltinOnly(), rules_mode: getRulesMode() });
|
|
11949
12072
|
});
|
|
11950
12073
|
console2.put("/api/layers", async (c) => {
|
|
11951
12074
|
const body = await c.req.json();
|
|
@@ -11980,7 +12103,7 @@ function createConsoleRouter() {
|
|
|
11980
12103
|
const rules = mc.rules || [];
|
|
11981
12104
|
let catEnabled = true;
|
|
11982
12105
|
try {
|
|
11983
|
-
const rt =
|
|
12106
|
+
const rt = displayRuntimeConfig();
|
|
11984
12107
|
catEnabled = rt.L2_2?.ltl_rules?.category_enabled !== false;
|
|
11985
12108
|
} catch {
|
|
11986
12109
|
}
|
|
@@ -12036,7 +12159,7 @@ function createConsoleRouter() {
|
|
|
12036
12159
|
return rc;
|
|
12037
12160
|
}
|
|
12038
12161
|
console2.get("/api/rules", (c) => {
|
|
12039
|
-
const rc =
|
|
12162
|
+
const rc = displayRuntimeConfig();
|
|
12040
12163
|
const layer = c.req.query("layer");
|
|
12041
12164
|
const category = c.req.query("category");
|
|
12042
12165
|
const out = {};
|
|
@@ -12101,8 +12224,8 @@ function createConsoleRouter() {
|
|
|
12101
12224
|
return c.json(withL22View(rc));
|
|
12102
12225
|
});
|
|
12103
12226
|
console2.get("/api/skills", (c) => {
|
|
12104
|
-
const rc =
|
|
12105
|
-
return c.json(rc.L3_skills);
|
|
12227
|
+
const rc = displayRuntimeConfig();
|
|
12228
|
+
return c.json(rc.L3_skills || {});
|
|
12106
12229
|
});
|
|
12107
12230
|
console2.put("/api/skills/enabled", async (c) => {
|
|
12108
12231
|
const b = await c.req.json();
|
|
@@ -12134,7 +12257,10 @@ function createConsoleRouter() {
|
|
|
12134
12257
|
}
|
|
12135
12258
|
const userPath = join15(dirname12(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
12136
12259
|
const builtinDir = resolveAssetDir(__dirname10, "skills");
|
|
12137
|
-
const candidates = [
|
|
12260
|
+
const candidates = [
|
|
12261
|
+
...isRuntimeConfigDisabled() ? [] : [userPath],
|
|
12262
|
+
builtinDir ? join15(builtinDir, `${skillId}.md`) : ""
|
|
12263
|
+
].filter(Boolean);
|
|
12138
12264
|
for (const p of candidates) {
|
|
12139
12265
|
if (existsSync18(p)) {
|
|
12140
12266
|
return c.json({ skill_id: skillId, path: p, content: readFileSync18(p, "utf-8") });
|
|
@@ -12143,7 +12269,7 @@ function createConsoleRouter() {
|
|
|
12143
12269
|
return c.json({ detail: `skill ${skillId} \u4E0D\u5B58\u5728` }, 404);
|
|
12144
12270
|
});
|
|
12145
12271
|
console2.get("/api/agents", (c) => {
|
|
12146
|
-
const rc =
|
|
12272
|
+
const rc = displayRuntimeConfig();
|
|
12147
12273
|
return c.json({ agents: getAgentRules(rc) });
|
|
12148
12274
|
});
|
|
12149
12275
|
console2.put("/api/agents/rules/enabled", async (c) => {
|
|
@@ -12182,7 +12308,7 @@ function createConsoleRouter() {
|
|
|
12182
12308
|
});
|
|
12183
12309
|
const enabledScenarioIds = () => (process.env.AGENT_MOSS_SCENARIO || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
12184
12310
|
console2.get("/api/scenarios", (c) => {
|
|
12185
|
-
const all = getScenarioRules(
|
|
12311
|
+
const all = getScenarioRules(displayRuntimeConfig());
|
|
12186
12312
|
const enabled = enabledScenarioIds();
|
|
12187
12313
|
if (!enabled.length) return c.json({ scenarios: {}, enabled: [] });
|
|
12188
12314
|
const shown = {};
|
|
@@ -12224,8 +12350,8 @@ function createConsoleRouter() {
|
|
|
12224
12350
|
return c.json({ scenarios: getScenarioRules(rc), enabled: enabledScenarioIds() });
|
|
12225
12351
|
});
|
|
12226
12352
|
console2.get("/api/config", (c) => {
|
|
12227
|
-
const rc =
|
|
12228
|
-
return c.json({ ...rc, L2_2: getL22View() });
|
|
12353
|
+
const rc = displayRuntimeConfig();
|
|
12354
|
+
return c.json({ ...rc, L2_2: getL22View(), builtin_only: isBuiltinOnly(), rules_mode: getRulesMode() });
|
|
12229
12355
|
});
|
|
12230
12356
|
console2.get("/api/env-overrides", (c) => {
|
|
12231
12357
|
return c.json({ overrides: getEnvOverrides() });
|
|
@@ -12269,6 +12395,7 @@ var init_router = __esm({
|
|
|
12269
12395
|
init_token_stats();
|
|
12270
12396
|
init_rules_loader();
|
|
12271
12397
|
init_asset_dir();
|
|
12398
|
+
init_rules_mode();
|
|
12272
12399
|
__dirname10 = dirname12(fileURLToPath11(import.meta.url));
|
|
12273
12400
|
STATIC_DIR = join15(__dirname10, "static");
|
|
12274
12401
|
CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
@@ -12300,34 +12427,54 @@ import net from "net";
|
|
|
12300
12427
|
import { existsSync as existsSync19 } from "fs";
|
|
12301
12428
|
function logDeploymentSelfCheck() {
|
|
12302
12429
|
try {
|
|
12430
|
+
const mode = getRulesMode();
|
|
12431
|
+
const builtinOnly = isBuiltinOnly();
|
|
12432
|
+
const runtimeDisabled = isRuntimeConfigDisabled();
|
|
12303
12433
|
console.log("================ AgentMoss \u90E8\u7F72\u81EA\u68C0 ================");
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
}
|
|
12312
|
-
const loaded = ruleFilesLoaded();
|
|
12313
|
-
if (loaded.length > 0) {
|
|
12314
|
-
const ov = loadOverrideRules();
|
|
12315
|
-
const ex = loadExtraRules();
|
|
12316
|
-
console.error(`\u26A0\uFE0F \u5DF2\u4ECE\u89C4\u5219\u76EE\u5F55\u52A0\u8F7D ${loaded.length} \u4E2A\u6587\u4EF6\uFF08\u6574\u4EFD\u66FF\u6362 / \u8FFD\u52A0\uFF0C\u5185\u7F6E\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4EEC\u4E0A\u9762\uFF09:`);
|
|
12317
|
-
for (const f of loaded) console.error(` ${f}`);
|
|
12318
|
-
const ovs = Object.entries(ov).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
12319
|
-
if (ovs) console.error(` \u8986\u76D6\u7C7B\u522B: ${ovs}\uFF08**\u6574\u4EFD\u66FF\u6362**\uFF1A\u672A\u5217\u51FA\u7684\u5185\u7F6E\u89C4\u5219\u4E0D\u518D\u751F\u6548\uFF09`);
|
|
12320
|
-
const exs = Object.entries(ex).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
12321
|
-
if (exs) console.log(` \u8FFD\u52A0\u7C7B\u522B: ${exs}\uFF08\u5185\u7F6E\u4FDD\u7559\uFF0C\u8FFD\u52A0\u5728\u5176\u540E\u4E00\u8D77\u5224\u5B9A\uFF09`);
|
|
12322
|
-
}
|
|
12323
|
-
const ignored = ignoredRuleFiles();
|
|
12324
|
-
if (ignored.length > 0) {
|
|
12434
|
+
if (runtimeDisabled) {
|
|
12435
|
+
console.log(`runtime \u914D\u7F6E: ${getRuntimeConfigPath()}\uFF08**\u5DF2\u5FFD\u7565**\uFF1A\u89C4\u5219\u6765\u6E90\u6A21\u5F0F=${mode}\uFF09`);
|
|
12436
|
+
if (builtinOnly) {
|
|
12437
|
+
console.error(
|
|
12438
|
+
"\u89C4\u5219\u6765\u6E90: **\u4EC5\u5185\u7F6E** \u2014\u2014 \u4E0D\u8BFB runtime \u914D\u7F6E / Console \u81EA\u5B9A\u4E49 / \u89C4\u5219\u76EE\u5F55 / AGENT_MOSS_CUSTOM_RULES\uFF1B\u4E0D seed\u3001\u4E0D merge\u3001\u4E0D\u5199\u56DE\u3002"
|
|
12439
|
+
);
|
|
12440
|
+
} else {
|
|
12325
12441
|
console.error(
|
|
12326
|
-
|
|
12442
|
+
"\u89C4\u5219\u6765\u6E90: **\u51B7\u542F\u52A8\uFF08cold\uFF09** \u2014\u2014 \u542F\u52A8\u65F6\u8BFB\u53D6\u5185\u7F6E\u89C4\u5219 + \u89C4\u5219\u76EE\u5F55 / AGENT_MOSS_CUSTOM_RULES / \u573A\u666F\uFF0C\u4E4B\u540E\u51BB\u7ED3\uFF1B\u4E0D\u8BFB runtime \u914D\u7F6E / Console\uFF0C\u4E0D seed\u3001\u4E0D merge\u3001\u4E0D\u5199\u56DE\u3002"
|
|
12327
12443
|
);
|
|
12328
|
-
|
|
12444
|
+
console.error("\u89C4\u5219\u76EE\u5F55\u5185\u5BB9\u6539\u52A8\u9700\u91CD\u542F\u670D\u52A1\u624D\u751F\u6548\u3002");
|
|
12445
|
+
}
|
|
12446
|
+
console.error("Console: \u53EA\u8BFB\uFF08\u89C4\u5219\u5199\u63A5\u53E3\u8FD4\u56DE 403\uFF09\uFF1B\u4FEE\u6539\u89C4\u5219\u9700\u91CD\u542F\u670D\u52A1\u5E76\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u3002");
|
|
12447
|
+
} else {
|
|
12448
|
+
console.log(`runtime \u914D\u7F6E: ${getRuntimeConfigPath()}`);
|
|
12449
|
+
}
|
|
12450
|
+
const layerKeys = ["L1_heuristic", "L2_logic_rules", "L3_llm_analysis", "agent_rules_enabled", "scenario_rules_enabled"];
|
|
12451
|
+
console.log("\u5C42\u7EA7\u5F00\u5173: " + layerKeys.map((k) => `${k}=${isLayerEnabled(k) ? "on" : "OFF"}`).join(" "));
|
|
12452
|
+
if (!builtinOnly) {
|
|
12453
|
+
try {
|
|
12454
|
+
const dirs = rulesDirs().filter((d) => existsSync19(d));
|
|
12455
|
+
if (dirs.length > 0) {
|
|
12456
|
+
console.log(`\u89C4\u5219\u76EE\u5F55: ${dirs.join(", ")}\uFF08\u53EA\u8BFB\u5176\u4E2D ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09`);
|
|
12457
|
+
}
|
|
12458
|
+
const loaded = ruleFilesLoaded();
|
|
12459
|
+
if (loaded.length > 0) {
|
|
12460
|
+
const ov = loadOverrideRules();
|
|
12461
|
+
const ex = loadExtraRules();
|
|
12462
|
+
console.error(`\u26A0\uFE0F \u5DF2\u4ECE\u89C4\u5219\u76EE\u5F55\u52A0\u8F7D ${loaded.length} \u4E2A\u6587\u4EF6\uFF08\u6574\u4EFD\u66FF\u6362 / \u8FFD\u52A0\uFF0C\u5185\u7F6E\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4EEC\u4E0A\u9762\uFF09:`);
|
|
12463
|
+
for (const f of loaded) console.error(` ${f}`);
|
|
12464
|
+
const ovs = Object.entries(ov).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
12465
|
+
if (ovs) console.error(` \u8986\u76D6\u7C7B\u522B: ${ovs}\uFF08**\u6574\u4EFD\u66FF\u6362**\uFF1A\u672A\u5217\u51FA\u7684\u5185\u7F6E\u89C4\u5219\u4E0D\u518D\u751F\u6548\uFF09`);
|
|
12466
|
+
const exs = Object.entries(ex).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
12467
|
+
if (exs) console.log(` \u8FFD\u52A0\u7C7B\u522B: ${exs}\uFF08\u5185\u7F6E\u4FDD\u7559\uFF0C\u8FFD\u52A0\u5728\u5176\u540E\u4E00\u8D77\u5224\u5B9A\uFF09`);
|
|
12468
|
+
}
|
|
12469
|
+
const ignored = ignoredRuleFiles();
|
|
12470
|
+
if (ignored.length > 0) {
|
|
12471
|
+
console.error(
|
|
12472
|
+
`\u26A0\uFE0F \u89C4\u5219\u76EE\u5F55\u91CC\u6709 ${ignored.length} \u4E2A json **\u4E0D\u4F1A\u88AB\u8BFB\u53D6**\uFF08\u53EA\u8BA4 ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09:`
|
|
12473
|
+
);
|
|
12474
|
+
for (const f of ignored) console.error(` ${f}`);
|
|
12475
|
+
}
|
|
12476
|
+
} catch {
|
|
12329
12477
|
}
|
|
12330
|
-
} catch {
|
|
12331
12478
|
}
|
|
12332
12479
|
const scenarioRaw = (process.env.AGENT_MOSS_SCENARIO || "").trim();
|
|
12333
12480
|
if (scenarioRaw) {
|
|
@@ -12485,6 +12632,7 @@ var init_server = __esm({
|
|
|
12485
12632
|
init_routes();
|
|
12486
12633
|
init_console();
|
|
12487
12634
|
init_runtime_config();
|
|
12635
|
+
init_rules_mode();
|
|
12488
12636
|
init_rules_loader();
|
|
12489
12637
|
WARMUP_COMMANDS = {
|
|
12490
12638
|
linux: "whoami",
|
|
@@ -9,6 +9,10 @@ Restart=on-failure
|
|
|
9
9
|
RestartSec=5
|
|
10
10
|
Environment=PYTHONUNBUFFERED=1
|
|
11
11
|
EnvironmentFile=-/etc/agent_moss/agent_moss.env
|
|
12
|
+
# 规则来源模式:cold=冷启动(规则目录启动时读一次,忽略 runtime/Console)
|
|
13
|
+
# Environment=AGENT_MOSS_RULES_MODE=cold
|
|
14
|
+
# builtin=仅内置(连规则目录也不读)
|
|
15
|
+
# Environment=AGENT_MOSS_RULES_MODE=builtin
|
|
12
16
|
|
|
13
17
|
[Install]
|
|
14
18
|
WantedBy=multi-user.target
|