@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,274 @@
1
+ /**
2
+ * Project Storage
3
+ * Local file operations for ~/.claudetools/projects.json
4
+ */
5
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, openSync, closeSync, unlinkSync, } from 'node:fs';
6
+ import { homedir } from 'node:os';
7
+ import { join, dirname } from 'node:path';
8
+ import { PROJECTS_SCHEMA_VERSION, computePathHash, } from './types.js';
9
+ import { LOCK_MAX_RETRIES, LOCK_RETRY_DELAY } from './constants.js';
10
+ /**
11
+ * Get the path to the projects file
12
+ */
13
+ export function getProjectsPath() {
14
+ return join(homedir(), '.claudetools', 'projects.json');
15
+ }
16
+ /**
17
+ * Migrate projects file to current schema version
18
+ */
19
+ function migrateProjects(data) {
20
+ const file = data;
21
+ let version = file.version ?? 0;
22
+ let projects = (file.projects ?? []);
23
+ // v0 -> v1: Add sync status fields
24
+ if (version < 1) {
25
+ projects = projects.map((p) => ({
26
+ ...p,
27
+ isSynced: p.isSynced ?? false,
28
+ isDeleted: p.isDeleted ?? false,
29
+ updatedAt: p.updatedAt ?? p.registeredAt,
30
+ }));
31
+ version = 1;
32
+ }
33
+ return { version, projects };
34
+ }
35
+ /**
36
+ * Load projects from disk
37
+ * Returns default file if not exists or parse fails
38
+ */
39
+ export function loadProjects() {
40
+ const path = getProjectsPath();
41
+ if (!existsSync(path)) {
42
+ return { version: PROJECTS_SCHEMA_VERSION, projects: [] };
43
+ }
44
+ try {
45
+ const content = readFileSync(path, 'utf-8');
46
+ const data = JSON.parse(content);
47
+ return migrateProjects(data);
48
+ }
49
+ catch {
50
+ // If parse fails, backup and start fresh
51
+ const backup = `${path}.backup.${Date.now()}`;
52
+ try {
53
+ const content = readFileSync(path, 'utf-8');
54
+ writeFileSync(backup, content);
55
+ console.warn(`Projects file corrupted, backed up to: ${backup}`);
56
+ }
57
+ catch {
58
+ // Ignore backup failures
59
+ }
60
+ return { version: PROJECTS_SCHEMA_VERSION, projects: [] };
61
+ }
62
+ }
63
+ /**
64
+ * Save projects to disk atomically
65
+ */
66
+ export function saveProjects(file) {
67
+ const path = getProjectsPath();
68
+ const dir = dirname(path);
69
+ // Ensure directory exists
70
+ if (!existsSync(dir)) {
71
+ mkdirSync(dir, { recursive: true });
72
+ }
73
+ const content = JSON.stringify(file, null, 2);
74
+ writeFileSync(path, content, 'utf-8');
75
+ }
76
+ /**
77
+ * Simple file-based lock using a .lock file
78
+ * Works cross-platform without native dependencies
79
+ */
80
+ function getLockPath() {
81
+ return `${getProjectsPath()}.lock`;
82
+ }
83
+ /**
84
+ * Try to acquire a file lock
85
+ * Returns a release function, or null if lock cannot be acquired
86
+ */
87
+ async function tryAcquireLock(maxRetries = LOCK_MAX_RETRIES, retryDelay = LOCK_RETRY_DELAY) {
88
+ const lockPath = getLockPath();
89
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
90
+ try {
91
+ // O_EXCL ensures atomic creation - fails if file exists
92
+ const fd = openSync(lockPath, 'wx');
93
+ closeSync(fd);
94
+ // Return release function
95
+ return () => {
96
+ try {
97
+ unlinkSync(lockPath);
98
+ }
99
+ catch {
100
+ // Ignore errors on unlock
101
+ }
102
+ };
103
+ }
104
+ catch (err) {
105
+ const error = err;
106
+ if (error.code === 'EEXIST') {
107
+ // Lock file exists, wait and retry
108
+ await new Promise((resolve) => setTimeout(resolve, retryDelay * (attempt + 1)));
109
+ continue;
110
+ }
111
+ // Other error, rethrow
112
+ throw error;
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+ /**
118
+ * Execute a function with file lock to prevent race conditions
119
+ * between CLI and desktop app
120
+ */
121
+ export async function withProjectsLock(fn) {
122
+ const path = getProjectsPath();
123
+ const dir = dirname(path);
124
+ // Ensure directory and file exist for locking
125
+ if (!existsSync(dir)) {
126
+ mkdirSync(dir, { recursive: true });
127
+ }
128
+ if (!existsSync(path)) {
129
+ saveProjects({ version: PROJECTS_SCHEMA_VERSION, projects: [] });
130
+ }
131
+ const release = await tryAcquireLock();
132
+ if (!release) {
133
+ throw new Error('Could not acquire lock on projects file - another process may be using it');
134
+ }
135
+ try {
136
+ return await fn();
137
+ }
138
+ finally {
139
+ release();
140
+ }
141
+ }
142
+ /**
143
+ * Get all active (non-deleted) projects
144
+ */
145
+ export function getActiveProjects() {
146
+ const file = loadProjects();
147
+ return file.projects.filter((p) => !p.isDeleted);
148
+ }
149
+ /**
150
+ * Find a project by ID
151
+ */
152
+ export function findProjectById(id) {
153
+ const file = loadProjects();
154
+ return file.projects.find((p) => p.id === id && !p.isDeleted) ?? null;
155
+ }
156
+ /**
157
+ * Find a project by name (case-insensitive)
158
+ */
159
+ export function findProjectByName(name) {
160
+ const file = loadProjects();
161
+ const lower = name.toLowerCase();
162
+ return (file.projects.find((p) => p.name.toLowerCase() === lower && !p.isDeleted) ??
163
+ null);
164
+ }
165
+ /**
166
+ * Find a project by path
167
+ */
168
+ export function findProjectByPath(path) {
169
+ const pathHash = computePathHash(path);
170
+ const file = loadProjects();
171
+ return (file.projects.find((p) => p.pathHash === pathHash && !p.isDeleted) ?? null);
172
+ }
173
+ /**
174
+ * Find a project by name, ID, or path
175
+ */
176
+ export function findProject(identifier) {
177
+ // Try by ID first
178
+ let project = findProjectById(identifier);
179
+ if (project)
180
+ return project;
181
+ // Try by name
182
+ project = findProjectByName(identifier);
183
+ if (project)
184
+ return project;
185
+ // Try by path
186
+ project = findProjectByPath(identifier);
187
+ return project;
188
+ }
189
+ /**
190
+ * Add a new project
191
+ */
192
+ export async function addProject(project) {
193
+ await withProjectsLock(async () => {
194
+ const file = loadProjects();
195
+ // Check for duplicate path
196
+ const existing = file.projects.find((p) => p.pathHash === project.pathHash && !p.isDeleted);
197
+ if (existing) {
198
+ throw new Error(`Project already registered at this path: ${existing.name}`);
199
+ }
200
+ file.projects.push(project);
201
+ saveProjects(file);
202
+ });
203
+ }
204
+ /**
205
+ * Update an existing project
206
+ */
207
+ export async function updateProject(id, updates) {
208
+ return withProjectsLock(async () => {
209
+ const file = loadProjects();
210
+ const index = file.projects.findIndex((p) => p.id === id);
211
+ if (index === -1) {
212
+ throw new Error(`Project not found: ${id}`);
213
+ }
214
+ const project = file.projects[index];
215
+ const updated = {
216
+ ...project,
217
+ name: updates.name ?? project.name,
218
+ description: updates.description ?? project.description,
219
+ teamId: updates.teamId ?? project.teamId,
220
+ gitRemoteUrl: updates.gitRemoteUrl ?? project.gitRemoteUrl,
221
+ updatedAt: new Date().toISOString(),
222
+ isSynced: false, // Mark as needing sync after update
223
+ settings: updates.settings ?? project.settings,
224
+ stackProfile: updates.stackProfile ?? project.stackProfile,
225
+ };
226
+ file.projects[index] = updated;
227
+ saveProjects(file);
228
+ return updated;
229
+ });
230
+ }
231
+ /**
232
+ * Soft delete a project (marks as deleted)
233
+ */
234
+ export async function removeProject(id) {
235
+ await withProjectsLock(async () => {
236
+ const file = loadProjects();
237
+ const index = file.projects.findIndex((p) => p.id === id);
238
+ if (index === -1) {
239
+ throw new Error(`Project not found: ${id}`);
240
+ }
241
+ const project = file.projects[index];
242
+ const now = new Date().toISOString();
243
+ // Mark as deleted (soft delete)
244
+ file.projects[index] = {
245
+ ...project,
246
+ updatedAt: now,
247
+ isSynced: false,
248
+ isDeleted: true,
249
+ deletedAt: now,
250
+ };
251
+ saveProjects(file);
252
+ });
253
+ }
254
+ /**
255
+ * Permanently delete projects marked as deleted for over 30 days
256
+ */
257
+ export async function cleanupDeletedProjects() {
258
+ return withProjectsLock(async () => {
259
+ const file = loadProjects();
260
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
261
+ const originalCount = file.projects.length;
262
+ file.projects = file.projects.filter((p) => {
263
+ if (!p.isDeleted || !p.deletedAt)
264
+ return true;
265
+ return new Date(p.deletedAt).getTime() > thirtyDaysAgo;
266
+ });
267
+ const removed = originalCount - file.projects.length;
268
+ if (removed > 0) {
269
+ saveProjects(file);
270
+ }
271
+ return removed;
272
+ });
273
+ }
274
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/project/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Project Sync Bridge
3
+ * Fire-and-forget sync calls invoked by project commands after local writes.
4
+ * All operations are best-effort — local operations always succeed regardless of sync status.
5
+ */
6
+ import type { Project } from './types.js';
7
+ import type { SyncProject } from '../sync-engine/protocol.js';
8
+ /**
9
+ * Check whether the sync engine is running and the user is logged in.
10
+ */
11
+ export declare function isSyncAvailable(): Promise<boolean>;
12
+ /**
13
+ * Push a project to the sync engine after a local write.
14
+ * On success, marks the project as synced in projects.json.
15
+ * On failure, logs a warning and leaves isSynced as false.
16
+ */
17
+ export declare function pushProjectToEngine(project: Project, action: 'insert' | 'update'): Promise<void>;
18
+ /**
19
+ * Delete a project from the sync engine.
20
+ */
21
+ export declare function deleteProjectFromEngine(projectId: string): Promise<void>;
22
+ /**
23
+ * Pull all projects from the sync engine.
24
+ */
25
+ export declare function pullProjectsFromEngine(): Promise<SyncProject[]>;
26
+ /**
27
+ * Merge cloud projects into local storage.
28
+ * - New cloud projects are inserted with default local-only fields.
29
+ * - Existing projects are updated if the cloud version is newer.
30
+ * - Local-only fields (pathHash, isSynced, settings, stackProfile) are preserved.
31
+ */
32
+ export declare function mergeCloudProjects(cloudProjects: SyncProject[]): Promise<void>;
33
+ //# sourceMappingURL=sync-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-bridge.d.ts","sourceRoot":"","sources":["../../src/project/sync-bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAMxD;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAC1B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9E;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAMrE;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqEpF"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Project Sync Bridge
3
+ * Fire-and-forget sync calls invoked by project commands after local writes.
4
+ * All operations are best-effort — local operations always succeed regardless of sync status.
5
+ */
6
+ import { defaultSettings, computePathHash } from './types.js';
7
+ import { getSyncEngineClient, isSyncEngineRunning } from '../sync-engine/client.js';
8
+ import { loadConfig } from '../auth/config.js';
9
+ import { loadProjects, saveProjects } from './storage.js';
10
+ import { projectToSyncProject, syncProjectToProject } from './mapper.js';
11
+ /**
12
+ * Check whether the sync engine is running and the user is logged in.
13
+ */
14
+ export async function isSyncAvailable() {
15
+ const config = loadConfig();
16
+ if (!config.userId) {
17
+ return false;
18
+ }
19
+ return isSyncEngineRunning();
20
+ }
21
+ /**
22
+ * Push a project to the sync engine after a local write.
23
+ * On success, marks the project as synced in projects.json.
24
+ * On failure, logs a warning and leaves isSynced as false.
25
+ */
26
+ export async function pushProjectToEngine(project, action) {
27
+ const config = loadConfig();
28
+ if (!config.userId) {
29
+ return;
30
+ }
31
+ const engineRunning = await isSyncEngineRunning();
32
+ if (!engineRunning) {
33
+ return;
34
+ }
35
+ const syncProject = projectToSyncProject(project, config.userId);
36
+ try {
37
+ const client = getSyncEngineClient();
38
+ await client.syncPushProject(syncProject, action);
39
+ // Mark as synced in local storage
40
+ const file = loadProjects();
41
+ const projectIndex = file.projects.findIndex((p) => p.id === project.id);
42
+ if (projectIndex !== -1) {
43
+ const now = new Date().toISOString();
44
+ file.projects[projectIndex] = {
45
+ ...file.projects[projectIndex],
46
+ isSynced: true,
47
+ lastSyncedAt: now,
48
+ };
49
+ saveProjects(file);
50
+ }
51
+ }
52
+ catch (syncError) {
53
+ const message = syncError instanceof Error ? syncError.message : String(syncError);
54
+ console.warn(` Warning: Failed to sync project to cloud: ${message}`);
55
+ }
56
+ }
57
+ /**
58
+ * Delete a project from the sync engine.
59
+ */
60
+ export async function deleteProjectFromEngine(projectId) {
61
+ const engineRunning = await isSyncEngineRunning();
62
+ if (!engineRunning) {
63
+ return;
64
+ }
65
+ try {
66
+ const client = getSyncEngineClient();
67
+ await client.syncDeleteProject(projectId);
68
+ }
69
+ catch (syncError) {
70
+ const message = syncError instanceof Error ? syncError.message : String(syncError);
71
+ console.warn(` Warning: Failed to delete project from cloud: ${message}`);
72
+ }
73
+ }
74
+ /**
75
+ * Pull all projects from the sync engine.
76
+ */
77
+ export async function pullProjectsFromEngine() {
78
+ if (!(await isSyncAvailable())) {
79
+ return [];
80
+ }
81
+ const client = getSyncEngineClient();
82
+ return client.syncPullProjects();
83
+ }
84
+ /**
85
+ * Merge cloud projects into local storage.
86
+ * - New cloud projects are inserted with default local-only fields.
87
+ * - Existing projects are updated if the cloud version is newer.
88
+ * - Local-only fields (pathHash, isSynced, settings, stackProfile) are preserved.
89
+ */
90
+ export async function mergeCloudProjects(cloudProjects) {
91
+ const file = loadProjects();
92
+ let modified = false;
93
+ for (const cloudProject of cloudProjects) {
94
+ const localIndex = file.projects.findIndex((p) => p.id === cloudProject.id);
95
+ if (localIndex === -1) {
96
+ // New project from cloud — insert with defaults
97
+ const partial = syncProjectToProject(cloudProject);
98
+ // Skip cloud-only projects without a local path — they'll appear
99
+ // in the web dashboard but not in CLI until explicitly bound
100
+ if (!partial.path) {
101
+ continue;
102
+ }
103
+ const newProject = {
104
+ id: partial.id,
105
+ path: partial.path ?? '',
106
+ pathHash: partial.path ? computePathHash(partial.path) : '',
107
+ name: partial.name,
108
+ description: partial.description,
109
+ teamId: partial.teamId,
110
+ gitRemoteUrl: partial.gitRemoteUrl,
111
+ registeredAt: partial.registeredAt,
112
+ updatedAt: partial.updatedAt,
113
+ isSynced: true,
114
+ isDeleted: partial.isDeleted ?? false,
115
+ deletedAt: partial.deletedAt,
116
+ settings: defaultSettings(),
117
+ };
118
+ file.projects.push(newProject);
119
+ modified = true;
120
+ }
121
+ else {
122
+ // Existing project — update if cloud is newer
123
+ const localProject = file.projects[localIndex];
124
+ const cloudUpdatedAt = new Date(cloudProject.updated_at).getTime();
125
+ const localUpdatedAt = new Date(localProject.updatedAt).getTime();
126
+ if (cloudUpdatedAt > localUpdatedAt) {
127
+ const partial = syncProjectToProject(cloudProject);
128
+ file.projects[localIndex] = {
129
+ ...localProject,
130
+ // Overwrite synced fields from cloud
131
+ name: partial.name ?? localProject.name,
132
+ description: partial.description,
133
+ teamId: partial.teamId,
134
+ gitRemoteUrl: partial.gitRemoteUrl,
135
+ path: partial.path ?? localProject.path,
136
+ pathHash: partial.path ? computePathHash(partial.path) : localProject.pathHash,
137
+ registeredAt: partial.registeredAt ?? localProject.registeredAt,
138
+ updatedAt: partial.updatedAt ?? localProject.updatedAt,
139
+ isDeleted: partial.isDeleted ?? localProject.isDeleted,
140
+ deletedAt: partial.deletedAt,
141
+ // Preserve local-only fields
142
+ isSynced: true,
143
+ lastSyncedAt: new Date().toISOString(),
144
+ settings: localProject.settings,
145
+ stackProfile: localProject.stackProfile,
146
+ };
147
+ modified = true;
148
+ }
149
+ }
150
+ }
151
+ if (modified) {
152
+ saveProjects(file);
153
+ }
154
+ }
155
+ //# sourceMappingURL=sync-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-bridge.js","sourceRoot":"","sources":["../../src/project/sync-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Project Registration Types
3
+ * Local-first project tracking for ClaudeTools
4
+ */
5
+ /**
6
+ * Stack profile detected from session files
7
+ */
8
+ export interface StackProfile {
9
+ primaryLanguage: string;
10
+ languages: Record<string, number>;
11
+ frameworks: string[];
12
+ detectedAt: string;
13
+ }
14
+ /**
15
+ * Project settings
16
+ */
17
+ export interface ProjectSettings {
18
+ autoSync: boolean;
19
+ visibility: 'personal' | 'team';
20
+ budgetAlertUsd?: number;
21
+ }
22
+ /**
23
+ * A registered project
24
+ */
25
+ export interface Project {
26
+ id: string;
27
+ path: string;
28
+ pathHash: string;
29
+ name: string;
30
+ description?: string;
31
+ teamId?: string;
32
+ gitRemoteUrl?: string;
33
+ registeredAt: string;
34
+ updatedAt: string;
35
+ lastSyncedAt?: string;
36
+ isSynced: boolean;
37
+ isDeleted: boolean;
38
+ deletedAt?: string;
39
+ settings: ProjectSettings;
40
+ stackProfile?: StackProfile;
41
+ }
42
+ /**
43
+ * The projects file stored at ~/.claudetools/projects.json
44
+ */
45
+ export interface ProjectsFile {
46
+ version: number;
47
+ projects: Project[];
48
+ }
49
+ /**
50
+ * Unregistered project discovered from session files
51
+ */
52
+ export interface UnregisteredProject {
53
+ path: string;
54
+ pathHash: string;
55
+ suggestedName: string;
56
+ detectedStack?: StackProfile;
57
+ sessionCount: number;
58
+ lastActivity?: string;
59
+ }
60
+ /**
61
+ * Project statistics
62
+ */
63
+ export interface ProjectStats {
64
+ sessionCount: number;
65
+ totalTokens: number;
66
+ inputTokens: number;
67
+ outputTokens: number;
68
+ cacheReadTokens: number;
69
+ costUsd: number;
70
+ lastActivity: string | null;
71
+ sparklineData: number[];
72
+ weekOverWeekChange: number;
73
+ }
74
+ /**
75
+ * Current schema version
76
+ */
77
+ export declare const PROJECTS_SCHEMA_VERSION = 1;
78
+ /**
79
+ * Normalize a path for consistent hashing
80
+ * - Resolves to absolute path
81
+ * - Lowercases on case-insensitive systems
82
+ * - Removes trailing slashes
83
+ */
84
+ export declare function normalizePath(inputPath: string): string;
85
+ /**
86
+ * Compute SHA256 hash of a normalized path
87
+ */
88
+ export declare function computePathHash(inputPath: string): string;
89
+ /**
90
+ * Generate a new project ID
91
+ */
92
+ export declare function generateProjectId(): string;
93
+ /**
94
+ * Create default project settings
95
+ */
96
+ export declare function defaultSettings(): ProjectSettings;
97
+ /**
98
+ * Create a new project with defaults
99
+ */
100
+ export declare function createProject(path: string, name: string, options?: {
101
+ description?: string;
102
+ teamId?: string;
103
+ gitRemoteUrl?: string;
104
+ settings?: Partial<ProjectSettings>;
105
+ stackProfile?: StackProfile;
106
+ }): Project;
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/project/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,eAAe,CAKjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACpC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,GACA,OAAO,CAqBT"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Project Registration Types
3
+ * Local-first project tracking for ClaudeTools
4
+ */
5
+ import { createHash } from 'node:crypto';
6
+ import { resolve, normalize } from 'node:path';
7
+ import { randomUUID } from 'node:crypto';
8
+ /**
9
+ * Current schema version
10
+ */
11
+ export const PROJECTS_SCHEMA_VERSION = 1;
12
+ /**
13
+ * Normalize a path for consistent hashing
14
+ * - Resolves to absolute path
15
+ * - Lowercases on case-insensitive systems
16
+ * - Removes trailing slashes
17
+ */
18
+ export function normalizePath(inputPath) {
19
+ let normalized = resolve(normalize(inputPath));
20
+ // Remove trailing slash (except for root)
21
+ if (normalized.length > 1 && normalized.endsWith('/')) {
22
+ normalized = normalized.slice(0, -1);
23
+ }
24
+ // Lowercase for case-insensitive filesystems (macOS, Windows)
25
+ if (process.platform === 'darwin' || process.platform === 'win32') {
26
+ normalized = normalized.toLowerCase();
27
+ }
28
+ return normalized;
29
+ }
30
+ /**
31
+ * Compute SHA256 hash of a normalized path
32
+ */
33
+ export function computePathHash(inputPath) {
34
+ const normalized = normalizePath(inputPath);
35
+ const hash = createHash('sha256').update(normalized).digest('hex');
36
+ return `sha256:${hash}`;
37
+ }
38
+ /**
39
+ * Generate a new project ID
40
+ */
41
+ export function generateProjectId() {
42
+ return randomUUID();
43
+ }
44
+ /**
45
+ * Create default project settings
46
+ */
47
+ export function defaultSettings() {
48
+ return {
49
+ autoSync: true,
50
+ visibility: 'personal',
51
+ };
52
+ }
53
+ /**
54
+ * Create a new project with defaults
55
+ */
56
+ export function createProject(path, name, options) {
57
+ const now = new Date().toISOString();
58
+ return {
59
+ id: generateProjectId(),
60
+ path,
61
+ pathHash: computePathHash(path),
62
+ name,
63
+ description: options?.description,
64
+ teamId: options?.teamId,
65
+ gitRemoteUrl: options?.gitRemoteUrl,
66
+ registeredAt: now,
67
+ updatedAt: now,
68
+ isSynced: false,
69
+ isDeleted: false,
70
+ settings: {
71
+ ...defaultSettings(),
72
+ ...options?.settings,
73
+ },
74
+ stackProfile: options?.stackProfile,
75
+ };
76
+ }
77
+ //# sourceMappingURL=types.js.map