@lazyingart/agintiflow 0.20.77 → 0.20.78

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.77",
3
+ "version": "0.20.78",
4
4
  "type": "module",
5
5
  "description": "Low-cost, project-aware Web and CLI agents with DeepSeek/Venice/OpenAI routing, visible tool calls, durable sessions, scouts, AAPS, SCS, and guarded local execution.",
6
6
  "license": "Apache-2.0",
@@ -263,6 +263,18 @@ try {
263
263
  assert(clonePolicy.allowed, "git clone should be allowed in docker-workspace allow mode");
264
264
  assert(clonePolicy.needsNetwork, "git clone was not classified as network");
265
265
  assert(clonePolicy.writesWorkspace, "git clone was not classified as workspace-writing");
266
+ const quotedDangerSearchPolicy = evaluateCommandPolicy(
267
+ 'grep -nE "rm -rf|git reset --hard|git clean -fd|find . -delete" reports/destructive-command-policy.md',
268
+ dockerWorkspacePolicy
269
+ );
270
+ assert(quotedDangerSearchPolicy.allowed, "read-only grep for destructive command strings should be allowed");
271
+ assert(
272
+ quotedDangerSearchPolicy.category !== "destructive",
273
+ "quoted destructive strings in grep pattern should not classify as a destructive command"
274
+ );
275
+ const actualDangerAfterQuotePolicy = evaluateCommandPolicy('echo "rm -rf is text" && rm -rf reports', dockerWorkspacePolicy);
276
+ assert(!actualDangerAfterQuotePolicy.allowed, "actual destructive command after quoted text should still be blocked");
277
+ assert(actualDangerAfterQuotePolicy.category === "destructive", "actual destructive command after quoted text was not classified as destructive");
266
278
  const unsafeCloneTarget = evaluateCommandPolicy("git clone https://github.com/lazyingart/AgInTiFlow.git ../AgInTiFlow", dockerWorkspacePolicy);
267
279
  assert(!unsafeCloneTarget.allowed, "git clone outside the workspace should be blocked");
268
280
  const blockedClonePolicy = evaluateCommandPolicy("git clone https://github.com/lazyingart/AgInTiFlow.git", {
@@ -11,6 +11,7 @@ const READ_ONLY_PATTERNS = [
11
11
  /^ls(?:\s+[-\w./~*]+)*$/,
12
12
  /^find(?:\s+[./~\w-]+)*(?:\s+-maxdepth\s+\d+)?(?:\s+-type\s+[fd])?$/,
13
13
  /^rg(?:\s+.+)?$/,
14
+ /^grep(?:\s+.+)?$/,
14
15
  /^cat(?:\s+[-\w./~*]+)+$/,
15
16
  /^head(?:\s+.+)?$/,
16
17
  /^tail(?:\s+.+)?$/,
@@ -151,6 +152,36 @@ function matchAny(patterns, command) {
151
152
  return patterns.some((pattern) => pattern.test(command));
152
153
  }
153
154
 
155
+ function stripQuotedSegments(command = "") {
156
+ let output = "";
157
+ let quote = "";
158
+ let escaped = false;
159
+ for (const char of String(command || "")) {
160
+ if (escaped) {
161
+ escaped = false;
162
+ if (!quote) output += " ";
163
+ continue;
164
+ }
165
+ if (char === "\\") {
166
+ escaped = true;
167
+ if (!quote) output += char;
168
+ continue;
169
+ }
170
+ if (quote) {
171
+ if (char === quote) quote = "";
172
+ output += " ";
173
+ continue;
174
+ }
175
+ if (char === "'" || char === '"') {
176
+ quote = char;
177
+ output += " ";
178
+ continue;
179
+ }
180
+ output += char;
181
+ }
182
+ return output;
183
+ }
184
+
154
185
  function isSafeRelativeDir(value) {
155
186
  const normalized = String(value || "").trim();
156
187
  if (!normalized || normalized.startsWith("/") || normalized.startsWith("~")) return false;
@@ -231,7 +262,8 @@ function classifySimpleCommand(normalized) {
231
262
  const gitCloneClassification = classifyGitClone(normalized);
232
263
  if (gitCloneClassification) return gitCloneClassification;
233
264
 
234
- const lowered = ` ${normalized.toLowerCase()} `;
265
+ const unquoted = stripQuotedSegments(normalized);
266
+ const lowered = ` ${unquoted.toLowerCase()} `;
235
267
  if (BLOCKED_WRITE_TOKENS.some((part) => lowered.includes(part))) {
236
268
  return {
237
269
  category: "destructive",
@@ -240,7 +272,7 @@ function classifySimpleCommand(normalized) {
240
272
  reason: `Command contains a write-capable or destructive token: ${normalized}`,
241
273
  };
242
274
  }
243
- if (BLOCKED_SHELL_TOKENS.some((part) => normalized.includes(part))) {
275
+ if (BLOCKED_SHELL_TOKENS.some((part) => unquoted.includes(part))) {
244
276
  return {
245
277
  category: "general-shell",
246
278
  needsNetwork: true,