tillerhand 3.27.0 → 3.27.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/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/kit/CHANGELOG.md +7 -0
- package/kit/VERSION +1 -1
- package/kit/kit.mjs +3 -1
- package/package.json +1 -1
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/kit/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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.1] - 2026-10-25
|
|
7
|
+
|
|
8
|
+
### Düzeltilen
|
|
9
|
+
- **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`).
|
|
10
|
+
- **`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.
|
|
11
|
+
- Elle uyarla: yok; `/kit-update` hook'ları yeniler.
|
|
12
|
+
|
|
6
13
|
## [3.27.0] - 2026-10-25
|
|
7
14
|
|
|
8
15
|
### Yeni
|
package/kit/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.27.
|
|
1
|
+
3.27.1
|
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