tillerhand 3.28.6 → 3.30.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.
@@ -41,7 +41,7 @@ Bulguları kısa bir tablo halinde göster. Hızlı taramada kodun içine dalma:
41
41
  ## Adım 2: Tip ve kurulum
42
42
 
43
43
  1. Taramaya göre tipi öner ve onaylat (web-saas / mobile / backend; AI özelliği var mı; Türkiye'de satış veya Türk kullanıcı varsa Türkiye eki `tr`, ayrıntı `/start` Adım 2).
44
- 2. Kur: `node <kit klasörü>/kit/kit.mjs install --type <tip> [--addons ai,tr] --project .` (kit klasörü `.kit.json` → `kit` alanında; alan `npx:tillerhand@<sürüm>` ise `npx -y tillerhand@<sürüm> install ...`; sürüm tam olarak `1.2.3` biçiminde ve `.kit.json` → `version` ile aynı değilse dur ve sor). Araç `init`'te seçilmediyse Adım 0'daki seçimi `--tool <liste>` olarak ekle.
44
+ 2. Kur: `node <kit klasörü>/kit/kit.mjs install --type <tip> [--addons ai,tr] --project .` (kit klasörü `.kit.json` → `kit` alanında; alan `local` ise klasör git dışı `.kit.local.json` → `kit`'te, o dosya yoksa proje başka makinede açılmıştır: kullanıcıya kit klasörünü sor ya da `npx -y tillerhand@<.kit.json → version>` kullan; alan `npx:tillerhand@<sürüm>` ise `npx -y tillerhand@<sürüm> install ...`; sürüm tam olarak `1.2.3` biçiminde ve `.kit.json` → `version` ile aynı değilse dur ve sor). Araç `init`'te seçilmediyse Adım 0'daki seçimi `--tool <liste>` olarak ekle.
45
45
  3. **`.kit-new` dosyaları:** Her biri için (`CLAUDE.md` ve `AGENTS.md` hariç, onlar Adım 4'te) farkı özetle ve karar olarak sor: kitinkini al / projeninkini koru / birleştir. Örnekler: `.env.example` genelde birleştirilir; `ci.yml` için mevcut CI'ın yaptıklarını kitinkiyle karşılaştır. Sonra `.kit-new` dosyasını sil.
46
46
 
47
47
  ## Adım 3: Belgeleri koddan çıkar
@@ -39,5 +39,6 @@ Boşsa `docs/workflow/progress.md` → "Sıradaki adım" veya `docs/product/road
39
39
  - Benim nasıl test edeceğim (adım adım)
40
40
  - Önerilen commit mesajı
41
41
  - Kontrol edemediğin veya şüpheli olduğun yerler
42
+ - Görevde bir davranışını düzelttiysem ya da tercih söylediysem: aynı AskUserQuestion çağrısında ayrı bir çoklu seçim sorusu olarak "Tercih olarak kaydedeyim mi?" (AGENTS.md → kural 9, varsa; seçilenler `prefs.mjs --add`). Not yoksa sorma.
42
43
  - Sonra ne yapalım? AskUserQuestion ile sor: `/review-changes` ve commit (Önerilen) / sıradaki göreve geç / bu görevde değişiklik iste. Commit'te hafif kurul denetimi otomatik istenir (commit kapısı hook'u). Commit atıldıktan ve testler yeşilken çalışan nokta kaydet: `node .claude/hooks/checkpoint.mjs --save "<görev kodu> bitti, testler yeşil"` (`/rollback` buraya döner).
43
44
  - Durum bloğu
@@ -5,7 +5,7 @@ argument-hint: [boş | --addons ai,tr | --tool claude,codex,antigravity]
5
5
 
6
6
  Ek argüman: $ARGUMENTS
7
7
 
8
- 1. `.kit.json`'u oku: mevcut sürüm, `kaynak` (kit repo adresi), tip, ekler.
8
+ 1. `.kit.json`'u oku: mevcut sürüm, `source` (kit repo adresi), tip, ekler.
9
9
  2. Commit edilmemiş değişiklik varsa dur ve önce commit etmeyi öner (güncelleme dosya yazar).
10
10
  3. Kiti geçici bir klasöre klonla ve güncellemeyi çalıştır:
11
11
 
@@ -28,7 +28,7 @@ Amaç: Bu projede öğrendiklerini kaybetmemek ve kiti (bundan sonraki tüm proj
28
28
  - Kural ekleme > kural değiştirme > kural silme sırasıyla tercih et; kiti şişirme. Aynı amaçlı mevcut kural varsa onu güçlendir. Metni `mattpocock-skills:writing-for-agents` ilkeleriyle yaz.
29
29
  - Önerileri **çoklu seçimle** onaylat.
30
30
  6. Onaylananları kite uygula:
31
- 1. `.kit.json` → `kaynak` reposunu geçici klasöre klonla.
31
+ 1. `.kit.json` → `source` reposunu geçici klasöre klonla.
32
32
  2. `retro/<proje>-<tarih>` dalı aç.
33
33
  3. Değişiklikleri yap, `kit/CHANGELOG.md` → "[Yayınlanmamış]" bölümüne ekle.
34
34
  4. `node --test "kit/tests/*.test.mjs"` çalıştır, commit at.
@@ -40,7 +40,7 @@ Bu bir **9 adımlı sihirbaz** (0-9). Kullanıcı hiçbir şeyi bilmiyormuş gib
40
40
  - **Kapalı (Önerilen):** Projenin hafızası `AGENTS.md`, `progress.md` ve karar günlüğünde; görünür ve git'te. Tekrarlayan hatalar `/fix-bug` ile "Öğrenilen kurallar"a önerilir. `.claude/settings.json`'a `"autoMemoryEnabled": false` ekle (dosyayı birleştir).
41
41
  - **Açık:** Tercihlerin oturumlar arasında kendiliğinden hatırlanır; notlar `AGENTS.md` ile çelişebilir. Ayara dokunma.
42
42
  Seçimi `**Profil:**` satırına ekle (örn. `hafıza: kapalı`). Kaynak: code.claude.com/docs/en/memory (2026-10-25).
43
- 1. Ortamı kontrol et ve tek satırla raporla: `node --version`, `git --version` ve kitin yeri. İki kurulum yolu var: kökte `kit/kit.mjs` (template yolu) ya da `.kit.json` → `kit` alanındaki klasör (`init` ile kurulmuş, `type` boş). `kit` alanı `npx:tillerhand@<sürüm>` ise kit npm paketinden kurulmuştur. Klasörde zaten uygulama kodu varsa (`package.json`, `pyproject.toml`, `src/` vb.) dur ve `/adopt` öner.
43
+ 1. Ortamı kontrol et ve tek satırla raporla: `node --version`, `git --version` ve kitin yeri. İki kurulum yolu var: kökte `kit/kit.mjs` (template yolu) ya da `.kit.json` → `kit` alanındaki klasör (`init` ile kurulmuş, `type` boş). `kit` alanı `npx:tillerhand@<sürüm>` ise kit npm paketinden kurulmuştur. `local` ise klasörün bu makinedeki yolu git dışı `.kit.local.json` → `kit`'tedir; o dosya yoksa kullanıcıya kit klasörünü sor ya da `npx -y tillerhand@<.kit.json → version>` kullan. Klasörde zaten uygulama kodu varsa (`package.json`, `pyproject.toml`, `src/` vb.) dur ve `/adopt` öner.
44
44
  2. `docs/workflow/skills.md`'deki plugin'lerin skill'leri senin skill listende var mı bak. LSP eklentisi dil sunucusu ister: web ve mobil için `npm i -g typescript-language-server typescript`, backend için `npm i -g pyright` (global kurulum; kullanıcı onayıyla). **Eklentiler:** Proje ayarı eklentileri açar ama indirmez; kurulmamış olanlar yükleme hatası verir ve skill'leri gelmez. Kullanıcıya listeyi göster ve sor: "Proje ayarındaki eklentiler kurulsun mu?" Önce `node .claude/hooks/plugins-sync.mjs` ile eksikleri listele; onay gelirse `node .claude/hooks/plugins-sync.mjs --install` çalıştır. Betik eksikleri proje kapsamında kurar, `false` olanları (paket eklentileri: tasarım, güvenlik, yayın, video) kurup kapatır. Kullanıcıya tek cümleyle söyle: "Paketler kapalı gelir, ilgili komut gerektiğinde açmayı sorar; durum için `/tools`." Sonra kullanıcıdan `/reload-plugins` çalıştırmasını iste. claude CLI yoksa eksik eklentilerin `/plugin install x@y` komutlarını ver ve "Kurup devam edelim mi, eksik skill olmadan mı?" diye sor.
45
45
  3. `caveman:caveman` skill'ini yükle (rapor dili).
46
46
  4. **Limit:** Limiti oku (`docs/workflow/usage-limits.md` §1) ve raporla. Seçilen derinliğin tahmini maliyetini kalan limitle karşılaştır; adımlar arasında durup sonra devam edilebileceğini söyle. Seviye sarı veya kırmızıysa bunu tek satırla söyle; durdurma.
@@ -88,7 +88,7 @@ Kullanıcıya ne yapılacağını tek cümleyle söyle, sonra çalıştır:
88
88
  ```bash
89
89
  # template yolu (kökte kit/ var): kit/ kurulumdan sonra silinir
90
90
  node kit/kit.mjs install --type <web-saas|mobile|backend> [--addons ai,tr] [--tool claude,codex,antigravity]
91
- # init yolu (.kit.json → kit): kit klasörüne dokunulmaz; araç init'te seçildiyse --tool gerekmez
91
+ # init yolu (.kit.json → kit; "local" ise .kit.local.json → kit, o dosya yoksa kullanıcıya sor): kit klasörüne dokunulmaz; araç init'te seçildiyse --tool gerekmez
92
92
  node <kit>/kit/kit.mjs install --type <web-saas|mobile|backend> [--addons ai,tr] --project .
93
93
  # npm yolu (.kit.json → kit = npx:tillerhand@<sürüm>): aynı sürümle. Sürüm tam olarak 1.2.3 biçiminde ve .kit.json → version ile aynı değilse dur, kullanıcıya sor
94
94
  npx -y tillerhand@<sürüm> install --type <web-saas|mobile|backend> [--addons ai,tr] --project .
@@ -20,6 +20,7 @@ Bu oturumu kapatıyoruz. Bir sonraki oturum (veya `/clear` sonrası) sıfır ba
20
20
  7. `node .claude/hooks/cost.mjs` ve `node .claude/hooks/dashboard.mjs` ile `dashboard.html`'i yenile.
21
21
  7b. Bu oturumda AI'nın bilmediği için hata yaptığı proje bilgisi çıktıysa `AGENTS.md`'ye eklemeyi öner (onayla; sadece Claude Code'a özelse `/revise-claude-md` ile `CLAUDE.md`'ye). Aynı düzeltmeyi kullanıcı iki kez yaptıysa `/hookify <kural>` ile kalıcı kural öner. Kural `AGENTS.md`'de "Öğrenilen kurallar" bölümüne gider; biçim ve kaynak/tarih satırı `/fix-bug` 8. adımdaki gibi (kaynak: bu oturumdaki olay).
22
22
  8. Commit edilmemiş iş varsa commit mesajı öner. Commit'i onayımla at. Testler yeşilse çalışan nokta kaydet: `node .claude/hooks/checkpoint.mjs --save "oturum sonu: <kısa özet>"`.
23
+ 8b. **Kişisel tercihler** (AGENTS.md → kural 9, varsa): Bu oturumda kullanıcı bir davranışı düzelttiyse ya da tercih söylediyse, notları AskUserQuestion ile çoklu seçim olarak sor ve seçilenleri `node .claude/hooks/prefs.mjs --add` ile yaz. Not yoksa bu adımı atla, soru sorma.
23
24
  9. Faz bittiyse sırayla öner: `/findings-tech` (teknik borç taraması), `/board convene phase-end` (tam kurul, tahmini maliyetiyle birlikte), sonra `/retro`.
24
25
  10. Limiti ve bağlamı oku. Kalan 5 saatlik payı, sıfırlanma saatini ve bağlam %50'yi geçtiyse `/clear` önerisini sıradaki adımla birlikte söyle.
25
26
 
@@ -205,7 +205,9 @@ export function scopeIssue(command, dir, root) {
205
205
  const vk = path.join(os.userInfo().homedir, '.vibe-kit');
206
206
  const touchesApproval = (y) => VIBE_KIT.test(y) || !/^\.\.|^$/.test(path.relative(y, vk)) && !path.isAbsolute(path.relative(y, vk));
207
207
  for (const h of targets) {
208
- if (touchesApproval(h) || touchesApproval(realPath(h))) return { decision: 'ask', reason: `${h}: kapı komut onayı kaydı (kullanıcı klasörü); kabukla değiştirilmez, node .claude/hooks/gate.mjs --approve kullanılır. Kullanıcı onayı gerekli.` };
208
+ if (touchesApproval(h) || touchesApproval(realPath(h))) return { decision: 'ask', reason: /tercihler\.md$/i.test(h)
209
+ ? `${h}: kişisel tercih dosyası (kullanıcı klasörü); kabukla değiştirilmez, node .claude/hooks/prefs.mjs --add / --remove kullanılır. Kullanıcı onayı gerekli.`
210
+ : `${h}: kapı komut onayı kaydı (kullanıcı klasörü); kabukla değiştirilmez, node .claude/hooks/gate.mjs --approve kullanılır. Kullanıcı onayı gerekli.` };
209
211
  const rel = relPath(realPath(h), groot);
210
212
  const k = protectedRule(rel) ?? protectedRule(`${rel}/`);
211
213
  if (k) return { decision: k[0], reason: k[0] === 'deny' ? `${rel}: ${k[2]}`
@@ -253,6 +255,7 @@ const PERMISSION_EQUIVALENT = [
253
255
  ['ask', /freeze-guard\.mjs['"]?\s+['"]?--plan-save\b/i, 'Kapsam kalkanının dosya listesi yazılıyor'],
254
256
  ['ask', /freeze-guard\.mjs['"]?\s+['"]?--plan-end\b/i, 'Kapsam kalkanı kapatılıyor'],
255
257
  ['ask', /commit-gate\.mjs['"]?\s+['"]?--skip\b/i, 'Commit kapısı ve kurul denetimi atlanıyor'],
258
+ ['ask', /prefs\.mjs['"]?\s+['"]?--(add|remove)\b/i, 'Kişisel tercih dosyası (~/.vibe-kit/tercihler.md) değişiyor'],
256
259
  ['ask', /(?<!(?:^|[\s'"=])(?:\.[\\/]|\$\{?CLAUDE_PROJECT_DIR\}?[\\/]?)?\.claude[\\/]?hooks[\\/]?commit-)gate\.mjs['"]?\s+['"]?--approve\b/i, 'Deterministik kapının çalıştıracağı komutlar onaylanıyor'],
257
260
  // Shell counterpart of the PROTECTED rule on file tools: a command that names a rule or guard file and writes/deletes is asked
258
261
  // (.git: the gate command approval and git hooks live there)
@@ -129,7 +129,9 @@ function hook() {
129
129
  const paths = g.files.map(({ path: p }) => realPath(path.resolve(g.dir, p)));
130
130
  // Gate command approval record (gate.mjs, in the user folder ~/.vibe-kit/): the AI must not write it by hand
131
131
  const approval = paths.find((p) => /[\\/]\.vibe-kit([\\/]|$)/i.test(p));
132
- if (approval) decide(g.tool, 'ask', `${approval}: kapı komut onayı kaydı; elle yazılmaz, node .claude/hooks/gate.mjs --approve kullanılır.`);
132
+ if (approval) decide(g.tool, 'ask', /tercihler\.md$/i.test(approval)
133
+ ? `${approval}: kişisel tercih dosyası; elle yazılmaz, node .claude/hooks/prefs.mjs --add / --remove kullanılır.`
134
+ : `${approval}: kapı komut onayı kaydı; elle yazılmaz, node .claude/hooks/gate.mjs --approve kullanılır.`);
133
135
  if (g.tool !== 'claude') {
134
136
  for (const p of paths) {
135
137
  const k = protectedRule(relPath(p, groot));
@@ -7,6 +7,7 @@
7
7
  // The result goes to .claude/state/gate.json with the same change signature as the commit gate; the commit gate stops
8
8
  // the commit on a red or stale result. A green check's output is not written, the last 30 lines of a red one are.
9
9
  // If no check passed (commands empty, no Semgrep) the result is EMPTY: the commit gate stays closed.
10
+ // "Mutlak yol": an added line with this machine's project or home path is red; a generic C:\Users\<name>, /home/<name> is a note.
10
11
  // node .claude/hooks/gate.mjs --approve saves the commands with user approval. A new or changed command does not run unapproved:
11
12
  // an untrusted repo's AGENTS.md must not run code through the gate. The approval lives in the user folder (~/.vibe-kit/).
12
13
  import fs from 'node:fs';
@@ -95,6 +96,55 @@ function semgrep(root, files) {
95
96
  return { name, status: 'failed', sec, output: tail(`${r.error ? `${r.error.message}\n` : ''}${r.stdout ?? ''}${r.stderr ?? ''}`) };
96
97
  }
97
98
 
99
+ // A path that only exists on this machine in a changed line breaks the code, tests and docs on every other machine.
100
+ // Red: this project's folder or the home folder (at least two levels, so /app or /root alone is not matched; a path
101
+ // boundary after it; any slash style, JSON-escaped too; case-insensitive only on Windows).
102
+ // Note only: a generic C:\Users\<name>, /home/<name>/, /Users/<name>/ (a container path like /home/node/app or a route
103
+ // is not a machine path, so it never blocks).
104
+ // "kit:yol-izinli" on the line or the line above allows a deliberate one (Dockerfile and JSON take no inline comment).
105
+ // Only added lines of tracked files are read (an old path elsewhere in the file is not this change's); a new file is
106
+ // read whole. Paths are read from the git top level, so a project in a monorepo subfolder is checked too.
107
+ const ESCAPE = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
108
+ export function absPathCheck(root, files) {
109
+ const name = 'Mutlak yol';
110
+ const git = (...a) => spawnSync('git', a, { cwd: root, encoding: 'utf8', maxBuffer: BUFFER });
111
+ const top = git('rev-parse', '--show-toplevel').stdout?.trim() || root;
112
+ const variants = (p) => { const f = p.replace(/\\/g, '/').replace(/\/+$/, ''); return [f, f.replace(/\//g, '\\'), f.replace(/\//g, '\\\\')]; };
113
+ const deep = (p) => p.replace(/\\/g, '/').replace(/^[A-Za-z]:/, '').split('/').filter(Boolean).length >= 2;
114
+ const own = [...new Set([root, top, os.homedir()].filter((p) => p && deep(p)).flatMap(variants))].map(ESCAPE);
115
+ const mine = own.length ? new RegExp(`(?:${own.join('|')})(?=[\\\\/'"\`\\s,;:)\\]}]|$)`, process.platform === 'win32' ? 'i' : '') : null;
116
+ const generic = /\b[A-Za-z]:(?:\\\\|\\|\/)Users(?:\\\\|\\|\/)[^\\/\s'"<>:]+|(?<![\w.-])\/(?:Users|home)\/[^/\s'"<>:]+\//;
117
+ // Added line numbers per file from one diff against HEAD (staged and unstaged); a file not in it is new: read whole
118
+ const added = new Map();
119
+ let file = null;
120
+ for (const l of (git('diff', 'HEAD', '-U0', '--no-color', '--no-renames', '--no-ext-diff').stdout ?? '').split('\n')) {
121
+ const f = l.match(/^\+\+\+ b\/(.+)$/);
122
+ if (f) { file = f[1]; added.set(file, new Set()); continue; }
123
+ const h = file && l.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
124
+ if (h) for (let n = +h[1]; n < +h[1] + +(h[2] ?? 1); n++) added.get(file).add(n);
125
+ }
126
+ const red = [], notes = [];
127
+ for (const f of files) {
128
+ if (/^\.claude\/state\/|(^|\/)\.kit\.local\.json$/.test(f)) continue;
129
+ let lines;
130
+ try {
131
+ const b = fs.readFileSync(path.join(top, f));
132
+ if (b.length > 2e6 || b.subarray(0, 8000).includes(0)) continue;
133
+ lines = b.toString('utf8').split(/\r?\n/);
134
+ } catch { continue; }
135
+ lines.forEach((l, i) => {
136
+ if (added.has(f) && !added.get(f).has(i + 1)) return;
137
+ if (l.includes('kit:yol-izinli') || lines[i - 1]?.includes('kit:yol-izinli')) return;
138
+ const at = `${f}:${i + 1}: ${l.trim().slice(0, 120)}`;
139
+ if (mine?.test(l)) red.push(at); else if (generic.test(l)) notes.push(at);
140
+ });
141
+ }
142
+ const list = (a) => [...a.slice(0, 15), a.length > 15 ? `… ve ${a.length - 15} satır daha` : ''].filter(Boolean).join('\n');
143
+ if (red.length) return { name, status: 'failed', note: 'bu makineye özel yol; import.meta.url, __dirname, path.join(kök, …), os.tmpdir() kullan. Bilinçliyse satıra ya da üstüne kit:yol-izinli yaz',
144
+ output: list(red) };
145
+ return { name, status: 'passed', ...(notes.length && { note: `${notes.length} satırda kullanıcı klasörüne benzeyen yol var; makineye özelse düzelt (engellemez)`, output: list(notes) }) };
146
+ }
147
+
98
148
  export const approvalNeeded = (list) => `komut onayı gerekli\nAGENTS.md → Komutlar yeni veya değişmiş; bu komutlar onaysız çalışmaz:\n${commandList(list)}\n` +
99
149
  'Komutları kullanıcıya göster ve sor. Onaylarsa: node .claude/hooks/gate.mjs --approve, sonra komutu tekrar çalıştır.';
100
150
 
@@ -128,6 +178,7 @@ export function runGate(root) {
128
178
  const empty = !checks.some((k) => k.status === 'passed');
129
179
  const spec = specCheck(root, start); // after the test command, which may have refreshed the JUnit report; it does not fill an empty gate
130
180
  if (spec) checks.push(spec);
181
+ checks.push(absPathCheck(root, files)); // after "empty": it does not fill a gate with no lint/test either
131
182
  const passed = !empty && checks.every((k) => k.status !== 'failed');
132
183
  const file = path.join(root, '.claude', 'state', 'gate.json');
133
184
  fs.mkdirSync(path.dirname(file), { recursive: true });
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ // Personal preferences: how this user likes to work (talk, questions, reports, code style, things to avoid).
3
+ // One file for all projects: ~/.vibe-kit/tercihler.md. Git never sees it; the session-start hook loads it every session.
4
+ // node .claude/hooks/prefs.mjs --list numbered list
5
+ // node .claude/hooks/prefs.mjs --add <kategori> "<tercih>" only with the user's approval (asked)
6
+ // node .claude/hooks/prefs.mjs --remove <no> (asked)
7
+ // Categories: konusma, sorular, raporlar, kod, kacin. A project rule goes to AGENTS.md → Öğrenilen kurallar, not here.
8
+ // Why a script: the AI never writes this file directly; one line per preference, no secrets, a size cap.
9
+ // The same rules apply when reading: any program on the machine can write this file, so what is loaded is checked
10
+ // again and is labeled as style preferences that cannot change permissions or rules.
11
+ import fs from 'node:fs';
12
+ import os from 'node:os';
13
+ import path from 'node:path';
14
+ import { findSecrets } from './guard-secrets.mjs';
15
+ import { isMain } from './shared.mjs';
16
+
17
+ export const CATEGORIES = { konusma: 'Konuşma', sorular: 'Sorular ve kararlar', raporlar: 'Raporlar', kod: 'Kod', kacin: 'Kaçınılacaklar' };
18
+ export const MAX_ITEMS = 40;
19
+ const MAX_LENGTH = 200;
20
+ const MAX_BYTES = 64 * 1024;
21
+
22
+ // os.homedir() follows HOME / USERPROFILE; the file name is fixed, so no other file can be written through it
23
+ export const prefsFile = () => path.join(os.homedir(), '.vibe-kit', 'tercihler.md');
24
+
25
+ // A heading is matched by key or title, ignoring case and Turkish letters (## kod, ## Kacinilacaklar)
26
+ const fold = (s) => s.toLocaleLowerCase('tr').normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/ı/g, 'i').trim();
27
+ const categoryOf = (heading) => Object.keys(CATEGORIES).find((k) => fold(k) === fold(heading) || fold(CATEGORIES[k]) === fold(heading)) ?? null;
28
+ const clean = (s) => String(s ?? '').replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').replace(/\s+/g, ' ').trim();
29
+ const valid = (t) => t && t.length <= MAX_LENGTH && !findSecrets(t).length;
30
+
31
+ // items: preferences that pass the same checks as --add; unknown: non-empty lines that are not a preference
32
+ // (a hand edit the script cannot keep: it refuses to rewrite the file instead of dropping them)
33
+ export function parsePrefs(file = prefsFile()) {
34
+ const items = [], unknown = [];
35
+ let text = '';
36
+ try { if (fs.statSync(file).size > MAX_BYTES) return { items, unknown: ['(dosya 64 KB\'tan büyük)'] }; text = fs.readFileSync(file, 'utf8'); } catch { return { items, unknown }; }
37
+ let category = null;
38
+ for (const line of text.split(/\r?\n/)) {
39
+ const h = line.match(/^##\s+(.+)$/);
40
+ if (h) { category = categoryOf(h[1]); if (!category) unknown.push(line); continue; }
41
+ const m = line.match(/^[-*]\s+(.+)$/);
42
+ if (m && category) { const t = clean(m[1]); if (valid(t) && items.length < MAX_ITEMS) items.push({ category, text: t }); else unknown.push(line); continue; }
43
+ if (line.trim() && !/^#\s/.test(line) && !/^>/.test(line)) unknown.push(line);
44
+ }
45
+ return { items, unknown };
46
+ }
47
+ export const readPrefs = (file = prefsFile()) => parsePrefs(file).items;
48
+
49
+ function writePrefs(items, file) {
50
+ const lines = ['# Kişisel tercihler (TillerHand)', '',
51
+ '> Her oturumda AI\'ya yüklenir, tüm projelerinde geçerlidir. `node .claude/hooks/prefs.mjs --add` ve `--remove` ile değiştir; elle düzenlersen başlıkları ve "- " satırlarını koru.', ''];
52
+ for (const [key, title] of Object.entries(CATEGORIES)) {
53
+ const list = items.filter((p) => p.category === key);
54
+ if (list.length) lines.push(`## ${title}`, '', ...list.map((p) => `- ${p.text}`), '');
55
+ }
56
+ try {
57
+ fs.mkdirSync(path.dirname(file), { recursive: true });
58
+ fs.writeFileSync(file, lines.join('\n'));
59
+ } catch (e) {
60
+ return `Dosya yazılamadı (${e.code ?? e.message}): ${file}. Araç ev klasörüne yazamıyorsa satırı elle ekle.`;
61
+ }
62
+ return null;
63
+ }
64
+
65
+ // Returns { error } | { existing: <category> } | {}
66
+ export function addPref(category, text, file = prefsFile()) {
67
+ if (!Object.hasOwn(CATEGORIES, category ?? '')) return { error: `Kategori şunlardan biri olmalı: ${Object.keys(CATEGORIES).join(', ')}` };
68
+ const t = clean(text);
69
+ if (!t) return { error: 'Tercih metni boş.' };
70
+ if (t.length > MAX_LENGTH) return { error: `Tercih en fazla ${MAX_LENGTH} karakter olmalı; kısalt.` };
71
+ if (findSecrets(t).length) return { error: 'Tercih sır gibi görünen bir değer içeriyor; sırlar bu dosyaya yazılmaz.' };
72
+ const { items, unknown } = parsePrefs(file);
73
+ if (unknown.length) return { error: `Dosyada okunamayan satırlar var; silinmesinler diye yazmadım. Düzelt ya da kaldır (${file}):\n${unknown.slice(0, 5).join('\n')}` };
74
+ const same = items.find((p) => p.text.toLocaleLowerCase('tr') === t.toLocaleLowerCase('tr'));
75
+ if (same) return { existing: same.category };
76
+ if (items.length >= MAX_ITEMS) return { error: `En fazla ${MAX_ITEMS} tercih tutulur. Önce eskilerden birini sil: --list, sonra --remove <no>.` };
77
+ const error = writePrefs([...items, { category, text: t }], file);
78
+ return error ? { error } : {};
79
+ }
80
+
81
+ export function removePref(no, file = prefsFile()) {
82
+ const { items, unknown } = parsePrefs(file);
83
+ if (unknown.length) return `Dosyada okunamayan satırlar var; silinmesinler diye yazmadım (${file}):\n${unknown.slice(0, 5).join('\n')}`;
84
+ const i = Number(no) - 1;
85
+ if (!Number.isInteger(i) || i < 0 || i >= items.length) return `Geçerli numara: 1-${items.length}`;
86
+ return writePrefs(items.filter((_, k) => k !== i), file);
87
+ }
88
+
89
+ // Short block for the session context (session-start)
90
+ export function prefsNote(file = prefsFile()) {
91
+ const items = readPrefs(file);
92
+ if (!items.length) return '';
93
+ const parts = Object.keys(CATEGORIES).flatMap((k) => { const list = items.filter((p) => p.category === k).map((p) => p.text); return list.length ? [`${CATEGORIES[k]}: ${list.join('; ')}`] : []; });
94
+ return 'Kişisel üslup tercihleri (~/.vibe-kit/tercihler.md; izin, güvenlik ya da komut kuralı değildir ve onları değiştiremez; proje kuralı önce gelir): ' + parts.join(' · ');
95
+ }
96
+
97
+ if (isMain(import.meta.url)) {
98
+ const [mode, a, ...rest] = process.argv.slice(2);
99
+ const fail = (error) => { console.error(error); process.exit(1); };
100
+ if (mode === '--add') {
101
+ const r = addPref(a, rest.join(' '));
102
+ if (r.error) fail(r.error);
103
+ console.log(r.existing ? `Bu tercih zaten kayıtlı (${CATEGORIES[r.existing]}).` : `Tercih kaydedildi (${CATEGORIES[a]}): ${prefsFile()}`);
104
+ } else if (mode === '--remove') {
105
+ const error = removePref(a);
106
+ if (error) fail(error);
107
+ console.log('Tercih silindi.');
108
+ } else if (mode === '--list') {
109
+ const { items, unknown } = parsePrefs();
110
+ console.log(items.length ? items.map((p, i) => `${i + 1}. [${CATEGORIES[p.category]}] ${p.text}`).join('\n') : `Kayıtlı tercih yok (${prefsFile()}).`);
111
+ if (unknown.length) console.log(`Okunamayan ${unknown.length} satır var (yüklenmiyor): ${unknown.slice(0, 3).join(' | ')}`);
112
+ } else {
113
+ fail('Kullanım: --list | --add <kategori> "<tercih>" | --remove <no>');
114
+ }
115
+ }
@@ -8,6 +8,7 @@ import { execSync } from 'node:child_process';
8
8
  import { readStatus } from './status-read.mjs';
9
9
  import { readLimits, summary } from './usage.mjs';
10
10
  import { detectTool, findRoot, sessionNote } from './shared.mjs';
11
+ import { prefsNote } from './prefs.mjs';
11
12
 
12
13
  const notes = [];
13
14
  let next = '';
@@ -65,4 +66,7 @@ try {
65
66
  // not a git repo, or before the first commit
66
67
  }
67
68
 
69
+ // The user's preferences from every project (~/.vibe-kit/tercihler.md), short; a broken file must not stop the session
70
+ try { const p = prefsNote(); if (p) notes.push(p.length > 1500 ? `${p.slice(0, 1500)}…` : p); } catch { /* no preferences */ }
71
+
68
72
  if (notes.length) console.log(sessionNote(tool, '[Kit] ' + notes.join('\n[Kit] '), next && `[Kit] ${next}`));
@@ -22,7 +22,8 @@
22
22
  "Bash(node .claude/hooks/tools.mjs)",
23
23
  "Bash(node .claude/hooks/tools.mjs --required:*)",
24
24
  "Bash(node .claude/hooks/tools.mjs --measure)",
25
- "Bash(node .claude/hooks/tools.mjs --disable:*)"
25
+ "Bash(node .claude/hooks/tools.mjs --disable:*)",
26
+ "Bash(node .claude/hooks/prefs.mjs --list)"
26
27
  ],
27
28
  "ask": [
28
29
  "Bash(git push:*)",
@@ -32,6 +33,8 @@
32
33
  "Bash(node .claude/hooks/freeze-guard.mjs --plan-save:*)",
33
34
  "Bash(node .claude/hooks/freeze-guard.mjs --plan-end)",
34
35
  "Bash(node .claude/hooks/commit-gate.mjs --skip:*)",
36
+ "Bash(node .claude/hooks/prefs.mjs --add:*)",
37
+ "Bash(node .claude/hooks/prefs.mjs --remove:*)",
35
38
  "Bash(node .claude/hooks/gate.mjs --approve)",
36
39
  "Edit(./CLAUDE.md)",
37
40
  "Edit(./AGENTS.md)",
package/AGENTS.md CHANGED
@@ -26,6 +26,8 @@ Yapıldı: … · Kurul: … · Otomatik kararlar: …
26
26
  Sıradaki: … · bekleyen karar: …
27
27
  ```
28
28
 
29
+ 9. **Kullanıcıyı tanı.** Oturum başında gelen "Kişisel tercihler"e uy (proje kuralı önce gelir). Kullanıcı bir davranışını düzeltirse ya da nasıl çalışmak istediğini söylerse (konuşma, soru sıklığı, rapor biçimi, kod tarzı, kaçınılacaklar) kısaca not al; akışı bölme. Görev sonunda (`/build`) ve oturum sonunda (`/wrap-up`) notları AskUserQuestion ile çoklu seçim olarak sor ("Tercih olarak kaydedeyim mi?"). Seçilenleri `node .claude/hooks/prefs.mjs --add <konusma|sorular|raporlar|kod|kacin> "<tercih>"` ile yaz. Onaysız yazma. Sır, kişisel veri ya da proje adı yazma. Projeye özgü kural bu dosyaya değil "Öğrenilen kurallar"a gider.
30
+
29
31
  <!-- kit:other-tools -->
30
32
  ## Codex ve Antigravity'de
31
33
 
@@ -81,6 +83,7 @@ build: [ ]
81
83
  - Onay almadan (soru modundan bağımsız): veri silme/sıfırlama, `git push --force`, `git reset --hard`, toplu dosya silme, prod deploy, para harcatan işlem.
82
84
  - Testi geçirmek için testi silme veya zayıflatma (test koruması hook'u sorar). Var olmayan API veya paket uydurma.
83
85
  - Hook'ları (sır engeli, commit kapısı) atlatmaya çalışma. Kullanıcı adına karar verip sonradan bildirme.
86
+ - Koda, teste veya belgeye bu makineye özel mutlak yol yazma (`C:\Users\<ad>\…`, `/home/<ad>/…`, proje klasörünün tam yolu). Yolu proje kökünden, betiğin konumundan veya geçici klasörden türet; kapı yakalar. Bilinçli bir örnekse satıra `kit:yol-izinli` yaz.
84
87
 
85
88
  ## Git
86
89
 
package/README.en.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.28.6-2a78d6?style=flat-square"></a>
9
+ <a href="kit/CHANGELOG.md"><img alt="Version" src="https://img.shields.io/badge/version-3.30.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">
@@ -45,6 +45,7 @@
45
45
  | **Sourced facts** | Anything that changes (versions, prices, regulations) is checked against a primary source, with link and date. |
46
46
  | **Rollback** | `/rollback` returns to the last working state; history is kept, unfinished work is saved. |
47
47
  | **Narrator mode** | Optionally explains every change in plain language, as if to someone who doesn't code. |
48
+ | **Learns how you work** | Picks up how you like to work (tone, questions, reports, code style). Preferences you approve apply to all your projects and stay on your computer. |
48
49
 
49
50
  ## Step by step for beginners
50
51
 
@@ -201,7 +202,7 @@ A new file outside the map is asked about, clutter like `*.bak` and `*-old.*` is
201
202
  | Package gate | Blocks packages that don't exist (on install and on `npx`, `uvx` runs); asks about very new ones or lookalikes of popular ones |
202
203
  | Structure guard | Asks about files outside the map, blocks clutter files |
203
204
  | Test guard | Asks before a test is deleted, skipped or weakened |
204
- | Deterministic gate | No commit until lint, type check, tests and Semgrep have run |
205
+ | Deterministic gate | No commit until lint, type check, tests and Semgrep have run; catches machine-specific paths written into code |
205
206
  | Commit gate | No commit without a board review and a green gate |
206
207
  | Edit lock | With `/freeze <folder>` on, the AI writes only inside that folder |
207
208
  | Scope shield | Asks before writing to a file outside the approved plan |
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="Sürüm" src="https://img.shields.io/badge/s%C3%BCr%C3%BCm-3.28.6-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.30.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">
@@ -43,6 +43,7 @@
43
43
  | **Doğru kaynak** | Değişebilen bilgi (sürüm, fiyat, mevzuat) birincil kaynaktan, kaynak ve tarihle doğrulanır. |
44
44
  | **Geri alma** | `/rollback` son çalışan hale döner; geçmiş silinmez, yarım iş saklanır. |
45
45
  | **Anlatıcı mod** | İstersen her değişikliği yazılım bilmeyen birine anlatır gibi sade Türkçe açıklar. |
46
+ | **Seni tanır** | Nasıl çalışmak istediğini (konuşma, soru, rapor, kod tarzı) öğrenir. Onayladığın tercihler tüm projelerinde geçerli olur ve bilgisayarında kalır. |
46
47
 
47
48
  ## Hiç bilmiyorsan: adım adım
48
49
 
@@ -199,7 +200,7 @@ Harita dışı yeni dosya sorulur, `*.bak` ve `*-old.*` gibi dağınıklık dosy
199
200
  | Paket kapısı | Var olmayan paketi engeller (kurulumda ve `npx`, `uvx` ile çalıştırmada); çok yeni veya popüler bir pakete benzeyeni sorar |
200
201
  | Yapı koruyucu | Harita dışı dosyayı sorar, dağınıklık dosyalarını engeller |
201
202
  | Test koruması | Silinen, atlanan veya gevşetilen testi sorar |
202
- | Deterministik kapı | Lint, tip, test ve Semgrep çalışmadan commit açılmaz |
203
+ | Deterministik kapı | Lint, tip, test ve Semgrep çalışmadan commit açılmaz; koda yazılmış makineye özel yolu yakalar |
203
204
  | Commit kapısı | Kurul denetimi ve yeşil kapı olmadan commit atılmaz |
204
205
  | Düzenleme kilidi | `/freeze <klasör>` açıkken AI sadece o klasöre yazar |
205
206
  | Kapsam kalkanı | Onaylı planın dışındaki dosyaya yazım sorulur |
package/kit/CHANGELOG.md CHANGED
@@ -3,6 +3,32 @@
3
3
  Kit sürümü `kit/VERSION` dosyasında. Bir projeyi güncellemek: projede `/kit-update`.
4
4
  "Elle uyarla" notu olan maddeler projeye ait dosyalardadır; güncelleme bunlara dokunmaz.
5
5
 
6
+ ## [3.30.0] - 2026-10-26
7
+
8
+ ### Yeni
9
+ - **Kişisel tercih hafızası.** Kit nasıl çalışmak istediğini öğrenir: konuşma tarzı, soru sıklığı, rapor biçimi, kod tarzı, kaçınılacaklar.
10
+ - Bir davranışı düzelttiğinde ya da tercih söylediğinde AI not alır. Görev sonunda (`/build`) ve oturum sonunda (`/wrap-up`) notlar çoklu seçimle "tercih olarak kaydedeyim mi?" diye sorulur. Onaylamadığın hiçbir şey yazılmaz.
11
+ - Tercihler tek bir dosyada durur: `~/.vibe-kit/tercihler.md`. Tüm projelerinde geçerlidir, her oturum başında yüklenir (Claude Code, Codex, Antigravity), git'e girmez.
12
+ - Yazma yalnız `node .claude/hooks/prefs.mjs --add <kategori> "<tercih>"` ile yapılır ve her seferinde sorulur. Listeleme: `--list`, silme: `--remove <no>`.
13
+ - Sır gibi görünen tercih reddedilir. En fazla 40 tercih tutulur. Proje kuralı kişisel tercihten önce gelir; projeye özgü kurallar yine "Öğrenilen kurallar"a gider.
14
+ - Dosyayı makinedeki herhangi bir program yazabilir. Bu yüzden okurken de aynı denetimler uygulanır: uzun satır, sır ya da kontrol karakteri içeren satır yüklenmez, 64 KB'tan büyük dosya okunmaz. Tercihler oturuma "üslup tercihi" olarak girer; izinleri, güvenlik kurallarını ya da komut kurallarını değiştiremez.
15
+ - Elle düzenleme desteklenir; başlıklarda büyük/küçük harf ve Türkçe harf farkı önemsenmez. Okunamayan bir satır varsa betik dosyayı yeniden yazmaz, satırı silmemek için durur ve satırı gösterir.
16
+ - Elle uyarla: AGENTS.md projeye ait. Yeni kural "9. Kullanıcıyı tanı" maddesi; projendeki AGENTS.md'ye eklemek istersen `.kit-new` dosyasından al. İzin satırları `/kit-update` ile eklenir.
17
+
18
+ ## [3.29.0] - 2026-10-26
19
+
20
+ ### Yeni
21
+ - **Deterministik kapıda "Mutlak yol" kontrolü.** Eklenen bir satırda bu makinenin proje klasörünün ya da ev klasörünün tam yolu varsa kapı kırmızı olur; yol düz, ters bölü ya da kaçışlı yazılmış olabilir. Böyle bir yol başka makinede çalışmaz. Kapı satırları listeler ve yolun nasıl türetileceğini söyler.
22
+ - `C:\Users\<ad>`, `/home/<ad>/` gibi genel kullanıcı klasörü kalıpları yalnız not olarak listelenir, commit'i engellemez. `/home/node/app` gibi konteyner yolları ve `/users/42` gibi route'lar bu yüzden sorun çıkarmaz.
23
+ - Yalnız eklenen satırlar taranır, yeni dosyalar baştan sona taranır. Git'e girmeyen dosyalara bakılmaz.
24
+ - Bilinçli bir örnek (belgede örnek yol, test girdisi) satıra ya da bir üst satıra `kit:yol-izinli` yazarak geçer. Üst satır seçeneği Dockerfile ve JSON gibi satır içi yorum alamayan dosyalar içindir.
25
+ - AGENTS.md (Asla) ve üç tipin stack belgesine (Sık yapılan AI hataları) aynı kural eklendi.
26
+
27
+ ### Düzeltilen
28
+ - **Kit, projenin dışındaki yerel bir klondan kurulunca kit klasörünün bu makinedeki tam yolu `.kit.json`'a yazılıyordu.** `.kit.json` commit edildiği için projeyi başka makinede açan kişi var olmayan bir yolu görüyordu. Yol artık git dışı `.kit.local.json` dosyasında; `.kit.json` → `kit` alanı `local` yazar. Eski kayıtlar `/kit-update` sırasında kendiliğinden taşınır. Kayıttaki yol bu makinede yoksa (başka makinede yazılmışsa) taşınmaz, yalnız kaldırılır. `/start` ve `/adopt` dosya yoksa kit klasörünü sorar ya da npm paketini kullanır.
29
+ - Rehberin alt bilgisindeki sürüm numarası eskide kalmıştı. Rehberdeki ve README rozetlerindeki sürüm artık testle denetleniyor.
30
+ - Elle uyarla: `docs/architecture/stack.md` projeye ait. Yeni madde "Sık yapılan AI hataları" bölümünde; istersen kendi stack belgene ekle. `.gitignore`'a `.kit.local.json` satırı güncellemede eklenir.
31
+
6
32
  ## [3.28.6] - 2026-10-26
7
33
 
8
34
  ### Düzeltilen
package/kit/VERSION CHANGED
@@ -1 +1 @@
1
- 3.28.6
1
+ 3.30.0
package/kit/guide.html CHANGED
@@ -287,7 +287,7 @@ footer .container { display: flex; flex-wrap: wrap; gap: 16px; justify-content:
287
287
  <section class="hero">
288
288
  <div class="container">
289
289
  <div>
290
- <span class="pill"><b>v3.28.6</b> Claude Code için başlangıç kiti · MIT</span>
290
+ <span class="pill"><b>v3.30.0</b> Claude Code için başlangıç kiti · MIT</span>
291
291
  <h1>Kodu AI yazar.<br><em>Dümen sende.</em></h1>
292
292
  <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>
293
293
  <div class="install"><span id="cmd">npx tillerhand init</span><button class="copy" type="button" data-copy="cmd">Kopyala</button></div>
@@ -764,7 +764,7 @@ node vibe-kit/kit/kit.mjs init
764
764
  <tr><td>Yapı koruyucu</td><td>Harita dışı yeni dosya sorulur; <code>*.bak</code>, <code>*-old.*</code>, kopya ve <code>temp/</code> gibi dağınıklıklar engellenir</td></tr>
765
765
  <tr><td>Yapılandırma onayı</td><td><code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>.claude/</code>, <code>.codex/</code>, <code>.mcp.json</code> ve iş akışı dosyaları onayın olmadan değişmez</td></tr>
766
766
  <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>
767
- <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 RET 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. Yeni veya değişen komut önce sana gösterilip onaylatılır</td></tr>
767
+ <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 RET 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>
768
768
  <tr><td>Commit kapısı</td><td>Kurul denetimi ve aynı değişiklikler için yeşil kapı olmadan commit atılmaz; denetimi atlamak (<code>--skip</code>) her seferinde sorulur</td></tr>
769
769
  <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>
770
770
  <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>
@@ -893,6 +893,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
893
893
  <article class="tile"><h3>Doğru kaynak</h3><p class="stack">source-research · Context7 · Firecrawl (isteğe bağlı)</p><ul><li>Önce resmî doküman, mevzuat, standart</li><li>Her iddiaya kaynak, tarih, güven seviyesi (A-D)</li><li>Kütüphane dokümanı Context7'den güncel</li><li>Firecrawl API anahtarı senin ortam değişkeninde kalır</li></ul></article>
894
894
  <article class="tile"><h3>Dağıtım kurulumu</h3><p class="stack">/release first · deploy-setup.md</p><ul><li>Hosting, ortam değişkenleri, alan adı ve DNS, yedek, geri alma provası</li><li>Vercel, Supabase, Railway, EAS; adımlar kaynaklı ve tarihli</li><li>Sırrı sen panelde girersin; sohbete ve dosyaya yazılmaz</li></ul></article>
895
895
  <article class="tile"><h3>Öğrenen kurallar</h3><p class="stack">/fix-bug · /retro · hookify · AGENTS.md</p><ul><li>Aynı hata sınıfı ikinci kez gelince /fix-bug kural önerir; panoda da uyarı çıkar</li><li>Mekanik kural hookify'a, gerisi AGENTS.md'ye; sen onaylamadan yazılmaz</li><li>Her kuralda kaynak ve tarih; /maintain 90 günden eskileri sorar</li><li>Auto memory /start'ta sorulur, önerilen kapalı</li></ul></article>
896
+ <article class="tile"><h3>Kişisel tercihler</h3><p class="stack">~/.vibe-kit/tercihler.md · prefs.mjs</p><ul><li>Bir davranışı düzelttiğinde ya da nasıl çalışmak istediğini söylediğinde AI not alır</li><li>Görev ve oturum sonunda "tercih olarak kaydedeyim mi?" diye sorar; onaylamadığın yazılmaz</li><li>Tercihler tüm projelerinde geçerli, her oturumda yüklenir; git'e girmez</li><li>Listele: <code>node .claude/hooks/prefs.mjs --list</code>, sil: <code>--remove &lt;no&gt;</code></li></ul></article>
896
897
  <article class="tile"><h3>Türkiye eki</h3><p class="stack">--addons tr · docs/legal/turkiye.md</p><ul><li>KVKK yurt dışı aktarım: standart sözleşme, 5 iş günü bildirim</li><li>e-Fatura ve e-Arşiv eşikleri (GİB)</li><li>iyzico ve PayTR bildirim imzası kodu ve saldırgan testi</li><li>İ/ı ve Türkçe sıralama testleri; hukuki görüş değildir</li></ul></article>
897
898
  <article class="tile"><h3>Tarayıcıda QA ve önizleme</h3><p class="stack">/qa · preview.mjs · Playwright CLI</p><ul><li>Arayüz kriterleri gerçek tarayıcıda test olarak koşar</li><li>Rapor test sonucundan yazılır, panoda kart</li><li>/build arayüz görevinde masaüstü ve mobil ekran görüntüsü</li></ul></article>
898
899
  <article class="tile"><h3>Spec ve sapma kontrolü</h3><p class="stack">docs/product/specs/ · gate.mjs</p><ul><li>Mevcut, beklenen ve değişmemesi gereken davranış</li><li>"Değişmemesi gereken" satırların testi kapıda denetlenir</li><li>3+ dosyalık işte /plan-task, her hatada /fix-bug yazar</li></ul></article>
@@ -1053,7 +1054,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
1053
1054
  <footer>
1054
1055
  <div class="container">
1055
1056
  <a class="brand" href="#top" style="font-size:16px"><svg class="mark" style="width:22px;height:22px"><use href="#mark"/></svg>TillerHand</a>
1056
- <span>Sürüm 3.26.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>
1057
+ <span>Sürüm 3.30.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>
1057
1058
  </div>
1058
1059
  </footer>
1059
1060
 
package/kit/kit.mjs CHANGED
@@ -31,7 +31,7 @@ const ADDONS = fs.readdirSync(path.join(TEMPLATES, 'addons'));
31
31
  const TOOLS = ['claude', 'codex', 'antigravity'];
32
32
  // Root entries that are not part of the common layer (the kit itself, generated and temporary files)
33
33
  // CLAUDE.local.md is personal (in .gitignore); it must not be carried into a project installed from a local folder
34
- const COMMON_EXCLUDE = new Set(['.git', 'kit', 'node_modules', '.kit.json', 'README.md', 'dashboard.html', '.previews', 'sandbox', '.calisma', '.impeccable', 'CLAUDE.local.md', 'LICENSE', 'README.en.md', 'package.json']);
34
+ const COMMON_EXCLUDE = new Set(['.git', 'kit', 'node_modules', '.kit.json', '.kit.local.json', 'README.md', 'dashboard.html', '.previews', 'sandbox', '.calisma', '.impeccable', 'CLAUDE.local.md', 'LICENSE', 'README.en.md', 'package.json']);
35
35
  // Files that only make sense in the kit repo and are not carried into projects
36
36
  const KIT_ONLY = ['.github/workflows/kit-tests.yml', '.github/workflows/npm-publish.yml'];
37
37
  // Run from the npm package (npx tillerhand): the kit lives in the npx cache, which can be cleared, so the record names
@@ -202,6 +202,19 @@ function writeRecord(projectDir, data) {
202
202
  fs.writeFileSync(path.join(projectDir, '.kit.json'), JSON.stringify(data, null, 2) + '\n');
203
203
  }
204
204
 
205
+ // A local kit clone outside the project is a folder on this machine only: its path goes to the git-ignored
206
+ // .kit.local.json and .kit.json says "local", so a clone of the project on another machine never points at this one.
207
+ // Returns the value for .kit.json → kit; an old record with an absolute path is moved the same way on install/update.
208
+ // A path written on another OS (D:\Kit read on Linux) counts too; one that does not exist here is not copied into
209
+ // .kit.local.json: /start and /adopt then ask for the kit folder instead of using another machine's path.
210
+ export function portableKit(projectDir, kit) {
211
+ if (typeof kit !== 'string' || !(path.win32.isAbsolute(kit) || path.posix.isAbsolute(kit))) return kit;
212
+ if (!fs.existsSync(kit)) return 'local';
213
+ fs.writeFileSync(path.join(projectDir, '.kit.local.json'), JSON.stringify({ kit }, null, 2) + '\n');
214
+ appendLine(path.join(projectDir, '.gitignore'), '.kit.local.json');
215
+ return 'local';
216
+ }
217
+
205
218
  function validateTools(tools) {
206
219
  for (const a of tools) if (!TOOLS.includes(a)) throw new Error(`Geçersiz araç: ${a}. Seçenekler: ${TOOLS.join(', ')}`);
207
220
  return tools.length ? tools : ['claude'];
@@ -319,7 +332,7 @@ function init({ project, tool }) {
319
332
  installTools(projectDir, tools, files, conflicts);
320
333
  const today = new Date().toISOString().slice(0, 10);
321
334
  // type: null = kit installed, no type chosen yet (/start step 3 or /adopt)
322
- writeRecord(projectDir, { version: VERSION, source: SOURCE, kit: VIA_NPX ? `npx:tillerhand@${VERSION}` : inside ? kitRel : ROOT, type: null, addons: [], tool: tool.length ? tools : null, created: today, updated: today, files });
335
+ writeRecord(projectDir, { version: VERSION, source: SOURCE, kit: VIA_NPX ? `npx:tillerhand@${VERSION}` : inside ? kitRel : portableKit(projectDir, ROOT), type: null, addons: [], tool: tool.length ? tools : null, created: today, updated: today, files });
323
336
 
324
337
  console.log(`Kit ${VERSION} kuruldu: ${projectDir} · araç: ${tool.length ? tools.join(', ') : 'seçilmedi (Claude Code dosyaları kuruldu; /start ve /adopt sorar, Codex/Antigravity için --tool)'}`);
325
338
  console.log(`Kit klasörü: ${VIA_NPX ? `npm paketi tillerhand@${VERSION}` : inside ? `${kitRel} (.gitignore'a eklendi)` : ROOT} · git deposu: ${git}`);
@@ -347,7 +360,7 @@ function installIntoProject(projectDir, type, addons, tool) {
347
360
  for (const p of patches) applyPatch(projectDir, p);
348
361
  const tools = tool.length ? validateTools(tool) : (j.tool ?? ['claude']);
349
362
  installTools(projectDir, tools, files, conflicts);
350
- writeRecord(projectDir, { ...j, version: VERSION, type, addons, tool: tool.length ? tools : (j.tool ?? null), updated: new Date().toISOString().slice(0, 10), files });
363
+ writeRecord(projectDir, { ...j, kit: portableKit(projectDir, j.kit), version: VERSION, type, addons, tool: tool.length ? tools : (j.tool ?? null), updated: new Date().toISOString().slice(0, 10), files });
351
364
  console.log(`Kuruldu: ${type}${addons.length ? ' + ' + addons.join(', ') : ''} (kit ${VERSION}) · ${projectDir}`);
352
365
  conflictReport(conflicts);
353
366
  }
@@ -442,7 +455,11 @@ function update({ project, addons: newAddons, tool }) {
442
455
  const tools = tool.length ? validateTools(tool) : (j.tool ?? ['claude']);
443
456
  installTools(project, tools, record, report.conflicts);
444
457
 
445
- writeRecord(project, { ...j, version: VERSION, addons: allAddons, tool: tool.length ? tools : (j.tool ?? null), updated: new Date().toISOString().slice(0, 10), files: record });
458
+ const kit = portableKit(project, j.kit);
459
+ if (kit !== j.kit) console.log(fs.existsSync(path.join(project, '.kit.local.json'))
460
+ ? 'Kit klasörünün bu makinedeki yolu .kit.json\'dan .kit.local.json\'a taşındı (git dışı).'
461
+ : '.kit.json\'daki kit klasörü yolu bu makinede yok (başka makinede yazılmış); kaldırıldı. /start ve /adopt kit klasörünü sorar.');
462
+ writeRecord(project, { ...j, kit, version: VERSION, addons: allAddons, tool: tool.length ? tools : (j.tool ?? null), updated: new Date().toISOString().slice(0, 10), files: record });
446
463
 
447
464
  console.log(`Kit ${j.version} -> ${VERSION}`);
448
465
  const printList = (title, list) => list.length && console.log(`${title} (${list.length}):\n ${list.join('\n ')}`);
@@ -18,6 +18,8 @@ CLAUDE.local.md
18
18
 
19
19
  # Kit güncellemesinden gelen, birleştirilmeyi bekleyen dosyalar
20
20
  *.kit-new
21
+ # Kit klasörünün bu makinedeki yolu (yerel kit klonu)
22
+ .kit.local.json
21
23
 
22
24
  # Loglar
23
25
  *.log
@@ -122,6 +122,7 @@ uv run pytest --junitxml=test-results/junit.xml
122
122
 
123
123
  ## Sık yapılan AI hataları (bunlara dikkat)
124
124
 
125
+ - Koda, teste veya ayara bu makineye özel mutlak yol yazmak (`C:\Users\<ad>\…`, `/home/<ad>/…`, proje klasörünün tam yolu): başka makinede çalışmaz. Yolu `Path(__file__).parent`, ayardan gelen kök veya testte `tmp_path` ile türet. Deterministik kapı bunu yakalar.
125
126
  - Pydantic v1 sözdizimini (`class Config`, `.dict()`) v2 ile karıştırmak.
126
127
  - Dış API çağrısında timeout koymamak, hatayı yutmak (`except: pass`).
127
128
  - CORS'u `allow_origins=["*"]` ile kimlik bilgisiyle birlikte açmak.
@@ -128,6 +128,7 @@ maestro test .maestro/ --format junit --output test-results/junit-e2e.xml
128
128
 
129
129
  ## Sık yapılan AI hataları (bunlara dikkat)
130
130
 
131
+ - Koda, teste veya ayara bu makineye özel mutlak yol yazmak (`C:\Users\<ad>\…`, `/home/<ad>/…`, proje klasörünün tam yolu): başka makinede çalışmaz. Yolu `import.meta.url` / `__dirname`, `path.join(process.cwd(), …)` veya `os.tmpdir()` ile türet. Deterministik kapı bunu yakalar.
131
132
  - Web'e özel API veya paket kullanmak (DOM, `window`, sadece web çalışan kütüphaneler).
132
133
  - `npm install` ile SDK ile uyumsuz sürüm kurmak.
133
134
  - Token'ı AsyncStorage'a yazmak.
@@ -134,6 +134,7 @@ npx vitest run --reporter=default --reporter=junit --outputFile.junit=test-resul
134
134
 
135
135
  ## Sık yapılan AI hataları (bunlara dikkat)
136
136
 
137
+ - Koda, teste veya ayara bu makineye özel mutlak yol yazmak (`C:\Users\<ad>\…`, `/home/<ad>/…`, proje klasörünün tam yolu): başka makinede çalışmaz. Yolu `import.meta.url` / `__dirname`, `path.join(process.cwd(), …)` veya `os.tmpdir()` ile türet. Deterministik kapı bunu yakalar.
137
138
  - Client component içinde Supabase admin istemcisi veya sır kullanmak.
138
139
  - Sayfayı middleware ile koruyup server action'ı korumasız bırakmak.
139
140
  - RLS'i "çalışmıyor" diye kapatmak.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tillerhand",
3
- "version": "3.28.6",
3
+ "version": "3.30.0",
4
4
  "description": "Claude Code, Codex ve Antigravity için Türkçe vibe coding kiti: kurallar, komutlar, korumalar ve proje şablonları.",
5
5
  "license": "MIT",
6
6
  "type": "module",