pitroom 0.6.1 → 0.6.4

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pitroom",
3
3
  "description": "A free pit crew for your expensive coding agent: the superpowers development workflow, run by cheap workers. Delegate research, fixes, tests, reviews and whole plans from Claude Code, Codex or any agent to OpenCode, Codex or Claude Code workers, with receipts that prove the savings.",
4
- "version": "0.6.1",
4
+ "version": "0.6.4",
5
5
  "author": {
6
6
  "name": "TahaAtas"
7
7
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pitroom",
3
- "version": "0.6.1",
4
- "description": "A free pit crew for your expensive coding agent: delegate research, fixes, tests and parallel investigations to cheap OpenCode, Codex or Claude Code workers, with verified answers, exact diffs and cost receipts.",
3
+ "version": "0.6.4",
4
+ "description": "A free pit crew for your expensive coding agent: delegate research, fixes, tests, reviews and parallel investigations to cheap worker agents running your own models, with verified answers, exact diffs and cost receipts.",
5
5
  "author": {
6
6
  "name": "TahaAtas"
7
7
  },
@@ -9,20 +9,20 @@
9
9
  "repository": "https://github.com/ATASTECH/pitroom",
10
10
  "license": "MIT",
11
11
  "keywords": [
12
- "claude-code",
13
- "codex",
12
+ "agent-skills",
14
13
  "cost",
15
14
  "delegation",
16
- "opencode",
17
15
  "parallel",
18
16
  "subagents",
19
- "workers"
17
+ "tokens",
18
+ "workers",
19
+ "workflow"
20
20
  ],
21
21
  "skills": "./skills/",
22
22
  "interface": {
23
23
  "displayName": "Pitroom",
24
24
  "shortDescription": "Cheap workers for your agent",
25
- "longDescription": "Pitroom lets your coding agent hand bounded work to OpenCode, Codex or Claude Code workers running your own free, paid or local models: read-only research, isolated code changes, second-opinion reviews and parallel crews, with per-run permission profiles, a git guard, verified file references, exact diffs and cost receipts. Fourteen skills adapt a full development workflow (brainstorm, plan, worker-driven development, review, debugging, TDD, verification). Requires the pitroom command (npm i -g pitroom), Node.js 18 or newer and at least one worker CLI.",
25
+ "longDescription": "Pitroom lets your coding agent hand bounded work to worker agents running your own free, paid or local models: read-only research, isolated code changes, second-opinion reviews and parallel crews, with per-run permission profiles, a git guard, verified file references, exact diffs and cost receipts. Fourteen skills adapt a full development workflow (brainstorm, plan, worker-driven development, review, debugging, TDD, verification). Requires the pitroom command (npm i -g pitroom), Node.js 18 or newer and at least one worker agent CLI, installed and signed in.",
26
26
  "developerName": "TahaAtas",
27
27
  "category": "Developer Tools",
28
28
  "capabilities": [
@@ -30,6 +30,10 @@
30
30
  "Write"
31
31
  ],
32
32
  "websiteURL": "https://github.com/ATASTECH/pitroom",
33
- "supportURL": "https://github.com/ATASTECH/pitroom/issues"
33
+ "supportURL": "https://github.com/ATASTECH/pitroom/issues",
34
+ "brandColor": "#FF6A2B",
35
+ "logo": "./assets/logo.svg",
36
+ "composerIcon": "./assets/icon.svg",
37
+ "privacyPolicyURL": "https://github.com/ATASTECH/pitroom/blob/main/PRIVACY.md"
34
38
  }
35
39
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.4
4
+
5
+ ### Deleting is the user's call
6
+ - `pitroom apply` (and `apply -g`) refuses a patch that deletes files unless you pass `--allow-delete`; nothing of the patch is applied. The run report flags deletions with a warning, for isolated runs and for `-w` runs (undo: `pitroom revert`).
7
+ - Workers are told to delete a file only when the task explicitly asks for it, to list every deleted file, and to propose any other deletion under OPEN ISSUES instead of doing it.
8
+ - The skills (`using-pitroom`, `pitroom-implement`, `pitroom-driven-development`, `pitroom-crew`) make the primary agent the decider: it sets each worker's permissions from the task and the user's session (read, isolate or write mode, `--web`), decides whether a deletion is wanted and passes `--allow-delete` itself, asking the user only when the worker deleted something that was not asked for. A fixed floor (no git history changes, no `sudo`, no publishing, no secrets) stays in place.
9
+
10
+ ## 0.6.3
11
+
12
+ ### Skills
13
+ - `pitroom-debugging` no longer bundles `find-polluter.sh`, an executable that ran the project's tests in a loop (a directory scan flagged it as a security risk). The test-pollution hunt is now a written procedure: bisect the test files by hand, in an isolated copy, with the project's own test command.
14
+
15
+ ## 0.6.2
16
+
17
+ ### Directory listing
18
+ - The Codex manifest no longer names other assistants or platforms in its name, descriptions and keywords (the OpenAI directory flags them), and carries an app icon (`assets/logo.svg`, `assets/icon.svg`) and a `privacyPolicyURL`.
19
+ - `PRIVACY.md`: what Pitroom stores and what reaches a worker's model provider.
20
+
3
21
  ## 0.6.1
4
22
 
5
23
  ### Install
package/PRIVACY.md ADDED
@@ -0,0 +1,31 @@
1
+ # Pitroom privacy policy
2
+
3
+ _Last updated: 2026-09-30_
4
+
5
+ Pitroom is a command-line tool and a set of agent skills that run on your own computer. This page says what it does with your data.
6
+
7
+ ## What the Pitroom authors collect
8
+
9
+ Nothing. Pitroom has no accounts, no analytics and no telemetry, and its own code makes no network requests. No data is sent to the authors.
10
+
11
+ ## What happens when you delegate work
12
+
13
+ Pitroom starts a worker agent CLI that you installed and signed in to yourself. Whatever you ask a worker to do is handled by that CLI and by the model provider behind it:
14
+
15
+ - the task text you or your agent write;
16
+ - the files the worker reads in your project;
17
+ - for reviews, the diff under review with 10 lines of context, written to a package file the reviewer reads.
18
+
19
+ That data goes to the provider of the worker's model, under that provider's terms and privacy policy, not under this one. Pitroom does not filter the content it hands to a worker: secrets that are committed to a reviewed range are sent as they are. Workers cannot read `.env` files or private key files through Pitroom's permission profiles. To keep code on your machine, point the worker at a local model.
20
+
21
+ ## What Pitroom stores on your computer
22
+
23
+ - Run records (the task, the worker's answer, diffs, receipts and the savings ledger) in `~/.local/state/pitroom`, or in the folder named by `PITROOM_HOME`.
24
+ - Optional settings in `~/.config/pitroom/config.json`.
25
+ - Private working copies of your project for isolated runs, inside the state folder. They are removed when you apply or discard a run.
26
+
27
+ Nothing is stored in your repository. To delete the records, run `pitroom clean` or remove the state folder.
28
+
29
+ ## Changes and contact
30
+
31
+ If this policy changes, the new version is published in this file with a new date. Questions and requests: <https://github.com/ATASTECH/pitroom/issues>.
package/README.md CHANGED
@@ -100,6 +100,7 @@ In isolate mode nothing reaches your tree until you apply it.
100
100
  - **Self-healing worker chain.** Free models get rate-limited or retired. List fallback workers once (`fallback`) and a run that hits "model not found", 429 or quota errors moves to the next model automatically. Still no model hardcoded: the chain is yours.
101
101
  - **A crew, not just one worker.** `pitroom crew` starts several workers at once, `pitroom watch --json` streams one line per change so your agent follows them live, `pitroom wait -g` collects every answer, `pitroom apply -g` lands isolated patches in order. A queue (`maxParallel`) keeps free tiers from rate-limiting you; parallel writers are refused.
102
102
  - **Exact changes, even in a dirty tree.** Pitroom snapshots the working tree with a throwaway git index (your index, branches and stash are never touched), so it reports *only the worker's* edits and can undo exactly those: `pitroom revert <id>`.
103
+ - **Your agent sets the permissions.** It creates each worker with the permissions the task and your session allow (read-only, isolated copy, in-place edits, web), and a worker never widens its own. A fixed floor stays for every run: no git history changes, no `sudo`, no publishing, no secrets. A worker cannot land a deletion either: `pitroom apply` refuses a patch that deletes files unless your agent passes `--allow-delete`.
103
104
  - **Real isolation.** `--isolate` runs the worker in a private copy of your **current** state (its own repository, sharing your objects read-only), uncommitted and untracked files included, then hands you a patch: `pitroom apply <id>` (checked, refuses on conflict) or `pitroom discard <id>`.
104
105
  - **Zero repo pollution.** No `.pitroom/` folder, no `.gitignore` edits, no branches. Records live in `~/.local/state/pitroom`.
105
106
  - **Works with any agent.** Fourteen [Agent Skills](https://agentskills.io): the superpowers development workflow run by workers, plus delegation (`using-pitroom`, `pitroom-research`, `-crew`, `-implement`), a CLI, and a Claude Code / Codex plugin whose session-start hook loads the workflow. Claude Code, Codex, Gemini CLI, Cursor, or anything that can run a shell command.
@@ -0,0 +1,32 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="Pitroom">
2
+ <rect width="512" height="512" rx="112" fill="#0B1020"/>
3
+ <rect x="128" y="88" width="24" height="336" rx="12" fill="#F4F6FB"/>
4
+ <g>
5
+ <rect x="152" y="104" width="40" height="40" fill="#F4F6FB"/>
6
+ <rect x="192" y="104" width="40" height="40" fill="#1B2547"/>
7
+ <rect x="232" y="104" width="40" height="40" fill="#F4F6FB"/>
8
+ <rect x="272" y="104" width="40" height="40" fill="#1B2547"/>
9
+ <rect x="312" y="104" width="40" height="40" fill="#F4F6FB"/>
10
+ <rect x="352" y="104" width="40" height="40" fill="#1B2547"/>
11
+ <rect x="152" y="144" width="40" height="40" fill="#1B2547"/>
12
+ <rect x="192" y="144" width="40" height="40" fill="#F4F6FB"/>
13
+ <rect x="232" y="144" width="40" height="40" fill="#1B2547"/>
14
+ <rect x="272" y="144" width="40" height="40" fill="#F4F6FB"/>
15
+ <rect x="312" y="144" width="40" height="40" fill="#1B2547"/>
16
+ <rect x="352" y="144" width="40" height="40" fill="#F4F6FB"/>
17
+ <rect x="152" y="184" width="40" height="40" fill="#F4F6FB"/>
18
+ <rect x="192" y="184" width="40" height="40" fill="#1B2547"/>
19
+ <rect x="232" y="184" width="40" height="40" fill="#F4F6FB"/>
20
+ <rect x="272" y="184" width="40" height="40" fill="#1B2547"/>
21
+ <rect x="312" y="184" width="40" height="40" fill="#F4F6FB"/>
22
+ <rect x="352" y="184" width="40" height="40" fill="#1B2547"/>
23
+ <rect x="152" y="224" width="40" height="40" fill="#1B2547"/>
24
+ <rect x="192" y="224" width="40" height="40" fill="#F4F6FB"/>
25
+ <rect x="232" y="224" width="40" height="40" fill="#1B2547"/>
26
+ <rect x="272" y="224" width="40" height="40" fill="#F4F6FB"/>
27
+ <rect x="312" y="224" width="40" height="40" fill="#1B2547"/>
28
+ <rect x="352" y="224" width="40" height="40" fill="#F4F6FB"/>
29
+ <rect x="152" y="104" width="240" height="160" fill="none" stroke="#F4F6FB" stroke-width="4"/>
30
+ </g>
31
+ <rect x="88" y="424" width="144" height="24" rx="12" fill="#FF6A2B"/>
32
+ </svg>
@@ -0,0 +1,32 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="Pitroom">
2
+ <rect width="512" height="512" rx="112" fill="#0B1020"/>
3
+ <rect x="128" y="88" width="24" height="336" rx="12" fill="#F4F6FB"/>
4
+ <g>
5
+ <rect x="152" y="104" width="40" height="40" fill="#F4F6FB"/>
6
+ <rect x="192" y="104" width="40" height="40" fill="#1B2547"/>
7
+ <rect x="232" y="104" width="40" height="40" fill="#F4F6FB"/>
8
+ <rect x="272" y="104" width="40" height="40" fill="#1B2547"/>
9
+ <rect x="312" y="104" width="40" height="40" fill="#F4F6FB"/>
10
+ <rect x="352" y="104" width="40" height="40" fill="#1B2547"/>
11
+ <rect x="152" y="144" width="40" height="40" fill="#1B2547"/>
12
+ <rect x="192" y="144" width="40" height="40" fill="#F4F6FB"/>
13
+ <rect x="232" y="144" width="40" height="40" fill="#1B2547"/>
14
+ <rect x="272" y="144" width="40" height="40" fill="#F4F6FB"/>
15
+ <rect x="312" y="144" width="40" height="40" fill="#1B2547"/>
16
+ <rect x="352" y="144" width="40" height="40" fill="#F4F6FB"/>
17
+ <rect x="152" y="184" width="40" height="40" fill="#F4F6FB"/>
18
+ <rect x="192" y="184" width="40" height="40" fill="#1B2547"/>
19
+ <rect x="232" y="184" width="40" height="40" fill="#F4F6FB"/>
20
+ <rect x="272" y="184" width="40" height="40" fill="#1B2547"/>
21
+ <rect x="312" y="184" width="40" height="40" fill="#F4F6FB"/>
22
+ <rect x="352" y="184" width="40" height="40" fill="#1B2547"/>
23
+ <rect x="152" y="224" width="40" height="40" fill="#1B2547"/>
24
+ <rect x="192" y="224" width="40" height="40" fill="#F4F6FB"/>
25
+ <rect x="232" y="224" width="40" height="40" fill="#1B2547"/>
26
+ <rect x="272" y="224" width="40" height="40" fill="#F4F6FB"/>
27
+ <rect x="312" y="224" width="40" height="40" fill="#1B2547"/>
28
+ <rect x="352" y="224" width="40" height="40" fill="#F4F6FB"/>
29
+ <rect x="152" y="104" width="240" height="160" fill="none" stroke="#F4F6FB" stroke-width="4"/>
30
+ </g>
31
+ <rect x="88" y="424" width="144" height="24" rx="12" fill="#FF6A2B"/>
32
+ </svg>
package/dist/pitroom.mjs CHANGED
@@ -7,6 +7,12 @@ var UserError = class extends Error {
7
7
  this.code = code;
8
8
  }
9
9
  };
10
+ var DeletionRefused = class extends UserError {
11
+ constructor(message, files) {
12
+ super(message, 3);
13
+ this.files = files;
14
+ }
15
+ };
10
16
 
11
17
  // src/backends/claude/index.ts
12
18
  import { spawnSync } from "node:child_process";
@@ -1174,6 +1180,7 @@ var BOOL_FLAGS = {
1174
1180
  "--probe": "probe",
1175
1181
  "--copy": "copy",
1176
1182
  "--force": "force",
1183
+ "--allow-delete": "allow-delete",
1177
1184
  "--yes": "yes",
1178
1185
  "--any": "any",
1179
1186
  "--brief": "brief",
@@ -1514,6 +1521,12 @@ function formatReport(meta, finalText = readSummary(meta), maxLines = 400) {
1514
1521
  );
1515
1522
  for (const c of meta.changes.slice(0, 50)) out.push(` ${c.status} ${c.path}`);
1516
1523
  if (meta.changes.length > 50) out.push(` \u2026 ${meta.changes.length - 50} more`);
1524
+ const deleted = meta.changes.filter((c) => c.status === "D").length;
1525
+ if (deleted && !meta.applied && !meta.reverted && !meta.discarded) {
1526
+ out.push(
1527
+ meta.mode === "isolate" ? ` \u26A0 deletes ${deleted} file${deleted === 1 ? "" : "s"}: check they are wanted before applying (apply refuses without --allow-delete)` : ` \u26A0 deleted ${deleted} file${deleted === 1 ? "" : "s"} in your tree: check they are wanted (undo: pitroom revert ${meta.id})`
1528
+ );
1529
+ }
1517
1530
  if (meta.changes.length) {
1518
1531
  out.push(` diff: pitroom show ${meta.id} --patch`);
1519
1532
  out.push(` review: pitroom review ${meta.id}`);
@@ -2598,6 +2611,7 @@ Rules:
2598
2611
  - Stay inside the task scope and the project directory.
2599
2612
  - Never commit, push, reset, checkout, restore, stash, clean, rebase or merge, and never discard or overwrite uncommitted work you did not create.
2600
2613
  - Never read or reveal secrets (.env files, keys, tokens).
2614
+ - Delete a file only when the task explicitly asks for it, and name every file you delete under FILES CHANGED. Whether anything else should be deleted or overwritten is the primary agent's decision: propose it under OPEN ISSUES and leave the file alone.
2601
2615
  - Do not ask questions. If something is ambiguous, choose the safest reasonable interpretation and state the assumption.
2602
2616
  - Be economical: open only what you need.
2603
2617
 
@@ -2720,7 +2734,7 @@ function inside(file, roots) {
2720
2734
  var escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2721
2735
 
2722
2736
  // src/core/run.ts
2723
- var VERSION2 = true ? "0.6.1" : "0.0.0-dev";
2737
+ var VERSION2 = true ? "0.6.4" : "0.0.0-dev";
2724
2738
  function planWork(o) {
2725
2739
  if (!o.plan) return { task: o.task.trim(), tier: o.tier };
2726
2740
  if (o.continueFrom) throw new UserError("a follow-up continues its parent's task; drop --plan/--step");
@@ -3020,10 +3034,21 @@ function runVerify(meta) {
3020
3034
  fs21.writeFileSync(runFile(meta.id, "verify.log"), output);
3021
3035
  return { ok: r.status === 0, code: r.status, tail: output.trimEnd().split("\n").slice(-25).join("\n") };
3022
3036
  }
3023
- function applyRun(meta) {
3037
+ function applyRun(meta, allowDelete = false) {
3024
3038
  if (meta.mode !== "isolate") throw new UserError(`run ${meta.id} edited your tree directly (${meta.mode}); nothing to apply`);
3025
3039
  if (meta.applied) throw new UserError(`run ${meta.id} was already applied`);
3026
3040
  if (!meta.changes?.length) throw new UserError(`run ${meta.id} has no changes`);
3041
+ const deleted = meta.changes.filter((c) => c.status === "D").map((c) => c.path);
3042
+ if (deleted.length && !allowDelete) {
3043
+ const list2 = deleted.slice(0, 10).map((f) => ` ${f}`).join("\n") + (deleted.length > 10 ? `
3044
+ \u2026 ${deleted.length - 10} more` : "");
3045
+ throw new DeletionRefused(
3046
+ `run ${meta.id} deletes ${deleted.length} file${deleted.length === 1 ? "" : "s"}; nothing was applied:
3047
+ ${list2}
3048
+ Check that the deletion is what the user asked for: if so apply with --allow-delete, otherwise ask the user or discard the run.`,
3049
+ deleted
3050
+ );
3051
+ }
3027
3052
  const res = applyPatch(meta.repoRoot, runFile(meta.id, "changes.patch"), false);
3028
3053
  if (!res.ok) throw new UserError(`patch does not apply cleanly (your tree changed since the snapshot):
3029
3054
  ${res.message}`, 1);
@@ -3229,19 +3254,21 @@ function cmdLs(p) {
3229
3254
  function cmdApply(p) {
3230
3255
  const group = flag(p, "group");
3231
3256
  if (!group) {
3232
- console.log(applyRun(freshMeta(resolveRun(p.positional[0]))));
3257
+ console.log(applyRun(freshMeta(resolveRun(p.positional[0])), has(p, "allow-delete")));
3233
3258
  return 0;
3234
3259
  }
3235
3260
  const pending = groupIds(group).map((id) => freshMeta(id)).filter((m) => m.mode === "isolate" && m.state === "done" && m.changes?.length && !m.applied && !m.discarded);
3236
3261
  if (!pending.length) throw new UserError(`group "${group}" has no finished isolate patches to apply`);
3237
3262
  for (const [i, m] of pending.entries()) {
3238
3263
  try {
3239
- console.log(applyRun(m));
3264
+ console.log(applyRun(m, has(p, "allow-delete")));
3240
3265
  } catch (e) {
3241
3266
  const rest = pending.slice(i + 1).map((r) => r.id);
3242
3267
  console.log(`\u2718 ${m.id}: ${e.message}`);
3243
3268
  if (rest.length) console.log(` not applied yet: ${rest.join(" ")}`);
3244
- console.log(` resolve it (e.g. pitroom run --continue ${m.id} "rebase your change on the current tree"), then apply the rest`);
3269
+ if (!(e instanceof DeletionRefused)) {
3270
+ console.log(` resolve it (e.g. pitroom run --continue ${m.id} "rebase your change on the current tree"), then apply the rest`);
3271
+ }
3245
3272
  return 1;
3246
3273
  }
3247
3274
  }
@@ -3588,7 +3615,9 @@ Usage
3588
3615
  live table (TTY) or one JSON line per change, until done
3589
3616
  pitroom show [run] [--patch|--events|--full|--json]
3590
3617
  pitroom ls [--running] [-g NAME] recent runs
3591
- pitroom apply [run | -g NAME] apply --isolate patch(es) to your tree (checked first)
3618
+ pitroom apply [run | -g NAME] [--allow-delete]
3619
+ apply --isolate patch(es) to your tree (checked first); a patch
3620
+ that deletes files is refused unless --allow-delete
3592
3621
  pitroom discard [run] drop an --isolate run's copy (the patch is kept)
3593
3622
  pitroom revert [run] undo the changes of a --write run (checked first)
3594
3623
  pitroom stop [run | -g NAME] stop running or queued workers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pitroom",
3
- "version": "0.6.1",
3
+ "version": "0.6.4",
4
4
  "description": "A free pit crew for your expensive coding agent: the superpowers development workflow, run by cheap workers. Delegate research, fixes, tests, reviews and whole plans from Claude Code, Codex or any agent to OpenCode, Codex or Claude Code workers, with receipts that prove the savings.",
5
5
  "type": "module",
6
6
  "author": "TahaAtas",
@@ -21,9 +21,11 @@
21
21
  "hooks",
22
22
  ".claude-plugin",
23
23
  ".codex-plugin",
24
+ "assets",
24
25
  "docs/backends.md",
25
26
  "README.md",
26
27
  "CHANGELOG.md",
28
+ "PRIVACY.md",
27
29
  "LICENSE"
28
30
  ],
29
31
  "engines": {
@@ -70,7 +70,7 @@ pitroom show <run> # the full report of the ones you need
70
70
  - Read each summary and understand what changed.
71
71
  - Check for conflicts: did two workers touch the same code or contradict each other?
72
72
  - Verify what you will rely on (`refs:` lines help), then combine the findings in your own words.
73
- - For `-i` crews: review each patch (`pitroom review <run>` or `pitroom show <run> --patch`), then `pitroom apply -g NAME`. It applies in order and stops at the first conflict; fix that one with `pitroom run --continue <run> "…"` or by hand, then apply the rest.
73
+ - For `-i` crews: review each patch (`pitroom review <run>` or `pitroom show <run> --patch`), then `pitroom apply -g NAME`. It applies in order, stops at the first conflict and refuses a patch that deletes files (decide whether the deletion is wanted, then `--allow-delete`); fix that one with `pitroom run --continue <run> "…"` or by hand, then apply the rest.
74
74
  - Run the full test suite yourself afterwards, and spot-check: workers make systematic errors.
75
75
 
76
76
  ## When things go wrong
@@ -98,13 +98,14 @@ npm test 2>&1 | grep 'DEBUG git init'
98
98
 
99
99
  If something appears during tests but you don't know which test:
100
100
 
101
- Use the bisection script `find-polluter.sh` in this directory:
101
+ Bisect the test files by hand, in an isolated copy so a polluting test cannot touch the real tree (`pitroom run -i`, or a scratch clone):
102
102
 
103
- ```bash
104
- ./find-polluter.sh '.git' 'src/**/*.test.ts'
105
- ```
103
+ 1. List the test files that could be responsible (for example the ones matching `src/**/*.test.ts`), in a fixed order.
104
+ 2. Before the first run, confirm the unwanted file or directory (for example `.git`) does not exist yet. If it does, remove it from the copy first.
105
+ 3. Run one test file at a time with your project's own test command, and after each run check whether the unwanted file has appeared.
106
+ 4. The first file after which it appears is the polluter. Stop there, then read that test and trace how it gets there (the stack-trace technique above).
106
107
 
107
- Runs tests one-by-one, stops at first polluter. See script for usage.
108
+ If the list is long, halve it: run the first half together, check, and continue in the half that polluted. Only run test commands you would run anyway, and never pass unchecked file names to a shell.
108
109
 
109
110
  ## Real Example: Empty projectDir
110
111
 
@@ -89,7 +89,7 @@ Adjudicate only at the cap; every adjudication is a note. A silent discard is fo
89
89
  When the review is clean, or every open finding is parked with a ruling at the cap:
90
90
 
91
91
  ```bash
92
- pitroom apply <last run> # checked apply; refuses on conflict
92
+ pitroom apply <last run> # checked apply; refuses on conflict, and on deleted files until you decide they are wanted (--allow-delete)
93
93
  <the task's tests, run by you>
94
94
  git add <the task's files> && git commit -m "<the plan's commit message>"
95
95
  pitroom plan note PLAN "Task N: complete (<base7>..<head7>, review clean)"
@@ -35,7 +35,7 @@ pitroom run -w "Rename getUserById to findUserById in src/ and update imports. N
35
35
 
36
36
  1. Read the report: `FILES CHANGED`, `VERIFICATION`, `OPEN ISSUES`, and the `verify:` line.
37
37
  2. `pitroom show <run> --patch`: review the diff as you would a colleague's.
38
- 3. isolate: `pitroom apply <run>` (checked apply; refuses on conflict) or `pitroom discard <run>`. write: keep it, or `pitroom revert <run>`.
38
+ 3. isolate: `pitroom apply <run>` (checked apply; refuses on conflict, and on a patch that deletes files until you decide they are wanted: `--allow-delete`) or `pitroom discard <run>`. write: keep it, or `pitroom revert <run>`.
39
39
  4. Run the relevant tests yourself after applying.
40
40
  5. Needs another pass? `pitroom run --continue <run> "Also handle the refresh-token path."` (same session and copy; the patch accumulates).
41
41
 
@@ -63,4 +63,7 @@ Workers can take minutes. Start long work with `--bg` and keep working; follow i
63
63
  - Worker output is draft work and a worker's report is a claim: verify what you rely on (`pitroom-verification`).
64
64
  - You apply patches and commit; workers never commit or push. Push, merge and pull requests happen only after the user asks.
65
65
  - Keep the decisions: delegate the reading and typing, not the architecture.
66
+ - You set a worker's permissions when you create it, from the task and from how much autonomy the user gave you in this session (for example auto mode): read-only by default, `-i` (an isolated copy) for changes, `-w` (edits in place) when the user wants that, `--web` only when the task needs the web. A worker never widens its own permissions.
67
+ - Pitroom keeps a fixed floor that no flag lifts: no git history changes, no `sudo`, no publishing, no secrets, no killing processes. Everything above that floor is your call.
68
+ - Deletions are your decision, made as the user's agent. `pitroom apply` refuses a patch that deletes files unless you pass `--allow-delete`. If removing files is what the user asked for or an obvious part of it, apply with the flag and tell them which files went; if the worker deleted something the user did not ask for, ask first, or discard the run.
66
69
  - If Pitroom fails, carry on yourself; if setup is broken, tell the user what `pitroom doctor` says.
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Bisection script to find which test creates unwanted files/state
3
- # Usage: ./find-polluter.sh <file_or_dir_to_check> <test_pattern>
4
- # Example: ./find-polluter.sh '.git' 'src/**/*.test.ts'
5
-
6
- set -e
7
-
8
- if [ $# -ne 2 ]; then
9
- echo "Usage: $0 <file_to_check> <test_pattern>"
10
- echo "Example: $0 '.git' 'src/**/*.test.ts'"
11
- exit 1
12
- fi
13
-
14
- POLLUTION_CHECK="$1"
15
- TEST_PATTERN="$2"
16
-
17
- echo "🔍 Searching for test that creates: $POLLUTION_CHECK"
18
- echo "Test pattern: $TEST_PATTERN"
19
- echo ""
20
-
21
- # Get list of test files (find . emits ./-prefixed paths, so accept the
22
- # pattern written with or without a leading ./)
23
- TEST_PATTERN="${TEST_PATTERN#./}"
24
- # find -path can't match '**/' against zero directory levels, so a pattern
25
- # like src/**/*.test.ts would skip src/top.test.ts; also try the pattern
26
- # with '**/' collapsed to cover files directly under the base directory.
27
- TEST_FILES=$(find . \( -path "./$TEST_PATTERN" -o -path "./${TEST_PATTERN//\*\*\//}" \) | sort -u)
28
- if [ -z "$TEST_FILES" ]; then
29
- TOTAL=0
30
- else
31
- TOTAL=$(printf '%s\n' "$TEST_FILES" | wc -l | tr -d ' ')
32
- fi
33
-
34
- echo "Found $TOTAL test files"
35
- echo ""
36
-
37
- COUNT=0
38
- for TEST_FILE in $TEST_FILES; do
39
- COUNT=$((COUNT + 1))
40
-
41
- # Skip if pollution already exists
42
- if [ -e "$POLLUTION_CHECK" ]; then
43
- echo "⚠️ Pollution already exists before test $COUNT/$TOTAL"
44
- echo " Skipping: $TEST_FILE"
45
- continue
46
- fi
47
-
48
- echo "[$COUNT/$TOTAL] Testing: $TEST_FILE"
49
-
50
- # Run the test
51
- npm test "$TEST_FILE" > /dev/null 2>&1 || true
52
-
53
- # Check if pollution appeared
54
- if [ -e "$POLLUTION_CHECK" ]; then
55
- echo ""
56
- echo "🎯 FOUND POLLUTER!"
57
- echo " Test: $TEST_FILE"
58
- echo " Created: $POLLUTION_CHECK"
59
- echo ""
60
- echo "Pollution details:"
61
- ls -la "$POLLUTION_CHECK"
62
- echo ""
63
- echo "To investigate:"
64
- echo " npm test $TEST_FILE # Run just this test"
65
- echo " cat $TEST_FILE # Review test code"
66
- exit 1
67
- fi
68
- done
69
-
70
- echo ""
71
- echo "✅ No polluter found - all tests clean!"
72
- exit 0