@ps-neko/nekowork 0.2.0-alpha.3 → 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/README.md CHANGED
@@ -10,23 +10,24 @@ pushes, or deploys on its own.
10
10
 
11
11
  ## Status
12
12
 
13
- **Published alpha** (`@ps-neko/nekowork`, alpha dist-tag). This package is the
14
- published slim verification gate. Install with:
13
+ **Published alpha** (`@ps-neko/nekowork`, `@alpha` dist-tag). This package is the
14
+ published slim verification gate. Always install with the **`@alpha`** tag —
15
+ `latest` is pinned to an old `0.2.0-alpha.0` and is not the alpha line:
15
16
 
16
17
  ```bash
17
- npm i -g @ps-neko/nekowork
18
+ npm i -g @ps-neko/nekowork@alpha
18
19
  ```
19
20
 
20
21
  The fuller legacy and power-user surface lives in the internal
21
22
  `@ps-neko/nekowork-harness` package (not separately published). See
22
- [HANDOFF-PACKAGE-SPLIT.md](./HANDOFF-PACKAGE-SPLIT.md) for the split history.
23
+ [HANDOFF-PACKAGE-SPLIT.md](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork/HANDOFF-PACKAGE-SPLIT.md) for the split history.
23
24
 
24
25
  ## Quickstart
25
26
 
26
27
  ```bash
27
28
  # right after your AI tool changes some files:
28
- npx -y @ps-neko/nekowork check # 30-sec environment check
29
- npx -y @ps-neko/nekowork verify-pr # scan the diff → get a verdict
29
+ npx -y @ps-neko/nekowork@alpha check # 30-sec environment check
30
+ npx -y @ps-neko/nekowork@alpha verify-pr # scan the diff → get a verdict
30
31
  ```
31
32
 
32
33
  `verify-pr` reads the diff, writes a plain-English `REPORT.md`, and tells you
@@ -39,7 +40,7 @@ whether the change is safe to merge.
39
40
  | `check` | Probe environment readiness (Node version, git repo, etc.) |
40
41
  | `verify-pr` | Scan working-tree diff. Produce REPORT.md + .nekowork/decision.json |
41
42
  | `report` | Render an existing decision.json to a human-readable REPORT.md |
42
- | `apply` | Session-based compatibility apply. Requires a completed work cycle (SHIP_READY marker + cleared Human Gate). NOT driven by verify-pr's decision.json. See [ADVANCED.md](../nekowork-cli/docs/ADVANCED.md). |
43
+ | `apply` | Session-based compatibility apply. Requires a completed work cycle (SHIP_READY marker + cleared Human Gate). NOT driven by verify-pr's decision.json. See [ADVANCED.md](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork-cli/docs/ADVANCED.md). |
43
44
 
44
45
  Anything else (`ask`, `plan`, `team`, `work`, `ship`, `build`, `auto`,
45
46
  `pr-prep`, `review`, ...) belongs to `@ps-neko/nekowork-harness` (legacy and
@@ -63,10 +64,10 @@ step — it is not triggered by `decision.json`.
63
64
 
64
65
  ## Docs
65
66
 
66
- - [Quickstart](../nekowork-cli/docs/QUICKSTART.md)
67
- - [How verification works](../nekowork-cli/docs/SCOPE-1.0.md)
68
- - [Benchmark](../nekowork-cli/docs/BENCHMARK.md) — 73/74 (99%) recall, 0/47 FP, 38 real OSS positives
69
- - [Integration](../nekowork-cli/docs/INTEGRATION.md)
67
+ - [Quickstart](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork-cli/docs/QUICKSTART.md)
68
+ - [How verification works](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork-cli/docs/SCOPE-1.0.md)
69
+ - [Benchmark](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork-cli/docs/BENCHMARK.md) — 85/86 (99%) recall, 0/47 FP, 30 real OSS positives (secret-fallback)
70
+ - [Integration](https://github.com/Ps-Neko/NEKOWORK/blob/main/packages/nekowork-cli/docs/INTEGRATION.md)
70
71
 
71
72
  ## License
72
73
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ps-neko/nekowork",
3
- "version": "0.2.0-alpha.3",
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 -r -f or rm -rf with variable expansion in the path
32
- re: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\b[^\n]*\$\{?\w/g,
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+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/(?!tmp(?:\/|$|\s)|var\/(?:log|cache|tmp)\/|home\/\w|root\/\w|node_modules\/|opt\/render\/)\S*/g,
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
- re: /process\.env\.(\w+)\s*\|\|\s*(["'`])([^"'`\n]+)\2/g,
22
- pickEnv: m => m[1],
23
- pickLiteral: m => m[3],
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
- re: /\b([A-Za-z_]\w*\.(?:apiKey|secret|secretKey|token|password|key|jwt|auth))\s*\|\|\s*(["'`])([^"'`\n]+)\2/g,
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[3],
51
+ pickLiteral: m => m[4],
48
52
  },
49
53
  {
50
54
  id: 'config-fallback-property',