tokencanary 0.1.3 → 0.1.4
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/dist/{chunk-4SHFFLSU.js → chunk-66ONBXHK.js} +2 -2
- package/dist/{chunk-GZLLOKQD.js → chunk-DCCFWI4O.js} +2 -2
- package/dist/{chunk-GZLLOKQD.js.map → chunk-DCCFWI4O.js.map} +1 -1
- package/dist/{chunk-DDYZRAAR.js → chunk-IUASFEXE.js} +2 -2
- package/dist/cli.js +10 -10
- package/dist/daemon.js +1 -1
- package/dist/{install-7Z4UZCDW.js → install-NA7R44O4.js} +29 -20
- package/dist/install-NA7R44O4.js.map +1 -0
- package/dist/{license-7FP2FILW.js → license-VKOP67LZ.js} +2 -2
- package/dist/{logs-XMA4R4ST.js → logs-U4OOGTGV.js} +2 -2
- package/dist/{stats-R5F7RE43.js → stats-7NLMKM67.js} +2 -2
- package/dist/{status-5RPOTLUD.js → status-2EAJQ5TH.js} +2 -2
- package/dist/stop-QJSJTHHO.js +8 -0
- package/dist/{uninstall-ZW74DUPS.js → uninstall-WUG7BEBH.js} +3 -3
- package/dist/{upgrade-DKFPZWUX.js → upgrade-IR4MHUD2.js} +2 -2
- package/package.json +4 -1
- package/dist/install-7Z4UZCDW.js.map +0 -1
- package/dist/stop-GEAGXYPB.js +0 -8
- /package/dist/{chunk-4SHFFLSU.js.map → chunk-66ONBXHK.js.map} +0 -0
- /package/dist/{chunk-DDYZRAAR.js.map → chunk-IUASFEXE.js.map} +0 -0
- /package/dist/{license-7FP2FILW.js.map → license-VKOP67LZ.js.map} +0 -0
- /package/dist/{logs-XMA4R4ST.js.map → logs-U4OOGTGV.js.map} +0 -0
- /package/dist/{stats-R5F7RE43.js.map → stats-7NLMKM67.js.map} +0 -0
- /package/dist/{status-5RPOTLUD.js.map → status-2EAJQ5TH.js.map} +0 -0
- /package/dist/{stop-GEAGXYPB.js.map → stop-QJSJTHHO.js.map} +0 -0
- /package/dist/{uninstall-ZW74DUPS.js.map → uninstall-WUG7BEBH.js.map} +0 -0
- /package/dist/{upgrade-DKFPZWUX.js.map → upgrade-IR4MHUD2.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getConfigDir
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DCCFWI4O.js";
|
|
4
4
|
|
|
5
5
|
// src/checks/claude.ts
|
|
6
6
|
import { execSync } from "child_process";
|
|
@@ -87,4 +87,4 @@ export {
|
|
|
87
87
|
runDoctor,
|
|
88
88
|
runAllChecks
|
|
89
89
|
};
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
90
|
+
//# sourceMappingURL=chunk-66ONBXHK.js.map
|
|
@@ -23,7 +23,7 @@ function getStatsPath() {
|
|
|
23
23
|
function getConfigPath() {
|
|
24
24
|
return `${getConfigDir()}/${CONFIG_FILENAME}`;
|
|
25
25
|
}
|
|
26
|
-
var DEFAULT_API_URL = "https://
|
|
26
|
+
var DEFAULT_API_URL = "https://www.tokencanary.com";
|
|
27
27
|
function getApiBaseUrl() {
|
|
28
28
|
return process.env.TOKENCANARY_API_URL ?? DEFAULT_API_URL;
|
|
29
29
|
}
|
|
@@ -227,4 +227,4 @@ export {
|
|
|
227
227
|
readConfigSync,
|
|
228
228
|
getPricePer1kTokens
|
|
229
229
|
};
|
|
230
|
-
//# sourceMappingURL=chunk-
|
|
230
|
+
//# sourceMappingURL=chunk-DCCFWI4O.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../shared/src/constants.ts","../../shared/src/fingerprint.ts","../../shared/src/license.ts","../../shared/src/license-store.ts","../../shared/src/license-api.ts","../../shared/src/session-stats.ts","../../shared/src/config.ts"],"sourcesContent":["/** App name for config/log paths */\nexport const APP_NAME = \"tokencanary\";\n\n/** Default log directory under user home */\nexport function getLogDir(): string {\n const home =\n process.env.HOME ?? process.env.USERPROFILE ?? process.env.TMP ?? \"/tmp\";\n return `${home}/.${APP_NAME}/logs`;\n}\n\n/** Default config directory under user home */\nexport function getConfigDir(): string {\n const home =\n process.env.HOME ?? process.env.USERPROFILE ?? process.env.TMP ?? \"/tmp\";\n return `${home}/.${APP_NAME}`;\n}\n\n/** Trial duration in days */\nexport const TRIAL_DAYS = 30;\n\n/** Offline grace period in days */\nexport const OFFLINE_GRACE_DAYS = 3;\n\n/** Default daemon port for hook HTTP server */\nexport const DEFAULT_DAEMON_PORT = 3847;\n\n/** License file name under config dir */\nexport const LICENSE_FILENAME = \"license.json\";\n\n/** Stats file name under config dir (session stats since daemon start) */\nexport const STATS_FILENAME = \"stats.json\";\n\n/** User config file under config dir (quiet, pricePer1kTokens, etc.) */\nexport const CONFIG_FILENAME = \"config.json\";\n\nexport function getLicensePath(): string {\n return `${getConfigDir()}/${LICENSE_FILENAME}`;\n}\n\nexport function getStatsPath(): string {\n return `${getConfigDir()}/${STATS_FILENAME}`;\n}\n\nexport function getConfigPath(): string {\n return `${getConfigDir()}/${CONFIG_FILENAME}`;\n}\n\n/** Default API/app base URL (override with TOKENCANARY_API_URL). */\nexport const DEFAULT_API_URL = \"https://app.tokencanary.com\";\n\nexport function getApiBaseUrl(): string {\n return process.env.TOKENCANARY_API_URL ?? DEFAULT_API_URL;\n}\n\n/** Upgrade page URL; pass installId to prefill for checkout. */\nexport const DEFAULT_UPGRADE_URL = `${DEFAULT_API_URL}/upgrade`;\n\nexport function getUpgradeUrl(installId?: string): string {\n const base = process.env.TOKENCANARY_UPGRADE_URL ?? DEFAULT_UPGRADE_URL;\n if (!installId) return base;\n const u = new URL(base);\n u.searchParams.set(\"install_id\", installId);\n return u.toString();\n}\n\n/** Hook request timeout in ms (fail open) */\nexport const HOOK_TIMEOUT_MS = 5000;\n","import { createHash } from \"node:crypto\";\nimport { hostname, platform, arch, cpus, networkInterfaces } from \"node:os\";\n\n/**\n * Deterministic machine fingerprint for license binding.\n * Uses hostname, OS, CPU model, and hashed network info (no raw MAC).\n */\nexport function getMachineId(): string {\n const parts: string[] = [];\n try {\n parts.push(hostname());\n } catch {\n parts.push(\"unknown-host\");\n }\n parts.push(platform());\n parts.push(arch());\n try {\n const cpu = cpus()[0];\n parts.push(cpu?.model ?? \"unknown-cpu\");\n } catch {\n parts.push(\"unknown-cpu\");\n }\n try {\n const nets = networkInterfaces();\n const addrs: string[] = [];\n for (const name of Object.keys(nets)) {\n const list = nets[name];\n if (list) {\n for (const iface of list) {\n if (iface.address && !iface.internal) addrs.push(name + \":\" + iface.address);\n }\n }\n }\n addrs.sort();\n if (addrs.length > 0) {\n parts.push(createHash(\"sha256\").update(addrs.join(\",\")).digest(\"hex\").slice(0, 16));\n }\n } catch {\n // skip network\n }\n return createHash(\"sha256\").update(parts.join(\"|\")).digest(\"hex\");\n}\n","import type { LicenseInfo, Plan } from \"./types.js\";\nimport { TRIAL_DAYS, OFFLINE_GRACE_DAYS } from \"./constants.js\";\n\nconst MS_PER_DAY = 86400 * 1000;\n\nexport function createTrialLicense(installId: string, machineId: string): LicenseInfo {\n const now = new Date();\n const expiry = new Date(now.getTime() + TRIAL_DAYS * MS_PER_DAY);\n return {\n installId,\n machineId,\n plan: \"trial\",\n expiry: expiry.toISOString(),\n createdAt: now.toISOString(),\n };\n}\n\n/**\n * Check if license is valid at the given date.\n * - Trial/monthly/yearly: valid if expiry > now.\n * - Offline grace: if lastKnownValid and within OFFLINE_GRACE_DAYS, still valid.\n */\nexport function isLicenseValid(\n license: LicenseInfo | null,\n now: Date = new Date(),\n options?: { lastKnownValid?: Date }\n): boolean {\n if (!license) return false;\n const expiry = new Date(license.expiry);\n if (expiry > now) return true;\n if (options?.lastKnownValid) {\n const graceEnd = new Date(\n options.lastKnownValid.getTime() + OFFLINE_GRACE_DAYS * MS_PER_DAY\n );\n if (now < graceEnd) return true;\n }\n return false;\n}\n\nexport function getPlanDisplay(plan: Plan): string {\n switch (plan) {\n case \"trial\":\n return \"Trial\";\n case \"monthly\":\n return \"Monthly\";\n case \"yearly\":\n return \"Yearly\";\n default:\n return String(plan);\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { getLicensePath } from \"./constants.js\";\nimport type { LicenseInfo } from \"./types.js\";\n\nexport function readLicenseSync(): LicenseInfo | null {\n const path = getLicensePath();\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as LicenseInfo;\n if (\n typeof data.installId === \"string\" &&\n typeof data.machineId === \"string\" &&\n typeof data.plan === \"string\" &&\n typeof data.expiry === \"string\" &&\n typeof data.createdAt === \"string\"\n ) {\n return data;\n }\n } catch {\n // invalid or missing\n }\n return null;\n}\n\nexport function writeLicenseSync(license: LicenseInfo): void {\n const path = getLicensePath();\n writeFileSync(path, JSON.stringify(license, null, 2), \"utf8\");\n}\n","import type { LicenseInfo } from \"./types.js\";\n\n/** Response shape from POST /api/install and POST /api/license/check */\nexport interface LicenseApiResponse {\n install_id: string;\n machine_id: string;\n plan: \"trial\" | \"monthly\" | \"yearly\";\n expiry: string;\n created_at: string;\n}\n\nexport function apiResponseToLicenseInfo(r: LicenseApiResponse): LicenseInfo {\n return {\n installId: r.install_id,\n machineId: r.machine_id,\n plan: r.plan,\n expiry: r.expiry,\n createdAt: r.created_at,\n };\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { getStatsPath, getConfigDir } from \"./constants.js\";\nimport type { SessionStats } from \"./types.js\";\n\nfunction defaultStats(): SessionStats {\n return {\n requests_optimized: 0,\n input_chars: 0,\n output_chars: 0,\n updated_at: new Date().toISOString(),\n };\n}\n\nexport function readSessionStatsSync(): SessionStats | null {\n const path = getStatsPath();\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as SessionStats;\n if (\n typeof data.requests_optimized === \"number\" &&\n typeof data.input_chars === \"number\" &&\n typeof data.output_chars === \"number\" &&\n typeof data.updated_at === \"string\"\n ) {\n return data;\n }\n } catch {\n // invalid or missing\n }\n return null;\n}\n\nexport function writeSessionStatsSync(stats: SessionStats): void {\n const dir = getConfigDir();\n mkdirSync(dir, { recursive: true });\n const path = getStatsPath();\n writeFileSync(path, JSON.stringify(stats, null, 2), \"utf8\");\n}\n\n/** Reset stats to zeros (call on daemon start). */\nexport function resetSessionStatsSync(): void {\n writeSessionStatsSync(defaultStats());\n}\n\n/** Add one request's chars to current stats and persist. */\nexport function updateSessionStatsSync(inputChars: number, outputChars: number): void {\n const current = readSessionStatsSync() ?? defaultStats();\n const next: SessionStats = {\n requests_optimized: current.requests_optimized + 1,\n input_chars: current.input_chars + inputChars,\n output_chars: current.output_chars + outputChars,\n updated_at: new Date().toISOString(),\n };\n writeSessionStatsSync(next);\n}\n","import { readFileSync, existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { getConfigPath, getConfigDir } from \"./constants.js\";\n\n/** User-configurable options (same file used by CLI and daemon). */\nexport interface UserConfig {\n /** When true, do not show in-Claude systemMessage (savings). */\n quiet?: boolean;\n /** Price per 1k tokens (for $ estimate in stats/systemMessage). Default ~$3/1M = 0.003. */\n pricePer1kTokens?: number;\n}\n\nconst DEFAULT_PRICE_PER_1K = 0.003;\n\nexport function readConfigSync(): UserConfig {\n const path = getConfigPath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as Record<string, unknown>;\n const config: UserConfig = {};\n if (typeof data.quiet === \"boolean\") config.quiet = data.quiet;\n if (typeof data.pricePer1kTokens === \"number\")\n config.pricePer1kTokens = data.pricePer1kTokens;\n return config;\n } catch {\n return {};\n }\n}\n\nexport function writeConfigSync(config: UserConfig): void {\n const dir = getConfigDir();\n mkdirSync(dir, { recursive: true });\n const path = getConfigPath();\n const existing = readConfigSync();\n const merged = { ...existing, ...config };\n writeFileSync(path, JSON.stringify(merged, null, 2), \"utf8\");\n}\n\n/** Price per 1k tokens for $ estimate (from config or default). */\nexport function getPricePer1kTokens(): number {\n const config = readConfigSync();\n return config.pricePer1kTokens ?? DEFAULT_PRICE_PER_1K;\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","readFileSync","existsSync","mkdirSync","writeFileSync","existsSync","readFileSync"]}
|
|
1
|
+
{"version":3,"sources":["../../shared/src/constants.ts","../../shared/src/fingerprint.ts","../../shared/src/license.ts","../../shared/src/license-store.ts","../../shared/src/license-api.ts","../../shared/src/session-stats.ts","../../shared/src/config.ts"],"sourcesContent":["/** App name for config/log paths */\nexport const APP_NAME = \"tokencanary\";\n\n/** Default log directory under user home */\nexport function getLogDir(): string {\n const home =\n process.env.HOME ?? process.env.USERPROFILE ?? process.env.TMP ?? \"/tmp\";\n return `${home}/.${APP_NAME}/logs`;\n}\n\n/** Default config directory under user home */\nexport function getConfigDir(): string {\n const home =\n process.env.HOME ?? process.env.USERPROFILE ?? process.env.TMP ?? \"/tmp\";\n return `${home}/.${APP_NAME}`;\n}\n\n/** Trial duration in days */\nexport const TRIAL_DAYS = 30;\n\n/** Offline grace period in days */\nexport const OFFLINE_GRACE_DAYS = 3;\n\n/** Default daemon port for hook HTTP server */\nexport const DEFAULT_DAEMON_PORT = 3847;\n\n/** License file name under config dir */\nexport const LICENSE_FILENAME = \"license.json\";\n\n/** Stats file name under config dir (session stats since daemon start) */\nexport const STATS_FILENAME = \"stats.json\";\n\n/** User config file under config dir (quiet, pricePer1kTokens, etc.) */\nexport const CONFIG_FILENAME = \"config.json\";\n\nexport function getLicensePath(): string {\n return `${getConfigDir()}/${LICENSE_FILENAME}`;\n}\n\nexport function getStatsPath(): string {\n return `${getConfigDir()}/${STATS_FILENAME}`;\n}\n\nexport function getConfigPath(): string {\n return `${getConfigDir()}/${CONFIG_FILENAME}`;\n}\n\n/** Default API/app base URL (override with TOKENCANARY_API_URL). */\nexport const DEFAULT_API_URL = \"https://www.tokencanary.com\";\n\nexport function getApiBaseUrl(): string {\n return process.env.TOKENCANARY_API_URL ?? DEFAULT_API_URL;\n}\n\n/** Upgrade page URL; pass installId to prefill for checkout. */\nexport const DEFAULT_UPGRADE_URL = `${DEFAULT_API_URL}/upgrade`;\n\nexport function getUpgradeUrl(installId?: string): string {\n const base = process.env.TOKENCANARY_UPGRADE_URL ?? DEFAULT_UPGRADE_URL;\n if (!installId) return base;\n const u = new URL(base);\n u.searchParams.set(\"install_id\", installId);\n return u.toString();\n}\n\n/** Hook request timeout in ms (fail open) */\nexport const HOOK_TIMEOUT_MS = 5000;\n","import { createHash } from \"node:crypto\";\nimport { hostname, platform, arch, cpus, networkInterfaces } from \"node:os\";\n\n/**\n * Deterministic machine fingerprint for license binding.\n * Uses hostname, OS, CPU model, and hashed network info (no raw MAC).\n */\nexport function getMachineId(): string {\n const parts: string[] = [];\n try {\n parts.push(hostname());\n } catch {\n parts.push(\"unknown-host\");\n }\n parts.push(platform());\n parts.push(arch());\n try {\n const cpu = cpus()[0];\n parts.push(cpu?.model ?? \"unknown-cpu\");\n } catch {\n parts.push(\"unknown-cpu\");\n }\n try {\n const nets = networkInterfaces();\n const addrs: string[] = [];\n for (const name of Object.keys(nets)) {\n const list = nets[name];\n if (list) {\n for (const iface of list) {\n if (iface.address && !iface.internal) addrs.push(name + \":\" + iface.address);\n }\n }\n }\n addrs.sort();\n if (addrs.length > 0) {\n parts.push(createHash(\"sha256\").update(addrs.join(\",\")).digest(\"hex\").slice(0, 16));\n }\n } catch {\n // skip network\n }\n return createHash(\"sha256\").update(parts.join(\"|\")).digest(\"hex\");\n}\n","import type { LicenseInfo, Plan } from \"./types.js\";\nimport { TRIAL_DAYS, OFFLINE_GRACE_DAYS } from \"./constants.js\";\n\nconst MS_PER_DAY = 86400 * 1000;\n\nexport function createTrialLicense(installId: string, machineId: string): LicenseInfo {\n const now = new Date();\n const expiry = new Date(now.getTime() + TRIAL_DAYS * MS_PER_DAY);\n return {\n installId,\n machineId,\n plan: \"trial\",\n expiry: expiry.toISOString(),\n createdAt: now.toISOString(),\n };\n}\n\n/**\n * Check if license is valid at the given date.\n * - Trial/monthly/yearly: valid if expiry > now.\n * - Offline grace: if lastKnownValid and within OFFLINE_GRACE_DAYS, still valid.\n */\nexport function isLicenseValid(\n license: LicenseInfo | null,\n now: Date = new Date(),\n options?: { lastKnownValid?: Date }\n): boolean {\n if (!license) return false;\n const expiry = new Date(license.expiry);\n if (expiry > now) return true;\n if (options?.lastKnownValid) {\n const graceEnd = new Date(\n options.lastKnownValid.getTime() + OFFLINE_GRACE_DAYS * MS_PER_DAY\n );\n if (now < graceEnd) return true;\n }\n return false;\n}\n\nexport function getPlanDisplay(plan: Plan): string {\n switch (plan) {\n case \"trial\":\n return \"Trial\";\n case \"monthly\":\n return \"Monthly\";\n case \"yearly\":\n return \"Yearly\";\n default:\n return String(plan);\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { getLicensePath } from \"./constants.js\";\nimport type { LicenseInfo } from \"./types.js\";\n\nexport function readLicenseSync(): LicenseInfo | null {\n const path = getLicensePath();\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as LicenseInfo;\n if (\n typeof data.installId === \"string\" &&\n typeof data.machineId === \"string\" &&\n typeof data.plan === \"string\" &&\n typeof data.expiry === \"string\" &&\n typeof data.createdAt === \"string\"\n ) {\n return data;\n }\n } catch {\n // invalid or missing\n }\n return null;\n}\n\nexport function writeLicenseSync(license: LicenseInfo): void {\n const path = getLicensePath();\n writeFileSync(path, JSON.stringify(license, null, 2), \"utf8\");\n}\n","import type { LicenseInfo } from \"./types.js\";\n\n/** Response shape from POST /api/install and POST /api/license/check */\nexport interface LicenseApiResponse {\n install_id: string;\n machine_id: string;\n plan: \"trial\" | \"monthly\" | \"yearly\";\n expiry: string;\n created_at: string;\n}\n\nexport function apiResponseToLicenseInfo(r: LicenseApiResponse): LicenseInfo {\n return {\n installId: r.install_id,\n machineId: r.machine_id,\n plan: r.plan,\n expiry: r.expiry,\n createdAt: r.created_at,\n };\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { getStatsPath, getConfigDir } from \"./constants.js\";\nimport type { SessionStats } from \"./types.js\";\n\nfunction defaultStats(): SessionStats {\n return {\n requests_optimized: 0,\n input_chars: 0,\n output_chars: 0,\n updated_at: new Date().toISOString(),\n };\n}\n\nexport function readSessionStatsSync(): SessionStats | null {\n const path = getStatsPath();\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as SessionStats;\n if (\n typeof data.requests_optimized === \"number\" &&\n typeof data.input_chars === \"number\" &&\n typeof data.output_chars === \"number\" &&\n typeof data.updated_at === \"string\"\n ) {\n return data;\n }\n } catch {\n // invalid or missing\n }\n return null;\n}\n\nexport function writeSessionStatsSync(stats: SessionStats): void {\n const dir = getConfigDir();\n mkdirSync(dir, { recursive: true });\n const path = getStatsPath();\n writeFileSync(path, JSON.stringify(stats, null, 2), \"utf8\");\n}\n\n/** Reset stats to zeros (call on daemon start). */\nexport function resetSessionStatsSync(): void {\n writeSessionStatsSync(defaultStats());\n}\n\n/** Add one request's chars to current stats and persist. */\nexport function updateSessionStatsSync(inputChars: number, outputChars: number): void {\n const current = readSessionStatsSync() ?? defaultStats();\n const next: SessionStats = {\n requests_optimized: current.requests_optimized + 1,\n input_chars: current.input_chars + inputChars,\n output_chars: current.output_chars + outputChars,\n updated_at: new Date().toISOString(),\n };\n writeSessionStatsSync(next);\n}\n","import { readFileSync, existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { getConfigPath, getConfigDir } from \"./constants.js\";\n\n/** User-configurable options (same file used by CLI and daemon). */\nexport interface UserConfig {\n /** When true, do not show in-Claude systemMessage (savings). */\n quiet?: boolean;\n /** Price per 1k tokens (for $ estimate in stats/systemMessage). Default ~$3/1M = 0.003. */\n pricePer1kTokens?: number;\n}\n\nconst DEFAULT_PRICE_PER_1K = 0.003;\n\nexport function readConfigSync(): UserConfig {\n const path = getConfigPath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf8\");\n const data = JSON.parse(raw) as Record<string, unknown>;\n const config: UserConfig = {};\n if (typeof data.quiet === \"boolean\") config.quiet = data.quiet;\n if (typeof data.pricePer1kTokens === \"number\")\n config.pricePer1kTokens = data.pricePer1kTokens;\n return config;\n } catch {\n return {};\n }\n}\n\nexport function writeConfigSync(config: UserConfig): void {\n const dir = getConfigDir();\n mkdirSync(dir, { recursive: true });\n const path = getConfigPath();\n const existing = readConfigSync();\n const merged = { ...existing, ...config };\n writeFileSync(path, JSON.stringify(merged, null, 2), \"utf8\");\n}\n\n/** Price per 1k tokens for $ estimate (from config or default). */\nexport function getPricePer1kTokens(): number {\n const config = readConfigSync();\n return config.pricePer1kTokens ?? DEFAULT_PRICE_PER_1K;\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","readFileSync","existsSync","mkdirSync","writeFileSync","existsSync","readFileSync"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getConfigDir
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DCCFWI4O.js";
|
|
4
4
|
|
|
5
5
|
// src/commands/stop.ts
|
|
6
6
|
import { readFile, unlink } from "fs/promises";
|
|
@@ -43,4 +43,4 @@ async function runStopCmd(_args) {
|
|
|
43
43
|
export {
|
|
44
44
|
runStopCmd
|
|
45
45
|
};
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
46
|
+
//# sourceMappingURL=chunk-IUASFEXE.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runDoctor
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-66ONBXHK.js";
|
|
5
|
+
import "./chunk-DCCFWI4O.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/index.ts
|
|
8
8
|
var COMMANDS = {
|
|
@@ -73,35 +73,35 @@ Quick start:
|
|
|
73
73
|
`);
|
|
74
74
|
}
|
|
75
75
|
async function runInstall(_args) {
|
|
76
|
-
const { runInstallCmd } = await import("./install-
|
|
76
|
+
const { runInstallCmd } = await import("./install-NA7R44O4.js");
|
|
77
77
|
return runInstallCmd(_args);
|
|
78
78
|
}
|
|
79
79
|
async function runStop(_args) {
|
|
80
|
-
const { runStopCmd } = await import("./stop-
|
|
80
|
+
const { runStopCmd } = await import("./stop-QJSJTHHO.js");
|
|
81
81
|
return runStopCmd(_args);
|
|
82
82
|
}
|
|
83
83
|
async function runUninstall(_args) {
|
|
84
|
-
const { runUninstallCmd } = await import("./uninstall-
|
|
84
|
+
const { runUninstallCmd } = await import("./uninstall-WUG7BEBH.js");
|
|
85
85
|
return runUninstallCmd(_args);
|
|
86
86
|
}
|
|
87
87
|
async function runStatus(_args) {
|
|
88
|
-
const { runStatusCmd } = await import("./status-
|
|
88
|
+
const { runStatusCmd } = await import("./status-2EAJQ5TH.js");
|
|
89
89
|
return runStatusCmd(_args);
|
|
90
90
|
}
|
|
91
91
|
async function runStats(_args) {
|
|
92
|
-
const { runStatsCmd } = await import("./stats-
|
|
92
|
+
const { runStatsCmd } = await import("./stats-7NLMKM67.js");
|
|
93
93
|
return runStatsCmd(_args);
|
|
94
94
|
}
|
|
95
95
|
async function runLogs(_args) {
|
|
96
|
-
const { runLogsCmd } = await import("./logs-
|
|
96
|
+
const { runLogsCmd } = await import("./logs-U4OOGTGV.js");
|
|
97
97
|
return runLogsCmd(_args);
|
|
98
98
|
}
|
|
99
99
|
async function runUpgrade(_args) {
|
|
100
|
-
const { runUpgradeCmd } = await import("./upgrade-
|
|
100
|
+
const { runUpgradeCmd } = await import("./upgrade-IR4MHUD2.js");
|
|
101
101
|
return runUpgradeCmd(_args);
|
|
102
102
|
}
|
|
103
103
|
async function runLicense(_args) {
|
|
104
|
-
const { runLicenseCmd } = await import("./license-
|
|
104
|
+
const { runLicenseCmd } = await import("./license-VKOP67LZ.js");
|
|
105
105
|
return runLicenseCmd(_args);
|
|
106
106
|
}
|
|
107
107
|
|
package/dist/daemon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runAllChecks
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-66ONBXHK.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_DAEMON_PORT,
|
|
6
6
|
apiResponseToLicenseInfo,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getMachineId,
|
|
10
10
|
readLicenseSync,
|
|
11
11
|
writeLicenseSync
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DCCFWI4O.js";
|
|
13
13
|
|
|
14
14
|
// src/commands/install.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
|
@@ -159,6 +159,7 @@ async function runInstallCmd(_args) {
|
|
|
159
159
|
await mkdir(configDir, { recursive: true });
|
|
160
160
|
let license = readLicenseSync();
|
|
161
161
|
const isFirstRun = !license;
|
|
162
|
+
let trialSkippedDueToNetwork = false;
|
|
162
163
|
if (!license) {
|
|
163
164
|
const installId = randomUUID();
|
|
164
165
|
const machineId = getMachineId();
|
|
@@ -172,24 +173,29 @@ async function runInstallCmd(_args) {
|
|
|
172
173
|
});
|
|
173
174
|
} catch (e) {
|
|
174
175
|
const msg = e instanceof Error ? e.message : String(e);
|
|
175
|
-
console.
|
|
176
|
-
console.
|
|
177
|
-
|
|
176
|
+
console.warn("Could not start trial:", msg);
|
|
177
|
+
console.warn(`Request was to: ${baseUrl}/api/install`);
|
|
178
|
+
console.warn(
|
|
179
|
+
"If the host cannot be resolved, you may be offline or the server may be unavailable. Setup will continue; run 'tokencanary setup' again when online to start your trial."
|
|
180
|
+
);
|
|
181
|
+
trialSkippedDueToNetwork = true;
|
|
178
182
|
}
|
|
179
|
-
if (!res
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
if (!trialSkippedDueToNetwork && res !== void 0) {
|
|
184
|
+
if (!res.ok) {
|
|
185
|
+
const text = await res.text();
|
|
186
|
+
console.error("Could not start trial. Server returned:", res.status, text || res.statusText);
|
|
187
|
+
return 1;
|
|
188
|
+
}
|
|
189
|
+
let data;
|
|
190
|
+
try {
|
|
191
|
+
data = await res.json();
|
|
192
|
+
} catch {
|
|
193
|
+
console.error("Invalid response from server.");
|
|
194
|
+
return 1;
|
|
195
|
+
}
|
|
196
|
+
license = apiResponseToLicenseInfo(data);
|
|
197
|
+
writeLicenseSync(license);
|
|
190
198
|
}
|
|
191
|
-
license = apiResponseToLicenseInfo(data);
|
|
192
|
-
writeLicenseSync(license);
|
|
193
199
|
} else {
|
|
194
200
|
const baseUrl = getApiBaseUrl();
|
|
195
201
|
try {
|
|
@@ -230,10 +236,13 @@ async function runInstallCmd(_args) {
|
|
|
230
236
|
});
|
|
231
237
|
}
|
|
232
238
|
console.log("");
|
|
233
|
-
if (isFirstRun) {
|
|
239
|
+
if (isFirstRun && license) {
|
|
234
240
|
console.log("Token Canary trial activated");
|
|
235
241
|
console.log("Your 30-day trial has started.\n");
|
|
236
242
|
}
|
|
243
|
+
if (trialSkippedDueToNetwork) {
|
|
244
|
+
console.log("Trial could not be started (server unreachable). Run 'tokencanary setup' again when online to start your 30-day trial.\n");
|
|
245
|
+
}
|
|
237
246
|
console.log("Setup complete");
|
|
238
247
|
console.log(` Config: ${hooksPath}`);
|
|
239
248
|
console.log(" Daemon: started");
|
|
@@ -253,4 +262,4 @@ async function runInstallCmd(_args) {
|
|
|
253
262
|
export {
|
|
254
263
|
runInstallCmd
|
|
255
264
|
};
|
|
256
|
-
//# sourceMappingURL=install-
|
|
265
|
+
//# sourceMappingURL=install-NA7R44O4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/install.ts","../src/daemon-client.ts"],"sourcesContent":["import {\n getConfigDir,\n getMachineId,\n getApiBaseUrl,\n readLicenseSync,\n writeLicenseSync,\n apiResponseToLicenseInfo,\n type LicenseInfo,\n type LicenseApiResponse,\n} from \"@token-canary/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getDaemonPort as getPort, startDaemonProcess } from \"../daemon-client.js\";\nimport { runAllChecks } from \"./doctor.js\";\n\nconst HOOKS_FILENAME = \"hooks.json\";\nconst FORWARDER_FILENAME = \"forward-hook.cjs\";\nconst CLAUDE_SETTINGS_PATH = join(homedir(), \".claude\", \"settings.json\");\n\nconst FORWARDER_SCRIPT = `\"use strict\";\nconst fs = require(\"fs\");\nconst path = require(\"path\");\nconst http = require(\"http\");\nconst https = require(\"https\");\n\nconst body = fs.readFileSync(0, \"utf8\");\nfunction passThrough() { process.stdout.write(body); process.exit(0); }\n\nlet hooks;\ntry {\n const hooksPath = path.join(path.dirname(__filename), \"hooks.json\");\n hooks = JSON.parse(fs.readFileSync(hooksPath, \"utf8\"));\n} catch {\n passThrough();\n}\n\nconst event = process.argv[2];\nconst url = hooks[event];\nif (!url) { passThrough(); }\n\nconst u = new URL(url);\nconst client = u.protocol === \"https:\" ? https : http;\nconst req = client.request(url, { method: \"POST\", headers: { \"Content-Type\": \"application/json\" } }, (res) => {\n if (res.statusCode !== 200) { passThrough(); return; }\n let data = \"\";\n res.on(\"data\", (c) => (data += c));\n res.on(\"end\", () => { process.stdout.write(data); process.exit(0); });\n});\nreq.setTimeout(5000, () => { req.destroy(); });\nreq.on(\"error\", () => { passThrough(); });\nreq.end(body);\n`;\n\n/** Write forwarder script to config dir. Call this before configureClaudeCodeHooks. */\nasync function writeForwarderScript(configDir: string): Promise<{ ok: boolean; path: string }> {\n const forwarderPath = join(configDir, FORWARDER_FILENAME);\n try {\n await writeFile(forwarderPath, FORWARDER_SCRIPT, \"utf8\");\n return { ok: true, path: forwarderPath };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Could not write ${forwarderPath}: ${msg}`);\n return { ok: false, path: forwarderPath };\n }\n}\n\n/** Merge Token Canary hooks into ~/.claude/settings.json. Requires forwarder already written. Returns true if written. */\nasync function configureClaudeCodeHooks(\n configDir: string,\n _hooksConfig: Record<string, string>\n): Promise<boolean> {\n const forwarderPath = join(configDir, FORWARDER_FILENAME);\n\n const commandUserPrompt = `node \"${forwarderPath}\" UserPromptSubmit`;\n const commandPreToolUse = `node \"${forwarderPath}\" PreToolUse`;\n\n let existing: Record<string, unknown> = {};\n try {\n const raw = await readFile(CLAUDE_SETTINGS_PATH, \"utf8\");\n existing = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // no file or invalid json\n }\n\n const existingHooks = (existing.hooks as Record<string, unknown[]>) || {};\n const isOurHook = (entry: unknown): boolean => {\n const hooks = typeof entry === \"object\" && entry !== null && \"hooks\" in entry\n ? (entry as { hooks?: unknown[] }).hooks\n : undefined;\n if (!Array.isArray(hooks)) return false;\n return hooks.some((h) => {\n const c = typeof h === \"object\" && h !== null && \"command\" in h\n ? String((h as { command?: string }).command ?? \"\")\n : \"\";\n return c.includes(forwarderPath);\n });\n };\n\n const tokenCanaryHooks: Record<string, unknown[]> = {\n UserPromptSubmit: [{ hooks: [{ type: \"command\", command: commandUserPrompt }] }],\n PreToolUse: [{ matcher: \"*\", hooks: [{ type: \"command\", command: commandPreToolUse }] }],\n };\n\n const merged: Record<string, unknown[]> = {};\n for (const [event, entries] of Object.entries(existingHooks)) {\n const filtered = Array.isArray(entries)\n ? entries.filter((e) => !isOurHook(e))\n : [];\n merged[event] = filtered;\n }\n for (const [event, entries] of Object.entries(tokenCanaryHooks)) {\n merged[event] = [...(merged[event] || []), ...entries];\n }\n existing.hooks = merged;\n\n try {\n const { mkdir: mkdirFs } = await import(\"node:fs/promises\");\n await mkdirFs(join(homedir(), \".claude\"), { recursive: true });\n await writeFile(CLAUDE_SETTINGS_PATH, JSON.stringify(existing, null, 2), \"utf8\");\n return true;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Could not write ${CLAUDE_SETTINGS_PATH}: ${msg}`);\n return false;\n }\n}\n\nfunction printManualClaudeSteps(forwarderPath: string): void {\n console.log(\"\\nAdd the following to the `hooks` key in ~/.claude/settings.json:\");\n console.log(\"(Create the file and ~/.claude if they do not exist.)\\n\");\n console.log(JSON.stringify({\n UserPromptSubmit: [{ hooks: [{ type: \"command\", command: `node \"${forwarderPath}\" UserPromptSubmit` }] }],\n PreToolUse: [{ matcher: \"*\", hooks: [{ type: \"command\", command: `node \"${forwarderPath}\" PreToolUse` }] }],\n }, null, 2));\n console.log(\"\");\n}\n\nexport async function runInstallCmd(_args: string[]): Promise<number> {\n const checks = await runAllChecks();\n const failed = checks.filter((c) => !c.ok);\n if (failed.length > 0) {\n console.log(\"Environment check\\n\");\n for (const c of checks) {\n console.log(` ${c.ok ? \"✓\" : \"✗\"} ${c.name}: ${c.message}`);\n }\n console.log(\"\\nFix the issues above first, then run: tokencanary doctor\");\n return 1;\n }\n\n const configDir = getConfigDir();\n await mkdir(configDir, { recursive: true });\n let license: LicenseInfo | null = readLicenseSync();\n const isFirstRun = !license;\n let trialSkippedDueToNetwork = false;\n if (!license) {\n const installId = randomUUID();\n const machineId = getMachineId();\n const baseUrl = getApiBaseUrl();\n let res: Response | undefined;\n try {\n res = await fetch(`${baseUrl}/api/install`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ install_id: installId, machine_id: machineId }),\n });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.warn(\"Could not start trial:\", msg);\n console.warn(`Request was to: ${baseUrl}/api/install`);\n console.warn(\n \"If the host cannot be resolved, you may be offline or the server may be unavailable. \" +\n \"Setup will continue; run 'tokencanary setup' again when online to start your trial.\"\n );\n trialSkippedDueToNetwork = true;\n }\n if (!trialSkippedDueToNetwork && res !== undefined) {\n if (!res.ok) {\n const text = await res.text();\n console.error(\"Could not start trial. Server returned:\", res.status, text || res.statusText);\n return 1;\n }\n let data: LicenseApiResponse;\n try {\n data = (await res.json()) as LicenseApiResponse;\n } catch {\n console.error(\"Invalid response from server.\");\n return 1;\n }\n license = apiResponseToLicenseInfo(data);\n writeLicenseSync(license);\n }\n } else {\n const baseUrl = getApiBaseUrl();\n try {\n const res = await fetch(`${baseUrl}/api/license/check`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n install_id: license.installId,\n machine_id: license.machineId,\n }),\n });\n if (res.ok) {\n const data = (await res.json()) as Parameters<typeof apiResponseToLicenseInfo>[0];\n license = apiResponseToLicenseInfo(data);\n writeLicenseSync(license);\n }\n } catch {\n // use cached license\n }\n }\n\n const port = getPort();\n const hooksConfig = {\n UserPromptSubmit: `http://127.0.0.1:${port}/hook/UserPromptSubmit`,\n PreToolUse: `http://127.0.0.1:${port}/hook/PreToolUse`,\n };\n const hooksPath = join(configDir, HOOKS_FILENAME);\n await writeFile(hooksPath, JSON.stringify(hooksConfig, null, 2));\n\n const forwarderResult = await writeForwarderScript(configDir);\n if (!forwarderResult.ok) {\n console.error(\"Setup cannot continue without the forwarder script.\");\n console.error(\"Create the file manually and re-run tokencanary setup.\");\n return 1;\n }\n\n const claudeConfigured = await configureClaudeCodeHooks(configDir, hooksConfig);\n\n const child = startDaemonProcess();\n const pidPath = join(configDir, \"daemon.pid\");\n if (child?.pid != null) {\n await writeFile(pidPath, String(child.pid), \"utf8\").catch(() => {});\n }\n\n console.log(\"\");\n if (isFirstRun && license) {\n console.log(\"Token Canary trial activated\");\n console.log(\"Your 30-day trial has started.\\n\");\n }\n if (trialSkippedDueToNetwork) {\n console.log(\"Trial could not be started (server unreachable). Run 'tokencanary setup' again when online to start your 30-day trial.\\n\");\n }\n console.log(\"Setup complete\");\n console.log(` Config: ${hooksPath}`);\n console.log(\" Daemon: started\");\n if (claudeConfigured) {\n console.log(\" Claude Code: hooks configured automatically\");\n console.log(\"\\nYou can start using Claude Code normally; prompts will be optimized.\");\n } else {\n printManualClaudeSteps(forwarderResult.path);\n }\n console.log(\"\\nUseful commands:\");\n console.log(\" tokencanary status — daemon and license status\");\n console.log(\" tokencanary logs — view recent logs\");\n console.log(\" tokencanary upgrade — subscribe when trial ends\");\n console.log(\"\");\n\n return 0;\n}\n","import { spawn } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { DEFAULT_DAEMON_PORT } from \"@token-canary/shared\";\n\n/**\n * Resolve the daemon entry path relative to the running CLI.\n * When published, cli.js and daemon.js live in the same dist/ dir.\n */\nexport function getDaemonEntryPath(): string {\n const cliUrl = import.meta.url;\n const cliPath = fileURLToPath(cliUrl);\n const cliDir = dirname(cliPath);\n return join(cliDir, \"daemon.js\");\n}\n\nexport function startDaemonProcess(): ReturnType<typeof spawn> {\n const entry = getDaemonEntryPath();\n const child = spawn(process.execPath, [entry], {\n stdio: \"ignore\",\n detached: true,\n });\n child.unref();\n child.on(\"error\", (err) => {\n console.error(\"Token Canary daemon failed to start:\", err.message);\n console.error(\"Daemon path:\", entry);\n });\n return child;\n}\n\nexport function getDaemonPort(): number {\n return Number(process.env.TOKENCANARY_PORT) || DEFAULT_DAEMON_PORT;\n}\n"],"mappings":"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","names":["join","join"]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
isLicenseValid,
|
|
7
7
|
readLicenseSync,
|
|
8
8
|
writeLicenseSync
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-DCCFWI4O.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/license.ts
|
|
12
12
|
async function runLicenseCmd(_args) {
|
|
@@ -52,4 +52,4 @@ async function runLicenseCmd(_args) {
|
|
|
52
52
|
export {
|
|
53
53
|
runLicenseCmd
|
|
54
54
|
};
|
|
55
|
-
//# sourceMappingURL=license-
|
|
55
|
+
//# sourceMappingURL=license-VKOP67LZ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLogDir
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DCCFWI4O.js";
|
|
4
4
|
|
|
5
5
|
// src/commands/logs.ts
|
|
6
6
|
import { readdir, readFile } from "fs/promises";
|
|
@@ -38,4 +38,4 @@ async function runLogsCmd(_args) {
|
|
|
38
38
|
export {
|
|
39
39
|
runLogsCmd
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=logs-
|
|
41
|
+
//# sourceMappingURL=logs-U4OOGTGV.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getStatsPath,
|
|
3
3
|
readSessionStatsSync
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DCCFWI4O.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/stats.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -29,4 +29,4 @@ async function runStatsCmd(_args) {
|
|
|
29
29
|
export {
|
|
30
30
|
runStatsCmd
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=stats-
|
|
32
|
+
//# sourceMappingURL=stats-7NLMKM67.js.map
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readLicenseSync,
|
|
7
7
|
readSessionStatsSync,
|
|
8
8
|
writeLicenseSync
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-DCCFWI4O.js";
|
|
10
10
|
|
|
11
11
|
// src/commands/status.ts
|
|
12
12
|
async function runStatusCmd(_args) {
|
|
@@ -54,4 +54,4 @@ async function runStatusCmd(_args) {
|
|
|
54
54
|
export {
|
|
55
55
|
runStatusCmd
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=status-
|
|
57
|
+
//# sourceMappingURL=status-2EAJQ5TH.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runStopCmd
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IUASFEXE.js";
|
|
4
4
|
import {
|
|
5
5
|
getConfigDir
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DCCFWI4O.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/uninstall.ts
|
|
9
9
|
import { homedir } from "os";
|
|
@@ -90,4 +90,4 @@ async function runUninstallCmd(_args) {
|
|
|
90
90
|
export {
|
|
91
91
|
runUninstallCmd
|
|
92
92
|
};
|
|
93
|
-
//# sourceMappingURL=uninstall-
|
|
93
|
+
//# sourceMappingURL=uninstall-WUG7BEBH.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getUpgradeUrl,
|
|
3
3
|
readLicenseSync
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DCCFWI4O.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/upgrade.ts
|
|
7
7
|
import { exec } from "child_process";
|
|
@@ -23,4 +23,4 @@ async function runUpgradeCmd(_args) {
|
|
|
23
23
|
export {
|
|
24
24
|
runUpgradeCmd
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=upgrade-
|
|
26
|
+
//# sourceMappingURL=upgrade-IR4MHUD2.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokencanary",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "CLI and daemon that reduces Claude Code token usage via hooks and local analysis",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -17,5 +17,8 @@
|
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"postinstall": "node -e 'console.log(\" ✓ Token Canary installed successfully.\\n\\n Get started:\\n tokencanary doctor Check your environment\\n tokencanary setup Configure hooks and start the daemon\\n\\n Then use Claude Code as usual — prompts are optimized automatically.\\n\\n Docs: https://www.npmjs.com/package/tokencanary\\n\")'"
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/install.ts","../src/daemon-client.ts"],"sourcesContent":["import {\n getConfigDir,\n getMachineId,\n getApiBaseUrl,\n readLicenseSync,\n writeLicenseSync,\n apiResponseToLicenseInfo,\n type LicenseInfo,\n type LicenseApiResponse,\n} from \"@token-canary/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getDaemonPort as getPort, startDaemonProcess } from \"../daemon-client.js\";\nimport { runAllChecks } from \"./doctor.js\";\n\nconst HOOKS_FILENAME = \"hooks.json\";\nconst FORWARDER_FILENAME = \"forward-hook.cjs\";\nconst CLAUDE_SETTINGS_PATH = join(homedir(), \".claude\", \"settings.json\");\n\nconst FORWARDER_SCRIPT = `\"use strict\";\nconst fs = require(\"fs\");\nconst path = require(\"path\");\nconst http = require(\"http\");\nconst https = require(\"https\");\n\nconst body = fs.readFileSync(0, \"utf8\");\nfunction passThrough() { process.stdout.write(body); process.exit(0); }\n\nlet hooks;\ntry {\n const hooksPath = path.join(path.dirname(__filename), \"hooks.json\");\n hooks = JSON.parse(fs.readFileSync(hooksPath, \"utf8\"));\n} catch {\n passThrough();\n}\n\nconst event = process.argv[2];\nconst url = hooks[event];\nif (!url) { passThrough(); }\n\nconst u = new URL(url);\nconst client = u.protocol === \"https:\" ? https : http;\nconst req = client.request(url, { method: \"POST\", headers: { \"Content-Type\": \"application/json\" } }, (res) => {\n if (res.statusCode !== 200) { passThrough(); return; }\n let data = \"\";\n res.on(\"data\", (c) => (data += c));\n res.on(\"end\", () => { process.stdout.write(data); process.exit(0); });\n});\nreq.setTimeout(5000, () => { req.destroy(); });\nreq.on(\"error\", () => { passThrough(); });\nreq.end(body);\n`;\n\n/** Write forwarder script to config dir. Call this before configureClaudeCodeHooks. */\nasync function writeForwarderScript(configDir: string): Promise<{ ok: boolean; path: string }> {\n const forwarderPath = join(configDir, FORWARDER_FILENAME);\n try {\n await writeFile(forwarderPath, FORWARDER_SCRIPT, \"utf8\");\n return { ok: true, path: forwarderPath };\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Could not write ${forwarderPath}: ${msg}`);\n return { ok: false, path: forwarderPath };\n }\n}\n\n/** Merge Token Canary hooks into ~/.claude/settings.json. Requires forwarder already written. Returns true if written. */\nasync function configureClaudeCodeHooks(\n configDir: string,\n _hooksConfig: Record<string, string>\n): Promise<boolean> {\n const forwarderPath = join(configDir, FORWARDER_FILENAME);\n\n const commandUserPrompt = `node \"${forwarderPath}\" UserPromptSubmit`;\n const commandPreToolUse = `node \"${forwarderPath}\" PreToolUse`;\n\n let existing: Record<string, unknown> = {};\n try {\n const raw = await readFile(CLAUDE_SETTINGS_PATH, \"utf8\");\n existing = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // no file or invalid json\n }\n\n const existingHooks = (existing.hooks as Record<string, unknown[]>) || {};\n const isOurHook = (entry: unknown): boolean => {\n const hooks = typeof entry === \"object\" && entry !== null && \"hooks\" in entry\n ? (entry as { hooks?: unknown[] }).hooks\n : undefined;\n if (!Array.isArray(hooks)) return false;\n return hooks.some((h) => {\n const c = typeof h === \"object\" && h !== null && \"command\" in h\n ? String((h as { command?: string }).command ?? \"\")\n : \"\";\n return c.includes(forwarderPath);\n });\n };\n\n const tokenCanaryHooks: Record<string, unknown[]> = {\n UserPromptSubmit: [{ hooks: [{ type: \"command\", command: commandUserPrompt }] }],\n PreToolUse: [{ matcher: \"*\", hooks: [{ type: \"command\", command: commandPreToolUse }] }],\n };\n\n const merged: Record<string, unknown[]> = {};\n for (const [event, entries] of Object.entries(existingHooks)) {\n const filtered = Array.isArray(entries)\n ? entries.filter((e) => !isOurHook(e))\n : [];\n merged[event] = filtered;\n }\n for (const [event, entries] of Object.entries(tokenCanaryHooks)) {\n merged[event] = [...(merged[event] || []), ...entries];\n }\n existing.hooks = merged;\n\n try {\n const { mkdir: mkdirFs } = await import(\"node:fs/promises\");\n await mkdirFs(join(homedir(), \".claude\"), { recursive: true });\n await writeFile(CLAUDE_SETTINGS_PATH, JSON.stringify(existing, null, 2), \"utf8\");\n return true;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Could not write ${CLAUDE_SETTINGS_PATH}: ${msg}`);\n return false;\n }\n}\n\nfunction printManualClaudeSteps(forwarderPath: string): void {\n console.log(\"\\nAdd the following to the `hooks` key in ~/.claude/settings.json:\");\n console.log(\"(Create the file and ~/.claude if they do not exist.)\\n\");\n console.log(JSON.stringify({\n UserPromptSubmit: [{ hooks: [{ type: \"command\", command: `node \"${forwarderPath}\" UserPromptSubmit` }] }],\n PreToolUse: [{ matcher: \"*\", hooks: [{ type: \"command\", command: `node \"${forwarderPath}\" PreToolUse` }] }],\n }, null, 2));\n console.log(\"\");\n}\n\nexport async function runInstallCmd(_args: string[]): Promise<number> {\n const checks = await runAllChecks();\n const failed = checks.filter((c) => !c.ok);\n if (failed.length > 0) {\n console.log(\"Environment check\\n\");\n for (const c of checks) {\n console.log(` ${c.ok ? \"✓\" : \"✗\"} ${c.name}: ${c.message}`);\n }\n console.log(\"\\nFix the issues above first, then run: tokencanary doctor\");\n return 1;\n }\n\n const configDir = getConfigDir();\n await mkdir(configDir, { recursive: true });\n let license: LicenseInfo | null = readLicenseSync();\n const isFirstRun = !license;\n if (!license) {\n const installId = randomUUID();\n const machineId = getMachineId();\n const baseUrl = getApiBaseUrl();\n let res: Response;\n try {\n res = await fetch(`${baseUrl}/api/install`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ install_id: installId, machine_id: machineId }),\n });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(\"Could not start trial:\", msg);\n console.error(\"Check your connection and try again.\");\n return 1;\n }\n if (!res.ok) {\n const text = await res.text();\n console.error(\"Could not start trial. Server returned:\", res.status, text || res.statusText);\n return 1;\n }\n let data: LicenseApiResponse;\n try {\n data = (await res.json()) as LicenseApiResponse;\n } catch {\n console.error(\"Invalid response from server.\");\n return 1;\n }\n license = apiResponseToLicenseInfo(data);\n writeLicenseSync(license);\n } else {\n const baseUrl = getApiBaseUrl();\n try {\n const res = await fetch(`${baseUrl}/api/license/check`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n install_id: license.installId,\n machine_id: license.machineId,\n }),\n });\n if (res.ok) {\n const data = (await res.json()) as Parameters<typeof apiResponseToLicenseInfo>[0];\n license = apiResponseToLicenseInfo(data);\n writeLicenseSync(license);\n }\n } catch {\n // use cached license\n }\n }\n\n const port = getPort();\n const hooksConfig = {\n UserPromptSubmit: `http://127.0.0.1:${port}/hook/UserPromptSubmit`,\n PreToolUse: `http://127.0.0.1:${port}/hook/PreToolUse`,\n };\n const hooksPath = join(configDir, HOOKS_FILENAME);\n await writeFile(hooksPath, JSON.stringify(hooksConfig, null, 2));\n\n const forwarderResult = await writeForwarderScript(configDir);\n if (!forwarderResult.ok) {\n console.error(\"Setup cannot continue without the forwarder script.\");\n console.error(\"Create the file manually and re-run tokencanary setup.\");\n return 1;\n }\n\n const claudeConfigured = await configureClaudeCodeHooks(configDir, hooksConfig);\n\n const child = startDaemonProcess();\n const pidPath = join(configDir, \"daemon.pid\");\n if (child?.pid != null) {\n await writeFile(pidPath, String(child.pid), \"utf8\").catch(() => {});\n }\n\n console.log(\"\");\n if (isFirstRun) {\n console.log(\"Token Canary trial activated\");\n console.log(\"Your 30-day trial has started.\\n\");\n }\n console.log(\"Setup complete\");\n console.log(` Config: ${hooksPath}`);\n console.log(\" Daemon: started\");\n if (claudeConfigured) {\n console.log(\" Claude Code: hooks configured automatically\");\n console.log(\"\\nYou can start using Claude Code normally; prompts will be optimized.\");\n } else {\n printManualClaudeSteps(forwarderResult.path);\n }\n console.log(\"\\nUseful commands:\");\n console.log(\" tokencanary status — daemon and license status\");\n console.log(\" tokencanary logs — view recent logs\");\n console.log(\" tokencanary upgrade — subscribe when trial ends\");\n console.log(\"\");\n\n return 0;\n}\n","import { spawn } from \"node:child_process\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { DEFAULT_DAEMON_PORT } from \"@token-canary/shared\";\n\n/**\n * Resolve the daemon entry path relative to the running CLI.\n * When published, cli.js and daemon.js live in the same dist/ dir.\n */\nexport function getDaemonEntryPath(): string {\n const cliUrl = import.meta.url;\n const cliPath = fileURLToPath(cliUrl);\n const cliDir = dirname(cliPath);\n return join(cliDir, \"daemon.js\");\n}\n\nexport function startDaemonProcess(): ReturnType<typeof spawn> {\n const entry = getDaemonEntryPath();\n const child = spawn(process.execPath, [entry], {\n stdio: \"ignore\",\n detached: true,\n });\n child.unref();\n child.on(\"error\", (err) => {\n console.error(\"Token Canary daemon failed to start:\", err.message);\n console.error(\"Daemon path:\", entry);\n });\n return child;\n}\n\nexport function getDaemonPort(): number {\n return Number(process.env.TOKENCANARY_PORT) || DEFAULT_DAEMON_PORT;\n}\n"],"mappings":"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","names":["join","join"]}
|
package/dist/stop-GEAGXYPB.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|