tillerhand 3.50.0 → 3.51.0

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.
@@ -3,6 +3,8 @@
3
3
  // PreToolUse (Bash) hook: without review approval it stops the commit with exit code 2 and says what to do.
4
4
  // node .claude/hooks/commit-gate.mjs --approve "<members who took part, or a note>" binds the approval to the current changes.
5
5
  // node .claude/hooks/commit-gate.mjs --skip "<reason>" only when the user asks: skips the board and the gate (always asked).
6
+ // Commands that make commits with no working-tree change to review (git merge, git revert…) and git calls the text cannot
7
+ // read ($g commit, git $(echo commit)) have nothing to bind an approval to: the user is asked.
6
8
  // Exempt: no board set up, "Commit review: off" in docs/workflow/board.md, or only docs changed.
7
9
  // Commits the user makes from their own terminal are not affected (this is a Claude Code hook).
8
10
  import fs from 'node:fs';
@@ -11,14 +13,14 @@ import crypto from 'node:crypto';
11
13
  import { execSync } from 'node:child_process';
12
14
  import { findRoot, isMain, reviewOff, parseInput, decisionText } from './shared.mjs';
13
15
  import { t } from './lang.mjs';
14
- import { unquote } from './destructive-guard.mjs';
16
+ import { unquote, MAX_COMMAND } from './destructive-guard.mjs';
15
17
  import { isTestFile, isTestConfig, digest, readRecord } from './test-guard.mjs';
16
18
  import { isCodeFile } from './edit-rounds.mjs';
17
19
 
18
20
  // Project root (the script's location) even when called from a subfolder: approval and gate must not be written elsewhere
19
21
  const root = findRoot();
20
22
  const approvalFile = path.join(root, '.claude', 'state', 'commit-approval.json');
21
- const git = (c) => execSync(`git ${c}`, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 64 * 1024 * 1024 });
23
+ const git = (c) => execSync(`git ${c}`, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 64 * 1024 * 1024, timeout: 20000 });
22
24
 
23
25
  // Changes that will go into the commit: staged, unstaged in tracked files (git commit -a) and untracked new
24
26
  // files (git add -A && git commit). -z: non-ASCII or spaced paths are not quoted and escaped
@@ -56,8 +58,28 @@ export function changes() {
56
58
  export const sinceApproval = (approval, d) => d.files.filter((f) => !approval?.hashes || !Object.hasOwn(approval.hashes, f) || approval.hashes[f] !== d.hashes[f]);
57
59
 
58
60
  // git's global options may come before commit: git --no-pager commit, git -C x commit, git --git-dir=x commit; git.exe on Windows
59
- const commitRe = (verbs) => new RegExp(`\\bgit(?:\\.exe)?["']?(?:\\s+(?:-[cC]\\s+\\S+|--?[\\w-]+(?:=\\S+)?))*\\s+(?:${verbs.join('|')})(?=\\s|$|["';&|)])`);
61
+ // Every option has one reading: with two, "-c -c -c …" or "--a --a --a …" backtracks exponentially, and a hook that times out lets the command run.
62
+ const VALUE_OPTIONS = '(?:-[cC]|--(?:git-dir|work-tree|namespace|exec-path|super-prefix|config-env|attr-source))';
63
+ // One shell word: git -C "my dir" commit, git -c user.name='A B' commit, git -C my\ dir commit
64
+ const WORD = `(?:"[^"]*"|'[^']*'|\\\\.|[^\\s"'\\\\])+`;
65
+ const GLOBALS = `(?:\\s+(?:${VALUE_OPTIONS}\\s+${WORD}|(?!${VALUE_OPTIONS}\\s)-[\\w-]+(?:=${WORD})?))*`;
66
+ const VERB_END = '(?=\\s|$|["\';&|)])';
67
+ // i: Windows runs GIT.exe as git. $GIT is a variable, not git by name.
68
+ const commitRe = (verbs) => new RegExp(`(?<!\\$)\\bgit(?:\\.exe)?["']?${GLOBALS}\\s+["']?(?:${verbs.join('|')})${VERB_END}`, 'i');
60
69
  const COMMIT = commitRe(['commit']);
70
+ // shortcut: these rules read text, so a quoted mention (grep "git merge") also asks; a script file, xargs git, base64 | sh or a mixed-quote spelling (git -C "a b" c"ommit") is not seen; a git hook would close that.
71
+ const MAKES_COMMITS = ['merge', 'cherry-pick', 'revert', 'am', 'rebase', 'commit-tree', 'fast-import'];
72
+ const OTHER_COMMIT = [
73
+ // git merge, git $(echo commit), git "$@"
74
+ commitRe([...MAKES_COMMITS, '[$`%@]\\S*']),
75
+ // $g commit, $(which git) merge, %g% commit
76
+ new RegExp(`(?:\\$\\{?\\w+\\}?|\\$\\([^)\\n]{0,200}\\)|\`[^\`\\n]{0,200}\`|%\\w+%)["']?${GLOBALS}\\s+["']?(?:commit|${MAKES_COMMITS.join('|')})${VERB_END}`, 'i'),
77
+ ];
78
+ // Backing out makes no commit, but only as a whole command: git merge x # --abort still merges
79
+ const BACK_OUT = new RegExp(`\\bgit(?:\\.exe)?${GLOBALS}\\s+(?:merge|cherry-pick|revert|am|rebase)\\s+--(?:abort|quit)(?=\\s*(?:$|[;&|\\n]))`, 'gi');
80
+ const makesOtherCommit = (command) => OTHER_COMMIT.some((re) => re.test(command.replace(BACK_OUT, '')));
81
+ // These rules are not linear in the length, and a hook that times out lets the command run: a long command that names any of this is asked unread
82
+ const GATE_WORDS = new RegExp(`git|commit|${MAKES_COMMITS.join('|')}|gate\\.mjs`, 'i');
61
83
  const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
62
84
 
63
85
  // git aliases that run commit ([alias] ci = commit, cm = !git commit), from git config and from an inline -c alias.x=commit
@@ -184,20 +206,26 @@ function stop(reason) {
184
206
  process.exit(2);
185
207
  }
186
208
 
209
+ const internalError = (e) => t(root, 'guard.commit.internalError', { error: String(e?.message ?? e).slice(0, 200) });
210
+
187
211
  async function hook() {
188
- let command = '', dir = root;
212
+ let raw = '', dir = root;
189
213
  try {
190
214
  const g = parseInput(JSON.parse(fs.readFileSync(0, 'utf8')) ?? {});
191
215
  tool = g.tool;
192
- // A backslash-newline is a line continuation: bash joins the words ("git comm\<newline>it" is git commit), the
193
- // text rules may also need it as a space ("git commit\<newline>-m x"). Whichever spelling is a commit is checked.
194
- const raw = String(g.command ?? '');
195
- const joined = raw.replace(/\\\r?\n/g, '');
196
- command = [joined, unquote(joined)].some((c) => commitPattern(joined).test(c)) ? joined : raw.replace(/\\\r?\n/g, ' ');
216
+ raw = String(g.command ?? '');
197
217
  if (g.dir) dir = g.dir;
198
218
  } catch {
199
219
  process.exit(0);
200
220
  }
221
+ if (raw.length > MAX_COMMAND) {
222
+ if ([raw, unquote(raw)].some((c) => GATE_WORDS.test(c))) decideOut('ask', t(root, 'guard.commit.tooLong'));
223
+ process.exit(0);
224
+ }
225
+ // A backslash-newline is a line continuation: bash joins the words ("git comm\<newline>it" is git commit), the
226
+ // text rules may also need it as a space ("git commit\<newline>-m x"). Whichever spelling is a commit is checked.
227
+ const joined = raw.replace(/\\\r?\n/g, '');
228
+ const command = [joined, unquote(joined)].some((c) => commitPattern(joined).test(c)) ? joined : raw.replace(/\\\r?\n/g, ' ');
201
229
  // --skip bypasses the gate and the board: the user is asked in every spelling (the AI must not write it on its own)
202
230
  // A commit whose message names --skip goes on to the commit checks below (a real --skip chained to a commit is stopped there).
203
231
  const open = unquote(command);
@@ -219,6 +247,8 @@ async function hook() {
219
247
  const note = unknown.length ? `\n${t(root, 'guard.commit.gateUnknownKeys', { keys: unknown.join(', ') })}` : '';
220
248
  decideOut('ask', t(root, 'guard.commit.gateApprovalAsk', { list }) + note);
221
249
  }
250
+ // A plain commit stays with the commit checks below: what its message names is text
251
+ if (!commit.test(command) && [command, open].some(makesOtherCommit) && hasBoard() && !boardReviewOff()) decideOut('ask', t(root, 'guard.commit.otherCommitAsk'));
222
252
  if (!commit.test(command) && !commit.test(open)) process.exit(0);
223
253
  if (!hasBoard() || boardReviewOff()) process.exit(0);
224
254
  const chain = chainIssue(command, commit.inline ? COMMIT : commit);
@@ -230,8 +260,8 @@ async function hook() {
230
260
  let d;
231
261
  try {
232
262
  d = changes();
233
- } catch {
234
- process.exit(0); // not a git repo
263
+ } catch (e) {
264
+ decideOut('ask', internalError(e)); // git failed or there is no repo: unread changes must not pass as reviewed
235
265
  }
236
266
  if (!d.files.length || docsOnly(d.files)) process.exit(0);
237
267
 
@@ -286,5 +316,5 @@ if (isMain(import.meta.url)) {
286
316
  if (i > -1) approve(process.argv[i + 1] || 'unspecified');
287
317
  else if (j > -1) save(`skipped: ${process.argv[j + 1] || 'user request'}`);
288
318
  else if (process.argv.includes('--status')) status();
289
- else hook();
319
+ else hook().catch((e) => decideOut('ask', internalError(e))); // a crash exits 1, which does not block the commit
290
320
  }
@@ -378,6 +378,9 @@ export const MESSAGES = {
378
378
  'dashboardData.prodRefAction': { en: '.mcp.json → dev ref (docs/operations/accounts.md → Environments)' },
379
379
  'dashboardData.rlsMissing': { en: 'Supabase is in use but there is no RLS attacker test (tests/security/rls.mjs).' },
380
380
  'dashboardData.rlsAction': { en: 'Get the template with /kit-update, add the tables to TABLES' },
381
+ 'guard.commit.otherCommitAsk': { en: 'Commit gate: this command can make a commit the board review and the deterministic gate cannot check (merge, revert, cherry-pick, am, rebase, commit-tree, fast-import, or git called through a variable). Approve only if the user asked for it.' },
382
+ 'guard.commit.internalError': { en: 'The commit gate could not check this command ({error}). User approval required.' },
383
+ 'guard.commit.tooLong': { en: 'Commit gate: this command is too long to check and it names git or a commit. Approve only if the user asked for it.' },
381
384
  'guard.commit.skipAsk': { en: 'Commit gate: --skip bypasses the board review and the deterministic gate. Approve only if the user explicitly asks.' },
382
385
  'guard.commit.noCommands': { en: '(no commands defined)' },
383
386
  'guard.commit.gateApprovalAsk': { en: 'Gate command approval: from now on the gate runs these commands from AGENTS.md → Commands every time:\n{list}\nApprove only if you trust them.' },
@@ -375,6 +375,9 @@
375
375
  "dashboardData.prodRefAction": ".mcp.json → dev ref (docs/operations/accounts.md → Environments)",
376
376
  "dashboardData.rlsMissing": "Supabase kullanılıyor ama RLS saldırgan testi yok (tests/security/rls.mjs).",
377
377
  "dashboardData.rlsAction": "/kit-update ile şablonu al, tabloları TABLES'a ekle",
378
+ "guard.commit.otherCommitAsk": "Commit kapısı: bu komut, kurul denetiminin ve deterministik kapının denetleyemeyeceği bir commit yapabilir (merge, revert, cherry-pick, am, rebase, commit-tree, fast-import veya değişkenle çağrılan git). Sadece kullanıcı istediyse onayla.",
379
+ "guard.commit.internalError": "Commit kapısı bu komutu denetleyemedi ({error}). Kullanıcı onayı gerekli.",
380
+ "guard.commit.tooLong": "Commit kapısı: bu komut denetlenemeyecek kadar uzun ve git veya commit geçiyor. Sadece kullanıcı istediyse onayla.",
378
381
  "guard.commit.skipAsk": "Commit kapısı: --skip kurul denetimini ve deterministik kapıyı aşar. Sadece kullanıcı açıkça isterse onayla.",
379
382
  "guard.commit.noCommands": "(tanımlı komut yok)",
380
383
  "guard.commit.gateApprovalAsk": "Kapı komut onayı: AGENTS.md → Commands bölümündeki şu komutlar bundan sonra her kapıda çalışır:\n{list}\nGüvendiğin komutlarsa onayla.",
@@ -84,6 +84,11 @@
84
84
  "Bash(rm -rf:*)"
85
85
  ]
86
86
  },
87
+ "attribution": {
88
+ "commit": "",
89
+ "pr": "",
90
+ "sessionUrl": false
91
+ },
87
92
  "env": {
88
93
  "ENABLE_STOP_REVIEW": "0"
89
94
  },
package/AGENTS.md CHANGED
@@ -21,9 +21,15 @@ This file holds the shared rules of the project. Claude Code, Codex and Antigrav
21
21
 
22
22
  ```
23
23
  ── Status ──────────────────────
24
- Phase: … · Task: … (x/y) · Question mode: … · Limit: 5h %… weekly %…
25
- Done: … · Board: … · Auto decisions: …
26
- Next: … · pending decision: …
24
+ Phase: …
25
+ Task: … (x/y)
26
+ Question mode: …
27
+ Limit: 5h %… weekly %…
28
+ Done: …
29
+ Board: …
30
+ Auto decisions: …
31
+ Next: …
32
+ Pending decision: …
27
33
  ```
28
34
 
29
35
  9. **Know the user.** Follow the "Personal preferences" that arrive at session start (project rules come first). If the user corrects a behavior or says how they want to work (conversation, question frequency, report format, code style, things to avoid), note it briefly; do not break the flow. At the end of a task (`/build`) and at the end of a session (`/wrap-up`), ask about the notes with AskUserQuestion as a multi-select ("Save as a preference?"). Write the selected ones with `node .claude/hooks/prefs.mjs --add <conversation|questions|reports|code|avoid> "<preference>"`. Do not write without approval. Do not write secrets, personal data or the project name. A project-specific rule goes to "Learned rules", not to this file.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  </p>
7
7
 
8
8
  <p align="center">
9
- <a href="kit/CHANGELOG.md"><img alt="Version" src="https://img.shields.io/badge/version-3.50.0-2a78d6?style=flat-square"></a>
9
+ <a href="kit/CHANGELOG.md"><img alt="Version" src="https://img.shields.io/badge/version-3.51.0-2a78d6?style=flat-square"></a>
10
10
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-2a78d6?style=flat-square"></a>
11
11
  <img alt="Claude Code" src="https://img.shields.io/badge/Claude%20Code-ready-d97757?style=flat-square">
12
12
  <img alt="Also Codex and Antigravity" src="https://img.shields.io/badge/also-Codex%20%C2%B7%20Antigravity-5b6577?style=flat-square">
@@ -242,7 +242,7 @@ A new file outside the map is asked about, clutter like `*.bak` and `*-old.*` is
242
242
  | Test separation | Only the `test-writer` agent writes test files; the main session and the coding agent are blocked |
243
243
  | Test guard | Asks before a test is deleted, skipped or weakened |
244
244
  | Deterministic gate | No commit until lint, type check, tests and Semgrep have run; catches machine-specific paths written into code |
245
- | Commit gate | No commit without a board review and a green gate; a test file changed by a patch or a script stops it too |
245
+ | Commit gate | No commit without a board review and a green gate; a test file changed by a patch or a script stops it too; merge, revert and other commands that make commits are asked |
246
246
  | Edit lock | With `/freeze <folder>` on, the AI writes only inside that folder |
247
247
  | Scope shield | Asks before writing to a file outside the approved plan |
248
248
  | Config approval | Rule and guard files never change without your approval |
package/README.tr.md CHANGED
@@ -6,7 +6,7 @@
6
6
  </p>
7
7
 
8
8
  <p align="center">
9
- <a href="kit/CHANGELOG.md"><img alt="Sürüm" src="https://img.shields.io/badge/s%C3%BCr%C3%BCm-3.50.0-2a78d6?style=flat-square"></a>
9
+ <a href="kit/CHANGELOG.md"><img alt="Sürüm" src="https://img.shields.io/badge/s%C3%BCr%C3%BCm-3.51.0-2a78d6?style=flat-square"></a>
10
10
  <a href="LICENSE"><img alt="Lisans: MIT" src="https://img.shields.io/badge/lisans-MIT-2a78d6?style=flat-square"></a>
11
11
  <img alt="Claude Code" src="https://img.shields.io/badge/Claude%20Code-haz%C4%B1r-d97757?style=flat-square">
12
12
  <img alt="Codex ve Antigravity" src="https://img.shields.io/badge/ayr%C4%B1ca-Codex%20%C2%B7%20Antigravity-5b6577?style=flat-square">
@@ -242,7 +242,7 @@ Harita dışı yeni dosya sorulur, `*.bak` ve `*-old.*` gibi dağınıklık dosy
242
242
  | Test ayrımı | Test dosyasına yalnız `test-writer` ajanı yazar; ana oturum ve kod ajanı denerse engellenir |
243
243
  | Test koruması | Silinen, atlanan veya gevşetilen testi sorar |
244
244
  | Deterministik kapı | Lint, tip, test ve Semgrep çalışmadan commit açılmaz; koda yazılmış makineye özel yolu yakalar |
245
- | Commit kapısı | Kurul denetimi ve yeşil kapı olmadan commit atılmaz; patch veya betikle değişen test dosyası da durur |
245
+ | Commit kapısı | Kurul denetimi ve yeşil kapı olmadan commit atılmaz; patch veya betikle değişen test dosyası da durur; merge, revert gibi commit üreten komutlar sorulur |
246
246
  | Düzenleme kilidi | `/freeze <klasör>` açıkken AI sadece o klasöre yazar |
247
247
  | Kapsam kalkanı | Onaylı planın dışındaki dosyaya yazım sorulur |
248
248
  | Yapılandırma onayı | Kural ve koruma dosyaları onayın olmadan değişmez |
@@ -80,14 +80,19 @@ Every `design` decision is asked with visuals. The user chooses an image, not te
80
80
 
81
81
  ## 6. Status block (at the end of every answer)
82
82
 
83
- In short, compressed language (caveman), at most 4 lines:
83
+ In short, compressed language (caveman), one item per line:
84
84
 
85
85
  ```
86
86
  ── Status ─────────────────────────────
87
- Phase: Phase 1 · Task: G-012 (7/23) · Question mode: open · Limit: 5h %34 weekly %5
88
- Done: signup form + validation, tests green · Board: APPROVE (ux, qa)
87
+ Phase: Phase 1
88
+ Task: G-012 (7/23)
89
+ Question mode: open
90
+ Limit: 5h %34 weekly %5
91
+ Done: signup form + validation, tests green
92
+ Board: APPROVE (ux, qa)
89
93
  Auto decisions: none
90
- Next: G-013 password reset · pending decision: email service
94
+ Next: G-013 password reset
95
+ Pending decision: email service
91
96
  ```
92
97
 
93
98
  - Phase and task come from `docs/workflow/progress.md`; the task count is checked/total in `docs/product/roadmap.md`.
package/kit/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  The kit version is in `kit/VERSION`. To update a project, run `/kit-update` in it.
4
4
  Items with an "Adapt by hand" note concern files owned by the project; the update does not touch them.
5
5
 
6
+ ## [3.51.0] - 2026-11-01
7
+
8
+ ### Changed
9
+ - **The status block has one item per line.** Phase, task, question mode, limit, done, board, auto decisions, next and pending decision each get their own line, so the block reads at a glance.
10
+ - **Commits and pull requests carry no AI attribution by default.** `.claude/settings.json` turns off the co-author line and the session link. This applies to Claude Code; Codex has no reliable local setting for it.
11
+
12
+ ## [3.50.1] - 2026-11-01
13
+
14
+ ### Fixed
15
+ - **The commit gate now asks about other commands that make commits.** `git merge`, `cherry-pick`, `revert`, `am`, `rebase`, `commit-tree` and `fast-import` are asked even on a clean tree, since a review cannot be bound to them. So is git called in a way the text cannot show (`$g commit`, `git $(echo commit)`, `git "$@"`). On Codex, which has no question, the command is blocked and the user runs it. A lone `--abort` or `--quit` is not asked. A quoted mention such as `grep "git merge"` is also asked.
16
+ - **An error inside the commit gate no longer lets a commit through.** When git fails, or the hook itself crashes, the command is asked instead of passing.
17
+ - **Long or repetitive commands can no longer time the commit gate out.** Text such as `git --a --a --a …` made matching exponentially slow, and a hook that times out lets the command run. Matching no longer backtracks that way, and a command over 10 000 characters that names git or a commit is asked without being read.
18
+ - **A global option's value no longer hides the subcommand.** `git -C "my dir" commit`, `git -c user.name="A B" commit`, `git --work-tree . commit` and `git --attr-source HEAD commit` used to pass as if they were not commits. `GIT commit` now counts as git too.
19
+
6
20
  ## [3.50.0] - 2026-10-30
7
21
 
8
22
  ### Added
package/kit/VERSION CHANGED
@@ -1 +1 @@
1
- 3.50.0
1
+ 3.51.0
package/kit/guide.html CHANGED
@@ -361,7 +361,7 @@ footer .container { display: flex; flex-wrap: wrap; gap: 16px; justify-content:
361
361
  <section class="hero">
362
362
  <div class="container">
363
363
  <div>
364
- <span class="pill"><b>v3.50.0</b> Starter kit for Claude Code · MIT</span>
364
+ <span class="pill"><b>v3.51.0</b> Starter kit for Claude Code · MIT</span>
365
365
  <h1>The AI builds.<br><em>You steer.</em></h1>
366
366
  <p class="sub">TillerHand takes a product from idea to production and maintenance with Claude Code. At every important decision the AI gives you the options, its recommendation and the cost of each option. An expert board reviews the work, and guardrails stop mistakes before they happen.</p>
367
367
  <div class="setup">
@@ -512,9 +512,15 @@ an environment variable and add its name to .env.example with an empty value.
512
512
  <div class="window">
513
513
  <div class="bar"><i></i><i></i><i></i><span>At the end of every answer</span></div>
514
514
  <pre class="term">── Status ──────────────────────
515
- Phase: 1 · Task: G-012 (7/23) · Question mode: open · Limit: 5h 34% weekly 5%
516
- Done: signup form + validation, tests green · Board: <span class="g">APPROVE</span> (ux, qa) · Auto decisions: none
517
- Next: G-013 password reset · pending decision: email service</pre>
515
+ Phase: 1
516
+ Task: G-012 (7/23)
517
+ Question mode: open
518
+ Limit: 5h 34% weekly 5%
519
+ Done: signup form + validation, tests green
520
+ Board: <span class="g">APPROVE</span> (ux, qa)
521
+ Auto decisions: none
522
+ Next: G-013 password reset
523
+ Pending decision: email service</pre>
518
524
  </div>
519
525
  <h3>You always know where you are</h3>
520
526
  <p>Phase, task, limit, the board's verdict and the next step at the end of every answer. When you come back after a break, your place is ready.</p>
@@ -948,7 +954,7 @@ npx tillerhand init
948
954
  <tr><td>Test separation</td><td>The tests are written before the code by a separate agent (<code>test-writer</code>, a different model is recommended), not by whoever writes the code. Nobody but this agent can write to a test file: the main session and the code agent are blocked if they try. A test file changed indirectly by a patch or script also stops at the commit gate. So whoever writes the code can't shape the test to fit their own code</td></tr>
949
955
  <tr><td>Test protection</td><td>Deleting or commenting out an assertion, <code>.skip</code>/<code>.only</code>, a loosened assertion, deleting or moving a test file, and narrowing coverage in the test config are asked; so is writing to a test file through the shell</td></tr>
950
956
  <tr><td>Deterministic gate</td><td><code>gate.mjs --run</code>: lint, type check, tests and Semgrep run; the output feeds the board, and a red check counts as REJECT. If the "must not change" behaviors in the spec have no test or the test is red, the gate is red. It is also red if an added line contains a path specific to this machine (the full path of the project folder or the home folder). A new or changed command is first shown to you for approval</td></tr>
951
- <tr><td>Commit gate</td><td>No commit without a board review and a green gate for the same changes; the task-end approval also counts for the commit, so the same change is not reviewed twice; skipping the review (<code>--skip</code>) is asked every time</td></tr>
957
+ <tr><td>Commit gate</td><td>No commit without a board review and a green gate for the same changes; the task-end approval also counts for the commit, so the same change is not reviewed twice; skipping the review (<code>--skip</code>) and commands that make commits with nothing to review (<code>git merge</code>, <code>git revert</code>…) are asked every time</td></tr>
952
958
  <tr><td>Edit lock</td><td>While <code>/freeze &lt;folder&gt;</code> is on, the AI writes only to that folder; writing outside through the shell is asked, and a symlink can't escape it</td></tr>
953
959
  <tr><td>Scope shield</td><td>After <code>/plan-task</code> approval, the plan's file list is saved; writing to an existing file not on the list is asked. Turning the shield on and off is asked too</td></tr>
954
960
  <tr><td>Edit round counter</td><td>When the same code file is edited for the 5th and 10th time in a session, a Semgrep and security review reminder appears</td></tr>
@@ -1017,9 +1023,15 @@ AGENTS.md · CLAUDE.md · README.md · CHANGELOG.md</pre>
1017
1023
  <div>
1018
1024
  <h3 style="margin-top:0">At the end of every answer: the status block</h3>
1019
1025
  <pre class="term">── Status ──────────────────────
1020
- Phase: 1 · Task: G-012 (7/23) · Question mode: open · Limit: 5h 34% weekly 5%
1021
- Done: signup form + validation, tests green · Board: APPROVE (ux, qa) · Auto decisions: none
1022
- Next: G-013 password reset · pending decision: email service</pre>
1026
+ Phase: 1
1027
+ Task: G-012 (7/23)
1028
+ Question mode: open
1029
+ Limit: 5h 34% weekly 5%
1030
+ Done: signup form + validation, tests green
1031
+ Board: APPROVE (ux, qa)
1032
+ Auto decisions: none
1033
+ Next: G-013 password reset
1034
+ Pending decision: email service</pre>
1023
1035
  <h3>Always: the status line</h3>
1024
1036
  <pre class="term">▶ Phase 1 · G-012 · task 7/23 · questions: open · 5h 34% · weekly 5% · context 42%</pre>
1025
1037
  </div>
@@ -1242,7 +1254,7 @@ Next: G-013 password reset · pending decision: email service</pre>
1242
1254
  <footer>
1243
1255
  <div class="container">
1244
1256
  <a class="brand" href="#top" style="font-size:16px"><svg class="mark" style="width:22px;height:22px"><use href="#mark"/></svg>TillerHand</a>
1245
- <span>Version 3.50.0 · <a href="https://github.com/burakdogrul/TillerHand">GitHub</a> · <a href="https://github.com/burakdogrul/TillerHand/blob/main/LICENSE">MIT license</a> · The KVKK section is a checklist, not legal advice.</span>
1257
+ <span>Version 3.51.0 · <a href="https://github.com/burakdogrul/TillerHand">GitHub</a> · <a href="https://github.com/burakdogrul/TillerHand/blob/main/LICENSE">MIT license</a> · The KVKK section is a checklist, not legal advice.</span>
1246
1258
  </div>
1247
1259
  </footer>
1248
1260
 
package/kit/guide.tr.html CHANGED
@@ -361,7 +361,7 @@ footer .container { display: flex; flex-wrap: wrap; gap: 16px; justify-content:
361
361
  <section class="hero">
362
362
  <div class="container">
363
363
  <div>
364
- <span class="pill"><b>v3.50.0</b> Claude Code için başlangıç kiti · MIT</span>
364
+ <span class="pill"><b>v3.51.0</b> Claude Code için başlangıç kiti · MIT</span>
365
365
  <h1>Kodu AI yazar.<br><em>Dümen sende.</em></h1>
366
366
  <p class="sub">TillerHand, Claude Code ile bir ürünü fikirden canlıya ve bakıma kadar götürür. Her önemli kararda AI sana seçenekleri, önerisini ve her seçeneğin bedelini sunar. Bir uzman kurulu işi denetler, korumalar hatayı daha olmadan durdurur.</p>
367
367
  <div class="setup">
@@ -512,10 +512,13 @@ ve adını .env.example'a boş değerle ekle.
512
512
  <div class="window">
513
513
  <div class="bar"><i></i><i></i><i></i><span>Her cevabın sonunda</span></div>
514
514
  <pre class="term">── Durum ─────────────────────────────
515
- Aşama: Faz 1 · Görev: G-012 (7/23)
516
- Soru modu: açık · Limit: 5s %34 hf %5
517
- Yapıldı: kayıt formu + doğrulama, test yeşil
515
+ Faz: 1
516
+ Görev: G-012 (7/23)
517
+ Soru modu: açık
518
+ Limit: 5s %34 hf %5
519
+ Biten: kayıt formu + doğrulama, test yeşil
518
520
  Kurul: <span class="g">APPROVE</span> (ux, qa)
521
+ Otomatik karar: yok
519
522
  Sıradaki: G-013 şifre sıfırlama
520
523
  Bekleyen karar: e-posta servisi</pre>
521
524
  </div>
@@ -951,7 +954,7 @@ npx tillerhand init
951
954
  <tr><td>Test ayrımı</td><td>Testleri kodu yazan değil, ayrı bir ajan (<code>test-writer</code>, farklı model önerilir) koddan önce yazar. Test dosyasına bu ajan dışında kimse yazamaz: ana oturum ve kod ajanı denerse engellenir. Patch veya betikle dolaylı değişen test dosyası da commit kapısında durur. Böylece kodu yazan testi kendi koduna göre şekillendiremez</td></tr>
952
955
  <tr><td>Test koruması</td><td>Beklenti silmek veya yoruma almak, <code>.skip</code>/<code>.only</code>, gevşek beklenti, test dosyasını silmek veya taşımak ve test ayarında kapsamı daraltmak sorulur; kabukla test dosyasına yazmak da</td></tr>
953
956
  <tr><td>Deterministik kapı</td><td><code>gate.mjs --run</code>: lint, tip kontrolü, test ve Semgrep çalışır; çıktı kurula girdi olur, kırmızı kontrol REJECT sayılır. Spec'teki "değişmemesi gereken" davranışların testi yoksa veya kırmızıysa kapı kırmızıdır. Eklenen bir satırda bu makineye özel bir yol (proje klasörünün ya da ev klasörünün tam yolu) varsa da kırmızıdır. Yeni veya değişen komut önce sana gösterilip onaylatılır</td></tr>
954
- <tr><td>Commit kapısı</td><td>Kurul denetimi ve aynı değişiklikler için yeşil kapı olmadan commit atılmaz; görev sonu onayı commit için de geçerli, aynı değişiklik iki kez denetlenmez; denetimi atlamak (<code>--skip</code>) her seferinde sorulur</td></tr>
957
+ <tr><td>Commit kapısı</td><td>Kurul denetimi ve aynı değişiklikler için yeşil kapı olmadan commit atılmaz; görev sonu onayı commit için de geçerli, aynı değişiklik iki kez denetlenmez; denetimi atlamak (<code>--skip</code>) ve denetlenecek değişiklik olmadan commit üreten komutlar (<code>git merge</code>, <code>git revert</code>…) her seferinde sorulur</td></tr>
955
958
  <tr><td>Düzenleme kilidi</td><td><code>/freeze &lt;klasör&gt;</code> açıkken AI sadece o klasöre yazar; kabukla dışarı yazmak sorulur, sembolik bağdan kaçılamaz</td></tr>
956
959
  <tr><td>Kapsam kalkanı</td><td><code>/plan-task</code> onayından sonra planın dosya listesi kaydedilir; listede olmayan mevcut dosyaya yazım sorulur. Kalkanı açmak ve kapatmak da sorulur</td></tr>
957
960
  <tr><td>Düzenleme turu sayacı</td><td>Aynı kod dosyası bir oturumda 5., 10. kez düzenlenince Semgrep ve güvenlik incelemesi hatırlatılır</td></tr>
@@ -1020,10 +1023,15 @@ AGENTS.md · CLAUDE.md · README.md · CHANGELOG.md</pre>
1020
1023
  <div>
1021
1024
  <h3 style="margin-top:0">Her cevabın sonunda: durum bloğu</h3>
1022
1025
  <pre class="term">── Durum ─────────────────────────────
1023
- Aşama: Faz 1 · Görev: G-012 (7/23) · Soru modu: açık · Limit: 5s %34 hf %5
1024
- Yapıldı: kayıt formu + doğrulama, test yeşil · Kurul: APPROVE (ux, qa)
1025
- Otomatik kararlar: yok
1026
- Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
1026
+ Faz: 1
1027
+ Görev: G-012 (7/23)
1028
+ Soru modu: açık
1029
+ Limit: 5s %34 hf %5
1030
+ Biten: kayıt formu + doğrulama, test yeşil
1031
+ Kurul: APPROVE (ux, qa)
1032
+ Otomatik karar: yok
1033
+ Sıradaki: G-013 şifre sıfırlama
1034
+ Bekleyen karar: e-posta servisi</pre>
1027
1035
  <h3>Her zaman: alt durum çubuğu</h3>
1028
1036
  <pre class="term">▶ Faz 1 · G-012 · görev 7/23 · soru: açık · 5s %34 · hf %5 · bağlam %42</pre>
1029
1037
  </div>
@@ -1246,7 +1254,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
1246
1254
  <footer>
1247
1255
  <div class="container">
1248
1256
  <a class="brand" href="#top" style="font-size:16px"><svg class="mark" style="width:22px;height:22px"><use href="#mark"/></svg>TillerHand</a>
1249
- <span>Sürüm 3.50.0 · <a href="https://github.com/burakdogrul/TillerHand">GitHub</a> · <a href="https://github.com/burakdogrul/TillerHand/blob/main/LICENSE">MIT lisansı</a> · KVKK bölümü kontrol listesidir, hukuki görüş değildir.</span>
1257
+ <span>Sürüm 3.51.0 · <a href="https://github.com/burakdogrul/TillerHand">GitHub</a> · <a href="https://github.com/burakdogrul/TillerHand/blob/main/LICENSE">MIT lisansı</a> · KVKK bölümü kontrol listesidir, hukuki görüş değildir.</span>
1250
1258
  </div>
1251
1259
  </footer>
1252
1260
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tillerhand",
3
- "version": "3.50.0",
3
+ "version": "3.51.0",
4
4
  "description": "Vibe coding kit for Claude Code, Codex and Antigravity: rules, commands, guards and project templates.",
5
5
  "license": "MIT",
6
6
  "type": "module",