@kenhkl/agent-moss 0.10.2 → 0.10.4

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
@@ -412,6 +412,27 @@ var init_inline_analyzer = __esm({
412
412
 
413
413
  // src/engine/logic-rules.ts
414
414
  import * as fs2 from "fs";
415
+ function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
416
+ if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
417
+ if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
418
+ if (/\bsed\s+-[a-zA-Z]*i/i.test(actionDetail)) return true;
419
+ if (actionDetail.includes(">")) {
420
+ const detailWithoutDevnull = actionDetail.replace(DEVNULL_REDIRECT_RE, "");
421
+ if (detailWithoutDevnull.includes(">")) {
422
+ const firstWord = actionDetail.trim().split(/\s+/)[0]?.toLowerCase() || "";
423
+ if (!READ_ONLY_COMMANDS.has(firstWord)) return true;
424
+ }
425
+ }
426
+ return false;
427
+ }
428
+ function matchDangerousAction(actionDetail, action) {
429
+ if (/[^\x00-\x7f]/.test(action)) {
430
+ return actionDetail.includes(action);
431
+ }
432
+ const escaped = action.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
433
+ const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
434
+ return re.test(actionDetail);
435
+ }
415
436
  function runLogicCheck(input) {
416
437
  const { actionHistory, aNext, cwd } = input;
417
438
  const actionDetail = aNext.actionDetail.toLowerCase();
@@ -426,7 +447,7 @@ function runLogicCheck(input) {
426
447
  const promptLower = input.promptSession.toLowerCase();
427
448
  for (const pattern of INTENT_DEVIATION_PATTERNS) {
428
449
  const intentMatched = pattern.intentKeywords.some((kw) => promptLower.includes(kw));
429
- const dangerousMatched = pattern.dangerousActions.some((kw) => actionDetail.includes(kw));
450
+ const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
430
451
  if (intentMatched && dangerousMatched) {
431
452
  return {
432
453
  allowed: false,
@@ -481,16 +502,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
481
502
  if (NON_WRITE_TOOL_PREFIXES.some((p) => actionType.startsWith(p))) return null;
482
503
  if (NON_WRITE_TOOLS.has(actionType)) return null;
483
504
  const isBashLike = actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash";
484
- let isWrite = isBashLike ? WRITE_KEYWORDS.some((kw) => actionType.includes(kw) || actionDetail.includes(kw)) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
485
- if (!isWrite && actionDetail.includes(">")) {
486
- const detailWithoutDevnull = actionDetail.replace(/(?:2|&|1)?\s*>\s*\/dev\/null\b/g, "");
487
- if (detailWithoutDevnull.includes(">")) {
488
- const firstWord = actionDetail.split(/\s/)[0]?.toLowerCase() || "";
489
- if (!READ_ONLY_REDIR_CMDS.has(firstWord)) {
490
- isWrite = true;
491
- }
492
- }
493
- }
505
+ const isWrite = isBashLike ? isWriteOperation(actionType, actionDetail) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
494
506
  if (!isWrite) return null;
495
507
  const targetPaths = extractFilePaths(actionDetail);
496
508
  if (targetPaths.length === 0) return null;
@@ -647,7 +659,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd) {
647
659
  violatedLayers: ["2"]
648
660
  };
649
661
  }
650
- var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, READ_ONLY_REDIR_CMDS, WRITE_KEYWORDS, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
662
+ var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, WRITE_COMMAND_RES, READ_ONLY_COMMANDS, DEVNULL_REDIRECT_RE, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
651
663
  var init_logic_rules = __esm({
652
664
  "src/engine/logic-rules.ts"() {
653
665
  "use strict";
@@ -719,8 +731,105 @@ var init_logic_rules = __esm({
719
731
  "cat"
720
732
  ]);
721
733
  NON_WRITE_TOOL_PREFIXES = ["memory-", "skill-manager-", "mailbox-", "app-"];
722
- READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
723
734
  WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362"];
735
+ WRITE_COMMAND_RES = [
736
+ /\brm\b/,
737
+ /\bunlink\b/,
738
+ /\brmdir\b/,
739
+ /\bshred\b/,
740
+ /\bcp\b/,
741
+ /\bmv\b/,
742
+ /\binstall\b/,
743
+ /\btee\b/,
744
+ /\bdd\b/,
745
+ /\bmkfs\b/,
746
+ /\b(fdisk|parted|cfdisk|sfdisk)\b/,
747
+ /\bchmod\b/,
748
+ /\bchown\b/,
749
+ /\btruncate\b/
750
+ ];
751
+ READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
752
+ "cat",
753
+ "head",
754
+ "tail",
755
+ "less",
756
+ "more",
757
+ "grep",
758
+ "find",
759
+ "awk",
760
+ "sed",
761
+ "sort",
762
+ "uniq",
763
+ "wc",
764
+ "cut",
765
+ "strings",
766
+ "od",
767
+ "xxd",
768
+ "hexdump",
769
+ "tr",
770
+ "file",
771
+ "stat",
772
+ "du",
773
+ "df",
774
+ "ls",
775
+ "dir",
776
+ "tree",
777
+ "nl",
778
+ "tac",
779
+ "rev",
780
+ "lsblk",
781
+ "blockdev",
782
+ "smartctl",
783
+ "udevadm",
784
+ "dmidecode",
785
+ "lscpu",
786
+ "lspci",
787
+ "lsusb",
788
+ "lsmem",
789
+ "lsns",
790
+ "lsof",
791
+ "hwinfo",
792
+ "inxi",
793
+ "fdisk",
794
+ "parted",
795
+ "dmesg",
796
+ "journalctl",
797
+ "systemctl",
798
+ "hostnamectl",
799
+ "localectl",
800
+ "timedatectl",
801
+ "ps",
802
+ "top",
803
+ "free",
804
+ "vmstat",
805
+ "iostat",
806
+ "mpstat",
807
+ "pidof",
808
+ "pgrep",
809
+ "ip",
810
+ "ifconfig",
811
+ "route",
812
+ "ss",
813
+ "netstat",
814
+ "arp",
815
+ "ethtool",
816
+ "nmcli",
817
+ "uname",
818
+ "arch",
819
+ "nproc",
820
+ "getconf",
821
+ "getent",
822
+ "id",
823
+ "whoami",
824
+ "who",
825
+ "w",
826
+ "last",
827
+ "uptime",
828
+ "lsmod",
829
+ "modinfo",
830
+ "sysctl"
831
+ ]);
832
+ DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
724
833
  READ_KEYWORDS = ["read", "\u8BFB\u53D6", "cat", "head", "tail", "less", "more", "view", "\u67E5\u770B", "open", "\u6253\u5F00", "load", "\u52A0\u8F7D", "grep", "search", "\u641C\u7D22", "find", "\u67E5\u627E"];
725
834
  CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
726
835
  PASSWORD_MODIFY_PATTERNS = [
@@ -742,7 +851,7 @@ var init_logic_rules = __esm({
742
851
  INTENT_DEVIATION_PATTERNS = [
743
852
  {
744
853
  intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
745
- dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
854
+ dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
746
855
  reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
747
856
  },
748
857
  {
@@ -1962,12 +2071,14 @@ function severityRank(s) {
1962
2071
  }
1963
2072
  function checkSensitivePath(command, cwd, agentExt) {
1964
2073
  const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
1965
- const _WRITE_CMD_RES = [/\brm\b/, /\bunlink\b/, /\brmdir\b/, /\bshred\b/, /\bcp\b/, /\bmv\b/, /\binstall\b/, /\btee\b/, /\bdd\b/, /\bmkfs\b/, /\b(fdisk|parted|cfdisk|sfdisk)\b/, /\bchmod\b/, /\bchown\b/, /\btruncate\b/];
1966
- const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
1967
- const _READONLY_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump", "tr", "file", "stat", "du", "df", "ls", "dir", "tree", "nl", "tac", "rev", "lsblk", "blockdev", "smartctl", "udevadm", "dmidecode", "lscpu", "lspci", "lsusb", "lsmem", "lsns", "lsof", "hwinfo", "inxi", "fdisk", "parted", "dmesg", "journalctl", "systemctl", "hostnamectl", "localectl", "timedatectl", "ps", "top", "free", "vmstat", "iostat", "mpstat", "pidof", "pgrep", "ip", "ifconfig", "route", "ss", "netstat", "arp", "ethtool", "nmcli", "uname", "arch", "nproc", "getconf", "getent", "id", "whoami", "who", "w", "last", "uptime", "lsmod", "modinfo", "sysctl"]);
1968
- const isWriteOpFlag = _WRITE_CMD_RES.some((rx) => rx.test(command)) || /\bsed\s+-[a-zA-Z]*i/.test(command) || command.includes(">") && !command.replace(_DEVNULL_RE, "").includes(">") || command.includes(">") && command.replace(_DEVNULL_RE, "").includes(">") && !_READONLY_CMDS.has(command.trim().split(/\s+/)[0]?.toLowerCase() || "") || WRITE_KEYWORDS.some((kw) => "".includes(kw) || command.includes(kw));
2074
+ const isWriteOpFlag = isWriteOperation("", command);
2075
+ const pathMatches = (text, path3) => {
2076
+ const escaped = path3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2077
+ const re = path3.startsWith(".") || path3.startsWith("/") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`, "i") : new RegExp(`\\b${escaped}\\b`, "i");
2078
+ return re.test(text);
2079
+ };
1969
2080
  for (const sp of ROOT_SENSITIVE_PATHS) {
1970
- if (command.includes(sp.path.toLowerCase())) {
2081
+ if (pathMatches(command, sp.path.toLowerCase())) {
1971
2082
  if (sp.path === "/dev/random") {
1972
2083
  if (isWriteOpFlag) {
1973
2084
  continue;
@@ -2021,7 +2132,7 @@ function checkSensitivePath(command, cwd, agentExt) {
2021
2132
  for (const sp of agentExt.extra_sensitive_paths) {
2022
2133
  const spPath = sp.path.toLowerCase();
2023
2134
  const expanded = `${expandedCwd}/${spPath}`;
2024
- if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
2135
+ if (pathMatches(command, spPath) || pathMatches(command, expanded.toLowerCase())) {
2025
2136
  const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
2026
2137
  if (denyMode === "deny_read") {
2027
2138
  if (isWriteOpFlag) continue;
@@ -4586,7 +4697,11 @@ var AnalyzeResponseSchema = z.object({
4586
4697
  });
4587
4698
  var HealthResponseSchema = z.object({
4588
4699
  status: z.string().default("healthy"),
4589
- version: z.string().default(version)
4700
+ version: z.string().default(version),
4701
+ // 归属实例标识:值来自 env AGENT_MOSS_INSTANCE(spawn/systemd 注入),默认空串。
4702
+ // 多个 agentmoss 同机并存时,调用方按 instance 过滤避免连到别人的进程。
4703
+ // 空=未配置(独立部署或旧版),调用方可选择兼容或严格过滤。
4704
+ instance: z.string().default("")
4590
4705
  });
4591
4706
 
4592
4707
  // src/routes.ts
@@ -4695,7 +4810,9 @@ function reportEnforcementEvent(opts) {
4695
4810
 
4696
4811
  // src/routes.ts
4697
4812
  async function healthRoute(c) {
4698
- return c.json(HealthResponseSchema.parse({}));
4813
+ return c.json(HealthResponseSchema.parse({
4814
+ instance: process.env.AGENT_MOSS_INSTANCE || ""
4815
+ }));
4699
4816
  }
4700
4817
  async function analyzeRoute(c) {
4701
4818
  const t0 = performance.now();