tillerhand 3.50.0 → 3.50.1

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.",
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.50.1-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.50.1-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 |
package/kit/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
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.50.1] - 2026-11-01
7
+
8
+ ### Fixed
9
+ - **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.
10
+ - **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.
11
+ - **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.
12
+ - **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.
13
+
6
14
  ## [3.50.0] - 2026-10-30
7
15
 
8
16
  ### Added
package/kit/VERSION CHANGED
@@ -1 +1 @@
1
- 3.50.0
1
+ 3.50.1
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.50.1</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">
@@ -948,7 +948,7 @@ npx tillerhand init
948
948
  <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
949
  <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
950
  <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>
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>) and commands that make commits with nothing to review (<code>git merge</code>, <code>git revert</code>…) are asked every time</td></tr>
952
952
  <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
953
  <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
954
  <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>
@@ -1242,7 +1242,7 @@ Next: G-013 password reset · pending decision: email service</pre>
1242
1242
  <footer>
1243
1243
  <div class="container">
1244
1244
  <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>
1245
+ <span>Version 3.50.1 · <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
1246
  </div>
1247
1247
  </footer>
1248
1248
 
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.50.1</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">
@@ -951,7 +951,7 @@ npx tillerhand init
951
951
  <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
952
  <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
953
  <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>
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>) ve denetlenecek değişiklik olmadan commit üreten komutlar (<code>git merge</code>, <code>git revert</code>…) her seferinde sorulur</td></tr>
955
955
  <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
956
  <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
957
  <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>
@@ -1246,7 +1246,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
1246
1246
  <footer>
1247
1247
  <div class="container">
1248
1248
  <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>
1249
+ <span>Sürüm 3.50.1 · <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
1250
  </div>
1251
1251
  </footer>
1252
1252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tillerhand",
3
- "version": "3.50.0",
3
+ "version": "3.50.1",
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",