tillerhand 3.27.0 → 3.27.2
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/budget.mjs +2 -2
- package/.claude/hooks/checkpoint.mjs +2 -2
- package/.claude/hooks/commit-gate.mjs +2 -3
- package/.claude/hooks/council.mjs +2 -2
- package/.claude/hooks/destructive-guard.mjs +2 -3
- package/.claude/hooks/edit-rounds.mjs +2 -3
- package/.claude/hooks/freeze-guard.mjs +2 -3
- package/.claude/hooks/gate.mjs +2 -3
- package/.claude/hooks/guard-secrets.mjs +2 -3
- package/.claude/hooks/package-gate.mjs +3 -3
- package/.claude/hooks/plugins-sync.mjs +2 -2
- package/.claude/hooks/preview.mjs +2 -3
- package/.claude/hooks/qa-report.mjs +2 -3
- package/.claude/hooks/shared.mjs +11 -0
- package/.claude/hooks/structure-guard.mjs +2 -3
- package/.claude/hooks/test-guard.mjs +2 -3
- package/.claude/hooks/tools.mjs +2 -2
- package/.claude/hooks/usage.mjs +2 -2
- package/README.en.md +9 -3
- package/README.md +9 -3
- package/kit/CHANGELOG.md +14 -0
- package/kit/VERSION +1 -1
- package/kit/guide.html +13 -14
- package/kit/kit.mjs +3 -1
- package/package.json +2 -2
package/.claude/hooks/budget.mjs
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
11
|
-
import { pathToFileURL } from 'node:url';
|
|
12
11
|
import { isTestFile } from './test-guard.mjs';
|
|
12
|
+
import { isMain } from './shared.mjs';
|
|
13
13
|
|
|
14
14
|
export const BUDGET = { complexity: 15, function: 80, file: 400 };
|
|
15
15
|
const LIZARD = ['pipx', 'run', 'lizard==1.24.1'];
|
|
@@ -58,7 +58,7 @@ function check() {
|
|
|
58
58
|
console.log(`Karmaşıklık bütçesi uygun: ${files.length} dosya.`);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (
|
|
61
|
+
if (isMain(import.meta.url)) {
|
|
62
62
|
if (process.argv.includes('--check')) check();
|
|
63
63
|
else { console.error('Kullanım: node .claude/hooks/budget.mjs --check [--base <commit>]'); process.exit(1); }
|
|
64
64
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Rollback does not delete history: unsaved work is stashed first, files are set to the target state and
|
|
7
7
|
// a NEW commit is made. So a rollback can be undone too. reset --hard is not used.
|
|
8
8
|
import { execFileSync } from 'node:child_process';
|
|
9
|
-
import {
|
|
9
|
+
import { isMain } from './shared.mjs';
|
|
10
10
|
|
|
11
11
|
// Tag prefix in users' repos: it stays as it is, existing tags must keep matching
|
|
12
12
|
const TAG_PREFIX = 'calisan/';
|
|
@@ -47,7 +47,7 @@ export function restore(root, target) {
|
|
|
47
47
|
return { changed: true, stashed, target: short, newCommit: git(root, 'rev-parse', '--short', 'HEAD') };
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
if (
|
|
50
|
+
if (isMain(import.meta.url)) {
|
|
51
51
|
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
52
52
|
const arg = process.argv.slice(2);
|
|
53
53
|
// ONLY the first argument sets the mode: the permission list matches by prefix ("--list:*", "--save:*"),
|
|
@@ -8,8 +8,7 @@ import fs from 'node:fs';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import crypto from 'node:crypto';
|
|
10
10
|
import { execSync } from 'node:child_process';
|
|
11
|
-
import {
|
|
12
|
-
import { findRoot } from './shared.mjs';
|
|
11
|
+
import { findRoot, isMain } from './shared.mjs';
|
|
13
12
|
import { unquote } from './destructive-guard.mjs';
|
|
14
13
|
import { approvedCommands, commandList } from './gate.mjs'; // circular import: used at run time only
|
|
15
14
|
|
|
@@ -161,7 +160,7 @@ function hook() {
|
|
|
161
160
|
process.exit(2);
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
if (
|
|
163
|
+
if (isMain(import.meta.url)) {
|
|
165
164
|
const i = process.argv.indexOf('--approve');
|
|
166
165
|
if (i > -1) approve(process.argv[i + 1] || 'belirtilmedi');
|
|
167
166
|
else hook();
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// node .claude/hooks/council.mjs docs/workflow/council/<tutanak>.md
|
|
5
5
|
// The tally is done in code: a model cannot add up the ranking wrong, the chair cannot change the count.
|
|
6
6
|
import fs from 'node:fs';
|
|
7
|
-
import { pathToFileURL } from 'node:url';
|
|
8
7
|
import { sections, findSection } from './status-read.mjs';
|
|
8
|
+
import { isMain } from './shared.mjs';
|
|
9
9
|
|
|
10
10
|
const VOTE = /^\s*[-*]?\s*([A-Z]\d+)\s*[:=]\s*(DOĞRU|YANLIŞ|ABARTILI)(?!\p{L})/gimu; // \b does not work on Turkish letters (Ş)
|
|
11
11
|
|
|
@@ -99,7 +99,7 @@ export function writeMinutes(minutes, s) {
|
|
|
99
99
|
return `${minutes.trimEnd()}\n\n${section}`;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
if (
|
|
102
|
+
if (isMain(import.meta.url)) {
|
|
103
103
|
const file = process.argv[2];
|
|
104
104
|
if (!file || !fs.existsSync(file)) { console.error('Kullanım: node .claude/hooks/council.mjs <tutanak.md>'); process.exit(1); }
|
|
105
105
|
const text = fs.readFileSync(file, 'utf8');
|
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import {
|
|
11
|
-
import { readInput, decide } from './shared.mjs';
|
|
10
|
+
import { readInput, decide, isMain } from './shared.mjs';
|
|
12
11
|
import { isTestFile, isTestConfig } from './test-guard.mjs';
|
|
13
12
|
import { readLock, readPlan, allowedInLock, inScope, realPath, relPath, protectedRule } from './freeze-guard.mjs';
|
|
14
13
|
|
|
@@ -319,7 +318,7 @@ function evaluateOne(command) {
|
|
|
319
318
|
return null;
|
|
320
319
|
}
|
|
321
320
|
|
|
322
|
-
if (
|
|
321
|
+
if (isMain(import.meta.url)) {
|
|
323
322
|
const g = readInput();
|
|
324
323
|
// Of the lists, the stricter wins (deny > ask)
|
|
325
324
|
const results = g ? [evaluate(g.command), g.tool !== 'claude' ? permissionEquivalent(g.command) : null, scopeIssue(g.command, g.dir, g.root)].filter(Boolean) : [];
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
// State: .claude/state/edit-rounds.json → { session, counts: { file: n }, pending: [note] }; reset when the session changes.
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
-
import {
|
|
10
|
-
import { readInput, findRoot } from './shared.mjs';
|
|
9
|
+
import { readInput, findRoot, isMain } from './shared.mjs';
|
|
11
10
|
|
|
12
11
|
export const ROUND = 5;
|
|
13
12
|
const CODE = /\.(m?[jt]sx?|cjs|py|go|rb|php|java|kt|swift|rs|sql|vue|svelte)$/i;
|
|
@@ -66,6 +65,6 @@ function inject() {
|
|
|
66
65
|
process.exit(0);
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
if (
|
|
68
|
+
if (isMain(import.meta.url)) {
|
|
70
69
|
process.argv.includes('--inject') ? inject() : hook();
|
|
71
70
|
}
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
// node .claude/hooks/freeze-guard.mjs --plan-end close when the task is done
|
|
17
17
|
import fs from 'node:fs';
|
|
18
18
|
import path from 'node:path';
|
|
19
|
-
import {
|
|
20
|
-
import { readInput, decide, findRoot } from './shared.mjs';
|
|
19
|
+
import { readInput, decide, findRoot, isMain } from './shared.mjs';
|
|
21
20
|
|
|
22
21
|
// Project root even when called from a subfolder: lock and plan are written where the hook reads them; paths are root-relative
|
|
23
22
|
const root = findRoot();
|
|
@@ -157,7 +156,7 @@ function hook() {
|
|
|
157
156
|
process.exit(0);
|
|
158
157
|
}
|
|
159
158
|
|
|
160
|
-
if (
|
|
159
|
+
if (isMain(import.meta.url)) {
|
|
161
160
|
const [mode, value] = process.argv.slice(2);
|
|
162
161
|
// A mistyped or removed flag must fail loudly: run as the hook it would pass silently and the AI would think the plan is saved
|
|
163
162
|
if (mode?.startsWith('--') && !MODES.includes(mode)) {
|
package/.claude/hooks/gate.mjs
CHANGED
|
@@ -14,10 +14,9 @@ import os from 'node:os';
|
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import crypto from 'node:crypto';
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
|
-
import { pathToFileURL } from 'node:url';
|
|
18
17
|
import { changes } from './commit-gate.mjs';
|
|
19
18
|
import { isCodeFile } from './edit-rounds.mjs';
|
|
20
|
-
import { findRoot } from './shared.mjs';
|
|
19
|
+
import { findRoot, isMain } from './shared.mjs';
|
|
21
20
|
import { specInvariants } from './dashboard-data.mjs';
|
|
22
21
|
|
|
23
22
|
// Keys of the AGENTS.md → Komutlar block (Turkish template text, matched as written)
|
|
@@ -139,7 +138,7 @@ export function runGate(root) {
|
|
|
139
138
|
return { passed, text: [`## Kapı · ${files.length} dosya değişti`, ...checks.map(line), result].join('\n') };
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
if (
|
|
141
|
+
if (isMain(import.meta.url)) {
|
|
143
142
|
const arg = process.argv[2];
|
|
144
143
|
if (arg === '--approve') { console.log(approve(findRoot())); process.exit(0); }
|
|
145
144
|
if (arg !== '--run') { console.error('Kullanım: node .claude/hooks/gate.mjs --run | --approve'); process.exit(1); }
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
// 2) Git pre-commit: `node .claude/hooks/guard-secrets.mjs --staged` scans the staged changes.
|
|
6
6
|
// High-confidence patterns only; no generic "password=" search, to avoid false alarms.
|
|
7
7
|
import { execSync } from 'node:child_process';
|
|
8
|
-
import {
|
|
9
|
-
import { readInput, decide } from './shared.mjs';
|
|
8
|
+
import { readInput, decide, isMain } from './shared.mjs';
|
|
10
9
|
|
|
11
10
|
export const PATTERNS = [
|
|
12
11
|
['Anthropic/OpenAI anahtarı', /\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{32,}/],
|
|
@@ -59,6 +58,6 @@ function stagedMode() {
|
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
// Run only when called directly, not when tests import this file
|
|
62
|
-
if (
|
|
61
|
+
if (isMain(import.meta.url)) {
|
|
63
62
|
process.argv.includes('--staged') ? stagedMode() : hookMode();
|
|
64
63
|
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// Package missing -> denied (deny)
|
|
5
5
|
// Very new / few downloads / very close to a popular package / unverified -> the user is asked (ask)
|
|
6
6
|
// The decision goes through Claude Code's permission UI; the AI cannot skip it.
|
|
7
|
-
|
|
8
|
-
import { readInput, decide } from './shared.mjs';
|
|
7
|
+
|
|
8
|
+
import { readInput, decide, isMain } from './shared.mjs';
|
|
9
9
|
|
|
10
10
|
export const THRESHOLD = { newDays: 30, npmWeeklyDownloads: 500 };
|
|
11
11
|
|
|
@@ -128,4 +128,4 @@ async function hook() {
|
|
|
128
128
|
process.exit(0);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
if (
|
|
131
|
+
if (isMain(import.meta.url)) hook();
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { execFileSync } from 'node:child_process';
|
|
12
|
-
import {
|
|
12
|
+
import { isMain } from './shared.mjs';
|
|
13
13
|
|
|
14
14
|
// Windows paths are case-insensitive; other systems are case-sensitive
|
|
15
15
|
const norm = (p) => (process.platform === 'win32' ? path.resolve(p).toLowerCase() : path.resolve(p));
|
|
@@ -33,7 +33,7 @@ export function disabledHere(wanted, installed, root) {
|
|
|
33
33
|
.map(([id]) => id);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
if (
|
|
36
|
+
if (isMain(import.meta.url)) {
|
|
37
37
|
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
38
38
|
// No shell: arguments go straight to claude (claude is a single-file executable, .exe on Windows)
|
|
39
39
|
const run = (...arg) => execFileSync('claude', arg, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 180000 });
|
|
@@ -9,9 +9,8 @@ import fs from 'node:fs';
|
|
|
9
9
|
import os from 'node:os';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { spawn, spawnSync } from 'node:child_process';
|
|
12
|
-
import { pathToFileURL } from 'node:url';
|
|
13
12
|
import { approvedCommands, approvalNeeded, isApproved } from './gate.mjs';
|
|
14
|
-
import { findRoot } from './shared.mjs';
|
|
13
|
+
import { findRoot, isMain } from './shared.mjs';
|
|
15
14
|
|
|
16
15
|
const CLI = 'npx -y @playwright/cli@0.1.22';
|
|
17
16
|
const SIZES = [['desktop', 1440, 900], ['mobile', 390, 844]];
|
|
@@ -120,7 +119,7 @@ export async function preview(root, task) {
|
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
if (
|
|
122
|
+
if (isMain(import.meta.url)) {
|
|
124
123
|
const { code, text } = await preview(findRoot(), process.argv[2]);
|
|
125
124
|
console.log(text);
|
|
126
125
|
process.exit(code);
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
// Exit code: 0 nothing failed, 1 a criterion failed, 2 nothing to report (no JUnit file, no PRD criterion, no test ran).
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import path from 'node:path';
|
|
10
|
-
import { pathToFileURL } from 'node:url';
|
|
11
10
|
import { prdCriteria, junitCases } from './dashboard-data.mjs';
|
|
12
|
-
import { findRoot } from './shared.mjs';
|
|
11
|
+
import { findRoot, isMain } from './shared.mjs';
|
|
13
12
|
|
|
14
13
|
// A pipe would split the table cell (the dashboard's table reader does not know \|)
|
|
15
14
|
const cell = (s) => String(s ?? '').split(/\r?\n/)[0].trim().slice(0, 160).replace(/\|/g, '/');
|
|
@@ -62,7 +61,7 @@ export function qaReport(root, junit = 'test-results-qa/junit.xml', now = new Da
|
|
|
62
61
|
return { code: count('kaldı') ? 1 : 0, text: `QA: ${summary} → ${file}${stale}` };
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
if (
|
|
64
|
+
if (isMain(import.meta.url)) {
|
|
66
65
|
const { code, text } = qaReport(findRoot(), process.argv[2]);
|
|
67
66
|
console.log(text);
|
|
68
67
|
process.exit(code);
|
package/.claude/hooks/shared.mjs
CHANGED
|
@@ -11,6 +11,17 @@ import fs from 'node:fs';
|
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
|
|
14
|
+
// Was this file started as the program (not imported)? Compared as real paths: a project opened through a symlink or a
|
|
15
|
+
// junction (macOS /tmp, linked folders, npx's node_modules/.bin) starts the script by its linked path, while
|
|
16
|
+
// import.meta.url is the target. A plain comparison would skip the guard silently there.
|
|
17
|
+
export function isMain(metaUrl) {
|
|
18
|
+
try {
|
|
19
|
+
return Boolean(process.argv[1]) && fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(metaUrl));
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
14
25
|
const AG_WRITE = ['write_to_file', 'replace_file_content', 'multi_replace_file_content'];
|
|
15
26
|
|
|
16
27
|
// Claude Code passes CLAUDE_PROJECT_DIR to hooks; Codex does not. Codex has no "ask", so a misdetection stays on the safe side.
|
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { execFileSync } from 'node:child_process';
|
|
10
|
-
import {
|
|
11
|
-
import { readInput, decide } from './shared.mjs';
|
|
10
|
+
import { readInput, decide, isMain } from './shared.mjs';
|
|
12
11
|
|
|
13
12
|
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
14
13
|
|
|
@@ -80,6 +79,6 @@ function checkAll() {
|
|
|
80
79
|
process.exit(1);
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
if (
|
|
82
|
+
if (isMain(import.meta.url)) {
|
|
84
83
|
process.argv.includes('--check') ? checkAll() : hook();
|
|
85
84
|
}
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
// It does not block: the user approves a justified change.
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
|
-
import {
|
|
12
|
-
import { readInput, decide } from './shared.mjs';
|
|
11
|
+
import { readInput, decide, isMain } from './shared.mjs';
|
|
13
12
|
|
|
14
13
|
const TEST = /(^|\/)(tests?|__tests__|e2e|spec)\/|\.(test|spec|e2e-spec)\.[cm]?[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.(py|go)$/i;
|
|
15
14
|
export const isTestFile = (file) => TEST.test(file.replace(/\\/g, '/'));
|
|
@@ -77,4 +76,4 @@ function hook() {
|
|
|
77
76
|
process.exit(0);
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
if (
|
|
79
|
+
if (isMain(import.meta.url)) hook();
|
package/.claude/hooks/tools.mjs
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
import fs from 'node:fs';
|
|
12
12
|
import os from 'node:os';
|
|
13
13
|
import path from 'node:path';
|
|
14
|
-
import { pathToFileURL } from 'node:url';
|
|
15
14
|
import { missingPlugins } from './plugins-sync.mjs';
|
|
15
|
+
import { isMain } from './shared.mjs';
|
|
16
16
|
|
|
17
17
|
// Keys are the package names users type (/tools ac tasarim): they stay Turkish
|
|
18
18
|
export const PACKAGES = {
|
|
@@ -142,7 +142,7 @@ const tokenOf = (measurement, ids) => {
|
|
|
142
142
|
return found.length ? `~${found.reduce((s, o) => s + o.skillTokens + o.agentTokens, 0)} token` : '? token (kurulu değil)';
|
|
143
143
|
};
|
|
144
144
|
const NOTE = 'Açtıktan sonra /reload-plugins. Oturum ortasında açmak prompt önbelleğini bozar; en iyisi faz sınırında, /clear ile.';
|
|
145
|
-
if (
|
|
145
|
+
if (isMain(import.meta.url)) {
|
|
146
146
|
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
147
147
|
const [flag, name] = process.argv.slice(2);
|
|
148
148
|
try {
|
package/.claude/hooks/usage.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// node .claude/hooks/usage.mjs --json machine-readable
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import path from 'node:path';
|
|
9
|
-
import {
|
|
9
|
+
import { isMain } from './shared.mjs';
|
|
10
10
|
|
|
11
11
|
export const THRESHOLDS = { five_hour: { yellow: 60, red: 85 }, seven_day: { yellow: 70, red: 90 } };
|
|
12
12
|
const WINDOWS = { five_hour: '5 saatlik', seven_day: 'haftalık' };
|
|
@@ -82,7 +82,7 @@ export function summary(data, now = Date.now()) {
|
|
|
82
82
|
return `${parts.join(' · ')} · seviye: ${LEVEL_LABEL[level(data)]} · ${data.ageMin} dk önce okundu${stale}`;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
if (
|
|
85
|
+
if (isMain(import.meta.url)) {
|
|
86
86
|
const root = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
87
87
|
const data = readLimits(root);
|
|
88
88
|
if (process.argv.includes('--json')) console.log(JSON.stringify({ ...data, level: level(data), thresholds: THRESHOLDS }));
|
package/README.en.md
CHANGED
|
@@ -56,7 +56,7 @@ You don't need to know how to code. Claude handles git, the terminal and install
|
|
|
56
56
|
|
|
57
57
|
**2. Create your project**
|
|
58
58
|
1. Make a folder for your project and select it in the **Code** tab of the Claude desktop app.
|
|
59
|
-
2. Type: `
|
|
59
|
+
2. Type: `run npx tillerhand init in this folder`.
|
|
60
60
|
3. **Start a new session** in the same folder. The kit's commands and guardrails load in the new session.
|
|
61
61
|
|
|
62
62
|
**3. Start**
|
|
@@ -87,14 +87,20 @@ Claude asks its questions one by one. **The first option is always the recommend
|
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
89
|
mkdir my-app && cd my-app
|
|
90
|
+
npx tillerhand init
|
|
91
|
+
claude
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
With git instead of npm (the kit stays in a `vibe-kit/` folder inside the project and goes into `.gitignore`):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
90
97
|
git clone https://github.com/burakdogrul/TillerHand.git vibe-kit
|
|
91
98
|
node vibe-kit/kit/kit.mjs init
|
|
92
|
-
claude
|
|
93
99
|
```
|
|
94
100
|
|
|
95
101
|
- On first launch Claude Code offers to install the kit's skill plugins; accept.
|
|
96
102
|
- Kit in another folder: `node <kit>/kit/kit.mjs init --project <project>`.
|
|
97
|
-
- For Codex or Antigravity: `
|
|
103
|
+
- For Codex or Antigravity: `npx tillerhand init --tool codex` (several: `--tool claude,codex`).
|
|
98
104
|
- Recommended: a code map ([codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)). The AI queries the code instead of reading it file by file, which saves tokens. `/start` offers to install it.
|
|
99
105
|
|
|
100
106
|
## How it works
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ Kod yazmayı bilmen gerekmez. Git, terminal ve kurulum işlerini Claude yapar; s
|
|
|
54
54
|
|
|
55
55
|
**2. Projeni oluştur**
|
|
56
56
|
1. Projen için bir klasör aç ve Claude masaüstü uygulamasında **Code** sekmesinde seç.
|
|
57
|
-
2. Şunu yaz: `
|
|
57
|
+
2. Şunu yaz: `bu klasörde npx tillerhand init komutunu çalıştır`.
|
|
58
58
|
3. Aynı klasörde **yeni oturum aç**. Kitin komutları ve korumaları yeni oturumda yüklenir.
|
|
59
59
|
|
|
60
60
|
**3. Başlat**
|
|
@@ -85,14 +85,20 @@ Claude sırayla soru sorar. **Her sorunun ilk seçeneği önerilendir**; emin de
|
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
87
|
mkdir yeni-proje && cd yeni-proje
|
|
88
|
+
npx tillerhand init
|
|
89
|
+
claude
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
npm yerine git ile (kit, proje içinde `vibe-kit/` klasöründe durur ve `.gitignore`'a girer):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
88
95
|
git clone https://github.com/burakdogrul/TillerHand.git vibe-kit
|
|
89
96
|
node vibe-kit/kit/kit.mjs init
|
|
90
|
-
claude
|
|
91
97
|
```
|
|
92
98
|
|
|
93
99
|
- Açılışta Claude Code, kitin skill eklentilerini kurmayı önerir; kabul et.
|
|
94
100
|
- Kit başka bir klasördeyse: `node <kit>/kit/kit.mjs init --project <proje>`.
|
|
95
|
-
- Codex veya Antigravity için: `
|
|
101
|
+
- Codex veya Antigravity için: `npx tillerhand init --tool codex` (birden fazlası: `--tool claude,codex`).
|
|
96
102
|
- Önerilen: kod haritası ([codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)). AI kodu dosya dosya okumak yerine sorgular, token tasarrufu sağlar. `/start` kurmayı sorar.
|
|
97
103
|
|
|
98
104
|
## Nasıl çalışır
|
package/kit/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
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.27.2] - 2026-10-25
|
|
7
|
+
|
|
8
|
+
### Belgeler
|
|
9
|
+
- **README ve rehberde npm ile kurulum:** `npx tillerhand init` önerilen yol; git klonu seçenek olarak duruyor. Codex/Antigravity için `npx tillerhand init --tool codex`.
|
|
10
|
+
- **Rehber:** Üstteki "Hemen başla" ve "Nasıl çalışır?" düğmeleri kaldırıldı. Kurulum komutları ve terminal blokları (durum bloğu, alt durum çubuğu) dar ekranda yana kaymadan alt satıra iner.
|
|
11
|
+
- Paket Node.js 18 ve üstünü kabul eder (belgedeki gereksinimle aynı).
|
|
12
|
+
|
|
13
|
+
## [3.27.1] - 2026-10-25
|
|
14
|
+
|
|
15
|
+
### Düzeltilen
|
|
16
|
+
- **Koruma hook'ları, proje sembolik bağlantı veya junction üzerinden açılınca sessizce çalışmıyordu.** Sır engeli, yıkıcı komut kalkanı, commit kapısı, yapı ve test korumaları dahil 17 betik, başlatıldıkları yolu gerçek yolla karşılaştırırken bağlantıyı çözmüyordu; macOS'ta `/tmp` gibi bağlantılı klasörlerde veya bağlantılı proje klasörlerinde hiçbir şey yapmadan çıkıyorlardı. Artık iki yol da gerçek yola çevrilip karşılaştırılıyor (`shared.mjs` → `isMain`).
|
|
17
|
+
- **`npx tillerhand init` Linux ve macOS'ta hiçbir şey yapmıyordu** (aynı neden: npx kiti `node_modules/.bin` bağlantısıyla başlatıyor). Windows'ta çalışıyordu. 3.27.0'ı Linux veya macOS'ta denediysen tekrar çalıştır.
|
|
18
|
+
- Elle uyarla: yok; `/kit-update` hook'ları yeniler.
|
|
19
|
+
|
|
6
20
|
## [3.27.0] - 2026-10-25
|
|
7
21
|
|
|
8
22
|
### Yeni
|
package/kit/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.27.
|
|
1
|
+
3.27.2
|
package/kit/guide.html
CHANGED
|
@@ -90,9 +90,9 @@ p { margin: 0 0 1em; }
|
|
|
90
90
|
.hero h1 { font-size: clamp(40px, 5.6vw, 64px); font-weight: 800; letter-spacing: -.035em; line-height: 1.04; margin-bottom: 22px; }
|
|
91
91
|
.hero h1 em { font-style: normal; color: var(--accent); }
|
|
92
92
|
.hero .sub { font-size: 19px; color: var(--fg-2); max-width: 34em; margin-bottom: 30px; }
|
|
93
|
-
.cta { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 30px; }
|
|
94
93
|
.install { display: flex; align-items: center; gap: 10px; max-width: 520px; background: var(--term-bg); color: var(--term-fg); border-radius: 12px; padding: 12px 12px 12px 18px; font: 14px var(--mono); }
|
|
95
|
-
.install
|
|
94
|
+
.install + .install { margin-top: 10px; }
|
|
95
|
+
.install span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
96
96
|
.install span::before { content: "$ "; color: var(--term-dim); }
|
|
97
97
|
.copy { flex: none; background: rgba(255,255,255,.08); color: var(--term-fg); border: 1px solid rgba(255,255,255,.14); border-radius: 8px; font: 500 12.5px var(--font); padding: 6px 10px; cursor: pointer; }
|
|
98
98
|
.copy:hover { background: rgba(255,255,255,.16); }
|
|
@@ -158,7 +158,7 @@ p { margin: 0 0 1em; }
|
|
|
158
158
|
.moments { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }
|
|
159
159
|
.moment h3 { font-size: 17px; margin: 18px 0 6px; }
|
|
160
160
|
.moment > p { color: var(--muted); font-size: 15px; margin: 0; }
|
|
161
|
-
.term { background: var(--term-bg); color: var(--term-fg); font: 13px/1.7 var(--mono); padding: 18px 20px; border-radius: 12px;
|
|
161
|
+
.term { background: var(--term-bg); color: var(--term-fg); font: 13px/1.7 var(--mono); padding: 18px 20px; border-radius: 12px; white-space: pre-wrap; overflow-wrap: anywhere; margin: 0 0 1.2em; }
|
|
162
162
|
.term .c { color: var(--term-dim); }
|
|
163
163
|
.term .r { color: #ff8a80; font-weight: 600; }
|
|
164
164
|
.term .g { color: #7ee2a8; }
|
|
@@ -287,14 +287,11 @@ 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.
|
|
290
|
+
<span class="pill"><b>v3.27.2</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
|
-
<div class="
|
|
294
|
-
|
|
295
|
-
<a class="btn ghost" href="#nasil">Nasıl çalışır?</a>
|
|
296
|
-
</div>
|
|
297
|
-
<div class="install"><span id="cmd">git clone https://github.com/burakdogrul/TillerHand.git vibe-kit</span><button class="copy" type="button" data-copy="cmd">Kopyala</button></div>
|
|
293
|
+
<div class="install"><span id="cmd">npx tillerhand init</span><button class="copy" type="button" data-copy="cmd">Kopyala</button></div>
|
|
294
|
+
<div class="install"><span id="cmd-git">git clone https://github.com/burakdogrul/TillerHand.git vibe-kit</span><button class="copy" type="button" data-copy="cmd-git">Kopyala</button></div>
|
|
298
295
|
<p class="hero-note">Claude Code için yazıldı · Codex ve Antigravity'de de çalışır · Kod bilmen gerekmez</p>
|
|
299
296
|
</div>
|
|
300
297
|
<div class="window" aria-label="Örnek: AI'nın sana sorduğu bir karar sorusu">
|
|
@@ -527,11 +524,13 @@ Bekleyen karar: e-posta servisi</pre>
|
|
|
527
524
|
<h2>Kurulum</h2>
|
|
528
525
|
<p class="lead">TillerHand ve projen ayrı klasörlerde durur. <code>init</code> gereken dosyaları (<code>.claude/</code>, <code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>docs/</code>) proje klasörüne kopyalar, git deposu açar ve kit klasörüne dokunmaz. Proje tipi kurulumda değil, <code>/start</code> sırasında soruyla seçilir.</p>
|
|
529
526
|
<p><b>Gereksinimler:</b> <a href="https://claude.com/claude-code">Claude Code</a>, Git, Node.js 18+.</p>
|
|
530
|
-
<pre class="term"><span class="c"># 1. Proje
|
|
527
|
+
<pre class="term"><span class="c"># 1. Proje klasöründe kiti kur (npm ile, önerilen)</span>
|
|
531
528
|
mkdir yeni-proje && cd yeni-proje
|
|
532
|
-
|
|
533
|
-
node vibe-kit/kit/kit.mjs init <span class="c"># vibe-kit/ .gitignore'a girer</span>
|
|
529
|
+
npx tillerhand init
|
|
534
530
|
claude
|
|
531
|
+
<span class="c"># ya da git ile: kit proje içinde vibe-kit/ klasöründe durur (.gitignore'a girer)</span>
|
|
532
|
+
git clone https://github.com/burakdogrul/TillerHand.git vibe-kit
|
|
533
|
+
node vibe-kit/kit/kit.mjs init
|
|
535
534
|
<span class="c"># 2. Claude Code içinde (yeni oturum)</span>
|
|
536
535
|
/start Serbest çalışanlar için fatura ve tahsilat takip uygulaması
|
|
537
536
|
<span class="c"># var olan projede /start yerine:</span>
|
|
@@ -549,7 +548,7 @@ claude
|
|
|
549
548
|
<ol>
|
|
550
549
|
<li><b>Hesaplar (bir kez):</b> <a href="https://github.com">GitHub</a> hesabı (ücretsiz) ve Claude <b>Pro</b> veya <b>Max</b> aboneliği.</li>
|
|
551
550
|
<li><b>Programlar (bir kez):</b> <a href="https://claude.com/download">Claude masaüstü uygulaması</a>, <a href="https://nodejs.org">Node.js</a> (LTS sürümü), <a href="https://git-scm.com/downloads">Git</a>. İstersen <a href="https://desktop.github.com">GitHub Desktop</a> da kurabilirsin.</li>
|
|
552
|
-
<li><b>Proje:</b> Projen için bir klasör aç ve Claude masaüstü uygulamasında <b>Code</b> sekmesinde seç. Claude'a yaz: "
|
|
551
|
+
<li><b>Proje:</b> Projen için bir klasör aç ve Claude masaüstü uygulamasında <b>Code</b> sekmesinde seç. Claude'a yaz: "bu klasörde <code>npx tillerhand init</code> komutunu çalıştır".</li>
|
|
553
552
|
<li><b>Aç:</b> Aynı klasörde <b>yeni oturum</b> aç; kitin komutları ve korumaları yeni oturumda yüklenir. Eklentileri kurmayı önerirse kabul et.</li>
|
|
554
553
|
<li><b>Başlat:</b> <code>/start fikrin</code> yaz. <b>Her sorunun ilk seçeneği önerilendir</b>; emin değilsen onu seç. Pro'daysan ilk sorular için öneri: profil <b>Hafif</b>, planlama derinliği <b>Hızlı</b> (5 saatlik limitin ~%25-35'i), pano <b>Evet</b>, anlatıcı mod <b>Evet</b>.</li>
|
|
555
554
|
</ol>
|
|
@@ -953,7 +952,7 @@ Sıradaki: G-013 şifre sıfırlama · bekleyen karar: e-posta servisi</pre>
|
|
|
953
952
|
<p class="path">Başka araçla</p>
|
|
954
953
|
<h2>Codex ve Antigravity</h2>
|
|
955
954
|
<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.</p>
|
|
956
|
-
<pre class="term">
|
|
955
|
+
<pre class="term">npx tillerhand init --tool codex <span class="c"># ya da antigravity, ya da claude,codex</span>
|
|
957
956
|
<span class="c"># var olan projeye araç eklemek</span>
|
|
958
957
|
/kit-update --tool claude,codex</pre>
|
|
959
958
|
<div class="table-wrap"><table>
|
package/kit/kit.mjs
CHANGED
|
@@ -474,7 +474,9 @@ async function askTools() {
|
|
|
474
474
|
return c.split(',').map((s) => TOOLS[Number(s.trim()) - 1] ?? s.trim().toLowerCase()).filter(Boolean);
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
|
|
477
|
+
// Real paths: npx starts the CLI through a link (node_modules/.bin/tillerhand), while import.meta.url is the target
|
|
478
|
+
const realArg = () => { try { return fs.realpathSync(process.argv[1]); } catch { return ''; } };
|
|
479
|
+
if (process.argv[1] && realArg() === fs.realpathSync(fileURLToPath(import.meta.url))) {
|
|
478
480
|
const [command, ...rest] = process.argv.slice(2);
|
|
479
481
|
try {
|
|
480
482
|
const a = parseArgs(rest);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tillerhand",
|
|
3
|
-
"version": "3.27.
|
|
3
|
+
"version": "3.27.2",
|
|
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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"CLAUDE.md"
|
|
23
23
|
],
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=18"
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|