@claudetools/cli 0.13.12 → 0.13.15

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.
Files changed (368) hide show
  1. package/dist/__tests__/factories.d.ts +173 -0
  2. package/dist/__tests__/factories.d.ts.map +1 -0
  3. package/dist/__tests__/factories.js +150 -0
  4. package/dist/__tests__/factories.js.map +1 -0
  5. package/dist/__tests__/helpers.d.ts +36 -0
  6. package/dist/__tests__/helpers.d.ts.map +1 -0
  7. package/dist/__tests__/helpers.js +52 -0
  8. package/dist/__tests__/helpers.js.map +1 -0
  9. package/dist/analytics/index.d.ts +14 -0
  10. package/dist/analytics/index.d.ts.map +1 -0
  11. package/dist/analytics/index.js +259 -0
  12. package/dist/analytics/index.js.map +1 -0
  13. package/dist/analytics/session.d.ts +17 -0
  14. package/dist/analytics/session.d.ts.map +1 -0
  15. package/dist/analytics/session.js +130 -0
  16. package/dist/analytics/session.js.map +1 -0
  17. package/dist/analytics/token-tracker.d.ts +48 -0
  18. package/dist/analytics/token-tracker.d.ts.map +1 -0
  19. package/dist/analytics/token-tracker.js +269 -0
  20. package/dist/analytics/token-tracker.js.map +1 -0
  21. package/dist/analytics/tracker.d.ts +33 -0
  22. package/dist/analytics/tracker.d.ts.map +1 -0
  23. package/dist/analytics/tracker.js +210 -0
  24. package/dist/analytics/tracker.js.map +1 -0
  25. package/dist/api-keys/index.d.ts +15 -0
  26. package/dist/api-keys/index.d.ts.map +1 -0
  27. package/dist/api-keys/index.js +228 -0
  28. package/dist/api-keys/index.js.map +1 -0
  29. package/dist/auth/config.d.ts +15 -0
  30. package/dist/auth/config.d.ts.map +1 -0
  31. package/dist/auth/config.js +67 -0
  32. package/dist/auth/config.js.map +1 -0
  33. package/dist/auth/index.d.ts +8 -0
  34. package/dist/auth/index.d.ts.map +1 -0
  35. package/dist/auth/index.js +299 -0
  36. package/dist/auth/index.js.map +1 -0
  37. package/dist/auth/keychain.d.ts +21 -0
  38. package/dist/auth/keychain.d.ts.map +1 -0
  39. package/dist/auth/keychain.js +256 -0
  40. package/dist/auth/keychain.js.map +1 -0
  41. package/dist/billing/index.d.ts +7 -0
  42. package/dist/billing/index.d.ts.map +1 -0
  43. package/dist/billing/index.js +233 -0
  44. package/dist/billing/index.js.map +1 -0
  45. package/dist/cli.js +291 -43
  46. package/dist/cli.js.map +1 -1
  47. package/dist/commands/hook.d.ts +12 -0
  48. package/dist/commands/hook.d.ts.map +1 -0
  49. package/dist/commands/hook.js +190 -0
  50. package/dist/commands/hook.js.map +1 -0
  51. package/dist/commands/keys.d.ts +4 -0
  52. package/dist/commands/keys.d.ts.map +1 -0
  53. package/dist/commands/keys.js +43 -0
  54. package/dist/commands/keys.js.map +1 -0
  55. package/dist/commands/mcp.d.ts +4 -0
  56. package/dist/commands/mcp.d.ts.map +1 -0
  57. package/dist/commands/mcp.js +43 -0
  58. package/dist/commands/mcp.js.map +1 -0
  59. package/dist/commands/project.d.ts +4 -0
  60. package/dist/commands/project.d.ts.map +1 -0
  61. package/dist/commands/project.js +68 -0
  62. package/dist/commands/project.js.map +1 -0
  63. package/dist/commands/skill.d.ts +4 -0
  64. package/dist/commands/skill.d.ts.map +1 -0
  65. package/dist/commands/skill.js +37 -0
  66. package/dist/commands/skill.js.map +1 -0
  67. package/dist/commands/stacks.d.ts +4 -0
  68. package/dist/commands/stacks.d.ts.map +1 -0
  69. package/dist/commands/stacks.js +103 -0
  70. package/dist/commands/stacks.js.map +1 -0
  71. package/dist/commands/stats.d.ts +4 -0
  72. package/dist/commands/stats.d.ts.map +1 -0
  73. package/dist/commands/stats.js +6 -0
  74. package/dist/commands/stats.js.map +1 -0
  75. package/dist/commands/sync.d.ts +4 -0
  76. package/dist/commands/sync.d.ts.map +1 -0
  77. package/dist/commands/sync.js +60 -0
  78. package/dist/commands/sync.js.map +1 -0
  79. package/dist/commands/update.d.ts +4 -0
  80. package/dist/commands/update.d.ts.map +1 -0
  81. package/dist/commands/update.js +63 -0
  82. package/dist/commands/update.js.map +1 -0
  83. package/dist/daemon/client.d.ts +107 -0
  84. package/dist/daemon/client.d.ts.map +1 -0
  85. package/dist/daemon/client.js +250 -0
  86. package/dist/daemon/client.js.map +1 -0
  87. package/dist/daemon/health.d.ts +38 -0
  88. package/dist/daemon/health.d.ts.map +1 -0
  89. package/dist/daemon/health.js +212 -0
  90. package/dist/daemon/health.js.map +1 -0
  91. package/dist/daemon/index.d.ts +34 -0
  92. package/dist/daemon/index.d.ts.map +1 -0
  93. package/dist/daemon/index.js +197 -0
  94. package/dist/daemon/index.js.map +1 -0
  95. package/dist/daemon/protocol.d.ts +144 -0
  96. package/dist/daemon/protocol.d.ts.map +1 -0
  97. package/dist/daemon/protocol.js +5 -0
  98. package/dist/daemon/protocol.js.map +1 -0
  99. package/dist/gamification/index.d.ts +13 -0
  100. package/dist/gamification/index.d.ts.map +1 -0
  101. package/dist/gamification/index.js +120 -0
  102. package/dist/gamification/index.js.map +1 -0
  103. package/dist/gamification/types.d.ts +34 -0
  104. package/dist/gamification/types.d.ts.map +1 -0
  105. package/dist/gamification/types.js +5 -0
  106. package/dist/gamification/types.js.map +1 -0
  107. package/dist/hooks/index.d.ts +65 -0
  108. package/dist/hooks/index.d.ts.map +1 -0
  109. package/dist/hooks/index.js +403 -0
  110. package/dist/hooks/index.js.map +1 -0
  111. package/dist/lib/api.d.ts +29 -0
  112. package/dist/lib/api.d.ts.map +1 -0
  113. package/dist/lib/api.js +213 -0
  114. package/dist/lib/api.js.map +1 -0
  115. package/dist/lib/browser.d.ts +6 -0
  116. package/dist/lib/browser.d.ts.map +1 -0
  117. package/dist/lib/browser.js +14 -0
  118. package/dist/lib/browser.js.map +1 -0
  119. package/dist/lib/channel-config.d.ts +10 -0
  120. package/dist/lib/channel-config.d.ts.map +1 -0
  121. package/dist/lib/channel-config.js +48 -0
  122. package/dist/lib/channel-config.js.map +1 -0
  123. package/dist/lib/command-runner.d.ts +16 -0
  124. package/dist/lib/command-runner.d.ts.map +1 -0
  125. package/dist/lib/command-runner.js +59 -0
  126. package/dist/lib/command-runner.js.map +1 -0
  127. package/dist/lib/command-utils.d.ts +22 -0
  128. package/dist/lib/command-utils.d.ts.map +1 -0
  129. package/dist/lib/command-utils.js +88 -0
  130. package/dist/lib/command-utils.js.map +1 -0
  131. package/dist/lib/error-handler.d.ts +13 -0
  132. package/dist/lib/error-handler.d.ts.map +1 -0
  133. package/dist/lib/error-handler.js +70 -0
  134. package/dist/lib/error-handler.js.map +1 -0
  135. package/dist/lib/errors.d.ts +35 -0
  136. package/dist/lib/errors.d.ts.map +1 -0
  137. package/dist/lib/errors.js +70 -0
  138. package/dist/lib/errors.js.map +1 -0
  139. package/dist/lib/exit.d.ts +10 -0
  140. package/dist/lib/exit.d.ts.map +1 -0
  141. package/dist/lib/exit.js +21 -0
  142. package/dist/lib/exit.js.map +1 -0
  143. package/dist/lib/formatters.d.ts +65 -0
  144. package/dist/lib/formatters.d.ts.map +1 -0
  145. package/dist/lib/formatters.js +180 -0
  146. package/dist/lib/formatters.js.map +1 -0
  147. package/dist/lib/hybrid-data.d.ts +47 -0
  148. package/dist/lib/hybrid-data.d.ts.map +1 -0
  149. package/dist/lib/hybrid-data.js +326 -0
  150. package/dist/lib/hybrid-data.js.map +1 -0
  151. package/dist/lib/local-store.d.ts +113 -0
  152. package/dist/lib/local-store.d.ts.map +1 -0
  153. package/dist/lib/local-store.js +220 -0
  154. package/dist/lib/local-store.js.map +1 -0
  155. package/dist/lib/machine-id.d.ts +8 -0
  156. package/dist/lib/machine-id.d.ts.map +1 -0
  157. package/dist/lib/machine-id.js +39 -0
  158. package/dist/lib/machine-id.js.map +1 -0
  159. package/dist/lib/network.d.ts +15 -0
  160. package/dist/lib/network.d.ts.map +1 -0
  161. package/dist/lib/network.js +46 -0
  162. package/dist/lib/network.js.map +1 -0
  163. package/dist/lib/theme.d.ts +77 -0
  164. package/dist/lib/theme.d.ts.map +1 -0
  165. package/dist/lib/theme.js +137 -0
  166. package/dist/lib/theme.js.map +1 -0
  167. package/dist/lib/tool-availability.d.ts +13 -0
  168. package/dist/lib/tool-availability.d.ts.map +1 -0
  169. package/dist/lib/tool-availability.js +48 -0
  170. package/dist/lib/tool-availability.js.map +1 -0
  171. package/dist/lib/update-checker.d.ts +21 -0
  172. package/dist/lib/update-checker.d.ts.map +1 -0
  173. package/dist/lib/update-checker.js +110 -0
  174. package/dist/lib/update-checker.js.map +1 -0
  175. package/dist/lib/validation.d.ts +30 -0
  176. package/dist/lib/validation.d.ts.map +1 -0
  177. package/dist/lib/validation.js +82 -0
  178. package/dist/lib/validation.js.map +1 -0
  179. package/dist/lib/validators.d.ts +18 -0
  180. package/dist/lib/validators.d.ts.map +1 -0
  181. package/dist/lib/validators.js +30 -0
  182. package/dist/lib/validators.js.map +1 -0
  183. package/dist/marketplace/api.d.ts +24 -0
  184. package/dist/marketplace/api.d.ts.map +1 -0
  185. package/dist/marketplace/api.js +92 -0
  186. package/dist/marketplace/api.js.map +1 -0
  187. package/dist/marketplace/index.d.ts +13 -0
  188. package/dist/marketplace/index.d.ts.map +1 -0
  189. package/dist/marketplace/index.js +155 -0
  190. package/dist/marketplace/index.js.map +1 -0
  191. package/dist/marketplace/installer.d.ts +18 -0
  192. package/dist/marketplace/installer.d.ts.map +1 -0
  193. package/dist/marketplace/installer.js +184 -0
  194. package/dist/marketplace/installer.js.map +1 -0
  195. package/dist/mcp/api.d.ts +93 -0
  196. package/dist/mcp/api.d.ts.map +1 -0
  197. package/dist/mcp/api.js +106 -0
  198. package/dist/mcp/api.js.map +1 -0
  199. package/dist/mcp/config.d.ts +72 -0
  200. package/dist/mcp/config.d.ts.map +1 -0
  201. package/dist/mcp/config.js +156 -0
  202. package/dist/mcp/config.js.map +1 -0
  203. package/dist/mcp/index.d.ts +54 -0
  204. package/dist/mcp/index.d.ts.map +1 -0
  205. package/dist/mcp/index.js +381 -0
  206. package/dist/mcp/index.js.map +1 -0
  207. package/dist/mcp/prompt.clean.d.ts +25 -0
  208. package/dist/mcp/prompt.clean.d.ts.map +1 -0
  209. package/dist/mcp/prompt.clean.js +206 -0
  210. package/dist/mcp/prompt.clean.js.map +1 -0
  211. package/dist/mcp/prompt.d.ts +52 -0
  212. package/dist/mcp/prompt.d.ts.map +1 -0
  213. package/dist/mcp/prompt.js +210 -0
  214. package/dist/mcp/prompt.js.map +1 -0
  215. package/dist/mcp/secrets.clean.d.ts +18 -0
  216. package/dist/mcp/secrets.clean.d.ts.map +1 -0
  217. package/dist/mcp/secrets.clean.js +357 -0
  218. package/dist/mcp/secrets.clean.js.map +1 -0
  219. package/dist/mcp/secrets.d.ts +46 -0
  220. package/dist/mcp/secrets.d.ts.map +1 -0
  221. package/dist/mcp/secrets.js +339 -0
  222. package/dist/mcp/secrets.js.map +1 -0
  223. package/dist/memory/index.d.ts +14 -0
  224. package/dist/memory/index.d.ts.map +1 -0
  225. package/dist/memory/index.js +98 -0
  226. package/dist/memory/index.js.map +1 -0
  227. package/dist/onboard/agents-md-builder.d.ts.map +1 -1
  228. package/dist/onboard/agents-md-builder.js +45 -0
  229. package/dist/onboard/agents-md-builder.js.map +1 -1
  230. package/dist/onboard/claude-inference.d.ts.map +1 -1
  231. package/dist/onboard/claude-inference.js +31 -5
  232. package/dist/onboard/claude-inference.js.map +1 -1
  233. package/dist/onboard/context7-fetcher.d.ts +1 -1
  234. package/dist/onboard/context7-fetcher.d.ts.map +1 -1
  235. package/dist/onboard/context7-fetcher.js +50 -16
  236. package/dist/onboard/context7-fetcher.js.map +1 -1
  237. package/dist/onboard/docs-builder.d.ts.map +1 -1
  238. package/dist/onboard/docs-builder.js +523 -50
  239. package/dist/onboard/docs-builder.js.map +1 -1
  240. package/dist/onboard/index.d.ts.map +1 -1
  241. package/dist/onboard/index.js +74 -25
  242. package/dist/onboard/index.js.map +1 -1
  243. package/dist/onboard/stack-detector.d.ts.map +1 -1
  244. package/dist/onboard/stack-detector.js +5 -55
  245. package/dist/onboard/stack-detector.js.map +1 -1
  246. package/dist/project/constants.d.ts +21 -0
  247. package/dist/project/constants.d.ts.map +1 -0
  248. package/dist/project/constants.js +21 -0
  249. package/dist/project/constants.js.map +1 -0
  250. package/dist/project/format.d.ts +16 -0
  251. package/dist/project/format.d.ts.map +1 -0
  252. package/dist/project/format.js +40 -0
  253. package/dist/project/format.js.map +1 -0
  254. package/dist/project/git.d.ts +28 -0
  255. package/dist/project/git.d.ts.map +1 -0
  256. package/dist/project/git.js +93 -0
  257. package/dist/project/git.js.map +1 -0
  258. package/dist/project/index.d.ts +36 -0
  259. package/dist/project/index.d.ts.map +1 -0
  260. package/dist/project/index.js +272 -0
  261. package/dist/project/index.js.map +1 -0
  262. package/dist/project/mapper.d.ts +27 -0
  263. package/dist/project/mapper.d.ts.map +1 -0
  264. package/dist/project/mapper.js +64 -0
  265. package/dist/project/mapper.js.map +1 -0
  266. package/dist/project/storage.d.ts +71 -0
  267. package/dist/project/storage.d.ts.map +1 -0
  268. package/dist/project/storage.js +274 -0
  269. package/dist/project/storage.js.map +1 -0
  270. package/dist/project/sync-bridge.d.ts +33 -0
  271. package/dist/project/sync-bridge.d.ts.map +1 -0
  272. package/dist/project/sync-bridge.js +155 -0
  273. package/dist/project/sync-bridge.js.map +1 -0
  274. package/dist/project/types.d.ts +107 -0
  275. package/dist/project/types.d.ts.map +1 -0
  276. package/dist/project/types.js +77 -0
  277. package/dist/project/types.js.map +1 -0
  278. package/dist/publish/index.d.ts +4 -0
  279. package/dist/publish/index.d.ts.map +1 -0
  280. package/dist/publish/index.js +92 -0
  281. package/dist/publish/index.js.map +1 -0
  282. package/dist/setup.d.ts.map +1 -1
  283. package/dist/setup.js +29 -10
  284. package/dist/setup.js.map +1 -1
  285. package/dist/skills/index.d.ts +51 -0
  286. package/dist/skills/index.d.ts.map +1 -0
  287. package/dist/skills/index.js +509 -0
  288. package/dist/skills/index.js.map +1 -0
  289. package/dist/stacks/check.d.ts +2 -0
  290. package/dist/stacks/check.d.ts.map +1 -0
  291. package/dist/stacks/check.js +144 -0
  292. package/dist/stacks/check.js.map +1 -0
  293. package/dist/stacks/diff.d.ts +11 -0
  294. package/dist/stacks/diff.d.ts.map +1 -0
  295. package/dist/stacks/diff.js +123 -0
  296. package/dist/stacks/diff.js.map +1 -0
  297. package/dist/stacks/index.d.ts +17 -0
  298. package/dist/stacks/index.d.ts.map +1 -0
  299. package/dist/stacks/index.js +525 -0
  300. package/dist/stacks/index.js.map +1 -0
  301. package/dist/stacks/index.refactored.d.ts.map +1 -0
  302. package/dist/stacks/index.refactored.js.map +1 -0
  303. package/dist/stacks/io.d.ts +11 -0
  304. package/dist/stacks/io.d.ts.map +1 -0
  305. package/dist/stacks/io.js +179 -0
  306. package/dist/stacks/io.js.map +1 -0
  307. package/dist/stacks/rollback.d.ts +5 -0
  308. package/dist/stacks/rollback.d.ts.map +1 -0
  309. package/dist/stacks/rollback.js +162 -0
  310. package/dist/stacks/rollback.js.map +1 -0
  311. package/dist/stacks/types.d.ts +70 -0
  312. package/dist/stacks/types.d.ts.map +1 -0
  313. package/dist/stacks/types.js +6 -0
  314. package/dist/stacks/types.js.map +1 -0
  315. package/dist/stacks/utils.d.ts +9 -0
  316. package/dist/stacks/utils.d.ts.map +1 -0
  317. package/dist/stacks/utils.js +11 -0
  318. package/dist/stacks/utils.js.map +1 -0
  319. package/dist/start/index.d.ts +23 -0
  320. package/dist/start/index.d.ts.map +1 -0
  321. package/dist/start/index.js +386 -0
  322. package/dist/start/index.js.map +1 -0
  323. package/dist/sync/index.d.ts +49 -0
  324. package/dist/sync/index.d.ts.map +1 -0
  325. package/dist/sync/index.js +207 -0
  326. package/dist/sync/index.js.map +1 -0
  327. package/dist/sync-engine/__tests__/test-helpers.d.ts +14 -0
  328. package/dist/sync-engine/__tests__/test-helpers.d.ts.map +1 -0
  329. package/dist/sync-engine/__tests__/test-helpers.js +73 -0
  330. package/dist/sync-engine/__tests__/test-helpers.js.map +1 -0
  331. package/dist/sync-engine/client.d.ts +128 -0
  332. package/dist/sync-engine/client.d.ts.map +1 -0
  333. package/dist/sync-engine/client.js +289 -0
  334. package/dist/sync-engine/client.js.map +1 -0
  335. package/dist/sync-engine/health.d.ts +38 -0
  336. package/dist/sync-engine/health.d.ts.map +1 -0
  337. package/dist/sync-engine/health.js +259 -0
  338. package/dist/sync-engine/health.js.map +1 -0
  339. package/dist/sync-engine/index.d.ts +34 -0
  340. package/dist/sync-engine/index.d.ts.map +1 -0
  341. package/dist/sync-engine/index.js +197 -0
  342. package/dist/sync-engine/index.js.map +1 -0
  343. package/dist/sync-engine/protocol.d.ts +153 -0
  344. package/dist/sync-engine/protocol.d.ts.map +1 -0
  345. package/dist/sync-engine/protocol.js +5 -0
  346. package/dist/sync-engine/protocol.js.map +1 -0
  347. package/dist/tasks/index.d.ts +14 -0
  348. package/dist/tasks/index.d.ts.map +1 -0
  349. package/dist/tasks/index.js +109 -0
  350. package/dist/tasks/index.js.map +1 -0
  351. package/dist/team/index.d.ts +12 -0
  352. package/dist/team/index.d.ts.map +1 -0
  353. package/dist/team/index.js +151 -0
  354. package/dist/team/index.js.map +1 -0
  355. package/dist/updater.d.ts +5 -5
  356. package/dist/updater.d.ts.map +1 -1
  357. package/dist/updater.js +24 -88
  358. package/dist/updater.js.map +1 -1
  359. package/dist/usage/index.d.ts +10 -0
  360. package/dist/usage/index.d.ts.map +1 -0
  361. package/dist/usage/index.js +104 -0
  362. package/dist/usage/index.js.map +1 -0
  363. package/dist/webhooks/index.d.ts +7 -0
  364. package/dist/webhooks/index.d.ts.map +1 -0
  365. package/dist/webhooks/index.js +81 -0
  366. package/dist/webhooks/index.js.map +1 -0
  367. package/package.json +26 -15
  368. package/scripts/postinstall.js +282 -0
@@ -0,0 +1,269 @@
1
+ // =============================================================================
2
+ // Token Tracker
3
+ // =============================================================================
4
+ // Tracks AI token usage for cost attribution and reporting
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
6
+ import { homedir } from 'os';
7
+ import { join } from 'path';
8
+ import { getApiClient } from '../lib/api.js';
9
+ import { isLoggedIn } from '../auth/config.js';
10
+ const TOKENS_DIR = join(homedir(), '.claudetools', 'tokens');
11
+ const USAGE_FILE = join(TOKENS_DIR, 'usage.json');
12
+ const FLUSH_THRESHOLD = 20; // Flush after 20 tracked calls
13
+ const FLUSH_INTERVAL_MS = 60000; // Flush every minute
14
+ // In-memory cache
15
+ let memoryCache = null;
16
+ let flushTimer = null;
17
+ let isDirty = false;
18
+ // Model pricing (as of January 2025)
19
+ const MODEL_PRICING = {
20
+ 'claude-opus-4-5': { input: 15.0, output: 75.0 }, // per million tokens
21
+ 'claude-sonnet-4-5': { input: 3.0, output: 15.0 },
22
+ 'claude-haiku-4-5': { input: 0.8, output: 4.0 },
23
+ 'claude-opus-4': { input: 15.0, output: 75.0 },
24
+ 'claude-sonnet-4': { input: 3.0, output: 15.0 },
25
+ 'claude-haiku-4': { input: 0.8, output: 4.0 },
26
+ 'opus': { input: 15.0, output: 75.0 }, // Alias for claude-opus
27
+ 'sonnet': { input: 3.0, output: 15.0 },
28
+ 'haiku': { input: 0.8, output: 4.0 },
29
+ 'gpt-4': { input: 30.0, output: 60.0 },
30
+ 'gpt-4-turbo': { input: 10.0, output: 30.0 },
31
+ 'gpt-3.5-turbo': { input: 0.5, output: 1.5 },
32
+ };
33
+ /**
34
+ * Calculate cost estimate based on token counts and model
35
+ */
36
+ function calculateCost(model, inputTokens, outputTokens) {
37
+ const pricing = MODEL_PRICING[model] || MODEL_PRICING['sonnet']; // Default to sonnet
38
+ const inputCost = (inputTokens / 1_000_000) * pricing.input;
39
+ const outputCost = (outputTokens / 1_000_000) * pricing.output;
40
+ return inputCost + outputCost;
41
+ }
42
+ /**
43
+ * Ensure the tokens directory exists
44
+ */
45
+ function ensureTokensDir() {
46
+ try {
47
+ if (!existsSync(TOKENS_DIR)) {
48
+ mkdirSync(TOKENS_DIR, { recursive: true, mode: 0o700 });
49
+ }
50
+ }
51
+ catch {
52
+ // Silent failure
53
+ }
54
+ }
55
+ /**
56
+ * Load usage data from memory or disk
57
+ */
58
+ function loadUsage() {
59
+ if (memoryCache !== null) {
60
+ return memoryCache;
61
+ }
62
+ try {
63
+ if (!existsSync(USAGE_FILE)) {
64
+ memoryCache = { entries: [], lastFlushIndex: 0 };
65
+ return memoryCache;
66
+ }
67
+ const content = readFileSync(USAGE_FILE, 'utf-8');
68
+ const rawData = JSON.parse(content);
69
+ // Migrate legacy lastFlush (timestamp) to lastFlushIndex
70
+ const parsedEntries = (rawData.entries ?? []);
71
+ let flushIndex = typeof rawData.lastFlushIndex === 'number'
72
+ ? rawData.lastFlushIndex
73
+ : 0;
74
+ // Filter entries older than 30 days
75
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
76
+ const filteredEntries = parsedEntries.filter((entry) => entry.timestamp > thirtyDaysAgo);
77
+ // Adjust flush index if entries were pruned
78
+ const prunedCount = parsedEntries.length - filteredEntries.length;
79
+ flushIndex = Math.max(0, flushIndex - prunedCount);
80
+ const data = {
81
+ entries: filteredEntries,
82
+ lastFlushIndex: flushIndex,
83
+ };
84
+ memoryCache = data;
85
+ return memoryCache;
86
+ }
87
+ catch {
88
+ memoryCache = { entries: [], lastFlushIndex: 0 };
89
+ return memoryCache;
90
+ }
91
+ }
92
+ /**
93
+ * Persist usage data to disk
94
+ */
95
+ function persistToDisk() {
96
+ if (!memoryCache || !isDirty) {
97
+ return true;
98
+ }
99
+ try {
100
+ ensureTokensDir();
101
+ writeFileSync(USAGE_FILE, JSON.stringify(memoryCache, null, 2), { mode: 0o600 });
102
+ isDirty = false;
103
+ return true;
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ /**
110
+ * Schedule periodic persistence
111
+ */
112
+ function schedulePersist() {
113
+ if (flushTimer !== null)
114
+ return;
115
+ flushTimer = setTimeout(() => {
116
+ persistToDisk();
117
+ flushTimer = null;
118
+ }, FLUSH_INTERVAL_MS);
119
+ flushTimer.unref?.();
120
+ }
121
+ /**
122
+ * Save usage data (in memory with periodic disk persistence)
123
+ */
124
+ function saveUsage(data) {
125
+ memoryCache = data;
126
+ isDirty = true;
127
+ schedulePersist();
128
+ return true;
129
+ }
130
+ /**
131
+ * Track token usage for an AI API call
132
+ */
133
+ export function trackTokenUsage(params) {
134
+ try {
135
+ const usage = loadUsage();
136
+ const entry = {
137
+ id: `tok_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
138
+ timestamp: Date.now(),
139
+ model: params.model,
140
+ inputTokens: params.inputTokens,
141
+ outputTokens: params.outputTokens,
142
+ costEstimate: calculateCost(params.model, params.inputTokens, params.outputTokens),
143
+ command: params.command,
144
+ session: params.session,
145
+ project: params.project,
146
+ };
147
+ usage.entries.push(entry);
148
+ saveUsage(usage);
149
+ // Auto-flush if threshold reached
150
+ if (usage.entries.length - usage.lastFlushIndex >= FLUSH_THRESHOLD) {
151
+ flushTokenUsage();
152
+ }
153
+ return true;
154
+ }
155
+ catch {
156
+ return false;
157
+ }
158
+ }
159
+ /**
160
+ * Flush token usage to the backend API
161
+ */
162
+ export async function flushTokenUsage() {
163
+ try {
164
+ if (!(await isLoggedIn())) {
165
+ return false;
166
+ }
167
+ const usage = loadUsage();
168
+ // Get entries that haven't been flushed
169
+ const entriesToFlush = usage.entries.slice(usage.lastFlushIndex);
170
+ if (entriesToFlush.length === 0) {
171
+ return true;
172
+ }
173
+ const client = getApiClient({ authenticated: true });
174
+ try {
175
+ await client.post('/usage/track', {
176
+ entries: entriesToFlush,
177
+ });
178
+ // Update last flush marker to current end of entries
179
+ usage.lastFlushIndex = usage.entries.length;
180
+ saveUsage(usage);
181
+ persistToDisk();
182
+ return true;
183
+ }
184
+ catch {
185
+ // Keep entries in queue if flush fails
186
+ return false;
187
+ }
188
+ }
189
+ catch {
190
+ return false;
191
+ }
192
+ }
193
+ export function getUsageStats(days = 7) {
194
+ const usage = loadUsage();
195
+ const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
196
+ const entries = usage.entries.filter((entry) => entry.timestamp > cutoff);
197
+ const stats = {
198
+ totalInputTokens: 0,
199
+ totalOutputTokens: 0,
200
+ totalCost: 0,
201
+ byModel: {},
202
+ byCommand: {},
203
+ byDay: [],
204
+ };
205
+ // Aggregate by model and command
206
+ for (const entry of entries) {
207
+ stats.totalInputTokens += entry.inputTokens;
208
+ stats.totalOutputTokens += entry.outputTokens;
209
+ stats.totalCost += entry.costEstimate;
210
+ // By model
211
+ if (!stats.byModel[entry.model]) {
212
+ stats.byModel[entry.model] = { inputTokens: 0, outputTokens: 0, cost: 0, count: 0 };
213
+ }
214
+ const modelStats = stats.byModel[entry.model];
215
+ if (modelStats) {
216
+ modelStats.inputTokens += entry.inputTokens;
217
+ modelStats.outputTokens += entry.outputTokens;
218
+ modelStats.cost += entry.costEstimate;
219
+ modelStats.count += 1;
220
+ }
221
+ // By command
222
+ const cmd = entry.command || 'unknown';
223
+ if (!stats.byCommand[cmd]) {
224
+ stats.byCommand[cmd] = { inputTokens: 0, outputTokens: 0, cost: 0, count: 0 };
225
+ }
226
+ const cmdStats = stats.byCommand[cmd];
227
+ if (cmdStats) {
228
+ cmdStats.inputTokens += entry.inputTokens;
229
+ cmdStats.outputTokens += entry.outputTokens;
230
+ cmdStats.cost += entry.costEstimate;
231
+ cmdStats.count += 1;
232
+ }
233
+ }
234
+ // Aggregate by day
235
+ const dayMap = new Map();
236
+ for (const entry of entries) {
237
+ const date = new Date(entry.timestamp).toISOString().split('T')[0];
238
+ if (!date)
239
+ continue;
240
+ if (!dayMap.has(date)) {
241
+ dayMap.set(date, { inputTokens: 0, outputTokens: 0, cost: 0, count: 0 });
242
+ }
243
+ const dayStats = dayMap.get(date);
244
+ if (dayStats) {
245
+ dayStats.inputTokens += entry.inputTokens;
246
+ dayStats.outputTokens += entry.outputTokens;
247
+ dayStats.cost += entry.costEstimate;
248
+ dayStats.count += 1;
249
+ }
250
+ }
251
+ stats.byDay = Array.from(dayMap.entries())
252
+ .map(([date, data]) => ({ date, ...data }))
253
+ .sort((a, b) => a.date.localeCompare(b.date));
254
+ return stats;
255
+ }
256
+ /**
257
+ * Clear all token usage data
258
+ */
259
+ export function clearTokenUsage() {
260
+ try {
261
+ const usage = { entries: [], lastFlushIndex: 0 };
262
+ saveUsage(usage);
263
+ return persistToDisk();
264
+ }
265
+ catch {
266
+ return false;
267
+ }
268
+ }
269
+ //# sourceMappingURL=token-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-tracker.js","sourceRoot":"","sources":["../../src/analytics/token-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Set the CLI version for event tracking
3
+ */
4
+ export declare function setCliVersion(version: string): void;
5
+ /**
6
+ * Flush events to the server
7
+ */
8
+ export declare function flushEvents(): Promise<boolean>;
9
+ /**
10
+ * Get the current queue size
11
+ */
12
+ export declare function getQueueSize(): number;
13
+ /**
14
+ * Clear all queued events
15
+ */
16
+ export declare function clearQueue(): boolean;
17
+ /**
18
+ * Track session start event
19
+ */
20
+ export declare function trackSessionStart(data?: Record<string, unknown>): boolean;
21
+ /**
22
+ * Track session end event
23
+ */
24
+ export declare function trackSessionEnd(data?: Record<string, unknown>): boolean;
25
+ /**
26
+ * Track file edit event
27
+ */
28
+ export declare function trackFileEdit(data?: Record<string, unknown>): boolean;
29
+ /**
30
+ * Track tokens used event
31
+ */
32
+ export declare function trackTokensUsed(data?: Record<string, unknown>): boolean;
33
+ //# sourceMappingURL=tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/analytics/tracker.ts"],"names":[],"mappings":"AA2BA;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMnD;AAsHD;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAgCpD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAOrC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAOpC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAE7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAE3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAEzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAE3E"}
@@ -0,0 +1,210 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { homedir, hostname, platform, arch, userInfo } from 'os';
3
+ import { join } from 'path';
4
+ import { createHash, randomBytes } from 'crypto';
5
+ import { getApiClient } from '../lib/api.js';
6
+ import { isLoggedIn } from '../auth/config.js';
7
+ const EVENTS_DIR = join(homedir(), '.claudetools', 'events');
8
+ const QUEUE_FILE = join(EVENTS_DIR, 'queue.json');
9
+ const FLUSH_THRESHOLD = 50;
10
+ const MAX_QUEUE_SIZE = 1000;
11
+ const EVENT_EXPIRY_DAYS = 7;
12
+ let cliVersion = '1.0.0';
13
+ /**
14
+ * Set the CLI version for event tracking
15
+ */
16
+ export function setCliVersion(version) {
17
+ try {
18
+ cliVersion = version;
19
+ }
20
+ catch {
21
+ // Silent failure
22
+ }
23
+ }
24
+ /**
25
+ * Generate a stable machine ID based on system information
26
+ */
27
+ function getMachineId() {
28
+ try {
29
+ const user = userInfo();
30
+ const data = `${hostname()}-${platform()}-${arch()}-${user.username}`;
31
+ return createHash('sha256').update(data).digest('hex').substring(0, 32);
32
+ }
33
+ catch {
34
+ return 'unknown';
35
+ }
36
+ }
37
+ /**
38
+ * Generate a unique event ID
39
+ */
40
+ function generateEventId() {
41
+ try {
42
+ const timestamp = Date.now();
43
+ const random = randomBytes(8).toString('hex');
44
+ return `evt_${timestamp}_${random}`;
45
+ }
46
+ catch {
47
+ return `evt_${Date.now()}_unknown`;
48
+ }
49
+ }
50
+ /**
51
+ * Ensure the events directory exists
52
+ */
53
+ function ensureEventsDir() {
54
+ try {
55
+ if (!existsSync(EVENTS_DIR)) {
56
+ mkdirSync(EVENTS_DIR, { recursive: true, mode: 0o700 });
57
+ }
58
+ }
59
+ catch {
60
+ // Silent failure
61
+ }
62
+ }
63
+ /**
64
+ * Load the event queue from disk
65
+ */
66
+ function loadQueue() {
67
+ try {
68
+ if (!existsSync(QUEUE_FILE)) {
69
+ return { events: [] };
70
+ }
71
+ const content = readFileSync(QUEUE_FILE, 'utf-8');
72
+ const queue = JSON.parse(content);
73
+ // Filter out expired events
74
+ const now = Date.now();
75
+ const expiryMs = EVENT_EXPIRY_DAYS * 24 * 60 * 60 * 1000;
76
+ queue.events = queue.events.filter((event) => now - event.timestamp < expiryMs);
77
+ return queue;
78
+ }
79
+ catch {
80
+ return { events: [] };
81
+ }
82
+ }
83
+ /**
84
+ * Save the event queue to disk
85
+ */
86
+ function saveQueue(queue) {
87
+ try {
88
+ ensureEventsDir();
89
+ writeFileSync(QUEUE_FILE, JSON.stringify(queue, null, 2), {
90
+ mode: 0o600,
91
+ });
92
+ return true;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ }
98
+ /**
99
+ * Add an event to the queue
100
+ */
101
+ function queueEvent(type, data) {
102
+ try {
103
+ const queue = loadQueue();
104
+ const event = {
105
+ id: generateEventId(),
106
+ timestamp: Date.now(),
107
+ machineId: getMachineId(),
108
+ type,
109
+ data: {
110
+ ...data,
111
+ cliVersion,
112
+ },
113
+ };
114
+ queue.events.push(event);
115
+ // Trim oldest events if queue exceeds max size
116
+ if (queue.events.length > MAX_QUEUE_SIZE) {
117
+ queue.events = queue.events.slice(-MAX_QUEUE_SIZE);
118
+ }
119
+ saveQueue(queue);
120
+ // Auto-flush if threshold reached
121
+ if (queue.events.length >= FLUSH_THRESHOLD) {
122
+ flushEvents();
123
+ }
124
+ return true;
125
+ }
126
+ catch {
127
+ return false;
128
+ }
129
+ }
130
+ /**
131
+ * Flush events to the server
132
+ */
133
+ export async function flushEvents() {
134
+ try {
135
+ // Only flush if user is logged in
136
+ if (!(await isLoggedIn())) {
137
+ return false;
138
+ }
139
+ const queue = loadQueue();
140
+ if (queue.events.length === 0) {
141
+ return true;
142
+ }
143
+ const client = getApiClient({ authenticated: true });
144
+ try {
145
+ await client.post('/events/batch', {
146
+ events: queue.events,
147
+ });
148
+ // Clear the queue on successful flush
149
+ queue.events = [];
150
+ saveQueue(queue);
151
+ return true;
152
+ }
153
+ catch {
154
+ // If flush fails, keep events in queue
155
+ return false;
156
+ }
157
+ }
158
+ catch {
159
+ return false;
160
+ }
161
+ }
162
+ /**
163
+ * Get the current queue size
164
+ */
165
+ export function getQueueSize() {
166
+ try {
167
+ const queue = loadQueue();
168
+ return queue.events.length;
169
+ }
170
+ catch {
171
+ return 0;
172
+ }
173
+ }
174
+ /**
175
+ * Clear all queued events
176
+ */
177
+ export function clearQueue() {
178
+ try {
179
+ const queue = { events: [] };
180
+ return saveQueue(queue);
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ /**
187
+ * Track session start event
188
+ */
189
+ export function trackSessionStart(data = {}) {
190
+ return queueEvent('session_start', data);
191
+ }
192
+ /**
193
+ * Track session end event
194
+ */
195
+ export function trackSessionEnd(data = {}) {
196
+ return queueEvent('session_end', data);
197
+ }
198
+ /**
199
+ * Track file edit event
200
+ */
201
+ export function trackFileEdit(data = {}) {
202
+ return queueEvent('file_edit', data);
203
+ }
204
+ /**
205
+ * Track tokens used event
206
+ */
207
+ export function trackTokensUsed(data = {}) {
208
+ return queueEvent('tokens_used', data);
209
+ }
210
+ //# sourceMappingURL=tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/analytics/tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * List all API keys
3
+ */
4
+ export declare function runKeysList(): Promise<void>;
5
+ /**
6
+ * Create a new API key
7
+ */
8
+ export declare function runKeysCreate(name: string): Promise<void>;
9
+ /**
10
+ * Revoke an API key
11
+ */
12
+ export declare function runKeysRevoke(keyId: string, options?: {
13
+ force?: boolean;
14
+ }): Promise<void>;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api-keys/index.ts"],"names":[],"mappings":"AAyDA;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAqEjD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwD/D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFnG"}