tillerhand 3.49.12 → 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.
- package/.claude/hooks/commit-gate.mjs +68 -36
- package/.claude/hooks/destructive-guard.mjs +2 -1
- package/.claude/hooks/messages.mjs +3 -0
- package/.claude/i18n/tr.json +3 -0
- package/AGENTS.md +1 -1
- package/README.md +3 -3
- package/README.tr.md +3 -3
- package/kit/CHANGELOG.md +16 -0
- package/kit/VERSION +1 -1
- package/kit/guide.html +6 -5
- package/kit/guide.tr.html +6 -5
- package/kit/tools/antigravity/.agents/hooks.json +2 -1
- package/kit/tools/codex/.codex/hooks.json +2 -1
- package/package.json +1 -1
|
@@ -3,22 +3,24 @@
|
|
|
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';
|
|
9
11
|
import path from 'node:path';
|
|
10
12
|
import crypto from 'node:crypto';
|
|
11
13
|
import { execSync } from 'node:child_process';
|
|
12
|
-
import { findRoot, isMain, reviewOff } from './shared.mjs';
|
|
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
|
-
|
|
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
|
|
@@ -174,28 +196,41 @@ export function maskOwnHook(command, dir) {
|
|
|
174
196
|
});
|
|
175
197
|
}
|
|
176
198
|
|
|
199
|
+
// Claude Code stops a tool call with exit code 2 and the reason on stderr; Codex and Antigravity get their JSON decision
|
|
200
|
+
// (shared.decisionText; Codex has no ask, so an ask is a deny there and the user runs the command themselves).
|
|
201
|
+
let tool = 'claude';
|
|
202
|
+
const decideOut = (decision, reason) => { console.log(decisionText(tool, decision, reason)); process.exit(0); };
|
|
203
|
+
function stop(reason) {
|
|
204
|
+
if (tool !== 'claude') decideOut('deny', reason.trim());
|
|
205
|
+
process.stderr.write(reason);
|
|
206
|
+
process.exit(2);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const internalError = (e) => t(root, 'guard.commit.internalError', { error: String(e?.message ?? e).slice(0, 200) });
|
|
210
|
+
|
|
177
211
|
async function hook() {
|
|
178
|
-
let
|
|
212
|
+
let raw = '', dir = root;
|
|
179
213
|
try {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const joined = raw.replace(/\\\r?\n/g, '');
|
|
185
|
-
command = [joined, unquote(joined)].some((c) => commitPattern(joined).test(c)) ? joined : raw.replace(/\\\r?\n/g, ' ');
|
|
186
|
-
if (typeof input.cwd === 'string' && input.cwd) dir = input.cwd;
|
|
214
|
+
const g = parseInput(JSON.parse(fs.readFileSync(0, 'utf8')) ?? {});
|
|
215
|
+
tool = g.tool;
|
|
216
|
+
raw = String(g.command ?? '');
|
|
217
|
+
if (g.dir) dir = g.dir;
|
|
187
218
|
} catch {
|
|
188
219
|
process.exit(0);
|
|
189
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, ' ');
|
|
190
229
|
// --skip bypasses the gate and the board: the user is asked in every spelling (the AI must not write it on its own)
|
|
191
230
|
// A commit whose message names --skip goes on to the commit checks below (a real --skip chained to a commit is stopped there).
|
|
192
231
|
const open = unquote(command);
|
|
193
232
|
const commit = commitPattern(command);
|
|
194
|
-
if (!commit.test(command) && [command, open].some((c) => /commit-gate\.mjs\b[^;&|\n]*--skip\b/i.test(c)))
|
|
195
|
-
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'ask',
|
|
196
|
-
permissionDecisionReason: t(root, 'guard.commit.skipAsk') } }));
|
|
197
|
-
process.exit(0);
|
|
198
|
-
}
|
|
233
|
+
if (!commit.test(command) && [command, open].some((c) => /commit-gate\.mjs\b[^;&|\n]*--skip\b/i.test(c))) decideOut('ask', t(root, 'guard.commit.skipAsk'));
|
|
199
234
|
// The gate command approval gives the commands in AGENTS.md permission to run: the user is asked (also covers spellings the permission list misses).
|
|
200
235
|
// Only this project's commit-gate.mjs --approve is left out (maskOwnHook); both the raw and unquoted text are tested.
|
|
201
236
|
const masked = maskOwnHook(command, dir);
|
|
@@ -203,33 +238,30 @@ async function hook() {
|
|
|
203
238
|
// The prompt reads AGENTS.md now: a chain, an env variable, a node flag or a redirect must not change it after the
|
|
204
239
|
// prompt and get another list approved. Only the exact spelling is accepted.
|
|
205
240
|
if (!/^\s*node\s+(\.\/)?\.claude[\\/]hooks[\\/]gate\.mjs\s+(['"]?)--approve\2\s*$/.test(command)) {
|
|
206
|
-
|
|
207
|
-
permissionDecisionReason: 'The gate command approval runs only with exactly this spelling, on its own (no chain, environment variable, flag or redirect): node .claude/hooks/gate.mjs --approve' } }));
|
|
208
|
-
process.exit(0);
|
|
241
|
+
decideOut('deny', 'The gate command approval runs only with exactly this spelling, on its own (no chain, environment variable, flag or redirect): node .claude/hooks/gate.mjs --approve');
|
|
209
242
|
}
|
|
210
243
|
// Loaded only here: every Bash call runs this hook, and gate.mjs pulls in the dashboard and edit-round modules
|
|
211
244
|
const { approvedCommands, commandList, readAgents, unknownCommandKeys } = await import('./gate.mjs');
|
|
212
245
|
const list = commandList(approvedCommands(root)) || t(root, 'guard.commit.noCommands');
|
|
213
246
|
const unknown = unknownCommandKeys(readAgents(root));
|
|
214
247
|
const note = unknown.length ? `\n${t(root, 'guard.commit.gateUnknownKeys', { keys: unknown.join(', ') })}` : '';
|
|
215
|
-
|
|
216
|
-
permissionDecisionReason: t(root, 'guard.commit.gateApprovalAsk', { list }) + note } }));
|
|
217
|
-
process.exit(0);
|
|
248
|
+
decideOut('ask', t(root, 'guard.commit.gateApprovalAsk', { list }) + note);
|
|
218
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'));
|
|
219
252
|
if (!commit.test(command) && !commit.test(open)) process.exit(0);
|
|
220
253
|
if (!hasBoard() || boardReviewOff()) process.exit(0);
|
|
221
254
|
const chain = chainIssue(command, commit.inline ? COMMIT : commit);
|
|
222
255
|
if (chain) {
|
|
223
|
-
|
|
256
|
+
stop(`Commit stopped: ${chain}. The gate reviews the changes as they were before the command runs; run the commit on its own ` +
|
|
224
257
|
'(or only as "git add … && git commit"). Run push and other commands separately.\n');
|
|
225
|
-
process.exit(2);
|
|
226
258
|
}
|
|
227
259
|
|
|
228
260
|
let d;
|
|
229
261
|
try {
|
|
230
262
|
d = changes();
|
|
231
|
-
} catch {
|
|
232
|
-
|
|
263
|
+
} catch (e) {
|
|
264
|
+
decideOut('ask', internalError(e)); // git failed or there is no repo: unread changes must not pass as reviewed
|
|
233
265
|
}
|
|
234
266
|
if (!d.files.length || docsOnly(d.files)) process.exit(0);
|
|
235
267
|
|
|
@@ -241,19 +273,19 @@ async function hook() {
|
|
|
241
273
|
// Deleted files are left to the guards that ask before a delete. Only code files: snapshots, images and fixtures are
|
|
242
274
|
// written by the test runner, not by Write/Edit. A partially staged test (git apply --cached, skip-worktree) commits an
|
|
243
275
|
// index blob the record does not describe, so it always stops.
|
|
276
|
+
// Only Claude Code records what test-writer wrote; on Codex and Antigravity test separation is a written rule (AGENTS.md)
|
|
244
277
|
const written = readRecord(root);
|
|
245
|
-
const foreign = d.files.filter((f) => isTestFile(f) && isCodeFile(f) && !isTestConfig(f) && d.hashes[f] !== 'deleted' && written[f] !== d.hashes[f]);
|
|
278
|
+
const foreign = tool !== 'claude' ? [] : d.files.filter((f) => isTestFile(f) && isCodeFile(f) && !isTestConfig(f) && d.hashes[f] !== 'deleted' && written[f] !== d.hashes[f]);
|
|
246
279
|
if (foreign.length && !(skipped && approval.signature === d.signature)) {
|
|
247
|
-
|
|
280
|
+
stop(`Commit stopped: test-writer did not write these test files, or they changed after it wrote them, or they were partially staged: ${foreign.join(', ')}.\n` +
|
|
248
281
|
'Only the test-writer agent writes test files with Write/Edit (AGENTS.md rule 7); a test written by patch, script, shell, git mv or Codex/Antigravity does not count.\n' +
|
|
249
282
|
'If a change is needed, have test-writer review the file and rewrite it with Write/Edit. If the user made the change themselves ' +
|
|
250
283
|
'and explicitly asks to skip the review for this commit, use --skip "user request".\n');
|
|
251
|
-
process.exit(2);
|
|
252
284
|
}
|
|
253
285
|
if (approval?.signature === d.signature && (skipped || (gate?.signature === d.signature && gate.passed === true))) process.exit(0);
|
|
254
286
|
if (approval?.signature === d.signature) {
|
|
255
287
|
const failed = gate?.signature === d.signature ? gate.checks.filter((k) => k.status === 'failed').map((k) => k.name) : null;
|
|
256
|
-
|
|
288
|
+
stop(failed && !failed.length && gate.empty
|
|
257
289
|
? 'Commit stopped: the deterministic gate is empty (no check ran). Fill in AGENTS.md → Commands and run the gate again.\n' +
|
|
258
290
|
'If the user explicitly asks for this commit, use --skip "user request".\n'
|
|
259
291
|
: failed
|
|
@@ -261,22 +293,22 @@ async function hook() {
|
|
|
261
293
|
'If the user explicitly asks for an intermediate (WIP) commit, use --skip "user request".\n'
|
|
262
294
|
: 'Commit stopped: the deterministic gate has not run for these changes (or the changes were modified after it ran). ' +
|
|
263
295
|
'Run node .claude/hooks/gate.mjs --run; if nothing is red, renew the board approval and try the commit again.\n');
|
|
264
|
-
process.exit(2);
|
|
265
296
|
}
|
|
266
297
|
|
|
267
298
|
const delta = approval && !skipped ? sinceApproval(approval, d) : [];
|
|
268
|
-
|
|
299
|
+
stop(
|
|
269
300
|
(delta.length && delta.length < d.files.length
|
|
270
301
|
? `Commit stopped: files changed since the last approval (${approval.note}) were not reviewed: ${delta.join(', ')}.\n` +
|
|
271
302
|
'The board looks only at the diff of these files; files approved earlier are not reviewed again.\n'
|
|
272
303
|
: `Commit stopped: the board has not reviewed these changes (${d.files.length} files).\n`) +
|
|
273
304
|
'0. Run the deterministic gate (lint, types, tests, Semgrep) with node .claude/hooks/gate.mjs --run; give its output to the members.\n' +
|
|
274
|
-
|
|
305
|
+
(tool === 'claude'
|
|
306
|
+
? '1. Following .claude/board/rules.md §3, run at most 2 relevant board members for the changed files with model "haiku", on the diff only.\n'
|
|
307
|
+
: '1. Following .claude/board/rules.md §3, read the definitions of at most 2 relevant board members (.claude/agents/board-*.md) and review the diff as those roles yourself (single model).\n') +
|
|
275
308
|
'2. If there is no REJECT: node .claude/hooks/commit-gate.mjs --approve "<members who took part>" and try the commit again.\n' +
|
|
276
309
|
'3. If there is a REJECT, do not commit; ask the user about the finding and the options.\n' +
|
|
277
310
|
'If the user explicitly wants to skip the review for this commit, use --skip "user request".\n'
|
|
278
311
|
);
|
|
279
|
-
process.exit(2);
|
|
280
312
|
}
|
|
281
313
|
|
|
282
314
|
if (isMain(import.meta.url)) {
|
|
@@ -284,5 +316,5 @@ if (isMain(import.meta.url)) {
|
|
|
284
316
|
if (i > -1) approve(process.argv[i + 1] || 'unspecified');
|
|
285
317
|
else if (j > -1) save(`skipped: ${process.argv[j + 1] || 'user request'}`);
|
|
286
318
|
else if (process.argv.includes('--status')) status();
|
|
287
|
-
else hook();
|
|
319
|
+
else hook().catch((e) => decideOut('ask', internalError(e))); // a crash exits 1, which does not block the commit
|
|
288
320
|
}
|
|
@@ -33,7 +33,8 @@ const DESTRUCTIVE = [
|
|
|
33
33
|
[/\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'],
|
|
34
34
|
[/\b(terraform|tofu|pulumi)\s+destroy\b/i, 'Cloud infrastructure is being destroyed'],
|
|
35
35
|
// Options may come before the service and between it and the subcommand (aws --profile x s3 --region r rm, heroku -a x apps:destroy)
|
|
36
|
-
|
|
36
|
+
// The flag is looked for once, before the gaps are tried: the rule stays fast on a long repeated input
|
|
37
|
+
[cmdRe(String.raw`\baws(\.exe)?\s(?=_L_\s--recursive\b)_G_s3\s_G_rm\b|\baws(\.exe)?\s(?=_L_\s--force\b)_G_s3\s_G_rb\b|\baws(\.exe)?\s_G_(s3api\s_G_delete-bucket|rds\s_G_delete-db-(instance|cluster)|dynamodb\s_G_delete-table|ec2\s_G_terminate-instances)\b|\bgcloud\s_G_((sql|compute)\s_G_instances\s_G_delete|projects\s_G_delete)\b|\b(gsutil|gcloud)\s(?=_L_\s(-[a-zA-Z]*r|--recursive)\b)_G_(storage\s_G_)?rm\b|\baz\s_G_(group|resource)\s_G_delete\b|\bheroku\s_G_apps:destroy\b|\b(fly|flyctl)\s_G_(apps|volumes)\s_G_destroy\b|\bgh\s_G_repo\s_G_delete\b|\bsupabase\s_G_projects\s_G_delete\b|\bnetlify(-cli)?\s_G_sites:delete\b`), 'Cloud data, an app or a repository is being deleted for good'],
|
|
37
38
|
];
|
|
38
39
|
|
|
39
40
|
// Database addresses other than localhost count as prod (or a shared environment)
|
|
@@ -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.' },
|
package/.claude/i18n/tr.json
CHANGED
|
@@ -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/AGENTS.md
CHANGED
|
@@ -37,7 +37,7 @@ The kit was written for Claude Code; these equivalents apply in these two tools:
|
|
|
37
37
|
- **Wherever AskUserQuestion appears:** in Antigravity, the `ask_question` tool. If there is no question tool with options (Codex), write the options as a numbered list, put the recommended one first and mark it "(Recommended)", then wait for the answer. The decision is still the user's.
|
|
38
38
|
- **Subagents** (board members, council, review agents in `.claude/agents/`): If you cannot run them, read the matching definition, assess as that role yourself and state "single model" in the report. The test separation (rule 7) cannot be enforced here by a hook: write the tests with the `test-writer` definition, before you think about the code, and show the red run; do not change the test file while writing the code.
|
|
39
39
|
- **Model and effort** (`docs/workflow/models.md`): Start the subagent with the role's equivalent (Codex: model and reasoning effort in the prompt; Antigravity: `inherit`, `flash` or `pro`). If you cannot, run the role yourself and suggest the model in text.
|
|
40
|
-
- **Protections** (secret block, destructive command shield, structure guard, edit lock, test protection, edit round counter, package gate and the equivalent of the Claude Code permission list) run as hooks: Codex `.codex/hooks.json`, Antigravity `.agents/hooks.json`. Writing to rule and protection files (`AGENTS.md`, `.claude/`, `.codex/`, `.agents/hooks.json`) needs approval. Do not try another route (for example a shell command) around a blocked action; tell the user why.
|
|
40
|
+
- **Protections** (secret block, destructive command shield, structure guard, edit lock, test protection, edit round counter, package gate, commit gate and the equivalent of the Claude Code permission list) run as hooks: Codex `.codex/hooks.json`, Antigravity `.agents/hooks.json`. Writing to rule and protection files (`AGENTS.md`, `.claude/`, `.codex/`, `.agents/hooks.json`) needs approval. Do not try another route (for example a shell command) around a blocked action; tell the user why. The commit gate stops a commit until `node .claude/hooks/gate.mjs --run` is green and the board review (you, as the relevant members) is approved with `commit-gate.mjs --approve`; it does not check who wrote a test file there. Known limit: the shell rules read the command text and can miss unusual spellings.
|
|
41
41
|
- Skills that belong to Claude Code plugins (named `plugin:skill`) do not exist in these tools: skip that step. There is also no limit reading and no status line: the limit stays "-" in the status block.
|
|
42
42
|
<!-- /kit:other-tools -->
|
|
43
43
|
|
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.
|
|
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 |
|
|
@@ -277,7 +277,7 @@ Every command, setting, tool and skill is in the **[guide](https://burakdogrul.g
|
|
|
277
277
|
|
|
278
278
|
## Codex and Antigravity
|
|
279
279
|
|
|
280
|
-
The kit is built for Claude Code; its rules, commands and guardrails also work in OpenAI Codex and Google Antigravity. There the board runs on a single model, and the question UI
|
|
280
|
+
The kit is built for Claude Code; its rules, commands and guardrails also work in OpenAI Codex and Google Antigravity. There the board runs on a single model, and the question UI and status bar are not available; the commit gate works there too. These tools don't report which agent is running, so test separation stays a written rule there. Install with `node <kit>/kit/kit.mjs init --tool codex` (or `antigravity`).
|
|
281
281
|
|
|
282
282
|
## Measured
|
|
283
283
|
|
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.
|
|
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 |
|
|
@@ -277,7 +277,7 @@ Tüm komutlar, ayarlar, araçlar ve skill'ler **[rehberde](https://burakdogrul.g
|
|
|
277
277
|
|
|
278
278
|
## Codex ve Antigravity
|
|
279
279
|
|
|
280
|
-
Kit Claude Code için yazıldı; kurallar, komutlar ve korumalar OpenAI Codex ve Google Antigravity'de de çalışır. Kurul tek modelle yürür; soru
|
|
280
|
+
Kit Claude Code için yazıldı; kurallar, komutlar ve korumalar OpenAI Codex ve Google Antigravity'de de çalışır. Kurul tek modelle yürür; soru arayüzü ve durum çubuğu bu araçlarda yok, commit kapısı orada da çalışır. Bu araçlar ajan kimliği bildirmediği için test ayrımı orada kural metninde kalır. Kurulum: `node <kit>/kit/kit.mjs init --tool codex` (veya `antigravity`).
|
|
281
281
|
|
|
282
282
|
## Ölçüm
|
|
283
283
|
|
package/kit/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
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
|
+
|
|
14
|
+
## [3.50.0] - 2026-10-30
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **The commit gate runs on Codex and Antigravity.** A commit stops there too until the deterministic gate (`gate.mjs --run`) is green and the board review is approved with `commit-gate.mjs --approve`; a commit chained to other commands stops as well. The stop comes as the tool's own decision. Since these tools run one model, the AI reviews the diff as the relevant board members itself. `commit-gate.mjs --skip` and the gate command approval are asked on Antigravity and left to you on Codex (it has no approval prompt). Test separation stays a written rule there: these tools do not report which agent wrote a test file.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- The cloud deletion rule of the shield no longer slows down on a long repeated command (`aws s3 rm` × 999: 24 ms).
|
|
21
|
+
|
|
6
22
|
## [3.49.12] - 2026-10-30
|
|
7
23
|
|
|
8
24
|
### Security
|
package/kit/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
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.
|
|
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>)
|
|
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 <folder></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>
|
|
@@ -1137,7 +1137,7 @@ Next: G-013 password reset · pending decision: email service</pre>
|
|
|
1137
1137
|
<section id="tools">
|
|
1138
1138
|
<p class="path">With another tool</p>
|
|
1139
1139
|
<h2>Codex and Antigravity</h2>
|
|
1140
|
-
<p class="lead">TillerHand was written for Claude Code. The rules, commands and guardrails also work in OpenAI Codex and Google Antigravity. The board runs on a single model; the question UI
|
|
1140
|
+
<p class="lead">TillerHand was written for Claude Code. The rules, commands and guardrails also work in OpenAI Codex and Google Antigravity. The board runs on a single model; the question UI and the status line are not available in these tools. The commit gate works there too.</p>
|
|
1141
1141
|
<pre class="term">npx tillerhand init --tool codex <span class="c"># or antigravity, or claude,codex</span>
|
|
1142
1142
|
<span class="c"># add a tool to an existing project</span>
|
|
1143
1143
|
/kit-update --tool claude,codex</pre>
|
|
@@ -1151,7 +1151,8 @@ Next: G-013 password reset · pending decision: email service</pre>
|
|
|
1151
1151
|
<tr><td>Questions with options</td><td>AskUserQuestion</td><td>Numbered plain text</td><td>ask_question</td></tr>
|
|
1152
1152
|
<tr><td>Board and council</td><td>Separate agents and models</td><td>One model takes the roles in turn</td><td>One model</td></tr>
|
|
1153
1153
|
<tr><td>Test separation</td><td>Enforced by a hook: only test-writer writes to a test file</td><td>A written rule (no agent identity)</td><td>A written rule (no agent identity)</td></tr>
|
|
1154
|
-
<tr><td>Status line, limit, dashboard refresh
|
|
1154
|
+
<tr><td>Status line, limit, dashboard refresh</td><td>Yes</td><td>No</td><td>No</td></tr>
|
|
1155
|
+
<tr><td>Commit gate</td><td>Yes</td><td>Yes; a stop is a block, the AI reviews as the board itself</td><td>Yes; the AI reviews as the board itself</td></tr>
|
|
1155
1156
|
</tbody>
|
|
1156
1157
|
</table></div>
|
|
1157
1158
|
<div class="note">The commands have a single source (<code>.claude/commands/</code>); the copies under <code>.agents/skills/</code> are generated by <code>init</code>, <code>install</code> and <code>update</code>. Codex runs the project's hooks only when you trust the folder and approve them with <code>/hooks</code>; do this in the first session. On first use, try writing a secret to see the guardrails work.</div>
|
|
@@ -1241,7 +1242,7 @@ Next: G-013 password reset · pending decision: email service</pre>
|
|
|
1241
1242
|
<footer>
|
|
1242
1243
|
<div class="container">
|
|
1243
1244
|
<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.
|
|
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>
|
|
1245
1246
|
</div>
|
|
1246
1247
|
</footer>
|
|
1247
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.
|
|
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 <klasör></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>
|
|
@@ -1141,7 +1141,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
|
|
|
1141
1141
|
<section id="araclar">
|
|
1142
1142
|
<p class="path">Başka araçla</p>
|
|
1143
1143
|
<h2>Codex ve Antigravity</h2>
|
|
1144
|
-
<p class="lead">TillerHand Claude Code için yazıldı. Kurallar, komutlar ve korumalar OpenAI Codex ve Google Antigravity'de de çalışır. Kurul tek modelle yürür; soru
|
|
1144
|
+
<p class="lead">TillerHand Claude Code için yazıldı. Kurallar, komutlar ve korumalar OpenAI Codex ve Google Antigravity'de de çalışır. Kurul tek modelle yürür; soru arayüzü ve durum çubuğu bu araçlarda yok. Commit kapısı orada da çalışır.</p>
|
|
1145
1145
|
<pre class="term">npx tillerhand init --tool codex <span class="c"># ya da antigravity, ya da claude,codex</span>
|
|
1146
1146
|
<span class="c"># var olan projeye araç eklemek</span>
|
|
1147
1147
|
/kit-update --tool claude,codex</pre>
|
|
@@ -1155,7 +1155,8 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
|
|
|
1155
1155
|
<tr><td>Seçenekli sorular</td><td>AskUserQuestion</td><td>Numaralı düz metin</td><td>ask_question</td></tr>
|
|
1156
1156
|
<tr><td>Kurul ve konsey</td><td>Ayrı ajanlar ve modeller</td><td>Tek model rolleri sırayla üstlenir</td><td>Tek model</td></tr>
|
|
1157
1157
|
<tr><td>Test ayrımı</td><td>Hook zorlar: test dosyasına yalnız test-writer yazar</td><td>Kural metinde (ajan kimliği yok)</td><td>Kural metinde (ajan kimliği yok)</td></tr>
|
|
1158
|
-
<tr><td>Durum çubuğu, limit, pano yenileme
|
|
1158
|
+
<tr><td>Durum çubuğu, limit, pano yenileme</td><td>Var</td><td>Yok</td><td>Yok</td></tr>
|
|
1159
|
+
<tr><td>Commit kapısı</td><td>Var</td><td>Var; durdurma engel olarak gelir, AI kurul rollerini kendisi üstlenir</td><td>Var; AI kurul rollerini kendisi üstlenir</td></tr>
|
|
1159
1160
|
</tbody>
|
|
1160
1161
|
</table></div>
|
|
1161
1162
|
<div class="note">Komutların kaynağı tektir (<code>.claude/commands/</code>); <code>.agents/skills/</code> altındaki kopyaları <code>init</code>, <code>install</code> ve <code>update</code> üretir. Codex proje hook'larını sadece klasöre güvendiğinde ve <code>/hooks</code> ile onayladığında çalıştırır; bunu ilk oturumda yap. İlk kullanımda bir sır yazma denemesiyle korumaların çalıştığını gör.</div>
|
|
@@ -1245,7 +1246,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
|
|
|
1245
1246
|
<footer>
|
|
1246
1247
|
<div class="container">
|
|
1247
1248
|
<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.
|
|
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>
|
|
1249
1250
|
</div>
|
|
1250
1251
|
</footer>
|
|
1251
1252
|
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"hooks": [
|
|
49
49
|
{ "type": "command", "command": "node .claude/hooks/guard-secrets.mjs" },
|
|
50
50
|
{ "type": "command", "command": "node .claude/hooks/destructive-guard.mjs" },
|
|
51
|
-
{ "type": "command", "command": "node .claude/hooks/package-gate.mjs", "timeout": 30 }
|
|
51
|
+
{ "type": "command", "command": "node .claude/hooks/package-gate.mjs", "timeout": 30 },
|
|
52
|
+
{ "type": "command", "command": "node .claude/hooks/commit-gate.mjs" }
|
|
52
53
|
]
|
|
53
54
|
}
|
|
54
55
|
]
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"hooks": [
|
|
25
25
|
{ "type": "command", "command": "node \"$(git rev-parse --show-toplevel)/.claude/hooks/guard-secrets.mjs\"", "commandWindows": "node .claude/hooks/guard-secrets.mjs" },
|
|
26
26
|
{ "type": "command", "command": "node \"$(git rev-parse --show-toplevel)/.claude/hooks/destructive-guard.mjs\"", "commandWindows": "node .claude/hooks/destructive-guard.mjs" },
|
|
27
|
-
{ "type": "command", "command": "node \"$(git rev-parse --show-toplevel)/.claude/hooks/package-gate.mjs\"", "commandWindows": "node .claude/hooks/package-gate.mjs", "timeout": 30 }
|
|
27
|
+
{ "type": "command", "command": "node \"$(git rev-parse --show-toplevel)/.claude/hooks/package-gate.mjs\"", "commandWindows": "node .claude/hooks/package-gate.mjs", "timeout": 30 },
|
|
28
|
+
{ "type": "command", "command": "node \"$(git rev-parse --show-toplevel)/.claude/hooks/commit-gate.mjs\"", "commandWindows": "node .claude/hooks/commit-gate.mjs" }
|
|
28
29
|
]
|
|
29
30
|
}
|
|
30
31
|
],
|