@kenhkl/agent-moss 0.12.0 → 0.12.2
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/static/index.html +282 -245
- package/dist/templates/security_judge_template.txt +7 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -683,6 +683,32 @@ function matchDangerousAction(actionDetail, action) {
|
|
|
683
683
|
const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
|
|
684
684
|
return re.test(actionDetail);
|
|
685
685
|
}
|
|
686
|
+
function collectIntentTexts(promptSession, promptHistory) {
|
|
687
|
+
const texts = [];
|
|
688
|
+
if (promptHistory) {
|
|
689
|
+
for (const turn of promptHistory) {
|
|
690
|
+
if (typeof turn === "string") {
|
|
691
|
+
const t2 = turn.trim();
|
|
692
|
+
if (t2) texts.push(t2.toLowerCase());
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
const t = (turn?.text || "").trim();
|
|
696
|
+
if (t) texts.push(t.toLowerCase());
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (promptSession && promptSession.trim()) {
|
|
700
|
+
texts.push(promptSession.toLowerCase());
|
|
701
|
+
}
|
|
702
|
+
const seen = /* @__PURE__ */ new Set();
|
|
703
|
+
const deduped = [];
|
|
704
|
+
for (const t of texts) {
|
|
705
|
+
if (!seen.has(t)) {
|
|
706
|
+
seen.add(t);
|
|
707
|
+
deduped.push(t);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return deduped;
|
|
711
|
+
}
|
|
686
712
|
function runLogicCheck(input) {
|
|
687
713
|
const { actionHistory, aNext, cwd } = input;
|
|
688
714
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
@@ -692,25 +718,24 @@ function runLogicCheck(input) {
|
|
|
692
718
|
const isExcludedType = EXCLUDED_PREFIXES.some((p) => actionType.startsWith(p));
|
|
693
719
|
const rbwResult = checkReadBeforeWrite(actionType, actionDetail, actionHistory, input.reason, resolvedCwd);
|
|
694
720
|
if (rbwResult) return rbwResult;
|
|
695
|
-
if (
|
|
696
|
-
if (!
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
721
|
+
if (!isExcludedType) {
|
|
722
|
+
if (!INLINE_SCRIPT_RE.test(actionDetail)) {
|
|
723
|
+
const intentTexts = collectIntentTexts(input.promptSession, input.promptHistory);
|
|
724
|
+
for (const pattern of INTENT_DEVIATION_PATTERNS) {
|
|
725
|
+
const intentMatched = intentTexts.some(
|
|
726
|
+
(text) => pattern.intentKeywords.some((kw) => text.includes(kw))
|
|
727
|
+
);
|
|
728
|
+
const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
|
|
729
|
+
if (intentMatched && dangerousMatched) {
|
|
730
|
+
return {
|
|
731
|
+
allowed: false,
|
|
732
|
+
reason: pattern.reason,
|
|
733
|
+
riskLevel: "high",
|
|
734
|
+
riskType: "intent_deviation",
|
|
735
|
+
confidence: 85,
|
|
736
|
+
source: "logic_rule",
|
|
737
|
+
violatedLayers: ["2"]
|
|
738
|
+
};
|
|
714
739
|
}
|
|
715
740
|
}
|
|
716
741
|
}
|
|
@@ -2275,7 +2300,7 @@ function runHeuristicCheck(input) {
|
|
|
2275
2300
|
} catch {
|
|
2276
2301
|
}
|
|
2277
2302
|
}
|
|
2278
|
-
const scanDetail = stripLiteralTextSegments(input.aNext.actionDetail);
|
|
2303
|
+
const scanDetail = normalizePathSegments(stripLiteralTextSegments(input.aNext.actionDetail));
|
|
2279
2304
|
const scanCommand = `${input.aNext.actionType}: ${scanDetail}`;
|
|
2280
2305
|
let topRiskType = "";
|
|
2281
2306
|
for (const rule of DANGEROUS_PATTERNS) {
|
|
@@ -2386,6 +2411,28 @@ function stripHeredocContent(actionDetail) {
|
|
|
2386
2411
|
"<<heredoc>>\n"
|
|
2387
2412
|
);
|
|
2388
2413
|
}
|
|
2414
|
+
function normalizePathSegments(text) {
|
|
2415
|
+
const protTokens = [];
|
|
2416
|
+
let t = text.replace(/\b(https?|ftp|file):\/\//gi, (m) => {
|
|
2417
|
+
const scheme = m.slice(0, m.indexOf(":"));
|
|
2418
|
+
protTokens.push("://");
|
|
2419
|
+
return `${scheme}__PROT${protTokens.length - 1}__`;
|
|
2420
|
+
});
|
|
2421
|
+
const quoteTokens = [];
|
|
2422
|
+
t = t.replace(/'[^']*'|"[^"]*"/g, (m) => {
|
|
2423
|
+
quoteTokens.push(m);
|
|
2424
|
+
return `__Q${quoteTokens.length - 1}__`;
|
|
2425
|
+
});
|
|
2426
|
+
t = t.replace(/\/{2,}/g, "/");
|
|
2427
|
+
t = t.replace(/\/\.\//g, "/");
|
|
2428
|
+
for (let i = 0; i < quoteTokens.length; i++) {
|
|
2429
|
+
t = t.replace(`__Q${i}__`, quoteTokens[i]);
|
|
2430
|
+
}
|
|
2431
|
+
for (let i = 0; i < protTokens.length; i++) {
|
|
2432
|
+
t = t.replace(`__PROT${i}__`, protTokens[i]);
|
|
2433
|
+
}
|
|
2434
|
+
return t;
|
|
2435
|
+
}
|
|
2389
2436
|
function splitCommandSegments(actionDetail) {
|
|
2390
2437
|
const segments = [];
|
|
2391
2438
|
let cur = "";
|
|
@@ -2438,7 +2485,7 @@ function isSearchActionType(actionType) {
|
|
|
2438
2485
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2439
2486
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2440
2487
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
2441
|
-
const pathScanText = stripLiteralTextSegments(command);
|
|
2488
|
+
const pathScanText = normalizePathSegments(stripLiteralTextSegments(command));
|
|
2442
2489
|
const pathMatches = (text, path3) => {
|
|
2443
2490
|
const parts = path3.split(/(\(\?!.*?\))/);
|
|
2444
2491
|
const escaped = parts.map((part) => {
|
|
@@ -3727,11 +3774,12 @@ ${prompt}
|
|
|
3727
3774
|
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "") {
|
|
3728
3775
|
const skillsText = formatSkillsForPrompt(matchedSkills);
|
|
3729
3776
|
const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
|
|
3777
|
+
const promptHistoryText = formatPromptHistory(input.promptHistory);
|
|
3730
3778
|
const scriptAnalysisText = scriptChainText ? scriptChainText : scriptAnalysis ? formatScriptAnalysisForPrompt(scriptAnalysis) : "";
|
|
3731
3779
|
const hintsText = formatHints(previous);
|
|
3732
3780
|
const securityJudgeTemplate = templates["security_judge"];
|
|
3733
3781
|
if (securityJudgeTemplate) {
|
|
3734
|
-
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("}}", "}");
|
|
3782
|
+
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("}}", "}");
|
|
3735
3783
|
}
|
|
3736
3784
|
console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
|
|
3737
3785
|
return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
|
|
@@ -3761,6 +3809,27 @@ ${scriptAnalysisText}` : ""}
|
|
|
3761
3809
|
\u8F93\u51FA\u683C\u5F0F:
|
|
3762
3810
|
{"allowed": true/false, "reason": "\u5224\u65AD\u7406\u7531", "riskLevel": "low|medium|high|critical", "riskType": "\u98CE\u9669\u7C7B\u578B", "confidence": 0-100}`;
|
|
3763
3811
|
}
|
|
3812
|
+
function formatPromptHistory(promptHistory, maxTextChars = 500) {
|
|
3813
|
+
if (!promptHistory || promptHistory.length === 0) {
|
|
3814
|
+
return "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
3815
|
+
}
|
|
3816
|
+
const lines = [];
|
|
3817
|
+
for (let i = 0; i < promptHistory.length; i++) {
|
|
3818
|
+
const turn = promptHistory[i];
|
|
3819
|
+
const text = (turn?.text || "").trim();
|
|
3820
|
+
if (!text) continue;
|
|
3821
|
+
let line = ` \u7B2C${i + 1}\u8F6E\u7528\u6237\u610F\u56FE: ${text.slice(0, maxTextChars)}`;
|
|
3822
|
+
const actions = turn?.actions;
|
|
3823
|
+
if (actions && actions.length > 0) {
|
|
3824
|
+
const types = actions.map((a) => a?.actionType).filter((t) => typeof t === "string" && t.length > 0);
|
|
3825
|
+
if (types.length > 0) {
|
|
3826
|
+
line += ` \u2192 \u52A8\u4F5C: ${types.join(", ")}`;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
lines.push(line);
|
|
3830
|
+
}
|
|
3831
|
+
return lines.length > 0 ? lines.join("\n") : "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
3832
|
+
}
|
|
3764
3833
|
function formatHints(previous) {
|
|
3765
3834
|
const hints = [];
|
|
3766
3835
|
if (previous.heuristic) {
|
|
@@ -5030,9 +5099,14 @@ var ActionItemSchema = z.object({
|
|
|
5030
5099
|
action_type: z.string().describe("Action type, e.g. bash, file_read, file_write"),
|
|
5031
5100
|
action_detail: z.string().describe("Action detail / command content")
|
|
5032
5101
|
});
|
|
5102
|
+
var PromptTurnSchema = z.object({
|
|
5103
|
+
text: z.string().default("").describe("User prompt text at this turn"),
|
|
5104
|
+
actions: z.array(ActionItemSchema).default([]).describe("Actions triggered by this prompt, in order, until the next prompt")
|
|
5105
|
+
});
|
|
5033
5106
|
var AnalyzeRequestSchema = z.object({
|
|
5034
5107
|
session_id: z.string().describe("Session / agent unique identifier"),
|
|
5035
|
-
prompt_session: z.string().default("").describe("User original prompt"),
|
|
5108
|
+
prompt_session: z.string().default("").describe("User original prompt (most recent user message; backward compat)"),
|
|
5109
|
+
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."),
|
|
5036
5110
|
action_history: z.array(ActionItemSchema).default([]).describe("Historical action sequence"),
|
|
5037
5111
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
5038
5112
|
reason: z.string().default("").describe("Reason for executing this action"),
|