@kenhkl/agent-moss 0.15.5 → 0.15.7

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.js CHANGED
@@ -408,6 +408,9 @@ function isLiteralTextCommand(command) {
408
408
  return false;
409
409
  }
410
410
  }
411
+ if (/\|\s*\b(?:tee|tac|install)\b/i.test(command)) {
412
+ return false;
413
+ }
411
414
  return true;
412
415
  }
413
416
  function extractInlineCode(command) {
@@ -1308,22 +1311,45 @@ var init_logic_rules = __esm({
1308
1311
  }
1309
1312
  });
1310
1313
 
1314
+ // src/engine/asset-dir.ts
1315
+ import { existsSync as existsSync3 } from "fs";
1316
+ import { resolve as resolve2 } from "path";
1317
+ function assetDirCandidates(moduleDir, name) {
1318
+ return [
1319
+ resolve2(moduleDir, name),
1320
+ resolve2(moduleDir, "../../..", "agent_moss", name)
1321
+ ];
1322
+ }
1323
+ function resolveAssetDir(moduleDir, name) {
1324
+ for (const dir of assetDirCandidates(moduleDir, name)) {
1325
+ if (existsSync3(dir)) return dir;
1326
+ }
1327
+ return null;
1328
+ }
1329
+ var init_asset_dir = __esm({
1330
+ "src/engine/asset-dir.ts"() {
1331
+ "use strict";
1332
+ init_esm_shims();
1333
+ }
1334
+ });
1335
+
1311
1336
  // src/engine/skill-loader.ts
1312
- import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
1313
- import { resolve as resolve2, dirname as dirname2 } from "path";
1337
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
1338
+ import { resolve as resolve3, dirname as dirname2 } from "path";
1314
1339
  import { fileURLToPath as fileURLToPath4 } from "url";
1315
1340
  function loadAllSkills() {
1316
1341
  if (cachedSkills) return cachedSkills;
1317
1342
  cachedSkills = {};
1318
- const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
1319
- if (!existsSync3(dir)) {
1320
- console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
1343
+ const dir = resolveAssetDir(__dirname3, "skills");
1344
+ if (!dir) {
1345
+ const [primary, fallback] = assetDirCandidates(__dirname3, "skills");
1346
+ console.warn("[AgentMoss] Skills directory not found:", primary, "and fallback:", fallback);
1321
1347
  return cachedSkills;
1322
1348
  }
1323
1349
  const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
1324
1350
  for (const f of files) {
1325
1351
  const name = f.replace(".md", "");
1326
- cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
1352
+ cachedSkills[name] = readFileSync3(resolve3(dir, f), "utf-8");
1327
1353
  }
1328
1354
  console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
1329
1355
  return cachedSkills;
@@ -1377,16 +1403,15 @@ function formatSkillsForPrompt(skills) {
1377
1403
  ${s.skillContent}`
1378
1404
  ).join("\n\n---\n\n");
1379
1405
  }
1380
- var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
1406
+ var __filename3, __dirname3, SKILL_KEYWORD_MAP, cachedSkills;
1381
1407
  var init_skill_loader = __esm({
1382
1408
  "src/engine/skill-loader.ts"() {
1383
1409
  "use strict";
1384
1410
  init_esm_shims();
1385
1411
  init_rules_loader();
1412
+ init_asset_dir();
1386
1413
  __filename3 = fileURLToPath4(import.meta.url);
1387
1414
  __dirname3 = dirname2(__filename3);
1388
- SKILLS_DIR = resolve2(__dirname3, "../skills");
1389
- SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
1390
1415
  SKILL_KEYWORD_MAP = (() => {
1391
1416
  const map = {};
1392
1417
  const cats = loadL3();
@@ -2556,7 +2581,7 @@ var init_runtime_config = __esm({
2556
2581
 
2557
2582
  // src/agents/index.ts
2558
2583
  import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2559
- import { resolve as resolve3, dirname as dirname4 } from "path";
2584
+ import { resolve as resolve4, dirname as dirname4 } from "path";
2560
2585
  import { fileURLToPath as fileURLToPath6 } from "url";
2561
2586
  function resolveAgentsDir() {
2562
2587
  if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
@@ -2576,7 +2601,7 @@ function getAgentExtensions(agentId) {
2576
2601
  }
2577
2602
  if (ext === null) {
2578
2603
  const agentsDir = resolveAgentsDir();
2579
- const rulesFile = resolve3(agentsDir, agentId, "rules.json");
2604
+ const rulesFile = resolve4(agentsDir, agentId, "rules.json");
2580
2605
  if (!existsSync5(rulesFile)) {
2581
2606
  cache.set(agentId, null);
2582
2607
  return null;
@@ -2623,15 +2648,15 @@ var init_agents = __esm({
2623
2648
  init_esm_shims();
2624
2649
  __filename4 = fileURLToPath6(import.meta.url);
2625
2650
  __dirname5 = dirname4(__filename4);
2626
- AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
2627
- AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
2651
+ AGENTS_DIR_PROD = resolve4(__dirname5, "agents");
2652
+ AGENTS_DIR_DEV_FALLBACK = resolve4(__dirname5, "../../../agent_moss/agents");
2628
2653
  cache = /* @__PURE__ */ new Map();
2629
2654
  }
2630
2655
  });
2631
2656
 
2632
2657
  // src/scenarios/index.ts
2633
2658
  import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
2634
- import { resolve as resolve4, dirname as dirname5 } from "path";
2659
+ import { resolve as resolve5, dirname as dirname5 } from "path";
2635
2660
  import { fileURLToPath as fileURLToPath7 } from "url";
2636
2661
  function resolveScenariosDir() {
2637
2662
  if (existsSync6(SCENARIOS_DIR_PROD)) return SCENARIOS_DIR_PROD;
@@ -2651,7 +2676,7 @@ function getScenarioExtensions(scenarioId) {
2651
2676
  }
2652
2677
  if (ext === null) {
2653
2678
  const scenariosDir = resolveScenariosDir();
2654
- const rulesFile = resolve4(scenariosDir, scenarioId, "rules.json");
2679
+ const rulesFile = resolve5(scenariosDir, scenarioId, "rules.json");
2655
2680
  if (!existsSync6(rulesFile)) {
2656
2681
  cache2.set(scenarioId, null);
2657
2682
  return null;
@@ -2704,8 +2729,8 @@ var init_scenarios = __esm({
2704
2729
  init_agents();
2705
2730
  __filename5 = fileURLToPath7(import.meta.url);
2706
2731
  __dirname6 = dirname5(__filename5);
2707
- SCENARIOS_DIR_PROD = resolve4(__dirname6, "scenarios");
2708
- SCENARIOS_DIR_DEV_FALLBACK = resolve4(__dirname6, "../../../agent_moss/scenarios");
2732
+ SCENARIOS_DIR_PROD = resolve5(__dirname6, "scenarios");
2733
+ SCENARIOS_DIR_DEV_FALLBACK = resolve5(__dirname6, "../../../agent_moss/scenarios");
2709
2734
  cache2 = /* @__PURE__ */ new Map();
2710
2735
  }
2711
2736
  });
@@ -2892,7 +2917,7 @@ function buildPathContext(actionDetail) {
2892
2917
  }
2893
2918
  function stripLiteralTextSegments(actionDetail) {
2894
2919
  const writeScriptExec = />\s*[/~]\S*\.(sh|py|pl|rb)\b/.test(actionDetail) && /(?:&&|\|\||;|\n|\|)\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)/.test(actionDetail);
2895
- const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)\b/.test(actionDetail);
2920
+ const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node|crontab|at)\b/.test(actionDetail);
2896
2921
  if (writeScriptExec || pipeToInterpreter) {
2897
2922
  return actionDetail;
2898
2923
  }
@@ -3455,18 +3480,19 @@ var init_heuristic = __esm({
3455
3480
 
3456
3481
  // src/engine/template-loader.ts
3457
3482
  import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
3458
- import { resolve as resolve5, dirname as dirname6 } from "path";
3483
+ import { resolve as resolve6, dirname as dirname6 } from "path";
3459
3484
  import { fileURLToPath as fileURLToPath8 } from "url";
3460
3485
  function loadTemplates() {
3461
3486
  if (cachedTemplates) return cachedTemplates;
3462
3487
  cachedTemplates = {};
3463
- const dir = existsSync7(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
3464
- if (!existsSync7(dir)) {
3465
- console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
3488
+ const dir = resolveAssetDir(__dirname7, "templates");
3489
+ if (!dir) {
3490
+ const [primary, fallback] = assetDirCandidates(__dirname7, "templates");
3491
+ console.warn("[AgentMoss] Templates directory not found:", primary, "and fallback:", fallback);
3466
3492
  return cachedTemplates;
3467
3493
  }
3468
3494
  for (const file of TEMPLATE_FILES) {
3469
- const filePath = resolve5(dir, file);
3495
+ const filePath = resolve6(dir, file);
3470
3496
  if (existsSync7(filePath)) {
3471
3497
  const key = file.replace(".txt", "").replace("_template", "");
3472
3498
  cachedTemplates[key] = readFileSync7(filePath, "utf-8");
@@ -3475,15 +3501,14 @@ function loadTemplates() {
3475
3501
  console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
3476
3502
  return cachedTemplates;
3477
3503
  }
3478
- var __filename6, __dirname7, TEMPLATES_DIR, TEMPLATES_DIR_FALLBACK, TEMPLATE_FILES, cachedTemplates;
3504
+ var __filename6, __dirname7, TEMPLATE_FILES, cachedTemplates;
3479
3505
  var init_template_loader = __esm({
3480
3506
  "src/engine/template-loader.ts"() {
3481
3507
  "use strict";
3482
3508
  init_esm_shims();
3509
+ init_asset_dir();
3483
3510
  __filename6 = fileURLToPath8(import.meta.url);
3484
3511
  __dirname7 = dirname6(__filename6);
3485
- TEMPLATES_DIR = resolve5(__dirname7, "../templates");
3486
- TEMPLATES_DIR_FALLBACK = resolve5(__dirname7, "../../../agent_moss/templates");
3487
3512
  TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
3488
3513
  cachedTemplates = null;
3489
3514
  }
@@ -3491,7 +3516,7 @@ var init_template_loader = __esm({
3491
3516
 
3492
3517
  // src/engine/script-analyzer.ts
3493
3518
  import { readFileSync as readFileSync8 } from "fs";
3494
- import { resolve as resolve6, join as join4 } from "path";
3519
+ import { resolve as resolve7, join as join4 } from "path";
3495
3520
  function emptyResult() {
3496
3521
  return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
3497
3522
  }
@@ -3544,7 +3569,7 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
3544
3569
  }
3545
3570
  function readScriptContent(scriptPath, maxLines = 500) {
3546
3571
  try {
3547
- const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve6(scriptPath);
3572
+ const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve7(scriptPath);
3548
3573
  const raw = readFileSync8(expandedPath, "utf-8");
3549
3574
  const lines = raw.split("\n").slice(0, maxLines);
3550
3575
  return { content: lines.join("\n"), lineCount: lines.length, error: "" };
@@ -5178,7 +5203,7 @@ var init_tracker = __esm({
5178
5203
 
5179
5204
  // src/engine/script-content-analyzer.ts
5180
5205
  import { statSync as statSync3, existsSync as existsSync9 } from "fs";
5181
- import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
5206
+ import { resolve as resolve9, join as join6, isAbsolute as isAbsolute2 } from "path";
5182
5207
  import { homedir as homedir4 } from "os";
5183
5208
  function emptyChain() {
5184
5209
  return {
@@ -5334,7 +5359,7 @@ function resolvePath2(p) {
5334
5359
  if (expanded.startsWith("~/") || expanded === "~") {
5335
5360
  expanded = join6(homedir4(), expanded.slice(1));
5336
5361
  }
5337
- return resolve8(expanded);
5362
+ return resolve9(expanded);
5338
5363
  }
5339
5364
  function scanScriptChainWithL1(chain, input) {
5340
5365
  for (const node of chain.nodes) {
@@ -5976,7 +6001,7 @@ async function analyzeWithLLM(prompt, config) {
5976
6001
  }
5977
6002
  if (attempt < maxRetries) {
5978
6003
  console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
5979
- await new Promise((resolve9) => setTimeout(resolve9, retryCfg.retryInterval * 1e3));
6004
+ await new Promise((resolve10) => setTimeout(resolve10, retryCfg.retryInterval * 1e3));
5980
6005
  } else {
5981
6006
  clearTimeout(totalTimeoutTimer);
5982
6007
  console.error("[AgentMoss] LLM call failed after all retries:", err.message);
@@ -8914,13 +8939,13 @@ var require_backup = __commonJS({
8914
8939
  var runBackup = (backup, handler) => {
8915
8940
  let rate = 0;
8916
8941
  let useDefault = true;
8917
- return new Promise((resolve9, reject) => {
8942
+ return new Promise((resolve10, reject) => {
8918
8943
  setImmediate(function step() {
8919
8944
  try {
8920
8945
  const progress = backup.transfer(rate);
8921
8946
  if (!progress.remainingPages) {
8922
8947
  backup.close();
8923
- resolve9(progress);
8948
+ resolve10(progress);
8924
8949
  return;
8925
8950
  }
8926
8951
  if (useDefault) {
@@ -10219,12 +10244,12 @@ function createApp() {
10219
10244
  }
10220
10245
  async function findFreePort(startPort, host = "127.0.0.1", scan = 100) {
10221
10246
  for (let port = startPort; port < startPort + scan; port++) {
10222
- const free = await new Promise((resolve9) => {
10247
+ const free = await new Promise((resolve10) => {
10223
10248
  const server = net.createServer();
10224
10249
  server.listen(port, host, () => {
10225
- server.close(() => resolve9(true));
10250
+ server.close(() => resolve10(true));
10226
10251
  });
10227
- server.on("error", () => resolve9(false));
10252
+ server.on("error", () => resolve10(false));
10228
10253
  });
10229
10254
  if (free) {
10230
10255
  if (port !== startPort) {
@@ -10449,13 +10474,13 @@ async function main() {
10449
10474
  let version2 = "";
10450
10475
  for (let port = 9090; port <= 9095; port++) {
10451
10476
  try {
10452
- const data = await new Promise((resolve9, reject) => {
10477
+ const data = await new Promise((resolve10, reject) => {
10453
10478
  const req = http.get(`http://127.0.0.1:${port}/api/v1/health`, { timeout: 2e3 }, (res) => {
10454
10479
  let body = "";
10455
10480
  res.on("data", (chunk) => body += chunk);
10456
10481
  res.on("end", () => {
10457
10482
  try {
10458
- resolve9(JSON.parse(body));
10483
+ resolve10(JSON.parse(body));
10459
10484
  } catch {
10460
10485
  reject();
10461
10486
  }
@@ -10483,13 +10508,13 @@ async function main() {
10483
10508
  console.log(` Systemd: \u672A\u6CE8\u518C\uFF08\u8FD0\u884C agent-moss install --enable \u5B89\u88C5\uFF09`);
10484
10509
  }
10485
10510
  try {
10486
- const data = await new Promise((resolve9, reject) => {
10511
+ const data = await new Promise((resolve10, reject) => {
10487
10512
  const req = http.get(`http://127.0.0.1:${foundPort}/console/api/config`, { timeout: 3e3 }, (res) => {
10488
10513
  let body = "";
10489
10514
  res.on("data", (chunk) => body += chunk);
10490
10515
  res.on("end", () => {
10491
10516
  try {
10492
- resolve9(JSON.parse(body));
10517
+ resolve10(JSON.parse(body));
10493
10518
  } catch {
10494
10519
  reject();
10495
10520
  }
@@ -10567,4 +10592,3 @@ export {
10567
10592
  //! P6 mc-ltl-rules LTL 模型检测
10568
10593
  //! P7 low-integrity-command-exec 低完整性命令执行
10569
10594
  //! P8 sensitive-data-aggregation 敏感数据聚合外传
10570
- //# sourceMappingURL=cli.js.map
@@ -403,6 +403,9 @@ function isLiteralTextCommand(command) {
403
403
  return false;
404
404
  }
405
405
  }
406
+ if (/\|\s*\b(?:tee|tac|install)\b/i.test(command)) {
407
+ return false;
408
+ }
406
409
  return true;
407
410
  }
408
411
  function extractInlineCode(command) {
@@ -1303,22 +1306,45 @@ var init_logic_rules = __esm({
1303
1306
  }
1304
1307
  });
1305
1308
 
1309
+ // src/engine/asset-dir.ts
1310
+ import { existsSync as existsSync3 } from "fs";
1311
+ import { resolve as resolve2 } from "path";
1312
+ function assetDirCandidates(moduleDir, name) {
1313
+ return [
1314
+ resolve2(moduleDir, name),
1315
+ resolve2(moduleDir, "../../..", "agent_moss", name)
1316
+ ];
1317
+ }
1318
+ function resolveAssetDir(moduleDir, name) {
1319
+ for (const dir of assetDirCandidates(moduleDir, name)) {
1320
+ if (existsSync3(dir)) return dir;
1321
+ }
1322
+ return null;
1323
+ }
1324
+ var init_asset_dir = __esm({
1325
+ "src/engine/asset-dir.ts"() {
1326
+ "use strict";
1327
+ init_esm_shims();
1328
+ }
1329
+ });
1330
+
1306
1331
  // src/engine/skill-loader.ts
1307
- import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
1308
- import { resolve as resolve2, dirname as dirname2 } from "path";
1332
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2 } from "fs";
1333
+ import { resolve as resolve3, dirname as dirname2 } from "path";
1309
1334
  import { fileURLToPath as fileURLToPath4 } from "url";
1310
1335
  function loadAllSkills() {
1311
1336
  if (cachedSkills) return cachedSkills;
1312
1337
  cachedSkills = {};
1313
- const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
1314
- if (!existsSync3(dir)) {
1315
- console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
1338
+ const dir = resolveAssetDir(__dirname3, "skills");
1339
+ if (!dir) {
1340
+ const [primary, fallback] = assetDirCandidates(__dirname3, "skills");
1341
+ console.warn("[AgentMoss] Skills directory not found:", primary, "and fallback:", fallback);
1316
1342
  return cachedSkills;
1317
1343
  }
1318
1344
  const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
1319
1345
  for (const f of files) {
1320
1346
  const name = f.replace(".md", "");
1321
- cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
1347
+ cachedSkills[name] = readFileSync3(resolve3(dir, f), "utf-8");
1322
1348
  }
1323
1349
  console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
1324
1350
  return cachedSkills;
@@ -1372,16 +1398,15 @@ function formatSkillsForPrompt(skills) {
1372
1398
  ${s.skillContent}`
1373
1399
  ).join("\n\n---\n\n");
1374
1400
  }
1375
- var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
1401
+ var __filename3, __dirname3, SKILL_KEYWORD_MAP, cachedSkills;
1376
1402
  var init_skill_loader = __esm({
1377
1403
  "src/engine/skill-loader.ts"() {
1378
1404
  "use strict";
1379
1405
  init_esm_shims();
1380
1406
  init_rules_loader();
1407
+ init_asset_dir();
1381
1408
  __filename3 = fileURLToPath4(import.meta.url);
1382
1409
  __dirname3 = dirname2(__filename3);
1383
- SKILLS_DIR = resolve2(__dirname3, "../skills");
1384
- SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
1385
1410
  SKILL_KEYWORD_MAP = (() => {
1386
1411
  const map = {};
1387
1412
  const cats = loadL3();
@@ -2551,7 +2576,7 @@ var init_runtime_config = __esm({
2551
2576
 
2552
2577
  // src/agents/index.ts
2553
2578
  import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2554
- import { resolve as resolve3, dirname as dirname4 } from "path";
2579
+ import { resolve as resolve4, dirname as dirname4 } from "path";
2555
2580
  import { fileURLToPath as fileURLToPath6 } from "url";
2556
2581
  function resolveAgentsDir() {
2557
2582
  if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
@@ -2571,7 +2596,7 @@ function getAgentExtensions(agentId) {
2571
2596
  }
2572
2597
  if (ext === null) {
2573
2598
  const agentsDir = resolveAgentsDir();
2574
- const rulesFile = resolve3(agentsDir, agentId, "rules.json");
2599
+ const rulesFile = resolve4(agentsDir, agentId, "rules.json");
2575
2600
  if (!existsSync5(rulesFile)) {
2576
2601
  cache.set(agentId, null);
2577
2602
  return null;
@@ -2618,15 +2643,15 @@ var init_agents = __esm({
2618
2643
  init_esm_shims();
2619
2644
  __filename4 = fileURLToPath6(import.meta.url);
2620
2645
  __dirname5 = dirname4(__filename4);
2621
- AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
2622
- AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
2646
+ AGENTS_DIR_PROD = resolve4(__dirname5, "agents");
2647
+ AGENTS_DIR_DEV_FALLBACK = resolve4(__dirname5, "../../../agent_moss/agents");
2623
2648
  cache = /* @__PURE__ */ new Map();
2624
2649
  }
2625
2650
  });
2626
2651
 
2627
2652
  // src/scenarios/index.ts
2628
2653
  import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
2629
- import { resolve as resolve4, dirname as dirname5 } from "path";
2654
+ import { resolve as resolve5, dirname as dirname5 } from "path";
2630
2655
  import { fileURLToPath as fileURLToPath7 } from "url";
2631
2656
  function resolveScenariosDir() {
2632
2657
  if (existsSync6(SCENARIOS_DIR_PROD)) return SCENARIOS_DIR_PROD;
@@ -2646,7 +2671,7 @@ function getScenarioExtensions(scenarioId) {
2646
2671
  }
2647
2672
  if (ext === null) {
2648
2673
  const scenariosDir = resolveScenariosDir();
2649
- const rulesFile = resolve4(scenariosDir, scenarioId, "rules.json");
2674
+ const rulesFile = resolve5(scenariosDir, scenarioId, "rules.json");
2650
2675
  if (!existsSync6(rulesFile)) {
2651
2676
  cache2.set(scenarioId, null);
2652
2677
  return null;
@@ -2699,8 +2724,8 @@ var init_scenarios = __esm({
2699
2724
  init_agents();
2700
2725
  __filename5 = fileURLToPath7(import.meta.url);
2701
2726
  __dirname6 = dirname5(__filename5);
2702
- SCENARIOS_DIR_PROD = resolve4(__dirname6, "scenarios");
2703
- SCENARIOS_DIR_DEV_FALLBACK = resolve4(__dirname6, "../../../agent_moss/scenarios");
2727
+ SCENARIOS_DIR_PROD = resolve5(__dirname6, "scenarios");
2728
+ SCENARIOS_DIR_DEV_FALLBACK = resolve5(__dirname6, "../../../agent_moss/scenarios");
2704
2729
  cache2 = /* @__PURE__ */ new Map();
2705
2730
  }
2706
2731
  });
@@ -2887,7 +2912,7 @@ function buildPathContext(actionDetail) {
2887
2912
  }
2888
2913
  function stripLiteralTextSegments(actionDetail) {
2889
2914
  const writeScriptExec = />\s*[/~]\S*\.(sh|py|pl|rb)\b/.test(actionDetail) && /(?:&&|\|\||;|\n|\|)\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)/.test(actionDetail);
2890
- const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node)\b/.test(actionDetail);
2915
+ const pipeToInterpreter = /\|\s*(?:bash|sh|zsh|dash|python|perl|ruby|node|crontab|at)\b/.test(actionDetail);
2891
2916
  if (writeScriptExec || pipeToInterpreter) {
2892
2917
  return actionDetail;
2893
2918
  }
@@ -3636,25 +3661,25 @@ init_skill_loader();
3636
3661
 
3637
3662
  // src/engine/template-loader.ts
3638
3663
  init_esm_shims();
3664
+ init_asset_dir();
3639
3665
  import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
3640
- import { resolve as resolve5, dirname as dirname6 } from "path";
3666
+ import { resolve as resolve6, dirname as dirname6 } from "path";
3641
3667
  import { fileURLToPath as fileURLToPath8 } from "url";
3642
3668
  var __filename6 = fileURLToPath8(import.meta.url);
3643
3669
  var __dirname7 = dirname6(__filename6);
3644
- var TEMPLATES_DIR = resolve5(__dirname7, "../templates");
3645
- var TEMPLATES_DIR_FALLBACK = resolve5(__dirname7, "../../../agent_moss/templates");
3646
3670
  var TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
3647
3671
  var cachedTemplates = null;
3648
3672
  function loadTemplates() {
3649
3673
  if (cachedTemplates) return cachedTemplates;
3650
3674
  cachedTemplates = {};
3651
- const dir = existsSync7(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
3652
- if (!existsSync7(dir)) {
3653
- console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
3675
+ const dir = resolveAssetDir(__dirname7, "templates");
3676
+ if (!dir) {
3677
+ const [primary, fallback] = assetDirCandidates(__dirname7, "templates");
3678
+ console.warn("[AgentMoss] Templates directory not found:", primary, "and fallback:", fallback);
3654
3679
  return cachedTemplates;
3655
3680
  }
3656
3681
  for (const file of TEMPLATE_FILES) {
3657
- const filePath = resolve5(dir, file);
3682
+ const filePath = resolve6(dir, file);
3658
3683
  if (existsSync7(filePath)) {
3659
3684
  const key = file.replace(".txt", "").replace("_template", "");
3660
3685
  cachedTemplates[key] = readFileSync7(filePath, "utf-8");
@@ -3667,7 +3692,7 @@ function loadTemplates() {
3667
3692
  // src/engine/script-analyzer.ts
3668
3693
  init_esm_shims();
3669
3694
  import { readFileSync as readFileSync8 } from "fs";
3670
- import { resolve as resolve6, join as join4 } from "path";
3695
+ import { resolve as resolve7, join as join4 } from "path";
3671
3696
  var SUSPICIOUS_PATTERNS = [
3672
3697
  // Network exfiltration (curl/wget POST in scripts is almost never legitimate)
3673
3698
  { name: "curl POST", pattern: /curl\s+(.*\s)?-X\s+POST/i },
@@ -3800,7 +3825,7 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
3800
3825
  }
3801
3826
  function readScriptContent(scriptPath, maxLines = 500) {
3802
3827
  try {
3803
- const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve6(scriptPath);
3828
+ const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve7(scriptPath);
3804
3829
  const raw = readFileSync8(expandedPath, "utf-8");
3805
3830
  const lines = raw.split("\n").slice(0, maxLines);
3806
3831
  return { content: lines.join("\n"), lineCount: lines.length, error: "" };
@@ -3857,7 +3882,7 @@ init_heuristic();
3857
3882
  init_logic_rules();
3858
3883
  init_inline_analyzer();
3859
3884
  import { statSync as statSync3, existsSync as existsSync9 } from "fs";
3860
- import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
3885
+ import { resolve as resolve9, join as join6, isAbsolute as isAbsolute2 } from "path";
3861
3886
  import { homedir as homedir4 } from "os";
3862
3887
 
3863
3888
  // src/engine/script-engine/tracker.ts
@@ -5560,7 +5585,7 @@ function resolvePath2(p) {
5560
5585
  if (expanded.startsWith("~/") || expanded === "~") {
5561
5586
  expanded = join6(homedir4(), expanded.slice(1));
5562
5587
  }
5563
- return resolve8(expanded);
5588
+ return resolve9(expanded);
5564
5589
  }
5565
5590
  function scanScriptChainWithL1(chain, input) {
5566
5591
  for (const node of chain.nodes) {
@@ -5936,7 +5961,7 @@ async function analyzeWithLLM(prompt, config) {
5936
5961
  }
5937
5962
  if (attempt < maxRetries) {
5938
5963
  console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
5939
- await new Promise((resolve9) => setTimeout(resolve9, retryCfg.retryInterval * 1e3));
5964
+ await new Promise((resolve10) => setTimeout(resolve10, retryCfg.retryInterval * 1e3));
5940
5965
  } else {
5941
5966
  clearTimeout(totalTimeoutTimer);
5942
5967
  console.error("[AgentMoss] LLM call failed after all retries:", err.message);
@@ -7860,4 +7885,3 @@ export {
7860
7885
  //! P6 mc-ltl-rules LTL 模型检测
7861
7886
  //! P7 low-integrity-command-exec 低完整性命令执行
7862
7887
  //! P8 sensitive-data-aggregation 敏感数据聚合外传
7863
- //# sourceMappingURL=coordinator.js.map
@@ -373,10 +373,10 @@
373
373
  "reason": "检测到 curl -F 表单上传到外部地址(可能为数据外传,回环地址除外)"
374
374
  },
375
375
  {
376
- "pattern": "[|]\\s*crontab\\b",
376
+ "pattern": "(?:@reboot|(?:[\\d*,\\-/]+\\s+){4}[\\d*,\\-/]+)\\s+(?:/tmp|/var/tmp|/dev/shm|/run/shm)/\\S+",
377
377
  "risk_level": "high",
378
- "risk_type": "sensitive_action",
379
- "reason": "检测到通过管道安装 crontab 定时任务(cron 后门/持久化)"
378
+ "risk_type": "persistence",
379
+ "reason": "检测到定时任务执行世界可写目录(/tmp、/var/tmp、/dev/shm)下的脚本(cron 持久化后门:任何用户可替换该脚本,重启/定时以任务属主身份执行)"
380
380
  }
381
381
  ],
382
382
  "injection_detection": [
@@ -719,6 +719,48 @@
719
719
  "deny_mode": "deny_write",
720
720
  "scope": "root"
721
721
  },
722
+ {
723
+ "path": "/etc/cron.hourly/",
724
+ "risk_level": "high",
725
+ "desc": "系统定时任务目录(小时级)——可放置脚本,重启/定时后以 root 执行",
726
+ "deny_mode": "deny_write",
727
+ "scope": "root"
728
+ },
729
+ {
730
+ "path": "/etc/cron.daily/",
731
+ "risk_level": "high",
732
+ "desc": "系统定时任务目录(日级)",
733
+ "deny_mode": "deny_write",
734
+ "scope": "root"
735
+ },
736
+ {
737
+ "path": "/etc/cron.weekly/",
738
+ "risk_level": "high",
739
+ "desc": "系统定时任务目录(周级)",
740
+ "deny_mode": "deny_write",
741
+ "scope": "root"
742
+ },
743
+ {
744
+ "path": "/etc/cron.monthly/",
745
+ "risk_level": "high",
746
+ "desc": "系统定时任务目录(月级)",
747
+ "deny_mode": "deny_write",
748
+ "scope": "root"
749
+ },
750
+ {
751
+ "path": "/etc/init.d/",
752
+ "risk_level": "high",
753
+ "desc": "SysV init 启动脚本目录——agent 写入脚本即持久化(重启后以 root 执行,不依赖 cron)",
754
+ "deny_mode": "deny_write",
755
+ "scope": "root"
756
+ },
757
+ {
758
+ "path": "/etc/rc*.d/",
759
+ "risk_level": "high",
760
+ "desc": "SysV init 运行级目录——指向 init.d 的符号链接,控制各运行级启动",
761
+ "deny_mode": "deny_write",
762
+ "scope": "root"
763
+ },
722
764
  {
723
765
  "path": "/var/spool/cron/",
724
766
  "risk_level": "high",
@@ -733,6 +775,20 @@
733
775
  "deny_mode": "deny_write",
734
776
  "scope": "root"
735
777
  },
778
+ {
779
+ "path": ".config/systemd/user/",
780
+ "risk_level": "high",
781
+ "desc": "用户级 systemd 服务目录——写 .service 并 enable 即用户级持久化(登录后运行)",
782
+ "deny_mode": "deny_write",
783
+ "scope": "home"
784
+ },
785
+ {
786
+ "path": ".config/autostart/",
787
+ "risk_level": "high",
788
+ "desc": "桌面自启动目录——写 .desktop 即登录自启动(Desktop Entry,持久化)",
789
+ "deny_mode": "deny_write",
790
+ "scope": "home"
791
+ },
736
792
  {
737
793
  "path": "/etc/ssh/sshd_config",
738
794
  "risk_level": "high",