@stoneforge/quarry 0.1.0

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 (330) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +160 -0
  3. package/dist/api/index.d.ts +8 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +8 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/quarry-api.d.ts +268 -0
  8. package/dist/api/quarry-api.d.ts.map +1 -0
  9. package/dist/api/quarry-api.js +3905 -0
  10. package/dist/api/quarry-api.js.map +1 -0
  11. package/dist/api/types.d.ts +1359 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/api/types.js +204 -0
  14. package/dist/api/types.js.map +1 -0
  15. package/dist/bin/sf.d.ts +3 -0
  16. package/dist/bin/sf.d.ts.map +1 -0
  17. package/dist/bin/sf.js +9 -0
  18. package/dist/bin/sf.js.map +1 -0
  19. package/dist/cli/commands/admin.d.ts +11 -0
  20. package/dist/cli/commands/admin.d.ts.map +1 -0
  21. package/dist/cli/commands/admin.js +465 -0
  22. package/dist/cli/commands/admin.js.map +1 -0
  23. package/dist/cli/commands/alias.d.ts +8 -0
  24. package/dist/cli/commands/alias.d.ts.map +1 -0
  25. package/dist/cli/commands/alias.js +70 -0
  26. package/dist/cli/commands/alias.js.map +1 -0
  27. package/dist/cli/commands/channel.d.ts +13 -0
  28. package/dist/cli/commands/channel.d.ts.map +1 -0
  29. package/dist/cli/commands/channel.js +680 -0
  30. package/dist/cli/commands/channel.js.map +1 -0
  31. package/dist/cli/commands/completion.d.ts +8 -0
  32. package/dist/cli/commands/completion.d.ts.map +1 -0
  33. package/dist/cli/commands/completion.js +87 -0
  34. package/dist/cli/commands/completion.js.map +1 -0
  35. package/dist/cli/commands/config.d.ts +12 -0
  36. package/dist/cli/commands/config.d.ts.map +1 -0
  37. package/dist/cli/commands/config.js +242 -0
  38. package/dist/cli/commands/config.js.map +1 -0
  39. package/dist/cli/commands/crud.d.ts +64 -0
  40. package/dist/cli/commands/crud.d.ts.map +1 -0
  41. package/dist/cli/commands/crud.js +805 -0
  42. package/dist/cli/commands/crud.js.map +1 -0
  43. package/dist/cli/commands/dep.d.ts +16 -0
  44. package/dist/cli/commands/dep.d.ts.map +1 -0
  45. package/dist/cli/commands/dep.js +499 -0
  46. package/dist/cli/commands/dep.js.map +1 -0
  47. package/dist/cli/commands/document.d.ts +12 -0
  48. package/dist/cli/commands/document.d.ts.map +1 -0
  49. package/dist/cli/commands/document.js +1039 -0
  50. package/dist/cli/commands/document.js.map +1 -0
  51. package/dist/cli/commands/embeddings.d.ts +12 -0
  52. package/dist/cli/commands/embeddings.d.ts.map +1 -0
  53. package/dist/cli/commands/embeddings.js +273 -0
  54. package/dist/cli/commands/embeddings.js.map +1 -0
  55. package/dist/cli/commands/entity.d.ts +16 -0
  56. package/dist/cli/commands/entity.d.ts.map +1 -0
  57. package/dist/cli/commands/entity.js +522 -0
  58. package/dist/cli/commands/entity.js.map +1 -0
  59. package/dist/cli/commands/gc.d.ts +10 -0
  60. package/dist/cli/commands/gc.d.ts.map +1 -0
  61. package/dist/cli/commands/gc.js +257 -0
  62. package/dist/cli/commands/gc.js.map +1 -0
  63. package/dist/cli/commands/help.d.ts +11 -0
  64. package/dist/cli/commands/help.d.ts.map +1 -0
  65. package/dist/cli/commands/help.js +169 -0
  66. package/dist/cli/commands/help.js.map +1 -0
  67. package/dist/cli/commands/history.d.ts +9 -0
  68. package/dist/cli/commands/history.d.ts.map +1 -0
  69. package/dist/cli/commands/history.js +160 -0
  70. package/dist/cli/commands/history.js.map +1 -0
  71. package/dist/cli/commands/identity.d.ts +18 -0
  72. package/dist/cli/commands/identity.d.ts.map +1 -0
  73. package/dist/cli/commands/identity.js +698 -0
  74. package/dist/cli/commands/identity.js.map +1 -0
  75. package/dist/cli/commands/inbox.d.ts +20 -0
  76. package/dist/cli/commands/inbox.d.ts.map +1 -0
  77. package/dist/cli/commands/inbox.js +493 -0
  78. package/dist/cli/commands/inbox.js.map +1 -0
  79. package/dist/cli/commands/init.d.ts +20 -0
  80. package/dist/cli/commands/init.d.ts.map +1 -0
  81. package/dist/cli/commands/init.js +144 -0
  82. package/dist/cli/commands/init.js.map +1 -0
  83. package/dist/cli/commands/install.d.ts +9 -0
  84. package/dist/cli/commands/install.d.ts.map +1 -0
  85. package/dist/cli/commands/install.js +200 -0
  86. package/dist/cli/commands/install.js.map +1 -0
  87. package/dist/cli/commands/library.d.ts +12 -0
  88. package/dist/cli/commands/library.d.ts.map +1 -0
  89. package/dist/cli/commands/library.js +665 -0
  90. package/dist/cli/commands/library.js.map +1 -0
  91. package/dist/cli/commands/message.d.ts +11 -0
  92. package/dist/cli/commands/message.d.ts.map +1 -0
  93. package/dist/cli/commands/message.js +608 -0
  94. package/dist/cli/commands/message.js.map +1 -0
  95. package/dist/cli/commands/plan.d.ts +17 -0
  96. package/dist/cli/commands/plan.d.ts.map +1 -0
  97. package/dist/cli/commands/plan.js +698 -0
  98. package/dist/cli/commands/plan.js.map +1 -0
  99. package/dist/cli/commands/playbook.d.ts +12 -0
  100. package/dist/cli/commands/playbook.d.ts.map +1 -0
  101. package/dist/cli/commands/playbook.js +730 -0
  102. package/dist/cli/commands/playbook.js.map +1 -0
  103. package/dist/cli/commands/reset.d.ts +12 -0
  104. package/dist/cli/commands/reset.d.ts.map +1 -0
  105. package/dist/cli/commands/reset.js +306 -0
  106. package/dist/cli/commands/reset.js.map +1 -0
  107. package/dist/cli/commands/serve.d.ts +11 -0
  108. package/dist/cli/commands/serve.d.ts.map +1 -0
  109. package/dist/cli/commands/serve.js +106 -0
  110. package/dist/cli/commands/serve.js.map +1 -0
  111. package/dist/cli/commands/stats.d.ts +8 -0
  112. package/dist/cli/commands/stats.d.ts.map +1 -0
  113. package/dist/cli/commands/stats.js +82 -0
  114. package/dist/cli/commands/stats.js.map +1 -0
  115. package/dist/cli/commands/sync.d.ts +14 -0
  116. package/dist/cli/commands/sync.d.ts.map +1 -0
  117. package/dist/cli/commands/sync.js +370 -0
  118. package/dist/cli/commands/sync.js.map +1 -0
  119. package/dist/cli/commands/task.d.ts +25 -0
  120. package/dist/cli/commands/task.d.ts.map +1 -0
  121. package/dist/cli/commands/task.js +1153 -0
  122. package/dist/cli/commands/task.js.map +1 -0
  123. package/dist/cli/commands/team.d.ts +13 -0
  124. package/dist/cli/commands/team.d.ts.map +1 -0
  125. package/dist/cli/commands/team.js +471 -0
  126. package/dist/cli/commands/team.js.map +1 -0
  127. package/dist/cli/commands/workflow.d.ts +16 -0
  128. package/dist/cli/commands/workflow.d.ts.map +1 -0
  129. package/dist/cli/commands/workflow.js +753 -0
  130. package/dist/cli/commands/workflow.js.map +1 -0
  131. package/dist/cli/completion.d.ts +28 -0
  132. package/dist/cli/completion.d.ts.map +1 -0
  133. package/dist/cli/completion.js +295 -0
  134. package/dist/cli/completion.js.map +1 -0
  135. package/dist/cli/db.d.ts +38 -0
  136. package/dist/cli/db.d.ts.map +1 -0
  137. package/dist/cli/db.js +90 -0
  138. package/dist/cli/db.js.map +1 -0
  139. package/dist/cli/formatter.d.ts +87 -0
  140. package/dist/cli/formatter.d.ts.map +1 -0
  141. package/dist/cli/formatter.js +464 -0
  142. package/dist/cli/formatter.js.map +1 -0
  143. package/dist/cli/index.d.ts +33 -0
  144. package/dist/cli/index.d.ts.map +1 -0
  145. package/dist/cli/index.js +38 -0
  146. package/dist/cli/index.js.map +1 -0
  147. package/dist/cli/parser.d.ts +45 -0
  148. package/dist/cli/parser.d.ts.map +1 -0
  149. package/dist/cli/parser.js +256 -0
  150. package/dist/cli/parser.js.map +1 -0
  151. package/dist/cli/plugin-loader.d.ts +39 -0
  152. package/dist/cli/plugin-loader.d.ts.map +1 -0
  153. package/dist/cli/plugin-loader.js +165 -0
  154. package/dist/cli/plugin-loader.js.map +1 -0
  155. package/dist/cli/plugin-registry.d.ts +50 -0
  156. package/dist/cli/plugin-registry.d.ts.map +1 -0
  157. package/dist/cli/plugin-registry.js +206 -0
  158. package/dist/cli/plugin-registry.js.map +1 -0
  159. package/dist/cli/plugin-types.d.ts +106 -0
  160. package/dist/cli/plugin-types.d.ts.map +1 -0
  161. package/dist/cli/plugin-types.js +103 -0
  162. package/dist/cli/plugin-types.js.map +1 -0
  163. package/dist/cli/runner.d.ts +35 -0
  164. package/dist/cli/runner.d.ts.map +1 -0
  165. package/dist/cli/runner.js +340 -0
  166. package/dist/cli/runner.js.map +1 -0
  167. package/dist/cli/suggest.d.ts +15 -0
  168. package/dist/cli/suggest.d.ts.map +1 -0
  169. package/dist/cli/suggest.js +49 -0
  170. package/dist/cli/suggest.js.map +1 -0
  171. package/dist/cli/types.d.ts +138 -0
  172. package/dist/cli/types.d.ts.map +1 -0
  173. package/dist/cli/types.js +63 -0
  174. package/dist/cli/types.js.map +1 -0
  175. package/dist/config/config.d.ts +86 -0
  176. package/dist/config/config.d.ts.map +1 -0
  177. package/dist/config/config.js +348 -0
  178. package/dist/config/config.js.map +1 -0
  179. package/dist/config/defaults.d.ts +66 -0
  180. package/dist/config/defaults.d.ts.map +1 -0
  181. package/dist/config/defaults.js +114 -0
  182. package/dist/config/defaults.js.map +1 -0
  183. package/dist/config/duration.d.ts +75 -0
  184. package/dist/config/duration.d.ts.map +1 -0
  185. package/dist/config/duration.js +190 -0
  186. package/dist/config/duration.js.map +1 -0
  187. package/dist/config/env.d.ts +67 -0
  188. package/dist/config/env.d.ts.map +1 -0
  189. package/dist/config/env.js +207 -0
  190. package/dist/config/env.js.map +1 -0
  191. package/dist/config/file.d.ts +97 -0
  192. package/dist/config/file.d.ts.map +1 -0
  193. package/dist/config/file.js +365 -0
  194. package/dist/config/file.js.map +1 -0
  195. package/dist/config/index.d.ts +35 -0
  196. package/dist/config/index.d.ts.map +1 -0
  197. package/dist/config/index.js +41 -0
  198. package/dist/config/index.js.map +1 -0
  199. package/dist/config/merge.d.ts +53 -0
  200. package/dist/config/merge.d.ts.map +1 -0
  201. package/dist/config/merge.js +226 -0
  202. package/dist/config/merge.js.map +1 -0
  203. package/dist/config/types.d.ts +257 -0
  204. package/dist/config/types.d.ts.map +1 -0
  205. package/dist/config/types.js +72 -0
  206. package/dist/config/types.js.map +1 -0
  207. package/dist/config/validation.d.ts +55 -0
  208. package/dist/config/validation.d.ts.map +1 -0
  209. package/dist/config/validation.js +251 -0
  210. package/dist/config/validation.js.map +1 -0
  211. package/dist/http/index.d.ts +8 -0
  212. package/dist/http/index.d.ts.map +1 -0
  213. package/dist/http/index.js +12 -0
  214. package/dist/http/index.js.map +1 -0
  215. package/dist/http/sync-handlers.d.ts +162 -0
  216. package/dist/http/sync-handlers.d.ts.map +1 -0
  217. package/dist/http/sync-handlers.js +271 -0
  218. package/dist/http/sync-handlers.js.map +1 -0
  219. package/dist/index.d.ts +25 -0
  220. package/dist/index.d.ts.map +1 -0
  221. package/dist/index.js +69 -0
  222. package/dist/index.js.map +1 -0
  223. package/dist/server/index.d.ts +34 -0
  224. package/dist/server/index.d.ts.map +1 -0
  225. package/dist/server/index.js +3329 -0
  226. package/dist/server/index.js.map +1 -0
  227. package/dist/server/static.d.ts +18 -0
  228. package/dist/server/static.d.ts.map +1 -0
  229. package/dist/server/static.js +71 -0
  230. package/dist/server/static.js.map +1 -0
  231. package/dist/server/ws/broadcaster.d.ts +8 -0
  232. package/dist/server/ws/broadcaster.d.ts.map +1 -0
  233. package/dist/server/ws/broadcaster.js +7 -0
  234. package/dist/server/ws/broadcaster.js.map +1 -0
  235. package/dist/server/ws/handler.d.ts +55 -0
  236. package/dist/server/ws/handler.d.ts.map +1 -0
  237. package/dist/server/ws/handler.js +160 -0
  238. package/dist/server/ws/handler.js.map +1 -0
  239. package/dist/services/blocked-cache.d.ts +297 -0
  240. package/dist/services/blocked-cache.d.ts.map +1 -0
  241. package/dist/services/blocked-cache.js +755 -0
  242. package/dist/services/blocked-cache.js.map +1 -0
  243. package/dist/services/dependency.d.ts +205 -0
  244. package/dist/services/dependency.d.ts.map +1 -0
  245. package/dist/services/dependency.js +566 -0
  246. package/dist/services/dependency.js.map +1 -0
  247. package/dist/services/embeddings/fusion.d.ts +33 -0
  248. package/dist/services/embeddings/fusion.d.ts.map +1 -0
  249. package/dist/services/embeddings/fusion.js +34 -0
  250. package/dist/services/embeddings/fusion.js.map +1 -0
  251. package/dist/services/embeddings/index.d.ts +12 -0
  252. package/dist/services/embeddings/index.d.ts.map +1 -0
  253. package/dist/services/embeddings/index.js +10 -0
  254. package/dist/services/embeddings/index.js.map +1 -0
  255. package/dist/services/embeddings/local-provider.d.ts +31 -0
  256. package/dist/services/embeddings/local-provider.d.ts.map +1 -0
  257. package/dist/services/embeddings/local-provider.js +80 -0
  258. package/dist/services/embeddings/local-provider.js.map +1 -0
  259. package/dist/services/embeddings/service.d.ts +76 -0
  260. package/dist/services/embeddings/service.d.ts.map +1 -0
  261. package/dist/services/embeddings/service.js +153 -0
  262. package/dist/services/embeddings/service.js.map +1 -0
  263. package/dist/services/embeddings/types.d.ts +70 -0
  264. package/dist/services/embeddings/types.d.ts.map +1 -0
  265. package/dist/services/embeddings/types.js +8 -0
  266. package/dist/services/embeddings/types.js.map +1 -0
  267. package/dist/services/id-length-cache.d.ts +156 -0
  268. package/dist/services/id-length-cache.d.ts.map +1 -0
  269. package/dist/services/id-length-cache.js +197 -0
  270. package/dist/services/id-length-cache.js.map +1 -0
  271. package/dist/services/inbox.d.ts +147 -0
  272. package/dist/services/inbox.d.ts.map +1 -0
  273. package/dist/services/inbox.js +428 -0
  274. package/dist/services/inbox.js.map +1 -0
  275. package/dist/services/index.d.ts +10 -0
  276. package/dist/services/index.d.ts.map +1 -0
  277. package/dist/services/index.js +10 -0
  278. package/dist/services/index.js.map +1 -0
  279. package/dist/services/priority-service.d.ts +145 -0
  280. package/dist/services/priority-service.d.ts.map +1 -0
  281. package/dist/services/priority-service.js +272 -0
  282. package/dist/services/priority-service.js.map +1 -0
  283. package/dist/services/search-utils.d.ts +47 -0
  284. package/dist/services/search-utils.d.ts.map +1 -0
  285. package/dist/services/search-utils.js +83 -0
  286. package/dist/services/search-utils.js.map +1 -0
  287. package/dist/sync/hash.d.ts +48 -0
  288. package/dist/sync/hash.d.ts.map +1 -0
  289. package/dist/sync/hash.js +136 -0
  290. package/dist/sync/hash.js.map +1 -0
  291. package/dist/sync/index.d.ts +11 -0
  292. package/dist/sync/index.d.ts.map +1 -0
  293. package/dist/sync/index.js +16 -0
  294. package/dist/sync/index.js.map +1 -0
  295. package/dist/sync/merge.d.ts +80 -0
  296. package/dist/sync/merge.d.ts.map +1 -0
  297. package/dist/sync/merge.js +310 -0
  298. package/dist/sync/merge.js.map +1 -0
  299. package/dist/sync/serialization.d.ts +132 -0
  300. package/dist/sync/serialization.d.ts.map +1 -0
  301. package/dist/sync/serialization.js +306 -0
  302. package/dist/sync/serialization.js.map +1 -0
  303. package/dist/sync/service.d.ts +102 -0
  304. package/dist/sync/service.d.ts.map +1 -0
  305. package/dist/sync/service.js +493 -0
  306. package/dist/sync/service.js.map +1 -0
  307. package/dist/sync/types.d.ts +275 -0
  308. package/dist/sync/types.d.ts.map +1 -0
  309. package/dist/sync/types.js +76 -0
  310. package/dist/sync/types.js.map +1 -0
  311. package/dist/systems/identity.d.ts +479 -0
  312. package/dist/systems/identity.d.ts.map +1 -0
  313. package/dist/systems/identity.js +817 -0
  314. package/dist/systems/identity.js.map +1 -0
  315. package/dist/systems/index.d.ts +8 -0
  316. package/dist/systems/index.d.ts.map +1 -0
  317. package/dist/systems/index.js +29 -0
  318. package/dist/systems/index.js.map +1 -0
  319. package/package.json +121 -0
  320. package/web/assets/charts-vendor-D1YcbGux.js +55 -0
  321. package/web/assets/dnd-vendor-DmxE-_ZH.js +5 -0
  322. package/web/assets/editor-vendor-BxraAWts.js +279 -0
  323. package/web/assets/index-B77vv208.js +341 -0
  324. package/web/assets/index-CF_XnVLh.css +1 -0
  325. package/web/assets/router-vendor-BCKpRBrB.js +41 -0
  326. package/web/assets/ui-vendor-DUahGnbT.js +45 -0
  327. package/web/assets/utils-vendor-CfYKiENT.js +813 -0
  328. package/web/favicon.ico +0 -0
  329. package/web/index.html +23 -0
  330. package/web/logo.png +0 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Merge Strategy - Conflict resolution for sync operations
3
+ *
4
+ * Implements Last-Write-Wins (LWW) strategy with special handling for:
5
+ * - Tombstones (soft deletes)
6
+ * - Status fields (closed wins over open)
7
+ * - Tags (set union merge)
8
+ * - Dependencies (removal is authoritative)
9
+ */
10
+ import type { Element, Dependency } from '@stoneforge/core';
11
+ import { MergeResolution, TombstoneStatus, type ConflictRecord, type DependencyConflictRecord } from './types.js';
12
+ /**
13
+ * Merge result for elements
14
+ */
15
+ export interface ElementMergeResult {
16
+ /** The winning element */
17
+ element: Element;
18
+ /** How the merge was resolved */
19
+ resolution: MergeResolution;
20
+ /** Whether local element was modified */
21
+ localModified: boolean;
22
+ /** Conflict record if there was a conflict */
23
+ conflict?: ConflictRecord;
24
+ }
25
+ /**
26
+ * Merge two versions of an element using Last-Write-Wins strategy
27
+ *
28
+ * Special cases:
29
+ * - Identical content hash: Skip (no conflict)
30
+ * - Tombstone handling: Fresh tombstone wins over live
31
+ * - Status merge: Closed wins over open states
32
+ * - Tags merge: Union of both tag sets
33
+ *
34
+ * @param local - Local element
35
+ * @param remote - Remote element (from import)
36
+ * @param tombstoneTtl - Tombstone TTL in milliseconds (default: 30 days)
37
+ * @returns Merge result
38
+ */
39
+ export declare function mergeElements(local: Element, remote: Element, tombstoneTtl?: number): ElementMergeResult;
40
+ /**
41
+ * Get tombstone status for an element
42
+ */
43
+ export declare function getTombstoneStatus(element: Element, ttlMs: number): TombstoneStatus;
44
+ /**
45
+ * Merge two tag arrays using set union
46
+ * Never loses a tag in merge
47
+ *
48
+ * @param localTags - Local tags
49
+ * @param remoteTags - Remote tags
50
+ * @returns Merged tags (sorted for determinism)
51
+ */
52
+ export declare function mergeTags(localTags: string[], remoteTags: string[]): string[];
53
+ /**
54
+ * Dependency merge result
55
+ */
56
+ export interface DependencyMergeResult {
57
+ /** Dependencies to keep */
58
+ keep: Dependency[];
59
+ /** Dependencies that were added */
60
+ added: Dependency[];
61
+ /** Dependencies that were removed */
62
+ removed: Dependency[];
63
+ /** Conflict records */
64
+ conflicts: DependencyConflictRecord[];
65
+ }
66
+ /**
67
+ * Merge dependencies between local and remote
68
+ *
69
+ * Rules:
70
+ * - Removal is authoritative (if one side removed, it's removed)
71
+ * - Additions from both sides kept
72
+ * - No duplicate dependencies
73
+ *
74
+ * @param localDeps - Local dependencies
75
+ * @param remoteDeps - Remote dependencies
76
+ * @param originalDeps - Original dependencies (baseline for detecting removals)
77
+ * @returns Merge result
78
+ */
79
+ export declare function mergeDependencies(localDeps: Dependency[], remoteDeps: Dependency[], originalDeps?: Dependency[]): DependencyMergeResult;
80
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/sync/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAkB,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EACL,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAOpB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,iCAAiC;IACjC,UAAU,EAAE,eAAe,CAAC;IAC5B,yCAAyC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,EACf,YAAY,GAAE,MAAiC,GAC9C,kBAAkB,CAgDpB;AA0DD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAenF;AA2ED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG7E;AAMD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2BAA2B;IAC3B,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,mCAAmC;IACnC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,qCAAqC;IACrC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,uBAAuB;IACvB,SAAS,EAAE,wBAAwB,EAAE,CAAC;CACvC;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,UAAU,EAAE,EACvB,UAAU,EAAE,UAAU,EAAE,EACxB,YAAY,GAAE,UAAU,EAAO,GAC9B,qBAAqB,CAkEvB"}
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Merge Strategy - Conflict resolution for sync operations
3
+ *
4
+ * Implements Last-Write-Wins (LWW) strategy with special handling for:
5
+ * - Tombstones (soft deletes)
6
+ * - Status fields (closed wins over open)
7
+ * - Tags (set union merge)
8
+ * - Dependencies (removal is authoritative)
9
+ */
10
+ import { createTimestamp } from '@stoneforge/core';
11
+ import { MergeResolution, TombstoneStatus, } from './types.js';
12
+ import { computeContentHashSync } from './hash.js';
13
+ /**
14
+ * Merge two versions of an element using Last-Write-Wins strategy
15
+ *
16
+ * Special cases:
17
+ * - Identical content hash: Skip (no conflict)
18
+ * - Tombstone handling: Fresh tombstone wins over live
19
+ * - Status merge: Closed wins over open states
20
+ * - Tags merge: Union of both tag sets
21
+ *
22
+ * @param local - Local element
23
+ * @param remote - Remote element (from import)
24
+ * @param tombstoneTtl - Tombstone TTL in milliseconds (default: 30 days)
25
+ * @returns Merge result
26
+ */
27
+ export function mergeElements(local, remote, tombstoneTtl = 30 * 24 * 60 * 60 * 1000) {
28
+ // Compute content hashes
29
+ const localHash = computeContentHashSync(local);
30
+ const remoteHash = computeContentHashSync(remote);
31
+ // Same content - no conflict
32
+ if (localHash.hash === remoteHash.hash) {
33
+ return {
34
+ element: local,
35
+ resolution: MergeResolution.IDENTICAL,
36
+ localModified: false,
37
+ };
38
+ }
39
+ // Get tombstone status for both
40
+ const localTombstone = getTombstoneStatus(local, tombstoneTtl);
41
+ const remoteTombstone = getTombstoneStatus(remote, tombstoneTtl);
42
+ // Apply tombstone merge rules
43
+ const tombstoneResolution = resolveTombstoneConflict(localTombstone, remoteTombstone);
44
+ if (tombstoneResolution !== null) {
45
+ const winner = tombstoneResolution === 'local' ? local : remote;
46
+ const resolution = tombstoneResolution === 'local' ? MergeResolution.LOCAL_WINS : MergeResolution.REMOTE_WINS;
47
+ return {
48
+ element: winner,
49
+ resolution,
50
+ localModified: tombstoneResolution === 'remote',
51
+ conflict: createConflictRecord(local, remote, localHash.hash, remoteHash.hash, resolution),
52
+ };
53
+ }
54
+ // Both are live elements - apply LWW with special handling
55
+ const merged = mergeLiveElements(local, remote);
56
+ return {
57
+ element: merged.element,
58
+ resolution: merged.resolution,
59
+ localModified: merged.resolution !== MergeResolution.LOCAL_WINS,
60
+ conflict: createConflictRecord(local, remote, localHash.hash, remoteHash.hash, merged.resolution),
61
+ };
62
+ }
63
+ /**
64
+ * Merge two live (non-tombstone) elements
65
+ */
66
+ function mergeLiveElements(local, remote) {
67
+ // Apply status merge rules first
68
+ const statusResolution = resolveStatusConflict(local, remote);
69
+ if (statusResolution !== null) {
70
+ return {
71
+ element: statusResolution === 'local' ? local : remote,
72
+ resolution: statusResolution === 'local' ? MergeResolution.LOCAL_WINS : MergeResolution.REMOTE_WINS,
73
+ };
74
+ }
75
+ // LWW by updatedAt timestamp
76
+ const localTime = new Date(local.updatedAt).getTime();
77
+ const remoteTime = new Date(remote.updatedAt).getTime();
78
+ if (localTime >= remoteTime) {
79
+ // Local wins - but merge tags
80
+ const mergedTags = mergeTags(local.tags, remote.tags);
81
+ if (arraysEqual(mergedTags, local.tags)) {
82
+ return {
83
+ element: local,
84
+ resolution: MergeResolution.LOCAL_WINS,
85
+ };
86
+ }
87
+ // Tags were merged
88
+ return {
89
+ element: { ...local, tags: mergedTags },
90
+ resolution: MergeResolution.TAGS_MERGED,
91
+ };
92
+ }
93
+ // Remote wins - but merge tags
94
+ const mergedTags = mergeTags(local.tags, remote.tags);
95
+ if (arraysEqual(mergedTags, remote.tags)) {
96
+ return {
97
+ element: remote,
98
+ resolution: MergeResolution.REMOTE_WINS,
99
+ };
100
+ }
101
+ // Tags were merged
102
+ return {
103
+ element: { ...remote, tags: mergedTags },
104
+ resolution: MergeResolution.TAGS_MERGED,
105
+ };
106
+ }
107
+ // ============================================================================
108
+ // Tombstone Handling
109
+ // ============================================================================
110
+ /**
111
+ * Get tombstone status for an element
112
+ */
113
+ export function getTombstoneStatus(element, ttlMs) {
114
+ // Check for deletedAt field (tombstone marker)
115
+ const record = element;
116
+ const deletedAt = record.deletedAt;
117
+ if (!deletedAt || typeof deletedAt !== 'string') {
118
+ return TombstoneStatus.LIVE;
119
+ }
120
+ // Check if within TTL
121
+ const deletedTime = new Date(deletedAt).getTime();
122
+ const now = Date.now();
123
+ const age = now - deletedTime;
124
+ return age <= ttlMs ? TombstoneStatus.FRESH : TombstoneStatus.EXPIRED;
125
+ }
126
+ /**
127
+ * Resolve conflict between elements with different tombstone statuses
128
+ *
129
+ * @returns 'local', 'remote', or null if both live/need further resolution
130
+ */
131
+ function resolveTombstoneConflict(local, remote) {
132
+ // Both live - no tombstone conflict
133
+ if (local === TombstoneStatus.LIVE && remote === TombstoneStatus.LIVE) {
134
+ return null;
135
+ }
136
+ // Fresh tombstone wins over live
137
+ if (local === TombstoneStatus.FRESH && remote === TombstoneStatus.LIVE) {
138
+ return 'local';
139
+ }
140
+ if (remote === TombstoneStatus.FRESH && local === TombstoneStatus.LIVE) {
141
+ return 'remote';
142
+ }
143
+ // Expired tombstone loses to live
144
+ if (local === TombstoneStatus.EXPIRED && remote === TombstoneStatus.LIVE) {
145
+ return 'remote';
146
+ }
147
+ if (remote === TombstoneStatus.EXPIRED && local === TombstoneStatus.LIVE) {
148
+ return 'local';
149
+ }
150
+ // Both tombstones - later deletedAt wins (handled by LWW in caller)
151
+ return null;
152
+ }
153
+ // ============================================================================
154
+ // Status Merge
155
+ // ============================================================================
156
+ /**
157
+ * Resolve status conflict - closed always wins over open states
158
+ *
159
+ * @returns 'local', 'remote', or null if no status-based resolution
160
+ */
161
+ function resolveStatusConflict(local, remote) {
162
+ const localStatus = local.status;
163
+ const remoteStatus = remote.status;
164
+ // Only applies to elements with status
165
+ if (typeof localStatus !== 'string' || typeof remoteStatus !== 'string') {
166
+ return null;
167
+ }
168
+ const closedStatuses = ['closed', 'tombstone'];
169
+ const localClosed = closedStatuses.includes(localStatus);
170
+ const remoteClosed = closedStatuses.includes(remoteStatus);
171
+ // Closed wins over open
172
+ if (localClosed && !remoteClosed) {
173
+ return 'local';
174
+ }
175
+ if (remoteClosed && !localClosed) {
176
+ return 'remote';
177
+ }
178
+ // Both same state - no status-based resolution
179
+ return null;
180
+ }
181
+ // ============================================================================
182
+ // Tags Merge
183
+ // ============================================================================
184
+ /**
185
+ * Merge two tag arrays using set union
186
+ * Never loses a tag in merge
187
+ *
188
+ * @param localTags - Local tags
189
+ * @param remoteTags - Remote tags
190
+ * @returns Merged tags (sorted for determinism)
191
+ */
192
+ export function mergeTags(localTags, remoteTags) {
193
+ const merged = new Set([...localTags, ...remoteTags]);
194
+ return [...merged].sort();
195
+ }
196
+ /**
197
+ * Dependency key for comparison
198
+ */
199
+ function getDependencyKey(dep) {
200
+ return `${dep.blockedId}|${dep.blockerId}|${dep.type}`;
201
+ }
202
+ /**
203
+ * Merge dependencies between local and remote
204
+ *
205
+ * Rules:
206
+ * - Removal is authoritative (if one side removed, it's removed)
207
+ * - Additions from both sides kept
208
+ * - No duplicate dependencies
209
+ *
210
+ * @param localDeps - Local dependencies
211
+ * @param remoteDeps - Remote dependencies
212
+ * @param originalDeps - Original dependencies (baseline for detecting removals)
213
+ * @returns Merge result
214
+ */
215
+ export function mergeDependencies(localDeps, remoteDeps, originalDeps = []) {
216
+ const localMap = new Map(localDeps.map((d) => [getDependencyKey(d), d]));
217
+ const remoteMap = new Map(remoteDeps.map((d) => [getDependencyKey(d), d]));
218
+ const originalMap = new Map(originalDeps.map((d) => [getDependencyKey(d), d]));
219
+ const keep = [];
220
+ const added = [];
221
+ const removed = [];
222
+ const conflicts = [];
223
+ // Track all keys
224
+ const allKeys = new Set([...localMap.keys(), ...remoteMap.keys()]);
225
+ for (const key of allKeys) {
226
+ const local = localMap.get(key);
227
+ const remote = remoteMap.get(key);
228
+ const original = originalMap.get(key);
229
+ if (local && remote) {
230
+ // Both have it - keep (prefer remote if different for consistency)
231
+ keep.push(remote);
232
+ }
233
+ else if (local && !remote) {
234
+ // Only local has it
235
+ if (original) {
236
+ // Was in original, remote removed it - honor removal
237
+ removed.push(local);
238
+ conflicts.push({
239
+ blockedId: local.blockedId,
240
+ blockerId: local.blockerId,
241
+ type: local.type,
242
+ resolution: 'removed',
243
+ resolvedAt: createTimestamp(),
244
+ });
245
+ }
246
+ else {
247
+ // New in local - keep
248
+ keep.push(local);
249
+ added.push(local);
250
+ }
251
+ }
252
+ else if (!local && remote) {
253
+ // Only remote has it
254
+ if (original) {
255
+ // Was in original, local removed it - honor removal
256
+ removed.push(remote);
257
+ conflicts.push({
258
+ blockedId: remote.blockedId,
259
+ blockerId: remote.blockerId,
260
+ type: remote.type,
261
+ resolution: 'removed',
262
+ resolvedAt: createTimestamp(),
263
+ });
264
+ }
265
+ else {
266
+ // New in remote - add
267
+ keep.push(remote);
268
+ added.push(remote);
269
+ conflicts.push({
270
+ blockedId: remote.blockedId,
271
+ blockerId: remote.blockerId,
272
+ type: remote.type,
273
+ resolution: 'added',
274
+ resolvedAt: createTimestamp(),
275
+ });
276
+ }
277
+ }
278
+ }
279
+ return { keep, added, removed, conflicts };
280
+ }
281
+ // ============================================================================
282
+ // Helpers
283
+ // ============================================================================
284
+ /**
285
+ * Create a conflict record
286
+ */
287
+ function createConflictRecord(local, remote, localHash, remoteHash, resolution) {
288
+ return {
289
+ elementId: local.id,
290
+ localHash,
291
+ remoteHash,
292
+ resolution,
293
+ localUpdatedAt: local.updatedAt,
294
+ remoteUpdatedAt: remote.updatedAt,
295
+ resolvedAt: createTimestamp(),
296
+ };
297
+ }
298
+ /**
299
+ * Check if two string arrays are equal (order-sensitive)
300
+ */
301
+ function arraysEqual(a, b) {
302
+ if (a.length !== b.length)
303
+ return false;
304
+ for (let i = 0; i < a.length; i++) {
305
+ if (a[i] !== b[i])
306
+ return false;
307
+ }
308
+ return true;
309
+ }
310
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/sync/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Sync Serialization - JSONL format serialization and parsing
3
+ *
4
+ * Handles conversion between Element/Dependency objects and JSONL format.
5
+ * All timestamps are normalized to ISO 8601 format.
6
+ */
7
+ import type { Element, Dependency } from '@stoneforge/core';
8
+ import type { SerializedElement, SerializedDependency } from './types.js';
9
+ /**
10
+ * Serialize an element to JSONL format
11
+ *
12
+ * @param element - Element to serialize
13
+ * @returns JSON string ready for JSONL file
14
+ */
15
+ export declare function serializeElement(element: Element): string;
16
+ /**
17
+ * Parse a JSONL line into an element
18
+ *
19
+ * @param line - JSON string from JSONL file
20
+ * @returns Parsed element
21
+ * @throws ValidationError if parsing fails
22
+ */
23
+ export declare function parseElement(line: string): Element;
24
+ /**
25
+ * Try to parse a JSONL line into an element
26
+ *
27
+ * @param line - JSON string from JSONL file
28
+ * @returns Parsed element or null if invalid
29
+ */
30
+ export declare function tryParseElement(line: string): Element | null;
31
+ /**
32
+ * Serialize a dependency to JSONL format
33
+ *
34
+ * @param dependency - Dependency to serialize
35
+ * @returns JSON string ready for JSONL file
36
+ */
37
+ export declare function serializeDependency(dependency: Dependency): string;
38
+ /**
39
+ * Parse a JSONL line into a dependency
40
+ *
41
+ * @param line - JSON string from JSONL file
42
+ * @returns Parsed dependency
43
+ * @throws ValidationError if parsing fails
44
+ */
45
+ export declare function parseDependency(line: string): Dependency;
46
+ /**
47
+ * Try to parse a JSONL line into a dependency
48
+ *
49
+ * @param line - JSON string from JSONL file
50
+ * @returns Parsed dependency or null if invalid
51
+ */
52
+ export declare function tryParseDependency(line: string): Dependency | null;
53
+ /**
54
+ * Serialize multiple elements to JSONL content
55
+ *
56
+ * @param elements - Elements to serialize
57
+ * @returns JSONL content (multiple lines)
58
+ */
59
+ export declare function serializeElements(elements: Element[]): string;
60
+ /**
61
+ * Serialize multiple dependencies to JSONL content
62
+ *
63
+ * @param dependencies - Dependencies to serialize
64
+ * @returns JSONL content (multiple lines)
65
+ */
66
+ export declare function serializeDependencies(dependencies: Dependency[]): string;
67
+ /**
68
+ * Parse JSONL content into elements
69
+ *
70
+ * @param content - JSONL content (multiple lines)
71
+ * @returns Array of parsed elements and any errors
72
+ */
73
+ export declare function parseElements(content: string): {
74
+ elements: Element[];
75
+ errors: ParseError[];
76
+ };
77
+ /**
78
+ * Parse JSONL content into dependencies
79
+ *
80
+ * @param content - JSONL content (multiple lines)
81
+ * @returns Array of parsed dependencies and any errors
82
+ */
83
+ export declare function parseDependencies(content: string): {
84
+ dependencies: Dependency[];
85
+ errors: ParseError[];
86
+ };
87
+ /**
88
+ * Parse error info
89
+ */
90
+ export interface ParseError {
91
+ /** Line number (1-indexed) */
92
+ line: number;
93
+ /** Error message */
94
+ message: string;
95
+ /** Truncated line content */
96
+ content: string;
97
+ }
98
+ /**
99
+ * Sort elements for export ordering
100
+ *
101
+ * Order by:
102
+ * 1. Type (entities first for references)
103
+ * 2. Creation time
104
+ * 3. ID (for stability)
105
+ *
106
+ * @param elements - Elements to sort
107
+ * @returns Sorted elements (new array)
108
+ */
109
+ export declare function sortElementsForExport(elements: Element[]): Element[];
110
+ /**
111
+ * Sort dependencies for export ordering
112
+ *
113
+ * Order by:
114
+ * 1. Creation time
115
+ * 2. Blocked ID
116
+ * 3. Blocker ID
117
+ * 4. Type (for stability)
118
+ *
119
+ * @param dependencies - Dependencies to sort
120
+ * @returns Sorted dependencies (new array)
121
+ */
122
+ export declare function sortDependenciesForExport(dependencies: Dependency[]): Dependency[];
123
+ /**
124
+ * Check if an object looks like a serialized element
125
+ * (less strict than isElement, for initial parsing)
126
+ */
127
+ export declare function isSerializedElement(value: unknown): value is SerializedElement;
128
+ /**
129
+ * Check if an object looks like a serialized dependency
130
+ */
131
+ export declare function isSerializedDependency(value: unknown): value is SerializedDependency;
132
+ //# sourceMappingURL=serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/sync/serialization.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAO1E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAuBzD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAsBlD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAM5D;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAwBlE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA8BxD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAMlE;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAE7D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,MAAM,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAAE,CAmB5F;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAmBA;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAapE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAiBlF;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAkB9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAepF"}