@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.
@@ -394,6 +394,52 @@ var init_runtime_config_bridge = __esm({
394
394
  }
395
395
  });
396
396
 
397
+ // src/infra/rules-mode.ts
398
+ function truthy(name) {
399
+ return TRUTHY.has((process.env[name] || "").trim().toLowerCase());
400
+ }
401
+ function getRulesMode() {
402
+ if (cached !== null) return cached;
403
+ const raw = (process.env[ENV_RULES_MODE] || "").trim().toLowerCase();
404
+ if (raw) {
405
+ if (VALID_MODES.has(raw)) {
406
+ cached = raw;
407
+ } else {
408
+ console.error(
409
+ `[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`
410
+ );
411
+ cached = "builtin";
412
+ }
413
+ return cached;
414
+ }
415
+ if (truthy(ENV_RULES_BUILTIN_ONLY)) cached = "builtin";
416
+ else if (truthy(ENV_DISABLE_RULE_HOT_RELOAD)) cached = "cold";
417
+ else cached = "hot";
418
+ return cached;
419
+ }
420
+ function isHotReloadEnabled() {
421
+ return getRulesMode() === "hot";
422
+ }
423
+ function isRuntimeConfigDisabled() {
424
+ return getRulesMode() !== "hot";
425
+ }
426
+ function isBuiltinOnly() {
427
+ return getRulesMode() === "builtin";
428
+ }
429
+ var ENV_RULES_MODE, ENV_RULES_BUILTIN_ONLY, ENV_DISABLE_RULE_HOT_RELOAD, TRUTHY, VALID_MODES, cached;
430
+ var init_rules_mode = __esm({
431
+ "src/infra/rules-mode.ts"() {
432
+ "use strict";
433
+ init_esm_shims();
434
+ ENV_RULES_MODE = "AGENT_MOSS_RULES_MODE";
435
+ ENV_RULES_BUILTIN_ONLY = "AGENT_MOSS_RULES_BUILTIN_ONLY";
436
+ ENV_DISABLE_RULE_HOT_RELOAD = "AGENT_MOSS_DISABLE_RULE_HOT_RELOAD";
437
+ TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
438
+ VALID_MODES = /* @__PURE__ */ new Set(["hot", "cold", "builtin"]);
439
+ cached = null;
440
+ }
441
+ });
442
+
397
443
  // src/infra/rules-loader.ts
398
444
  import { readFileSync as readFileSync2, existsSync, readdirSync, statSync } from "fs";
399
445
  import { resolve, dirname, join as join2 } from "path";
@@ -407,6 +453,7 @@ function parseDirEnv(envName) {
407
453
  return raw.split(/[,;]/).map((s) => s.trim()).filter(Boolean).map((s) => resolve(s));
408
454
  }
409
455
  function rulesDirs() {
456
+ if (isBuiltinOnly()) return [];
410
457
  const dirs = [];
411
458
  for (const env of RULES_DIR_ENVS) dirs.push(...parseDirEnv(env));
412
459
  dirs.push(resolve(dataRootDir(), "rules"));
@@ -420,10 +467,16 @@ function findRulesFile(name) {
420
467
  return null;
421
468
  }
422
469
  function loadJson(name) {
470
+ if (!isHotReloadEnabled()) {
471
+ const cached2 = frozenJsonCache.get(name);
472
+ if (cached2 !== void 0) return cached2;
473
+ }
423
474
  const p = findRulesFile(name);
424
475
  if (!p) return {};
425
476
  try {
426
- return JSON.parse(readFileSync2(p, "utf-8")) || {};
477
+ const parsed = JSON.parse(readFileSync2(p, "utf-8")) || {};
478
+ if (!isHotReloadEnabled()) frozenJsonCache.set(name, parsed);
479
+ return parsed;
427
480
  } catch {
428
481
  return {};
429
482
  }
@@ -748,6 +801,7 @@ function scanRuleDirs() {
748
801
  return { override, extra, loaded, ignored };
749
802
  }
750
803
  function rulesCached() {
804
+ if (!isHotReloadEnabled() && _RULES_CACHE) return _RULES_CACHE;
751
805
  const dirs = rulesDirs();
752
806
  const sig = RULES_DIR_ENVS.map((e) => `${e}=${process.env[e] || ""}`).join("|") + "|" + dirs.join("|");
753
807
  const files = [];
@@ -783,17 +837,20 @@ function identicalToBuiltin(override) {
783
837
  return Object.keys(override).length > 0;
784
838
  }
785
839
  function loadOverrideRules() {
840
+ if (isBuiltinOnly()) return {};
786
841
  return rulesCached().override;
787
842
  }
788
843
  function loadExtraRules() {
844
+ if (isBuiltinOnly()) return {};
789
845
  return rulesCached().extra;
790
846
  }
791
- 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;
847
+ 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;
792
848
  var init_rules_loader = __esm({
793
849
  "src/infra/rules-loader.ts"() {
794
850
  "use strict";
795
851
  init_esm_shims();
796
852
  init_paths();
853
+ init_rules_mode();
797
854
  init_runtime_config_bridge();
798
855
  __filename2 = fileURLToPath2(import.meta.url);
799
856
  __dirname2 = dirname(__filename2);
@@ -816,6 +873,7 @@ var init_rules_loader = __esm({
816
873
  ];
817
874
  return cands.filter((c) => existsSync(c));
818
875
  })();
876
+ frozenJsonCache = /* @__PURE__ */ new Map();
819
877
  SCENARIO_LIST_KEYS = ["extra_command_patterns", "extra_injection_keywords", "extra_sensitive_paths"];
820
878
  EXTRA_CATEGORIES = {
821
879
  dangerous_commands: ["pattern"],
@@ -1898,6 +1956,7 @@ function userSkillsDir() {
1898
1956
  return resolve3(getDataRoot(), "agent_moss_skills");
1899
1957
  }
1900
1958
  function runtimeCustomSkillKeywords() {
1959
+ if (isRuntimeConfigDisabled()) return {};
1901
1960
  try {
1902
1961
  const rt = runtimeConfigBridge.current?.loadRuntimeConfig?.();
1903
1962
  if (!rt) return {};
@@ -1915,6 +1974,7 @@ function runtimeCustomSkillKeywords() {
1915
1974
  }
1916
1975
  }
1917
1976
  function loadUserSkill(name) {
1977
+ if (isRuntimeConfigDisabled()) return "";
1918
1978
  if (userSkillCache[name] !== void 0) return userSkillCache[name];
1919
1979
  try {
1920
1980
  const p = resolve3(userSkillsDir(), `${name}.md`);
@@ -1983,6 +2043,7 @@ var init_skill_loader = __esm({
1983
2043
  init_esm_shims();
1984
2044
  init_rules_loader();
1985
2045
  init_paths();
2046
+ init_rules_mode();
1986
2047
  init_asset_dir();
1987
2048
  init_runtime_config_bridge();
1988
2049
  __filename3 = fileURLToPath3(import.meta.url);
@@ -2043,6 +2104,7 @@ __export(runtime_config_exports, {
2043
2104
  getEnabledScenarioExtensions: () => getEnabledScenarioExtensions,
2044
2105
  getEnvOverrides: () => getEnvOverrides,
2045
2106
  getProfileOrDetect: () => getProfileOrDetect,
2107
+ getRuleSourceFingerprint: () => getRuleSourceFingerprint,
2046
2108
  getRuntimeConfigPath: () => getRuntimeConfigPath,
2047
2109
  getScenarioRules: () => getScenarioRules,
2048
2110
  hasRuntimeConfig: () => hasRuntimeConfig,
@@ -2077,7 +2139,22 @@ function getRuntimeConfigPath() {
2077
2139
  if (envPath) return envPath;
2078
2140
  return RUNTIME_CONFIG_PATH;
2079
2141
  }
2142
+ function getRuleSourceFingerprint() {
2143
+ if (isRuntimeConfigDisabled()) return `mode:${getRulesMode()}`;
2144
+ const p = getRuntimeConfigPath();
2145
+ try {
2146
+ const st = statSync2(p);
2147
+ return `${p}|${st.mtimeMs}|${st.size}`;
2148
+ } catch {
2149
+ return `${p}|absent`;
2150
+ }
2151
+ }
2080
2152
  function saveRuntimeConfig(config) {
2153
+ if (isRuntimeConfigDisabled()) {
2154
+ throw new Error(
2155
+ `\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`
2156
+ );
2157
+ }
2081
2158
  const p = getRuntimeConfigPath();
2082
2159
  const dir = p.substring(0, p.lastIndexOf("/"));
2083
2160
  if (dir && !existsSync5(dir)) mkdirSync(dir, { recursive: true });
@@ -2101,6 +2178,18 @@ function invalidateRuntimeConfigCache() {
2101
2178
  hasRuntimeConfigCache.clear();
2102
2179
  }
2103
2180
  function loadRuntimeConfig() {
2181
+ if (isRuntimeConfigDisabled()) {
2182
+ return {
2183
+ version: 1,
2184
+ layers: { ...DEFAULT_LAYERS },
2185
+ L1_rules: {},
2186
+ L2_rules: {},
2187
+ L3_skills: {},
2188
+ L2_2: {},
2189
+ agent_rules: {},
2190
+ scenario_rules: {}
2191
+ };
2192
+ }
2104
2193
  const p = getRuntimeConfigPath();
2105
2194
  if (!existsSync5(p)) {
2106
2195
  const seeded = mergeConfig({}, generateSourceDefaults());
@@ -2147,6 +2236,7 @@ function loadRuntimeConfig() {
2147
2236
  function isLayerEnabled(layerKey) {
2148
2237
  const disableKey = LAYER_DISABLE_ENV[layerKey];
2149
2238
  if (disableKey && process.env[disableKey] === "1") return false;
2239
+ if (isRuntimeConfigDisabled()) return true;
2150
2240
  const runtime = loadRuntimeConfig();
2151
2241
  const layers = runtime.layers || {};
2152
2242
  if (layerKey in layers) return !!layers[layerKey];
@@ -2247,6 +2337,7 @@ function getEnabledL2SensitivePaths(runtime, osType) {
2247
2337
  });
2248
2338
  }
2249
2339
  function hasRuntimeConfig() {
2340
+ if (isRuntimeConfigDisabled()) return false;
2250
2341
  const p = getRuntimeConfigPath();
2251
2342
  let key;
2252
2343
  try {
@@ -2255,8 +2346,8 @@ function hasRuntimeConfig() {
2255
2346
  } catch {
2256
2347
  return false;
2257
2348
  }
2258
- const cached = hasRuntimeConfigCache.get(key);
2259
- if (cached !== void 0) return cached;
2349
+ const cached2 = hasRuntimeConfigCache.get(key);
2350
+ if (cached2 !== void 0) return cached2;
2260
2351
  let ok = false;
2261
2352
  try {
2262
2353
  JSON.parse(readFileSync4(p, "utf-8"));
@@ -3136,6 +3227,11 @@ function deleteCustomRule(layer, category, ruleId) {
3136
3227
  }
3137
3228
  function addCustomSkill(skillId, category, keywords, content) {
3138
3229
  _validateSkillId(skillId);
3230
+ if (isRuntimeConfigDisabled()) {
3231
+ throw new Error(
3232
+ `\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`
3233
+ );
3234
+ }
3139
3235
  const runtime = loadRuntimeConfig();
3140
3236
  const skillsDir = join3(getRuntimeConfigDir(), "agent_moss_skills");
3141
3237
  try {
@@ -3362,6 +3458,7 @@ var init_runtime_config = __esm({
3362
3458
  init_skill_loader();
3363
3459
  init_rules_loader();
3364
3460
  init_runtime_config_bridge();
3461
+ init_rules_mode();
3365
3462
  __dirname4 = dirname3(fileURLToPath4(import.meta.url));
3366
3463
  ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
3367
3464
  RUNTIME_CONFIG_DIR = runtimeDir();
@@ -3433,6 +3530,7 @@ __export(config_exports, {
3433
3530
  isPolicyGenEnabled: () => isPolicyGenEnabled,
3434
3531
  isPolicySaveEnabled: () => isPolicySaveEnabled,
3435
3532
  probeLLMConnection: () => probeLLMConnection,
3533
+ reloadCustomRules: () => reloadCustomRules,
3436
3534
  updateLLMConfig: () => updateLLMConfig,
3437
3535
  userRuleVariantPattern: () => userRuleVariantPattern,
3438
3536
  wildcardToRegExp: () => wildcardToRegExp
@@ -3513,17 +3611,19 @@ function wildcardToRegExp(pattern) {
3513
3611
  }
3514
3612
  function loadCustomRules() {
3515
3613
  const rules = [];
3516
- try {
3517
- const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
3518
- if (raw) {
3519
- const parsed = JSON.parse(raw);
3520
- if (Array.isArray(parsed)) {
3521
- for (const r of parsed) {
3522
- if (r && r.pattern && r.action) rules.push({ pattern: r.pattern, action: r.action, severity: r.severity || "high" });
3614
+ if (!isBuiltinOnly()) {
3615
+ try {
3616
+ const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
3617
+ if (raw) {
3618
+ const parsed = JSON.parse(raw);
3619
+ if (Array.isArray(parsed)) {
3620
+ for (const r of parsed) {
3621
+ if (r && r.pattern && r.action) rules.push({ pattern: r.pattern, action: r.action, severity: r.severity || "high" });
3622
+ }
3523
3623
  }
3524
3624
  }
3625
+ } catch {
3525
3626
  }
3526
- } catch {
3527
3627
  }
3528
3628
  for (const rulesPath of USER_RULES_PATHS) {
3529
3629
  try {
@@ -3552,6 +3652,9 @@ function userRuleVariantPattern(pattern) {
3552
3652
  }
3553
3653
  return null;
3554
3654
  }
3655
+ function reloadCustomRules() {
3656
+ customRules = loadCustomRules();
3657
+ }
3555
3658
  function getLLMConfig() {
3556
3659
  return llmConfig;
3557
3660
  }
@@ -3639,6 +3742,7 @@ function layerEnabledOrDefault(key) {
3639
3742
  }
3640
3743
  }
3641
3744
  function isBrainEnabled() {
3745
+ if (isRuntimeConfigDisabled()) return false;
3642
3746
  return getAgentMossSetting("AGENT_MOSS_BRAIN_ENABLED", "") === "1";
3643
3747
  }
3644
3748
  function getAgentMossSetting(key, def = "") {
@@ -3680,6 +3784,7 @@ var init_config = __esm({
3680
3784
  init_esm_shims();
3681
3785
  init_paths();
3682
3786
  init_runtime_config();
3787
+ init_rules_mode();
3683
3788
  __configModuleDir = (() => {
3684
3789
  try {
3685
3790
  return path2.dirname(fileURLToPath5(import.meta.url));
@@ -3736,7 +3841,9 @@ function resolveAgentsDir() {
3736
3841
  }
3737
3842
  function getAgentExtensions(agentId) {
3738
3843
  if (!agentId) return null;
3739
- if (cache.has(agentId)) return cache.get(agentId) ?? null;
3844
+ const fp = getRuleSourceFingerprint();
3845
+ const cached2 = cache.get(agentId);
3846
+ if (cached2 && cached2.fp === fp) return cached2.ext;
3740
3847
  let ext = null;
3741
3848
  try {
3742
3849
  if (hasRuntimeConfig()) {
@@ -3748,7 +3855,7 @@ function getAgentExtensions(agentId) {
3748
3855
  const agentsDir = resolveAgentsDir();
3749
3856
  const rulesFile = resolve4(agentsDir, agentId, "rules.json");
3750
3857
  if (!existsSync6(rulesFile)) {
3751
- cache.set(agentId, null);
3858
+ cache.set(agentId, { fp, ext: null });
3752
3859
  return null;
3753
3860
  }
3754
3861
  try {
@@ -3756,16 +3863,16 @@ function getAgentExtensions(agentId) {
3756
3863
  ext = JSON.parse(raw);
3757
3864
  if (!ext.agent_id) {
3758
3865
  console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
3759
- cache.set(agentId, null);
3866
+ cache.set(agentId, { fp, ext: null });
3760
3867
  return null;
3761
3868
  }
3762
3869
  } catch (e) {
3763
3870
  console.error(`[AgentMoss agents] \u52A0\u8F7D agent ${agentId} rules.json \u5931\u8D25:`, e.message);
3764
- cache.set(agentId, null);
3871
+ cache.set(agentId, { fp, ext: null });
3765
3872
  return null;
3766
3873
  }
3767
3874
  }
3768
- cache.set(agentId, ext);
3875
+ cache.set(agentId, { fp, ext });
3769
3876
  console.error(
3770
3877
  `[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`
3771
3878
  );
@@ -3811,7 +3918,9 @@ function resolveScenariosDir() {
3811
3918
  }
3812
3919
  function getScenarioExtensions(scenarioId) {
3813
3920
  if (!scenarioId) return null;
3814
- if (cache2.has(scenarioId)) return cache2.get(scenarioId) ?? null;
3921
+ const fp = getRuleSourceFingerprint();
3922
+ const cached2 = cache2.get(scenarioId);
3923
+ if (cached2 && cached2.fp === fp) return cached2.ext;
3815
3924
  let ext = null;
3816
3925
  let overrideHit = null;
3817
3926
  try {
@@ -3835,7 +3944,7 @@ function getScenarioExtensions(scenarioId) {
3835
3944
  );
3836
3945
  }
3837
3946
  if (!existsSync7(rulesFile)) {
3838
- cache2.set(scenarioId, null);
3947
+ cache2.set(scenarioId, { fp, ext: null });
3839
3948
  return null;
3840
3949
  }
3841
3950
  try {
@@ -3844,7 +3953,7 @@ function getScenarioExtensions(scenarioId) {
3844
3953
  const id = data.scenario_id || data.agent_id || "";
3845
3954
  if (!id) {
3846
3955
  console.warn(`[AgentMoss scenarios] rules.json \u7F3A\u5C11 scenario_id \u5B57\u6BB5: ${rulesFile}`);
3847
- cache2.set(scenarioId, null);
3956
+ cache2.set(scenarioId, { fp, ext: null });
3848
3957
  return null;
3849
3958
  }
3850
3959
  ext = {
@@ -3859,11 +3968,11 @@ function getScenarioExtensions(scenarioId) {
3859
3968
  };
3860
3969
  } catch (e) {
3861
3970
  console.error(`[AgentMoss scenarios] \u52A0\u8F7D\u573A\u666F ${scenarioId} rules.json \u5931\u8D25:`, e.message);
3862
- cache2.set(scenarioId, null);
3971
+ cache2.set(scenarioId, { fp, ext: null });
3863
3972
  return null;
3864
3973
  }
3865
3974
  }
3866
- cache2.set(scenarioId, ext);
3975
+ cache2.set(scenarioId, { fp, ext });
3867
3976
  console.error(
3868
3977
  `[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`
3869
3978
  );
@@ -7184,10 +7293,10 @@ async function runLLMAnalysis(input, previous) {
7184
7293
  const config = input.llmConfig?.apiKey ? { ...globalConfig, ...input.llmConfig } : globalConfig;
7185
7294
  const rawDetail = input.aNext.actionDetail.replace(/^terminal-\w+:\s*command=([^,]+).*/, "$1").trim();
7186
7295
  const cacheKey = `${input.aNext.actionType}:${rawDetail || input.aNext.actionDetail}`;
7187
- const cached = llmCache.get(cacheKey);
7188
- if (cached) {
7296
+ const cached2 = llmCache.get(cacheKey);
7297
+ if (cached2) {
7189
7298
  console.log("[AgentMoss] LLM cache hit");
7190
- return cached;
7299
+ return cached2;
7191
7300
  }
7192
7301
  const matchedSkills = matchSkills(input.aNext.actionType, input.aNext.actionDetail, input.reason);
7193
7302
  const templates = loadTemplates();