tillerhand 3.49.7 → 3.49.9

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.
@@ -27,6 +27,8 @@ const DESTRUCTIVE = [
27
27
  [/\bgit\s+clean\b(?=[^;]*\s--?[a-z]*f)(?=[^;]*\s-[a-z]*d)/i, 'git clean permanently deletes untracked files'],
28
28
  [/\bredis-cli\b[^;]*\b(flushall|flushdb)\b/i, 'Redis data is being deleted'],
29
29
  [/\bfirebase\s+firestore:delete\b/i, 'Firestore data is being deleted'],
30
+ [/\bheroku\s+pg:reset\b|\bdrop(Database|Collection)\s*\(|\bdeleteMany\s*\(\s*\{\s*\}\s*\)|\bartisan\s+migrate:(fresh|refresh|reset)\b|\btypeorm\b[^;]*\bschema:drop\b|\bknex\b[^;]*\bmigrate:rollback\b[^;]*--all\b|\bprisma\s+db\s+push\b[^;]*--accept-data-loss\b/i, 'Database data is being deleted or reset'],
31
+ [/\b(terraform|tofu|pulumi)\s+destroy\b/i, 'Cloud infrastructure is being destroyed'],
30
32
  ];
31
33
 
32
34
  // Database addresses other than localhost count as prod (or a shared environment)
@@ -45,8 +47,9 @@ const NEEDS_APPROVAL = [
45
47
  // The subcommand can also come after flags: vercel --scope team promote <url>
46
48
  [/\b(vercel|vc)(@[\w.-]+)?\b[^;&|]*\s(promote|rollback)\b/i, 'guard.destructive.promoteRollback'],
47
49
  [UNCLEAR_ENV, 'guard.destructive.unclearEnv'],
48
- [/\b(fly|flyctl)\s+deploy\b|\brailway\s+up\b|\bnetlify\s+deploy\b[^;]*--prod/i, 'guard.destructive.serverDeploy'],
49
- [/\beas(-cli(@[\w.-]+)?)?\s+(submit\b|update:(rollback|republish)\b|update\b(?=[^;\n]*--(branch|channel|environment)(=|\s+)['"]?prod(uction)?\b)|deploy\b(?=[^;\n]*--prod\b))/i, 'guard.destructive.storeSubmit'],
50
+ // A package spelling (npx netlify-cli, firebase-tools, wrangler@3) deploys the same way
51
+ [/\b(fly|flyctl)\s+deploy\b|\brailway\s+up\b|\bnetlify(-cli)?(@[\w.-]+)?\s+deploy\b[^;]*--prod|\bfirebase(-tools)?(@[\w.-]+)?\s+deploy\b|\bwrangler(@[\w.-]+)?\s+(deploy|publish|pages\s+deploy)\b|\bgcloud\s+app\s+deploy\b|\b(serverless|sls)\s+deploy\b|\bcdk\s+deploy\b|\bpulumi\s+up\b|\bamplify\s+(push|publish)\b|\b(terraform|tofu)\s+apply\b|\bexpo\s+publish\b/i, 'guard.destructive.serverDeploy'],
52
+ [/\beas(-cli(@[\w.-]+)?)?\s+(submit\b|build\b(?=[^;\n]*--auto-submit\b)|update:(rollback|republish)\b|update\b(?=[^;\n]*--(branch|channel|environment)(=|\s+)['"]?prod(uction)?\b)|deploy\b(?=[^;\n]*--prod\b))/i, 'guard.destructive.storeSubmit'],
50
53
  [/\bgit\s+push\b[^;]*\b(main|master|production)\b/i, 'guard.destructive.pushMain'],
51
54
  [/\bgit\s+(rebase|filter-branch|filter-repo)\b/i, 'guard.destructive.rewriteHistory'],
52
55
  [/\b(alembic\s+upgrade|prisma\s+migrate\s+deploy|supabase\s+db\s+push)\b/i, 'guard.destructive.migration'],
@@ -304,6 +307,8 @@ const PERMISSION_EQUIVALENT = [
304
307
  ['deny', /\bgit\s+reset\s+[^;&|]*--hard\b/i, 'git reset --hard deletes uncommitted work'],
305
308
  ['deny', /\bgit\s+push\b[^;&|]*\s(--force\S*|-\w*f\w*|\+\S+)(?=\s|$)/i, 'git push --force overwrites the remote history'],
306
309
  ['deny', ENV_ACCESS, 'Access to .env or secrets/ (the AI does not read or write them)'],
310
+ // Claude asks every push through settings.json (Bash(git push:*)); a push to any branch can deploy (Vercel's prod branch)
311
+ ['ask', /\bgit\s+push\b/i, 'guard.destructive.perm.push'],
307
312
  ['ask', /freeze-guard\.mjs['"]?\s+['"]?--off\b/i, 'guard.destructive.perm.freezeOff'],
308
313
  ['ask', /tools\.mjs['"]?\s+['"]?--commands\b/i, 'guard.destructive.perm.toolsCommands'],
309
314
  ['ask', /freeze-guard\.mjs['"]?\s+['"]?--plan-add\b/i, 'guard.destructive.perm.planAdd'],
@@ -400,6 +400,7 @@ export const MESSAGES = {
400
400
  'guard.destructive.envShell': { en: 'The command names a .env file (secrets). The AI does not read or write it; if needed, the user does it. User approval required.' },
401
401
  'guard.destructive.gitOutput': { en: 'git writes its output to a file the command chooses (--output / format-patch -o); it can overwrite a guard, test or settings file. User approval required.' },
402
402
  'guard.destructive.boardShell': { en: 'docs/workflow/board.md (board members, commit review switch) is changed from the shell. Use the file tools; otherwise user approval required.' },
403
+ 'guard.destructive.perm.push': { en: 'Pushing to the remote repository (a pushed branch can deploy)' },
403
404
  'guard.destructive.perm.freezeOff': { en: 'The edit lock is being removed' },
404
405
  'guard.destructive.perm.toolsCommands': { en: 'The shared .claude/settings.json → skillOverrides is changing (command list)' },
405
406
  'guard.destructive.perm.planAdd': { en: 'The approved plan\'s file list is widening (scope shield)' },
@@ -444,6 +445,8 @@ export const MESSAGES = {
444
445
  'guard.package.newPypi': { en: 'first release was published {age} days ago' },
445
446
  'guard.package.timeout': { en: 'could not be verified (timeout)' },
446
447
  'guard.package.network': { en: 'could not be verified (network error)' },
448
+ 'guard.package.tooMany': { en: 'Package gate: {count} packages in one command (more than {max}) are not checked one by one. User approval required.' },
449
+ 'guard.package.error': { en: 'The package gate could not check this command ({error}). User approval required.' },
447
450
  'guard.package.ask': { en: 'Package gate warning: {list}. Before installing, make sure the package is really the one you want.' },
448
451
  'guard.structure.offMap': { en: '"{rel}" is not in the structure map (.claude/structure.json). The right place is probably one of: {top}. If it is temporary or a trial, write it under sandbox/. If a new permanent place is needed, ask it as a technical decision and update the map (docs/architecture/structure.md).' },
449
452
  'guard.structure.prefix': { en: 'Structure: {reason}' },
@@ -24,19 +24,20 @@ const POPULAR = {
24
24
  'langchain', 'transformers', 'torch', 'scikit-learn', 'aiohttp', 'tenacity', 'ruff', 'black', 'mypy'],
25
25
  };
26
26
 
27
+ // Case-insensitive (the Windows shell is); npm's install aliases (in, ins, isntall, it…) count as install
27
28
  const COMMANDS = [
28
- [/^(npm|pnpm|bun)\s+(i|install|add)\b/, 'npm'], [/^yarn\s+(global\s+)?add\b/, 'npm'], [/^npx\s+expo\s+install\b/, 'npm'],
29
- [/^uv\s+(add|pip\s+install)\b/, 'pypi'], [/^(python3?\s+-m\s+)?pip3?\s+install\b/, 'pypi'], [/^poetry\s+add\b/, 'pypi'],
29
+ [/^(npm|pnpm|bun)\s+(i|in|ins|inst|insta|instal|install|isnt|isnta|isntal|isntall|it|add)\b/i, 'npm'], [/^yarn\s+(global\s+)?add\b/i, 'npm'], [/^npx\s+expo\s+install\b/i, 'npm'],
30
+ [/^uv\s+(add|pip\s+install)\b/i, 'pypi'], [/^(python3?\s+-m\s+)?pip3?\s+install\b/i, 'pypi'], [/^poetry\s+add\b/i, 'pypi'],
30
31
  ];
31
32
 
32
33
  // Download-and-run: the first positional is the package (the rest are its arguments), or the values of the package flags.
33
34
  // local: the runner uses a bin the project already has before downloading (npx, npm exec, bunx); pnpm/yarn dlx always download.
34
35
  // positional: false for uv run (its positional is a script; only --with names packages).
35
36
  const EXEC = [
36
- { re: /^(npx|npm\s+(exec|x)|bunx|bun\s+x)\b/, eco: 'npm', local: true, positional: true },
37
- { re: /^(pnpx|pnpm\s+dlx|yarn\s+dlx)\b/, eco: 'npm', local: false, positional: true },
38
- { re: /^(uvx|uv\s+tool\s+run|pipx\s+run)\b/, eco: 'pypi', local: false, positional: true },
39
- { re: /^uv\s+run\b/, eco: 'pypi', local: false, positional: false },
37
+ { re: /^(npx|npm\s+(exec|x)|bunx|bun\s+x)\b/i, eco: 'npm', local: true, positional: true },
38
+ { re: /^(pnpx|pnpm\s+dlx|yarn\s+dlx)\b/i, eco: 'npm', local: false, positional: true },
39
+ { re: /^(uvx|uv\s+tool\s+run|pipx\s+run)\b/i, eco: 'pypi', local: false, positional: true },
40
+ { re: /^uv\s+run\b/i, eco: 'pypi', local: false, positional: false },
40
41
  ];
41
42
  const FLAGS = {
42
43
  npm: { pkg: /^(-p|--package)$/, value: /^(-p|--package|-c|--call|--registry|--prefix|--cache|--userconfig|--globalconfig|-w|--workspace|--node-options|--script-shell|--shell|--loglevel|-C|--dir|--filter)$/ },
@@ -68,14 +69,17 @@ function execArgs(args, eco, positional) {
68
69
 
69
70
  // What runs a segment: wrappers, VAR=x, a path or .cmd/.exe on the tool, and the manager's own flags before its subcommand are
70
71
  // dropped (FOO=1 npx x, cmd /c npx x, bash -c "npx x", /usr/bin/npx x, npx.cmd x, pnpm -C . dlx x, npm --silent exec x).
71
- const WRAPPER = /^(?:\(|[A-Za-z_]\w*=\S*\s+|(?:sudo|env|time|nohup|exec|command|xargs|corepack|call|start)\s+|(?:bash|sh|zsh|dash|cmd|pwsh|powershell)(?:\.exe)?\s+(?:-c|\/c|\/k|-Command)\s+["']?)/i;
72
+ // Also timeout/nice/stdbuf, shell keywords (then, do, else, !) and combined shell flags (bash -lc).
73
+ const WRAPPER = /^(?:\(|\{|!\s*|[A-Za-z_]\w*=\S*\s+|(?:sudo|env|time|nohup|exec|command|xargs|corepack|call|start|then|do|else|ionice|stdbuf)\s+|timeout\s+(?:-\S+\s+)*\S+\s+|nice\s+(?:-n\s*\S+\s+|-\d+\s+)?|(?:bash|sh|zsh|dash|cmd|pwsh|powershell)(?:\.exe)?\s+(?:-\w*c|\/c|\/k|-Command)\s+["']?)/i;
72
74
  const SUBCOMMAND = /^(install|i|add|exec|x|dlx|tool|pip|run|global)$/;
73
75
  export function normalize(part) {
74
76
  let s = part.trim(), prev;
75
77
  do { prev = s; s = s.replace(WRAPPER, '').trim(); } while (s !== prev);
76
- s = s.replace(/^["']?(?:[^\s"']*[\/])?([\w.-]+?)(?:\.cmd|\.exe|\.ps1)?["']?(?=\s|$)/i, '$1');
78
+ // A path (Windows \ too, quoted with spaces) and .cmd/.exe on the tool: "C:\Program Files\nodejs\npm.cmd" i x → npm i x
79
+ s = s.replace(/^"(?:[^"]*[\\/])?([\w.-]+?)(?:\.cmd|\.exe|\.ps1)?"(?=\s|$)/i, '$1')
80
+ .replace(/^["']?(?:[^\s"']*[\\/])?([\w.-]+?)(?:\.cmd|\.exe|\.ps1)?["']?(?=\s|$)/i, '$1');
77
81
  const t = s.split(/\s+/);
78
- if (/^(npm|pnpm|yarn|bun|uv)$/.test(t[0])) {
82
+ if (/^(npm|pnpm|yarn|bun|uv)$/i.test(t[0])) {
79
83
  let i = 1;
80
84
  while (i < t.length && t[i].startsWith('-')) i += !t[i].includes('=') && t[i + 1] && !t[i + 1].startsWith('-') && !SUBCOMMAND.test(t[i + 1]) ? 2 : 1;
81
85
  s = [t[0], ...t.slice(i)].join(' ');
@@ -85,13 +89,15 @@ export function normalize(part) {
85
89
 
86
90
  const NOT_REGISTRY = /^(\.|\/|file:|link:|git\+|git:|https?:|github:|workspace:)/;
87
91
  function npmName(arg) {
88
- if (NOT_REGISTRY.test(arg)) return null;
89
- const at = arg.indexOf('@', 1), spec = at > 0 ? arg.slice(at + 1) : '';
90
- // name@npm:other installs "other": the alias target is checked. name@github:x/y, @https:… are not from the registry
91
- // (like a bare URL, not checked here); the name in front is not what gets installed.
92
- if (spec.startsWith('npm:')) return npmName(spec.slice(4));
93
- if (/[:/]/.test(spec)) return null;
94
- return (at > 0 ? arg.slice(0, at) : arg) || null;
92
+ // name@npm:other installs "other": the alias target is checked (a loop: a deep a@npm:a@npm:… chain must not overflow
93
+ // the stack). name@github:x/y, @https:… are not from the registry (like a bare URL, not checked here).
94
+ for (;;) {
95
+ if (NOT_REGISTRY.test(arg)) return null;
96
+ const at = arg.indexOf('@', 1), spec = at > 0 ? arg.slice(at + 1) : '';
97
+ if (spec.startsWith('npm:')) { arg = spec.slice(4); continue; }
98
+ if (/[:/]/.test(spec)) return null;
99
+ return (at > 0 ? arg.slice(0, at) : arg) || null;
100
+ }
95
101
  }
96
102
 
97
103
  function pypiName(arg) {
@@ -101,7 +107,9 @@ function pypiName(arg) {
101
107
 
102
108
  export function findPackages(command) {
103
109
  const result = [];
104
- for (const part of command.split(/&&|\|\||;|\|/)) {
110
+ // Every place a new command can start: chains, a newline, a background &, $( ), backticks, ( ) and { } groups.
111
+ // A redirect's & (2>&1, &>) is not a separator.
112
+ for (const part of command.split(/\n|&&|\|\||;|\||(?<![>&])&(?![>&])|\$\(|`|[(){}]/)) {
105
113
  const s = normalize(part);
106
114
  const match = COMMANDS.find(([re]) => re.test(s));
107
115
  const exec = match ? null : EXEC.find((e) => e.re.test(s));
@@ -182,15 +190,23 @@ export async function check({ eco, name }, get = fetch, now = Date.now()) {
182
190
  }
183
191
  }
184
192
 
193
+ // More names than this in one command are asked without checking each one (unbounded fetches would hit the hook timeout)
194
+ const MAX_PACKAGES = 50;
185
195
  async function hook() {
186
196
  const g = readInput();
187
197
  if (!g) process.exit(0);
198
+ // A gate that throws or times out lets the command run: any error asks instead
199
+ try { await gate(g); } catch (e) { decide(g.tool, 'ask', t(g.root, 'guard.package.error', { error: String(e?.message ?? e).slice(0, 200) })); }
200
+ process.exit(0);
201
+ }
202
+ async function gate(g) {
188
203
  // npx/bunx run a bin the project already installed without downloading: a local bin (tsc, eas) is not a package name
189
204
  const bin = (name) => /^\w[\w.-]*$/.test(name) && [g.dir, g.root].some((d) => fs.existsSync(path.join(d, 'node_modules', '.bin', name)));
190
205
  // The kit's own package (/start and /adopt run npx -y tillerhand@<version> install): the kit already trusts itself
191
206
  // Both only for the plain spelling: name@1.2 or name@npm:other downloads, it does not run the local bin or the kit's release
192
207
  const packages = findPackages(g.command).filter((p) => !(p.local && p.spec === p.name && bin(p.name)) && !(p.eco === 'npm' && /^tillerhand(@\d+\.\d+\.\d+)?$/.test(p.spec ?? '')));
193
- if (!packages.length) process.exit(0);
208
+ if (!packages.length) return;
209
+ if (packages.length > MAX_PACKAGES) decide(g.tool, 'ask', t(g.root, 'guard.package.tooMany', { count: packages.length, max: MAX_PACKAGES }));
194
210
  const results = await Promise.all(packages.map(async (p) => ({ ...p, ...(await check(p)) })));
195
211
  const missing = results.filter((s) => s.status === 'missing' && !s.unsure);
196
212
  if (missing.length) {
@@ -397,6 +397,7 @@
397
397
  "guard.destructive.envShell": "Komut bir .env dosyasını (sırlar) anıyor. AI onu okumaz, yazmaz; gerekirse kullanıcı yapar. Kullanıcı onayı gerekli.",
398
398
  "guard.destructive.gitOutput": "git çıktısını komutun seçtiği bir dosyaya yazıyor (--output / format-patch -o); bir koruma, test ya da ayar dosyasını ezebilir. Kullanıcı onayı gerekli.",
399
399
  "guard.destructive.boardShell": "docs/workflow/board.md (kurul üyeleri, commit incelemesi anahtarı) kabuktan değiştiriliyor. Dosya araçlarını kullan; yoksa kullanıcı onayı gerekli.",
400
+ "guard.destructive.perm.push": "Uzak depoya gönderiliyor (gönderilen dal yayına çıkabilir)",
400
401
  "guard.destructive.perm.freezeOff": "Düzenleme kilidi kaldırılıyor",
401
402
  "guard.destructive.perm.toolsCommands": "Paylaşılan .claude/settings.json → skillOverrides değişiyor (komut listesi)",
402
403
  "guard.destructive.perm.planAdd": "Onaylı planın dosya listesi genişliyor (kapsam kalkanı)",
@@ -441,6 +442,8 @@
441
442
  "guard.package.newPypi": "ilk sürümü {age} gün önce yayımlanmış",
442
443
  "guard.package.timeout": "doğrulanamadı (zaman aşımı)",
443
444
  "guard.package.network": "doğrulanamadı (ağ hatası)",
445
+ "guard.package.tooMany": "Paket kapısı: tek komutta {count} paket var ({max} sınırının üstünde), tek tek denetlenmiyor. Kullanıcı onayı gerekli.",
446
+ "guard.package.error": "Paket kapısı bu komutu denetleyemedi ({error}). Kullanıcı onayı gerekli.",
444
447
  "guard.package.ask": "Paket kapısı uyarısı: {list}. Kurmadan önce paketin gerçekten istenen paket olduğundan emin ol.",
445
448
  "guard.structure.offMap": "\"{rel}\" yapı haritasında yok (.claude/structure.json). Doğru yer muhtemelen şunlardan biri: {top}. Geçici veya deneme ise sandbox/ altına yaz. Kalıcı yeni bir yer gerekiyorsa bunu teknik karar olarak sor ve haritayı güncelle (docs/architecture/structure.md).",
446
449
  "guard.structure.prefix": "Yapı: {reason}",
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.49.7-2a78d6?style=flat-square"></a>
9
+ <a href="kit/CHANGELOG.md"><img alt="Version" src="https://img.shields.io/badge/version-3.49.9-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">
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.49.7-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.49.9-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">
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.49.9] - 2026-10-30
7
+
8
+ ### Security
9
+ - **More production deploys ask you:** `firebase deploy`, `wrangler deploy`/`publish`/`pages deploy`, `gcloud app deploy`, `serverless deploy`, `cdk deploy`, `pulumi up`, `amplify push`, `terraform apply`, `expo publish`, `eas build --auto-submit`, and `netlify deploy --prod` through `npx netlify-cli`.
10
+ - **More data deletion is blocked:** `heroku pg:reset`, MongoDB `dropDatabase()`/`dropCollection()`/`deleteMany({})`, Laravel `migrate:fresh`/`refresh`/`reset`, TypeORM `schema:drop`, Knex `migrate:rollback --all`, `prisma db push --accept-data-loss`, and `terraform`/`tofu`/`pulumi destroy`.
11
+ - On Codex and Antigravity every `git push` asks, as it already did in Claude Code: a pushed branch can deploy.
12
+ - The structure guard blocks more clutter names in new projects: `a.old.ts`, `a.bak.ts`, `a.backup.ts`, `a-copy.ts`, `a (1).ts`, `Copy of a.ts`, `old/`, `backup/`, editor swap files (`.swp`, `.rej`, `.sav`) and OS files (`.DS_Store`, `Thumbs.db`).
13
+
14
+ ## [3.49.8] - 2026-10-30
15
+
16
+ ### Security
17
+ - **The package gate sees installs in more places.** An `npm i` after a newline, a background `&`, inside `$( )`, backticks, `if … then`, `( )` or `{ }` is checked, and so are `timeout`/`nice`/`bash -lc` in front, a quoted Windows path (`"C:\Program Files\nodejs\npm.cmd" i`), upper case (`NPM i`) and npm's install aliases (`npm in`, `npm isntall`, `npm it`…).
18
+ - A command the package gate cannot check (a parser error, more than 50 packages at once) asks you instead of running unchecked.
19
+
6
20
  ## [3.49.7] - 2026-10-30
7
21
 
8
22
  ### Security
package/kit/VERSION CHANGED
@@ -1 +1 @@
1
- 3.49.7
1
+ 3.49.9
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.49.7</b> Starter kit for Claude Code · MIT</span>
364
+ <span class="pill"><b>v3.49.9</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">
@@ -1241,7 +1241,7 @@ Next: G-013 password reset · pending decision: email service</pre>
1241
1241
  <footer>
1242
1242
  <div class="container">
1243
1243
  <a class="brand" href="#top" style="font-size:16px"><svg class="mark" style="width:22px;height:22px"><use href="#mark"/></svg>TillerHand</a>
1244
- <span>Version 3.49.7 · <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>
1244
+ <span>Version 3.49.9 · <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
1245
  </div>
1246
1246
  </footer>
1247
1247
 
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.49.7</b> Claude Code için başlangıç kiti · MIT</span>
364
+ <span class="pill"><b>v3.49.9</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">
@@ -1245,7 +1245,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
1245
1245
  <footer>
1246
1246
  <div class="container">
1247
1247
  <a class="brand" href="#top" style="font-size:16px"><svg class="mark" style="width:22px;height:22px"><use href="#mark"/></svg>TillerHand</a>
1248
- <span>Sürüm 3.49.7 · <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>
1248
+ <span>Sürüm 3.49.9 · <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
1249
  </div>
1250
1250
  </footer>
1251
1251
 
@@ -55,7 +55,6 @@
55
55
  "CLAUDE-SECURITY-*/**"
56
56
  ],
57
57
  "deny": [
58
- "**/*.bak",
59
58
  "**/*.orig",
60
59
  "**/*.tmp",
61
60
  "**/*~",
@@ -69,6 +68,25 @@
69
68
  "**/tmp/**",
70
69
  "**/untitled*",
71
70
  "**/test.*",
72
- "**/deneme*"
71
+ "**/deneme*",
72
+ "**/*.bak*",
73
+ "**/*.old",
74
+ "**/*.old.*",
75
+ "**/*_bak.*",
76
+ "**/*.backup.*",
77
+ "**/*-backup.*",
78
+ "**/*_backup.*",
79
+ "**/*-copy.*",
80
+ "**/*-copy?.*",
81
+ "**/*_copy.*",
82
+ "**/* (?).*",
83
+ "**/Copy of *",
84
+ "**/old/**",
85
+ "**/backup/**",
86
+ "**/*.sav",
87
+ "**/*.swp",
88
+ "**/*.rej",
89
+ "**/.DS_Store",
90
+ "**/Thumbs.db"
73
91
  ]
74
92
  }
@@ -66,7 +66,6 @@
66
66
  "CLAUDE-SECURITY-*/**"
67
67
  ],
68
68
  "deny": [
69
- "**/*.bak",
70
69
  "**/*.orig",
71
70
  "**/*.tmp",
72
71
  "**/*~",
@@ -80,6 +79,25 @@
80
79
  "**/tmp/**",
81
80
  "**/untitled*",
82
81
  "**/test.*",
83
- "**/deneme*"
82
+ "**/deneme*",
83
+ "**/*.bak*",
84
+ "**/*.old",
85
+ "**/*.old.*",
86
+ "**/*_bak.*",
87
+ "**/*.backup.*",
88
+ "**/*-backup.*",
89
+ "**/*_backup.*",
90
+ "**/*-copy.*",
91
+ "**/*-copy?.*",
92
+ "**/*_copy.*",
93
+ "**/* (?).*",
94
+ "**/Copy of *",
95
+ "**/old/**",
96
+ "**/backup/**",
97
+ "**/*.sav",
98
+ "**/*.swp",
99
+ "**/*.rej",
100
+ "**/.DS_Store",
101
+ "**/Thumbs.db"
84
102
  ]
85
103
  }
@@ -71,7 +71,6 @@
71
71
  "CLAUDE-SECURITY-*/**"
72
72
  ],
73
73
  "deny": [
74
- "**/*.bak",
75
74
  "**/*.orig",
76
75
  "**/*.tmp",
77
76
  "**/*~",
@@ -85,6 +84,25 @@
85
84
  "**/tmp/**",
86
85
  "**/untitled*",
87
86
  "**/test.*",
88
- "**/deneme*"
87
+ "**/deneme*",
88
+ "**/*.bak*",
89
+ "**/*.old",
90
+ "**/*.old.*",
91
+ "**/*_bak.*",
92
+ "**/*.backup.*",
93
+ "**/*-backup.*",
94
+ "**/*_backup.*",
95
+ "**/*-copy.*",
96
+ "**/*-copy?.*",
97
+ "**/*_copy.*",
98
+ "**/* (?).*",
99
+ "**/Copy of *",
100
+ "**/old/**",
101
+ "**/backup/**",
102
+ "**/*.sav",
103
+ "**/*.swp",
104
+ "**/*.rej",
105
+ "**/.DS_Store",
106
+ "**/Thumbs.db"
89
107
  ]
90
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tillerhand",
3
- "version": "3.49.7",
3
+ "version": "3.49.9",
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",