tillerhand 3.49.2 → 3.49.3
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.
- package/.claude/hooks/destructive-guard.mjs +33 -7
- package/.claude/hooks/messages.mjs +1 -0
- package/.claude/i18n/tr.json +1 -0
- package/README.md +1 -1
- package/README.tr.md +1 -1
- package/kit/CHANGELOG.md +6 -0
- package/kit/VERSION +1 -1
- package/kit/guide.html +2 -2
- package/kit/guide.tr.html +2 -2
- package/package.json +1 -1
|
@@ -261,11 +261,32 @@ export function scopeIssue(command, dir, root) {
|
|
|
261
261
|
// .env in a shell command (git show :.env, curl -d @.env, cat apps/web/.env.local); .env.example, .env.sample (any middle part) are free
|
|
262
262
|
const ENV_ACCESS = /(?<![\w.-])\.env(?![\w.-]*\.(example|sample)(?![\w.-]))(\.[\w.-]+|\*)?(?=$|[\s'";|&)<>])|(^|[\s'"/\\])secrets[/\\]/i;
|
|
263
263
|
// A glob that can match .env (.e*, .en?, .e[n]v): the shell expands it to the file
|
|
264
|
-
const ENV_NAMES = ['.env', '.env.local', '.env.production', '.env.development'];
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
const ENV_NAMES = ['.env', '.env.local', '.env.production', '.env.development', '.env.staging', '.env.test', '.env.preview'];
|
|
265
|
+
// Glob match (* ? [..] [!..]) by dynamic programming, not a regex: no throw on an unclosed [ (bash reads it as a
|
|
266
|
+
// plain [) and no backtracking blow-up on ********. Case-insensitive, like the Windows file system.
|
|
267
|
+
export function globMatch(glob, name) {
|
|
268
|
+
const tokens = [];
|
|
269
|
+
for (let i = 0; i < glob.length; i++) {
|
|
270
|
+
const c = glob[i], end = c === '[' ? glob.indexOf(']', i + 2) : -1;
|
|
271
|
+
if (c === '*') { if (tokens.at(-1) !== '*') tokens.push('*'); }
|
|
272
|
+
else if (c === '?') tokens.push((x) => true);
|
|
273
|
+
else if (end > -1) {
|
|
274
|
+
const body = glob.slice(i + 1, end).toLowerCase(), neg = /^[!^]/.test(body), set = neg ? body.slice(1) : body;
|
|
275
|
+
tokens.push((x) => set.includes(x) !== neg);
|
|
276
|
+
i = end;
|
|
277
|
+
} else tokens.push((x) => x === c.toLowerCase());
|
|
278
|
+
}
|
|
279
|
+
const s = name.toLowerCase();
|
|
280
|
+
let row = [true, ...Array(s.length).fill(false)];
|
|
281
|
+
for (const k of tokens) {
|
|
282
|
+
const next = [k === '*' && row[0], ...Array(s.length).fill(false)];
|
|
283
|
+
for (let j = 1; j <= s.length; j++) next[j] = k === '*' ? row[j] || next[j - 1] : row[j - 1] && k(s[j - 1]);
|
|
284
|
+
row = next;
|
|
285
|
+
}
|
|
286
|
+
return row[s.length];
|
|
287
|
+
}
|
|
288
|
+
const envGlob = (s) => [...s.matchAll(/(?<![\w.-])\.[^\s'";|&)<>/\\]*[*?[][^\s'";|&)<>/\\]*/g)]
|
|
289
|
+
.some(([g]) => ENV_NAMES.some((n) => globMatch(g, n)));
|
|
269
290
|
// vercel env pull writes the dev values into .env.local without showing them (a prod pull is denied above). Only the
|
|
270
291
|
// pull's own part of the chain is free; a comment (#) after it is not.
|
|
271
292
|
const envIssue = (k) => k.split(/;|&&|\|\||[|&\n]/).some((s) =>
|
|
@@ -406,8 +427,13 @@ function evaluateOne(command) {
|
|
|
406
427
|
|
|
407
428
|
if (isMain(import.meta.url)) {
|
|
408
429
|
const g = readInput();
|
|
409
|
-
// Of the lists, the stricter wins (deny > ask)
|
|
410
|
-
|
|
430
|
+
// Of the lists, the stricter wins (deny > ask). A guard that throws would let the command run: asked instead
|
|
431
|
+
let results;
|
|
432
|
+
try {
|
|
433
|
+
results = g ? [evaluate(g.command, g), g.tool !== 'claude' ? permissionEquivalent(g.command) : null, scopeIssue(g.command, g.dir, g.root)].filter(Boolean) : [];
|
|
434
|
+
} catch (e) {
|
|
435
|
+
results = [{ decision: 'ask', reason: tr('guard.destructive.internalError', { error: String(e?.message ?? e).slice(0, 200) }) }];
|
|
436
|
+
}
|
|
411
437
|
const s = results.find((x) => x.decision === 'deny') ?? results[0];
|
|
412
438
|
if (s) decide(g.tool, s.decision, s.decision === 'ask' ? tr('guard.destructive.prefix', { reason: s.reason }) : `Shield: ${s.reason}`);
|
|
413
439
|
process.exit(0);
|
|
@@ -394,6 +394,7 @@ export const MESSAGES = {
|
|
|
394
394
|
'guard.destructive.remoteDb': { en: 'The command connects to a database other than localhost (could be prod). User approval required; the AI must not use prod access credentials.' },
|
|
395
395
|
'guard.destructive.testShell': { en: 'A test file is being changed, moved or deleted with a shell command. Weakening a test to make it pass is forbidden (AGENTS.md rule 7); edit tests with a file tool. User approval required.' },
|
|
396
396
|
'guard.destructive.inlineTest': { en: 'An inline script names a test path; it may write to a test file. Only the test-writer agent writes to test files (AGENTS.md rule 7). User approval required.' },
|
|
397
|
+
'guard.destructive.internalError': { en: 'The shell guard could not check this command ({error}). User approval required.' },
|
|
397
398
|
'guard.destructive.obfuscated': { en: 'The command looks obfuscated (line ending \\, $\'..\', $(...), `...` or ${...}) and contains a guarded operation. User approval required.' },
|
|
398
399
|
'guard.destructive.indirectHook': { en: 'A kit guard script is run with an indirect spelling ($VARIABLE, $(...), `...`, ${...} or * ?); the rule text cannot see inside it. User approval required.' },
|
|
399
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.' },
|
package/.claude/i18n/tr.json
CHANGED
|
@@ -391,6 +391,7 @@
|
|
|
391
391
|
"guard.destructive.remoteDb": "Komut localhost dışındaki bir veritabanına bağlanıyor (prod olabilir). Kullanıcı onayı gerekli; AI prod erişim bilgisi kullanmamalı.",
|
|
392
392
|
"guard.destructive.testShell": "Test dosyası kabuk komutuyla değiştiriliyor, taşınıyor veya siliniyor. Testi geçirmek için testi zayıflatmak yasak (AGENTS.md kural 7); test düzenlemesini dosya aracıyla yap. Kullanıcı onayı gerekli.",
|
|
393
393
|
"guard.destructive.inlineTest": "Satır içi betik bir test yolunu anıyor; test dosyasına yazıyor olabilir. Test dosyasına yalnız test-writer ajanı yazar (AGENTS.md kural 7). Kullanıcı onayı gerekli.",
|
|
394
|
+
"guard.destructive.internalError": "Kabuk kalkanı bu komutu denetleyemedi ({error}). Kullanıcı onayı gerekli.",
|
|
394
395
|
"guard.destructive.obfuscated": "Komut gizlenmiş görünüyor (satır sonu \\, $'..', $(...), `...` veya ${...}) ve korunan bir işlem içeriyor. Kullanıcı onayı gerekli.",
|
|
395
396
|
"guard.destructive.indirectHook": "Kitin koruma betiği dolaylı yazımla çalıştırılıyor ($DEĞİŞKEN, $(...), `...`, ${...} veya * ?); kural metni bunun içini göremez. Kullanıcı onayı gerekli.",
|
|
396
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.",
|
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.
|
|
9
|
+
<a href="kit/CHANGELOG.md"><img alt="Version" src="https://img.shields.io/badge/version-3.49.3-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.
|
|
9
|
+
<a href="kit/CHANGELOG.md"><img alt="Sürüm" src="https://img.shields.io/badge/s%C3%BCr%C3%BCm-3.49.3-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,12 @@
|
|
|
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.3] - 2026-10-30
|
|
7
|
+
|
|
8
|
+
### Security
|
|
9
|
+
- **The shell guard no longer crashes on a glob with an unclosed `[`** (`…; echo .[`, `jq '.["a"]'`). The 3.49.2 `.env` glob check threw there, and a crashed hook lets the command run. Globs are now matched without regular expressions, so `.**********z` cannot stall the hook either, and any unexpected error in the shell guard asks you instead of passing.
|
|
10
|
+
- `.env` globs also cover `.env.staging`, `.env.test` and `.env.preview` (`cat .env.st*`).
|
|
11
|
+
|
|
6
12
|
## [3.49.2] - 2026-10-30
|
|
7
13
|
|
|
8
14
|
### Security
|
package/kit/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.49.
|
|
1
|
+
3.49.3
|
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.
|
|
364
|
+
<span class="pill"><b>v3.49.3</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.
|
|
1244
|
+
<span>Version 3.49.3 · <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.
|
|
364
|
+
<span class="pill"><b>v3.49.3</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.
|
|
1248
|
+
<span>Sürüm 3.49.3 · <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
|
|