@lazyingart/agintiflow 0.20.176 → 0.20.177

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.176",
3
+ "version": "0.20.177",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -1103,6 +1103,29 @@ try {
1103
1103
  );
1104
1104
  assert(safeEnvReferenceResult.ok, "write_file should allow safe env-var credential references in source code");
1105
1105
 
1106
+ const safeTokenVariableSyntaxResult = await executeWorkspaceTool(
1107
+ "write_file",
1108
+ {
1109
+ path: "scripts/safe-token-variable-syntax.py",
1110
+ content: [
1111
+ "def validate(tokens):",
1112
+ " for token in tokens:",
1113
+ " if not isinstance(token, dict) or \"t\" not in token:",
1114
+ " raise ValueError(\"token must contain t\")",
1115
+ " text = str(token.get(\"t\", \"\"))",
1116
+ " if token:",
1117
+ " print(text)",
1118
+ "",
1119
+ ].join("\n"),
1120
+ mode: "create",
1121
+ },
1122
+ {
1123
+ commandCwd: workspace,
1124
+ allowFileTools: true,
1125
+ }
1126
+ );
1127
+ assert(safeTokenVariableSyntaxResult.ok, "write_file should allow benign token variable syntax in source code");
1128
+
1106
1129
  const redactedContentResult = await executeWorkspaceTool(
1107
1130
  "write_file",
1108
1131
  {
package/src/redaction.js CHANGED
@@ -2,7 +2,7 @@ const SECRET_PATTERNS = [
2
2
  /\bsk-[A-Za-z0-9_-]{16,}\b/g,
3
3
  /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
4
4
  /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g,
5
- /((?:api[_-]?key|token|secret|password|passwd|npm_token|_authToken|grsai|venice_api_key)\s*[:=]\s*)[^\s"'`]+/gi,
5
+ /((?:api[_-]?key|token|secret|password|passwd|npm_token|_authToken|grsai|venice_api_key)[^\S\r\n]*[:=][^\S\r\n]*)[^\s"'`]+/gi,
6
6
  /(\/\/registry\.npmjs\.org\/:_authToken=)[^\s"'`]+/gi,
7
7
  /(Authorization:\s*Bearer\s+)[^\s"'`]+/gi,
8
8
  ];
@@ -90,7 +90,36 @@ function splitInlineTerms(text = "") {
90
90
  return String(text || "")
91
91
  .split(/[、,,;;]/)
92
92
  .map((item) => item.replace(/[。.!!??::]/g, "").trim())
93
- .filter((item) => item.length >= 2 && item.length <= 40 && !/[\\/]/.test(item));
93
+ .filter((item) => item.length >= 2 && item.length <= 40 && !/[\\/"'“”‘’`]/.test(item));
94
+ }
95
+
96
+ function trimForbiddenTail(tail = "") {
97
+ let text = String(tail || "").trim();
98
+ if (!text) return "";
99
+ const stopPatterns = [
100
+ /(?:^|[,,、\s])(?:并|且)?(?:末尾|最后|最後|保存|存到|写入|寫入|输出|輸出|完成后|完成後|运行|执行|執行|用命令|检查|檢查|验证|驗證|确认|確認|保留)/,
101
+ /(?:^|[,\s])(?:and\s+)?(?:then|save|write|output|run|execute|check|verify|confirm|after)\b/i,
102
+ ];
103
+ const stops = stopPatterns.map((pattern) => text.search(pattern)).filter((index) => index >= 0);
104
+ if (stops.length) text = text.slice(0, Math.min(...stops)).trim();
105
+ return text.replace(/[,,、;;:\s]+$/g, "").trim();
106
+ }
107
+
108
+ function forbiddenTails(text = "") {
109
+ const tails = [];
110
+ const source = String(text || "");
111
+ const patterns = [
112
+ /(?:不要(?:写|寫)成|不得(?:写|寫)成|禁止(?:写|寫)成)\s*([^,,。;;\n]+)/g,
113
+ /(?:(?:不要|不得|禁止)(?:(?:写|寫)(?!成)|包含|提到)|(?:确认|確認)[^。;;\n]{0,40}?(?:没有|沒有))\s*([^。;;\n]+)/g,
114
+ /\b(?:do not|don't|dont|must not|never)\s+(?:write|include|mention|contain)\s+([^.\n;]+)/gi,
115
+ ];
116
+ for (const pattern of patterns) {
117
+ for (const match of source.matchAll(pattern)) {
118
+ const tail = trimForbiddenTail(match[1] || "");
119
+ if (tail) tails.push(tail);
120
+ }
121
+ }
122
+ return tails;
94
123
  }
95
124
 
96
125
  function inferExactOutputPaths(goal = "") {
@@ -98,7 +127,7 @@ function inferExactOutputPaths(goal = "") {
98
127
  const lines = String(goal || "").split(/\n+/);
99
128
  const pathPattern = /(?:^|[\s"'`::])((?:~|\.{1,2}|[A-Za-z0-9_\-\u4e00-\u9fff])[\w./~\-\u4e00-\u9fff ]{0,220}\.(?:md|txt|json|ya?ml|html|css|js|ts|tsx|jsx|py|sh|csv|tex|svg|png|jpe?g|webp|mp4|mov|pdf|docx))(?:$|[\s"'`,,。;;])/gi;
100
129
  for (const line of lines) {
101
- if (!/\b(save|saved|write|written|output|create|store)\b|保存|写入|寫入|输出|輸出|创建|建立/.test(line)) continue;
130
+ if (!/\b(save|saved|write|written|output|create|store|update|modify|edit)\b|保存|写入|寫入|输出|輸出|创建|建立|更新|修改|编辑|編輯/.test(line)) continue;
102
131
  for (const match of line.matchAll(pathPattern)) {
103
132
  const raw = String(match[1] || "").trim();
104
133
  if (!raw) continue;
@@ -108,6 +137,13 @@ function inferExactOutputPaths(goal = "") {
108
137
  return uniqueLimited(paths, 8);
109
138
  }
110
139
 
140
+ function stripForbiddenTextClauses(text = "") {
141
+ return String(text || "")
142
+ .replace(/(?:不要(?:写|寫)成|不得(?:写|寫)成|禁止(?:写|寫)成)\s*[^,,。;;\n]+/g, "")
143
+ .replace(/(?:(?:不要|不得|禁止)(?:(?:写|寫)(?!成)|包含|提到)|(?:确认|確認)[^。;;\n]{0,40}?(?:没有|沒有))\s*[^。;;\n]+/g, "")
144
+ .replace(/\b(?:do not|don't|dont|must not|never)\s+(?:write|include|mention|contain)\s+[^.\n;]+/gi, "");
145
+ }
146
+
111
147
  function inferRequiredTextTerms(goal = "") {
112
148
  const terms = [];
113
149
  const lines = String(goal || "").split(/\n+/);
@@ -115,11 +151,12 @@ function inferRequiredTextTerms(goal = "") {
115
151
  const positiveSegment = String(line || "").split(
116
152
  /(?:并)?确认没有|(?:并)?確認沒有|没有|沒有|\b(?:does not contain|do not contain|not contain|not include|without)\b/i
117
153
  )[0];
154
+ const requiredSegment = stripForbiddenTextClauses(positiveSegment);
118
155
  if (
119
156
  /\b(must|require|required|include|contain|contains|check|verify|grep|keyword|keywords)\b/i.test(line) ||
120
157
  /必须|必須|要求|包含|检查|檢查|验证|驗證|关键词|關鍵詞|自检|自檢/.test(line)
121
158
  ) {
122
- terms.push(...quotedTerms(positiveSegment));
159
+ terms.push(...quotedTerms(requiredSegment));
123
160
  }
124
161
  }
125
162
  return uniqueLimited(terms, 24);
@@ -129,16 +166,7 @@ function inferForbiddenTextTerms(goal = "") {
129
166
  const terms = [];
130
167
  const lines = String(goal || "").split(/\n+/);
131
168
  for (const line of lines) {
132
- const text = String(line || "");
133
- if (
134
- /\b(?:do not|don't|dont|must not|never)\s+(?:write|include|mention|contain)\b/i.test(text) ||
135
- /不要(?:写|寫|包含|提到)|不得(?:写|寫|包含|提到)|禁止(?:写|寫|包含|提到)|(?:确认|確認)(?:没有|沒有)/.test(text)
136
- ) {
137
- const tail =
138
- text.match(/(?:不要(?:写|寫|包含|提到)|不得(?:写|寫|包含|提到)|禁止(?:写|寫|包含|提到))(.+)/)?.[1] ||
139
- text.match(/(?:确认|確認)(?:没有|沒有)(.+)/)?.[1] ||
140
- text.match(/\b(?:do not|don't|dont|must not|never)\s+(?:write|include|mention|contain)\s+(.+)/i)?.[1] ||
141
- "";
169
+ for (const tail of forbiddenTails(line)) {
142
170
  terms.push(...quotedTerms(tail));
143
171
  const unquotedTail = tail.replace(/“[^”]+”|"[^"\n]+"|'[^'\n]+'|`[^`\n]+`/g, "");
144
172
  terms.push(...splitInlineTerms(unquotedTail).filter((item) => !/^(and|or|the|a|an|other|其他|上一集道具)$/.test(item)));