@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 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
- return JSON.parse(readFileSync2(p, "utf-8")) || {};
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 cached = hasRuntimeConfigCache.get(key);
2362
- if (cached !== void 0) return cached;
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
- try {
3620
- const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
3621
- if (raw) {
3622
- const parsed = JSON.parse(raw);
3623
- if (Array.isArray(parsed)) {
3624
- for (const r of parsed) {
3625
- if (r && r.pattern && r.action) rules.push({ pattern: r.pattern, action: r.action, severity: r.severity || "high" });
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
- if (cache.has(agentId)) return cache.get(agentId) ?? null;
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
- if (cache2.has(scenarioId)) return cache2.get(scenarioId) ?? null;
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 cached = llmCache.get(cacheKey);
7324
- if (cached) {
7432
+ const cached2 = llmCache.get(cacheKey);
7433
+ if (cached2) {
7325
7434
  console.log("[AgentMoss] LLM cache hit");
7326
- return cached;
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 cached = cache3.get(input.sessionId, input.promptSession);
11077
- if (cached !== null) {
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, cached);
11080
- const res = allowResult(cached, judgment);
11081
- mossLog.logResult("Allow", res.reason, cached);
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 = loadRuntimeConfig();
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 = loadRuntimeConfig();
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 = loadRuntimeConfig();
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 = loadRuntimeConfig();
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 = [userPath, builtinDir ? join15(builtinDir, `${skillId}.md`) : ""].filter(Boolean);
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 = loadRuntimeConfig();
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(loadRuntimeConfig());
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 = loadRuntimeConfig();
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
- console.log(`runtime \u914D\u7F6E: ${getRuntimeConfigPath()}`);
12305
- const layerKeys = ["L1_heuristic", "L2_logic_rules", "L3_llm_analysis", "agent_rules_enabled", "scenario_rules_enabled"];
12306
- console.log("\u5C42\u7EA7\u5F00\u5173: " + layerKeys.map((k) => `${k}=${isLayerEnabled(k) ? "on" : "OFF"}`).join(" "));
12307
- try {
12308
- const dirs = rulesDirs().filter((d) => existsSync19(d));
12309
- if (dirs.length > 0) {
12310
- console.log(`\u89C4\u5219\u76EE\u5F55: ${dirs.join(", ")}\uFF08\u53EA\u8BFB\u5176\u4E2D ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09`);
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
- `\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:`
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
- for (const f of ignored) console.error(` ${f}`);
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