@ps-neko/nekowork 0.2.0-alpha.4 → 0.2.0-alpha.5
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": "@ps-neko/nekowork",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.5",
|
|
4
4
|
"description": "Local verification gate for AI-written code diffs. Deterministic rules decide the verdict, never the LLM. No auto-commit, push, or deploy — you decide at the Human Gate.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-code-review",
|
|
@@ -276,10 +276,15 @@ function synthesizeUntrackedDiff(cwd) {
|
|
|
276
276
|
* @returns {string} concatenated unified-diff chunks
|
|
277
277
|
*/
|
|
278
278
|
const SYNTH_FILE_SIZE_LIMIT = 2 * 1024 * 1024; // 2 MB per file
|
|
279
|
+
const SYNTH_TOTAL_SIZE_LIMIT = 64 * 1024 * 1024; // 64 MB aggregate (guards full-scan OOM)
|
|
279
280
|
|
|
280
281
|
function synthesizeFilesAsDiff(cwd, relPaths) {
|
|
281
282
|
let chunks = '';
|
|
283
|
+
let truncated = false;
|
|
282
284
|
for (const rel of relPaths) {
|
|
285
|
+
// Aggregate cap: stop accumulating once the synthesized diff is very large,
|
|
286
|
+
// so a huge full-scan / untracked tree cannot exhaust memory.
|
|
287
|
+
if (chunks.length >= SYNTH_TOTAL_SIZE_LIMIT) { truncated = true; break; }
|
|
283
288
|
const full = path.join(cwd, rel);
|
|
284
289
|
let content;
|
|
285
290
|
try {
|
|
@@ -300,6 +305,11 @@ function synthesizeFilesAsDiff(cwd, relPaths) {
|
|
|
300
305
|
chunks += `@@ -0,0 +1,${lines.length} @@\n`;
|
|
301
306
|
for (const line of lines) chunks += `+${line}\n`;
|
|
302
307
|
}
|
|
308
|
+
if (truncated) {
|
|
309
|
+
process.stderr.write(
|
|
310
|
+
`warning: diff synthesis truncated at ${Math.round(SYNTH_TOTAL_SIZE_LIMIT / (1024 * 1024))}MB; some files were not scanned. Narrow the scope (avoid --full-scan on very large trees).\n`,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
303
313
|
return chunks;
|
|
304
314
|
}
|
|
305
315
|
|
|
@@ -28,8 +28,9 @@ const PATTERNS = [
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
id: 'rm-rf-variable',
|
|
31
|
-
// rm
|
|
32
|
-
|
|
31
|
+
// rm with recursive+force flags (combined `-rf`/`-fr` or separated `-r -f`/`-f -r`)
|
|
32
|
+
// and variable expansion in the path.
|
|
33
|
+
re: /\brm\s+(?=-[a-zA-Z]*(?:rf|fr)|-[a-zA-Z]*r[a-zA-Z]*\s+-[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*\s+-[a-zA-Z]*r)-[a-zA-Z][^\n]*\$\{?\w/g,
|
|
33
34
|
severity: 'critical',
|
|
34
35
|
title: 'rm -rf with variable path',
|
|
35
36
|
description: 'Removing with a variable path is dangerous — if the variable is empty, the parent directory is wiped.',
|
|
@@ -39,7 +40,7 @@ const PATTERNS = [
|
|
|
39
40
|
id: 'rm-rf-system',
|
|
40
41
|
// rm -rf on a root-like path (not allowed: /tmp, /var/{log,cache,tmp},
|
|
41
42
|
// /home/<u>, /root/<x>, /node_modules — common safe targets)
|
|
42
|
-
re: /\brm\s
|
|
43
|
+
re: /\brm\s+(?=-[a-zA-Z]*(?:rf|fr)|-[a-zA-Z]*r[a-zA-Z]*\s+-[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*\s+-[a-zA-Z]*r)-[a-zA-Z][^\n]*?\s+\/(?!tmp(?:\/|$|\s)|var\/(?:log|cache|tmp)\/|home\/\w|root\/\w|node_modules\/|opt\/render\/)\S*/g,
|
|
43
44
|
severity: 'critical',
|
|
44
45
|
title: 'rm -rf on system path',
|
|
45
46
|
description: 'Removing system paths is destructive and rarely intentional in a build/automation script.',
|
|
@@ -18,9 +18,10 @@ import { addedLines as collectAddedLines } from '../diff-parser.js';
|
|
|
18
18
|
const PATTERNS = [
|
|
19
19
|
{
|
|
20
20
|
id: 'env-or-literal',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// dot form process.env.X || "lit" and bracket form process.env['X'] || "lit"
|
|
22
|
+
re: /process\.env(?:\.(\w+)|\[(["'`])(\w+)\2\])\s*\|\|\s*(["'`])([^"'`\n]+)\4/g,
|
|
23
|
+
pickEnv: m => m[1] || m[3],
|
|
24
|
+
pickLiteral: m => m[5],
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
27
|
id: 'nullish-fallback',
|
|
@@ -42,9 +43,12 @@ const PATTERNS = [
|
|
|
42
43
|
},
|
|
43
44
|
{
|
|
44
45
|
id: 'config-or-literal',
|
|
45
|
-
|
|
46
|
+
// dot form obj.secretProp || "lit" and bracket form obj['SECRET_KEY'] || "lit".
|
|
47
|
+
// The bracket key is gated to secret-keyword names so generic config defaults
|
|
48
|
+
// (e.g. config['timeout'] || 5000) do not match.
|
|
49
|
+
re: /\b([A-Za-z_]\w*\.(?:apiKey|secret|secretKey|token|password|key|jwt|auth)|[A-Za-z_]\w*\[(["'`])[\w-]*(?:KEY|TOKEN|SECRET|PASSWORD|PASS|AUTH|JWT|API|CREDENTIAL|apiKey|secretKey)[\w-]*\2\])\s*\|\|\s*(["'`])([^"'`\n]+)\3/g,
|
|
46
50
|
pickEnv: m => m[1],
|
|
47
|
-
pickLiteral: m => m[
|
|
51
|
+
pickLiteral: m => m[4],
|
|
48
52
|
},
|
|
49
53
|
{
|
|
50
54
|
id: 'config-fallback-property',
|