@tokmizer/plugin 0.9.52 → 0.9.53

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.
@@ -0,0 +1,22 @@
1
+ {
2
+ "darwin-arm64": {
3
+ "version": "0.9.53",
4
+ "file": "tkr-exec-darwin-arm64",
5
+ "sha256": "8cb00f985b29288b27f885b7ccae95ecf641d97841573753af82c5425acd8bb0"
6
+ },
7
+ "darwin-x64": {
8
+ "version": "0.9.53",
9
+ "file": "tkr-exec-darwin-x64",
10
+ "sha256": "f9cf769a626b142a8e2a6a32f5dd79bac097e482e0e452fe776197928863427d"
11
+ },
12
+ "linux-arm64": {
13
+ "version": "0.9.53",
14
+ "file": "tkr-exec-linux-arm64",
15
+ "sha256": "04f5944b5bb29dc6b72e010e567c21932c44d0c773c8affbcbecab3b79379484"
16
+ },
17
+ "linux-x64": {
18
+ "version": "0.9.53",
19
+ "file": "tkr-exec-linux-x64",
20
+ "sha256": "2b149b65d0bcee0e1f10d978cd53005dd9caaa21bd712611af7db5acfd022451"
21
+ }
22
+ }
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokmizer/plugin",
3
- "version": "0.9.52",
3
+ "version": "0.9.53",
4
4
  "description": "Tokmizer reduces token consumption for AI coding tools (Claude Code, Codex, Cursor, Aider, Gemini CLI, Cline, Windsurf, Copilot). Cross-OS.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -9,7 +9,7 @@
9
9
  "main": "dist/index.js",
10
10
  "bin": {
11
11
  "tkr": "dist/bin/tkr.js",
12
- "tkr-exec": "dist/bin/tkr-exec.js",
12
+ "tkr-exec": "dist/bin/tkr-exec",
13
13
  "tkr-shim": "dist/bin/tkr-shim.js",
14
14
  "tkr-codex-hook": "dist/bin/tkr-codex-hook.js",
15
15
  "tkr-daemon": "dist/bin/tkr-daemon.js"
@@ -22,13 +22,16 @@
22
22
  "command-templates",
23
23
  "scripts/install-mac-linux.sh",
24
24
  "scripts/install-windows.ps1",
25
+ "scripts/install-native.mjs",
25
26
  "scripts/README-INSTALL.md",
26
27
  "README.md"
27
28
  ],
28
29
  "scripts": {
29
30
  "lint": "tsc --noEmit",
30
31
  "build": "tsc -p tsconfig.json --noEmit && node scripts/bundle.mjs",
31
- "prepublishOnly": "npm run build && ( cd ../.. && npx vitest run packages/plugin ) && node scripts/check-prod-key.mjs && node scripts/check-version.mjs && node scripts/check-dist-clean.mjs && node scripts/check-pack-clean.mjs && node dist/bin/tkr-exec.js echo dist-smoke-ok && node dist/bin/tkr.js help > /dev/null"
32
+ "build:native": "node scripts/build-native.mjs",
33
+ "postinstall": "node scripts/install-native.mjs",
34
+ "prepublishOnly": "npm run build && node scripts/check-native-artifacts.mjs && ( cd ../.. && npx vitest run packages/plugin ) && node scripts/check-prod-key.mjs && node scripts/check-version.mjs && node scripts/check-dist-clean.mjs && node scripts/check-pack-clean.mjs && node dist/bin/tkr-exec.js echo dist-smoke-ok && node dist/bin/tkr.js help > /dev/null"
32
35
  },
33
36
  "devDependencies": {
34
37
  "@types/cross-spawn": "^6.0.6",
@@ -0,0 +1,66 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { execFileSync } from "node:child_process";
3
+ import { chmodSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const packageDirectory = resolve(dirname(fileURLToPath(import.meta.url)), "..");
8
+
9
+ function configureHook(directory, native) {
10
+ const path = join(directory, "hooks", "hooks.json");
11
+ let manifest;
12
+ try { manifest = JSON.parse(readFileSync(path, "utf8")); } catch { return; }
13
+ const nodeCommand = 'node "${CLAUDE_PLUGIN_ROOT}/dist/hooks-host/pre-tool-use.js"';
14
+ const nativeCommand = '"${CLAUDE_PLUGIN_ROOT}/dist/bin/tkr-exec" --pre-tool-use';
15
+ let changed = false;
16
+ for (const group of manifest.hooks?.PreToolUse ?? []) {
17
+ for (const hook of group.hooks ?? []) {
18
+ if (hook.command !== nodeCommand && hook.command !== nativeCommand) continue;
19
+ const command = native ? nativeCommand : nodeCommand;
20
+ if (hook.command !== command) { hook.command = command; changed = true; }
21
+ }
22
+ }
23
+ if (!changed) return;
24
+ const temporary = `${path}.${randomUUID()}.tmp`;
25
+ try {
26
+ writeFileSync(temporary, JSON.stringify(manifest, null, 2) + "\n", { flag: "wx", mode: 0o644 });
27
+ renameSync(temporary, path);
28
+ } finally {
29
+ rmSync(temporary, { force: true });
30
+ }
31
+ }
32
+
33
+ export function installNative(directory = packageDirectory, platform = process.platform, arch = process.arch) {
34
+ const target = join(directory, "dist", "bin", "tkr-exec");
35
+ const temporary = `${target}.${randomUUID()}.tmp`;
36
+ const replace = (bytes) => {
37
+ writeFileSync(temporary, bytes, { flag: "wx", mode: 0o755 });
38
+ chmodSync(temporary, 0o755);
39
+ renameSync(temporary, target);
40
+ };
41
+ try {
42
+ configureHook(directory, false);
43
+ replace(readFileSync(join(directory, "dist", "bin", "tkr-exec.js")));
44
+ if (process.env.TOKMIZER_NATIVE_EXEC === "0" || !["darwin", "linux"].includes(platform) || !["arm64", "x64"].includes(arch)) return false;
45
+ const { version } = JSON.parse(readFileSync(join(directory, "package.json"), "utf8"));
46
+ const manifest = JSON.parse(readFileSync(join(directory, "dist", "native", "manifest.json"), "utf8"));
47
+ const key = `${platform}-${arch}`;
48
+ const entry = manifest[key];
49
+ if (!entry || entry.version !== version || entry.file !== `tkr-exec-${key}` || !/^[0-9a-f]{64}$/.test(entry.sha256)) return false;
50
+ const source = join(directory, "dist", "native", entry.file);
51
+ const bytes = readFileSync(source);
52
+ if (createHash("sha256").update(bytes).digest("hex") !== entry.sha256) return false;
53
+ chmodSync(source, 0o755);
54
+ const probe = execFileSync(source, ["--native-check"], { encoding: "utf8", timeout: 2000, maxBuffer: 1024, stdio: ["ignore", "pipe", "ignore"] });
55
+ if (probe.trim() !== `tokmizer-native ${version} protocol=2`) return false;
56
+ replace(bytes);
57
+ configureHook(directory, true);
58
+ return true;
59
+ } catch {
60
+ return false;
61
+ } finally {
62
+ try { rmSync(temporary, { force: true }); } catch {}
63
+ }
64
+ }
65
+
66
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) installNative();