@kenhkl/agent-moss 0.12.0 → 0.12.1
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 +97 -23
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.d.ts +9 -0
- package/dist/engine/coordinator.js +91 -22
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/server.js +97 -23
- package/dist/server.js.map +1 -1
- package/dist/templates/security_judge_template.txt +7 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -682,6 +682,32 @@ function matchDangerousAction(actionDetail, action) {
|
|
|
682
682
|
const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
|
|
683
683
|
return re.test(actionDetail);
|
|
684
684
|
}
|
|
685
|
+
function collectIntentTexts(promptSession, promptHistory) {
|
|
686
|
+
const texts = [];
|
|
687
|
+
if (promptHistory) {
|
|
688
|
+
for (const turn of promptHistory) {
|
|
689
|
+
if (typeof turn === "string") {
|
|
690
|
+
const t2 = turn.trim();
|
|
691
|
+
if (t2) texts.push(t2.toLowerCase());
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
const t = (turn?.text || "").trim();
|
|
695
|
+
if (t) texts.push(t.toLowerCase());
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (promptSession && promptSession.trim()) {
|
|
699
|
+
texts.push(promptSession.toLowerCase());
|
|
700
|
+
}
|
|
701
|
+
const seen = /* @__PURE__ */ new Set();
|
|
702
|
+
const deduped = [];
|
|
703
|
+
for (const t of texts) {
|
|
704
|
+
if (!seen.has(t)) {
|
|
705
|
+
seen.add(t);
|
|
706
|
+
deduped.push(t);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return deduped;
|
|
710
|
+
}
|
|
685
711
|
function runLogicCheck(input) {
|
|
686
712
|
const { actionHistory, aNext, cwd } = input;
|
|
687
713
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
@@ -691,25 +717,24 @@ function runLogicCheck(input) {
|
|
|
691
717
|
const isExcludedType = EXCLUDED_PREFIXES.some((p) => actionType.startsWith(p));
|
|
692
718
|
const rbwResult = checkReadBeforeWrite(actionType, actionDetail, actionHistory, input.reason, resolvedCwd);
|
|
693
719
|
if (rbwResult) return rbwResult;
|
|
694
|
-
if (
|
|
695
|
-
if (!
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
}
|
|
720
|
+
if (!isExcludedType) {
|
|
721
|
+
if (!INLINE_SCRIPT_RE.test(actionDetail)) {
|
|
722
|
+
const intentTexts = collectIntentTexts(input.promptSession, input.promptHistory);
|
|
723
|
+
for (const pattern of INTENT_DEVIATION_PATTERNS) {
|
|
724
|
+
const intentMatched = intentTexts.some(
|
|
725
|
+
(text) => pattern.intentKeywords.some((kw) => text.includes(kw))
|
|
726
|
+
);
|
|
727
|
+
const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
|
|
728
|
+
if (intentMatched && dangerousMatched) {
|
|
729
|
+
return {
|
|
730
|
+
allowed: false,
|
|
731
|
+
reason: pattern.reason,
|
|
732
|
+
riskLevel: "high",
|
|
733
|
+
riskType: "intent_deviation",
|
|
734
|
+
confidence: 85,
|
|
735
|
+
source: "logic_rule",
|
|
736
|
+
violatedLayers: ["2"]
|
|
737
|
+
};
|
|
713
738
|
}
|
|
714
739
|
}
|
|
715
740
|
}
|
|
@@ -2274,7 +2299,7 @@ function runHeuristicCheck(input) {
|
|
|
2274
2299
|
} catch {
|
|
2275
2300
|
}
|
|
2276
2301
|
}
|
|
2277
|
-
const scanDetail = stripLiteralTextSegments(input.aNext.actionDetail);
|
|
2302
|
+
const scanDetail = normalizePathSegments(stripLiteralTextSegments(input.aNext.actionDetail));
|
|
2278
2303
|
const scanCommand = `${input.aNext.actionType}: ${scanDetail}`;
|
|
2279
2304
|
let topRiskType = "";
|
|
2280
2305
|
for (const rule of DANGEROUS_PATTERNS) {
|
|
@@ -2385,6 +2410,28 @@ function stripHeredocContent(actionDetail) {
|
|
|
2385
2410
|
"<<heredoc>>\n"
|
|
2386
2411
|
);
|
|
2387
2412
|
}
|
|
2413
|
+
function normalizePathSegments(text) {
|
|
2414
|
+
const protTokens = [];
|
|
2415
|
+
let t = text.replace(/\b(https?|ftp|file):\/\//gi, (m) => {
|
|
2416
|
+
const scheme = m.slice(0, m.indexOf(":"));
|
|
2417
|
+
protTokens.push("://");
|
|
2418
|
+
return `${scheme}__PROT${protTokens.length - 1}__`;
|
|
2419
|
+
});
|
|
2420
|
+
const quoteTokens = [];
|
|
2421
|
+
t = t.replace(/'[^']*'|"[^"]*"/g, (m) => {
|
|
2422
|
+
quoteTokens.push(m);
|
|
2423
|
+
return `__Q${quoteTokens.length - 1}__`;
|
|
2424
|
+
});
|
|
2425
|
+
t = t.replace(/\/{2,}/g, "/");
|
|
2426
|
+
t = t.replace(/\/\.\//g, "/");
|
|
2427
|
+
for (let i = 0; i < quoteTokens.length; i++) {
|
|
2428
|
+
t = t.replace(`__Q${i}__`, quoteTokens[i]);
|
|
2429
|
+
}
|
|
2430
|
+
for (let i = 0; i < protTokens.length; i++) {
|
|
2431
|
+
t = t.replace(`__PROT${i}__`, protTokens[i]);
|
|
2432
|
+
}
|
|
2433
|
+
return t;
|
|
2434
|
+
}
|
|
2388
2435
|
function splitCommandSegments(actionDetail) {
|
|
2389
2436
|
const segments = [];
|
|
2390
2437
|
let cur = "";
|
|
@@ -2437,7 +2484,7 @@ function isSearchActionType(actionType) {
|
|
|
2437
2484
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2438
2485
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2439
2486
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
2440
|
-
const pathScanText = stripLiteralTextSegments(command);
|
|
2487
|
+
const pathScanText = normalizePathSegments(stripLiteralTextSegments(command));
|
|
2441
2488
|
const pathMatches = (text, path3) => {
|
|
2442
2489
|
const parts = path3.split(/(\(\?!.*?\))/);
|
|
2443
2490
|
const escaped = parts.map((part) => {
|
|
@@ -3716,9 +3763,14 @@ var ActionItemSchema = z.object({
|
|
|
3716
3763
|
action_type: z.string().describe("Action type, e.g. bash, file_read, file_write"),
|
|
3717
3764
|
action_detail: z.string().describe("Action detail / command content")
|
|
3718
3765
|
});
|
|
3766
|
+
var PromptTurnSchema = z.object({
|
|
3767
|
+
text: z.string().default("").describe("User prompt text at this turn"),
|
|
3768
|
+
actions: z.array(ActionItemSchema).default([]).describe("Actions triggered by this prompt, in order, until the next prompt")
|
|
3769
|
+
});
|
|
3719
3770
|
var AnalyzeRequestSchema = z.object({
|
|
3720
3771
|
session_id: z.string().describe("Session / agent unique identifier"),
|
|
3721
|
-
prompt_session: z.string().default("").describe("User original prompt"),
|
|
3772
|
+
prompt_session: z.string().default("").describe("User original prompt (most recent user message; backward compat)"),
|
|
3773
|
+
prompt_history: z.array(PromptTurnSchema).default([]).describe("Full interleaved prompt history (ordered turns, each with its triggered actions). Optional; empty = fall back to prompt_session only."),
|
|
3722
3774
|
action_history: z.array(ActionItemSchema).default([]).describe("Historical action sequence"),
|
|
3723
3775
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
3724
3776
|
reason: z.string().default("").describe("Reason for executing this action"),
|
|
@@ -4567,11 +4619,12 @@ ${prompt}
|
|
|
4567
4619
|
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "") {
|
|
4568
4620
|
const skillsText = formatSkillsForPrompt(matchedSkills);
|
|
4569
4621
|
const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
|
|
4622
|
+
const promptHistoryText = formatPromptHistory(input.promptHistory);
|
|
4570
4623
|
const scriptAnalysisText = scriptChainText ? scriptChainText : scriptAnalysis ? formatScriptAnalysisForPrompt(scriptAnalysis) : "";
|
|
4571
4624
|
const hintsText = formatHints(previous);
|
|
4572
4625
|
const securityJudgeTemplate = templates["security_judge"];
|
|
4573
4626
|
if (securityJudgeTemplate) {
|
|
4574
|
-
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{action_history}", historyStr).replaceAll("{action_type}", input.aNext.actionType).replaceAll("{action_detail}", input.aNext.actionDetail).replaceAll("{reason}", input.reason || "\u672A\u8BF4\u660E").replaceAll("{skills_text}", skillsText).replaceAll("{hints_text}", hintsText).replaceAll("{script_analysis_text}", scriptAnalysisText).replaceAll("{skip_l3_hints}", skipL3Hints).replaceAll("{{", "{").replaceAll("}}", "}");
|
|
4627
|
+
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{prompt_history_text}", promptHistoryText).replaceAll("{action_history}", historyStr).replaceAll("{action_type}", input.aNext.actionType).replaceAll("{action_detail}", input.aNext.actionDetail).replaceAll("{reason}", input.reason || "\u672A\u8BF4\u660E").replaceAll("{skills_text}", skillsText).replaceAll("{hints_text}", hintsText).replaceAll("{script_analysis_text}", scriptAnalysisText).replaceAll("{skip_l3_hints}", skipL3Hints).replaceAll("{{", "{").replaceAll("}}", "}");
|
|
4575
4628
|
}
|
|
4576
4629
|
console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
|
|
4577
4630
|
return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
|
|
@@ -4601,6 +4654,27 @@ ${scriptAnalysisText}` : ""}
|
|
|
4601
4654
|
\u8F93\u51FA\u683C\u5F0F:
|
|
4602
4655
|
{"allowed": true/false, "reason": "\u5224\u65AD\u7406\u7531", "riskLevel": "low|medium|high|critical", "riskType": "\u98CE\u9669\u7C7B\u578B", "confidence": 0-100}`;
|
|
4603
4656
|
}
|
|
4657
|
+
function formatPromptHistory(promptHistory, maxTextChars = 500) {
|
|
4658
|
+
if (!promptHistory || promptHistory.length === 0) {
|
|
4659
|
+
return "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
4660
|
+
}
|
|
4661
|
+
const lines = [];
|
|
4662
|
+
for (let i = 0; i < promptHistory.length; i++) {
|
|
4663
|
+
const turn = promptHistory[i];
|
|
4664
|
+
const text = (turn?.text || "").trim();
|
|
4665
|
+
if (!text) continue;
|
|
4666
|
+
let line = ` \u7B2C${i + 1}\u8F6E\u7528\u6237\u610F\u56FE: ${text.slice(0, maxTextChars)}`;
|
|
4667
|
+
const actions = turn?.actions;
|
|
4668
|
+
if (actions && actions.length > 0) {
|
|
4669
|
+
const types = actions.map((a) => a?.actionType).filter((t) => typeof t === "string" && t.length > 0);
|
|
4670
|
+
if (types.length > 0) {
|
|
4671
|
+
line += ` \u2192 \u52A8\u4F5C: ${types.join(", ")}`;
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
lines.push(line);
|
|
4675
|
+
}
|
|
4676
|
+
return lines.length > 0 ? lines.join("\n") : "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
4677
|
+
}
|
|
4604
4678
|
function formatHints(previous) {
|
|
4605
4679
|
const hints = [];
|
|
4606
4680
|
if (previous.heuristic) {
|