@knpkv/confluence-to-markdown 0.2.0 → 0.4.1

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 (336) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +282 -14
  4. package/dist/ConfluenceAuth.d.ts +76 -0
  5. package/dist/ConfluenceAuth.d.ts.map +1 -0
  6. package/dist/ConfluenceAuth.js +356 -0
  7. package/dist/ConfluenceAuth.js.map +1 -0
  8. package/dist/ConfluenceClient.d.ts +26 -2
  9. package/dist/ConfluenceClient.d.ts.map +1 -1
  10. package/dist/ConfluenceClient.js +98 -92
  11. package/dist/ConfluenceClient.js.map +1 -1
  12. package/dist/ConfluenceConfig.d.ts +4 -24
  13. package/dist/ConfluenceConfig.d.ts.map +1 -1
  14. package/dist/ConfluenceConfig.js +45 -7
  15. package/dist/ConfluenceConfig.js.map +1 -1
  16. package/dist/ConfluenceError.d.ts +89 -6
  17. package/dist/ConfluenceError.d.ts.map +1 -1
  18. package/dist/ConfluenceError.js +88 -5
  19. package/dist/ConfluenceError.js.map +1 -1
  20. package/dist/GitError.d.ts +103 -0
  21. package/dist/GitError.d.ts.map +1 -0
  22. package/dist/GitError.js +85 -0
  23. package/dist/GitError.js.map +1 -0
  24. package/dist/GitService.d.ts +175 -0
  25. package/dist/GitService.d.ts.map +1 -0
  26. package/dist/GitService.js +431 -0
  27. package/dist/GitService.js.map +1 -0
  28. package/dist/LocalFileSystem.d.ts +29 -4
  29. package/dist/LocalFileSystem.d.ts.map +1 -1
  30. package/dist/LocalFileSystem.js +80 -6
  31. package/dist/LocalFileSystem.js.map +1 -1
  32. package/dist/MarkdownConverter.d.ts +49 -2
  33. package/dist/MarkdownConverter.d.ts.map +1 -1
  34. package/dist/MarkdownConverter.js +73 -111
  35. package/dist/MarkdownConverter.js.map +1 -1
  36. package/dist/SchemaConverterError.d.ts +108 -0
  37. package/dist/SchemaConverterError.d.ts.map +1 -0
  38. package/dist/SchemaConverterError.js +84 -0
  39. package/dist/SchemaConverterError.js.map +1 -0
  40. package/dist/Schemas.d.ts +225 -1
  41. package/dist/Schemas.d.ts.map +1 -1
  42. package/dist/Schemas.js +155 -6
  43. package/dist/Schemas.js.map +1 -1
  44. package/dist/SyncEngine.d.ts +30 -20
  45. package/dist/SyncEngine.d.ts.map +1 -1
  46. package/dist/SyncEngine.js +566 -117
  47. package/dist/SyncEngine.js.map +1 -1
  48. package/dist/ast/BlockNode.d.ts +468 -0
  49. package/dist/ast/BlockNode.d.ts.map +1 -0
  50. package/dist/ast/BlockNode.js +319 -0
  51. package/dist/ast/BlockNode.js.map +1 -0
  52. package/dist/ast/Document.d.ts +244 -0
  53. package/dist/ast/Document.d.ts.map +1 -0
  54. package/dist/ast/Document.js +69 -0
  55. package/dist/ast/Document.js.map +1 -0
  56. package/dist/ast/InlineNode.d.ts +477 -0
  57. package/dist/ast/InlineNode.d.ts.map +1 -0
  58. package/dist/ast/InlineNode.js +263 -0
  59. package/dist/ast/InlineNode.js.map +1 -0
  60. package/dist/ast/MacroNode.d.ts +267 -0
  61. package/dist/ast/MacroNode.d.ts.map +1 -0
  62. package/dist/ast/MacroNode.js +164 -0
  63. package/dist/ast/MacroNode.js.map +1 -0
  64. package/dist/ast/index.d.ts +10 -0
  65. package/dist/ast/index.d.ts.map +1 -0
  66. package/dist/ast/index.js +14 -0
  67. package/dist/ast/index.js.map +1 -0
  68. package/dist/bin.js +33 -149
  69. package/dist/bin.js.map +1 -1
  70. package/dist/commands/auth.d.ts +15 -0
  71. package/dist/commands/auth.d.ts.map +1 -0
  72. package/dist/commands/auth.js +86 -0
  73. package/dist/commands/auth.js.map +1 -0
  74. package/dist/commands/clone.d.ts +12 -0
  75. package/dist/commands/clone.d.ts.map +1 -0
  76. package/dist/commands/clone.js +93 -0
  77. package/dist/commands/clone.js.map +1 -0
  78. package/dist/commands/delete.d.ts +13 -0
  79. package/dist/commands/delete.d.ts.map +1 -0
  80. package/dist/commands/delete.js +48 -0
  81. package/dist/commands/delete.js.map +1 -0
  82. package/dist/commands/errorHandler.d.ts +14 -0
  83. package/dist/commands/errorHandler.d.ts.map +1 -0
  84. package/dist/commands/errorHandler.js +33 -0
  85. package/dist/commands/errorHandler.js.map +1 -0
  86. package/dist/commands/git.d.ts +22 -0
  87. package/dist/commands/git.d.ts.map +1 -0
  88. package/dist/commands/git.js +72 -0
  89. package/dist/commands/git.js.map +1 -0
  90. package/dist/commands/index.d.ts +11 -0
  91. package/dist/commands/index.d.ts.map +1 -0
  92. package/dist/commands/index.js +11 -0
  93. package/dist/commands/index.js.map +1 -0
  94. package/dist/commands/layers.d.ts +31 -0
  95. package/dist/commands/layers.d.ts.map +1 -0
  96. package/dist/commands/layers.js +137 -0
  97. package/dist/commands/layers.js.map +1 -0
  98. package/dist/commands/new.d.ts +9 -0
  99. package/dist/commands/new.d.ts.map +1 -0
  100. package/dist/commands/new.js +80 -0
  101. package/dist/commands/new.js.map +1 -0
  102. package/dist/commands/pageTree.d.ts +18 -0
  103. package/dist/commands/pageTree.d.ts.map +1 -0
  104. package/dist/commands/pageTree.js +20 -0
  105. package/dist/commands/pageTree.js.map +1 -0
  106. package/dist/commands/shared.d.ts +15 -0
  107. package/dist/commands/shared.d.ts.map +1 -0
  108. package/dist/commands/shared.js +27 -0
  109. package/dist/commands/shared.js.map +1 -0
  110. package/dist/commands/sync.d.ts +15 -0
  111. package/dist/commands/sync.d.ts.map +1 -0
  112. package/dist/commands/sync.js +101 -0
  113. package/dist/commands/sync.js.map +1 -0
  114. package/dist/index.d.ts +10 -1
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +14 -0
  117. package/dist/index.js.map +1 -1
  118. package/dist/internal/NodeLayers.d.ts +7 -0
  119. package/dist/internal/NodeLayers.d.ts.map +1 -0
  120. package/dist/internal/NodeLayers.js +19 -0
  121. package/dist/internal/NodeLayers.js.map +1 -0
  122. package/dist/internal/frontmatter.d.ts +10 -0
  123. package/dist/internal/frontmatter.d.ts.map +1 -1
  124. package/dist/internal/frontmatter.js +16 -0
  125. package/dist/internal/frontmatter.js.map +1 -1
  126. package/dist/internal/gitCommands.d.ts +78 -0
  127. package/dist/internal/gitCommands.d.ts.map +1 -0
  128. package/dist/internal/gitCommands.js +156 -0
  129. package/dist/internal/gitCommands.js.map +1 -0
  130. package/dist/internal/hashUtils.d.ts +42 -1
  131. package/dist/internal/hashUtils.d.ts.map +1 -1
  132. package/dist/internal/hashUtils.js +38 -2
  133. package/dist/internal/hashUtils.js.map +1 -1
  134. package/dist/internal/oauthServer.d.ts +55 -0
  135. package/dist/internal/oauthServer.d.ts.map +1 -0
  136. package/dist/internal/oauthServer.js +110 -0
  137. package/dist/internal/oauthServer.js.map +1 -0
  138. package/dist/internal/pathUtils.d.ts +21 -4
  139. package/dist/internal/pathUtils.d.ts.map +1 -1
  140. package/dist/internal/pathUtils.js +24 -13
  141. package/dist/internal/pathUtils.js.map +1 -1
  142. package/dist/internal/tokenStorage.d.ts +75 -0
  143. package/dist/internal/tokenStorage.d.ts.map +1 -0
  144. package/dist/internal/tokenStorage.js +149 -0
  145. package/dist/internal/tokenStorage.js.map +1 -0
  146. package/dist/internal/userCache.d.ts +42 -0
  147. package/dist/internal/userCache.d.ts.map +1 -0
  148. package/dist/internal/userCache.js +51 -0
  149. package/dist/internal/userCache.js.map +1 -0
  150. package/dist/parsers/ConfluenceParser.d.ts +26 -0
  151. package/dist/parsers/ConfluenceParser.d.ts.map +1 -0
  152. package/dist/parsers/ConfluenceParser.js +792 -0
  153. package/dist/parsers/ConfluenceParser.js.map +1 -0
  154. package/dist/parsers/MarkdownParser.d.ts +26 -0
  155. package/dist/parsers/MarkdownParser.d.ts.map +1 -0
  156. package/dist/parsers/MarkdownParser.js +873 -0
  157. package/dist/parsers/MarkdownParser.js.map +1 -0
  158. package/dist/parsers/index.d.ts +8 -0
  159. package/dist/parsers/index.d.ts.map +1 -0
  160. package/dist/parsers/index.js +8 -0
  161. package/dist/parsers/index.js.map +1 -0
  162. package/dist/schemas/ConfluenceSchema.d.ts +21 -0
  163. package/dist/schemas/ConfluenceSchema.d.ts.map +1 -0
  164. package/dist/schemas/ConfluenceSchema.js +38 -0
  165. package/dist/schemas/ConfluenceSchema.js.map +1 -0
  166. package/dist/schemas/ConversionSchema.d.ts +35 -0
  167. package/dist/schemas/ConversionSchema.d.ts.map +1 -0
  168. package/dist/schemas/ConversionSchema.js +208 -0
  169. package/dist/schemas/ConversionSchema.js.map +1 -0
  170. package/dist/schemas/MarkdownSchema.d.ts +21 -0
  171. package/dist/schemas/MarkdownSchema.d.ts.map +1 -0
  172. package/dist/schemas/MarkdownSchema.js +38 -0
  173. package/dist/schemas/MarkdownSchema.js.map +1 -0
  174. package/dist/schemas/hast/HastFromHtml.d.ts +27 -0
  175. package/dist/schemas/hast/HastFromHtml.d.ts.map +1 -0
  176. package/dist/schemas/hast/HastFromHtml.js +107 -0
  177. package/dist/schemas/hast/HastFromHtml.js.map +1 -0
  178. package/dist/schemas/hast/HastSchema.d.ts +195 -0
  179. package/dist/schemas/hast/HastSchema.d.ts.map +1 -0
  180. package/dist/schemas/hast/HastSchema.js +183 -0
  181. package/dist/schemas/hast/HastSchema.js.map +1 -0
  182. package/dist/schemas/hast/index.d.ts +9 -0
  183. package/dist/schemas/hast/index.d.ts.map +1 -0
  184. package/dist/schemas/hast/index.js +3 -0
  185. package/dist/schemas/hast/index.js.map +1 -0
  186. package/dist/schemas/index.d.ts +14 -0
  187. package/dist/schemas/index.d.ts.map +1 -0
  188. package/dist/schemas/index.js +16 -0
  189. package/dist/schemas/index.js.map +1 -0
  190. package/dist/schemas/mdast/MdastFromMarkdown.d.ts +30 -0
  191. package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +1 -0
  192. package/dist/schemas/mdast/MdastFromMarkdown.js +79 -0
  193. package/dist/schemas/mdast/MdastFromMarkdown.js.map +1 -0
  194. package/dist/schemas/mdast/MdastSchema.d.ts +385 -0
  195. package/dist/schemas/mdast/MdastSchema.d.ts.map +1 -0
  196. package/dist/schemas/mdast/MdastSchema.js +266 -0
  197. package/dist/schemas/mdast/MdastSchema.js.map +1 -0
  198. package/dist/schemas/mdast/index.d.ts +10 -0
  199. package/dist/schemas/mdast/index.d.ts.map +1 -0
  200. package/dist/schemas/mdast/index.js +4 -0
  201. package/dist/schemas/mdast/index.js.map +1 -0
  202. package/dist/schemas/mdast/mdastToString.d.ts +13 -0
  203. package/dist/schemas/mdast/mdastToString.d.ts.map +1 -0
  204. package/dist/schemas/mdast/mdastToString.js +85 -0
  205. package/dist/schemas/mdast/mdastToString.js.map +1 -0
  206. package/dist/schemas/nodes/block/BlockSchema.d.ts +43 -0
  207. package/dist/schemas/nodes/block/BlockSchema.d.ts.map +1 -0
  208. package/dist/schemas/nodes/block/BlockSchema.js +634 -0
  209. package/dist/schemas/nodes/block/BlockSchema.js.map +1 -0
  210. package/dist/schemas/nodes/block/index.d.ts +7 -0
  211. package/dist/schemas/nodes/block/index.d.ts.map +1 -0
  212. package/dist/schemas/nodes/block/index.js +7 -0
  213. package/dist/schemas/nodes/block/index.js.map +1 -0
  214. package/dist/schemas/nodes/index.d.ts +9 -0
  215. package/dist/schemas/nodes/index.d.ts.map +1 -0
  216. package/dist/schemas/nodes/index.js +12 -0
  217. package/dist/schemas/nodes/index.js.map +1 -0
  218. package/dist/schemas/nodes/inline/InlineSchema.d.ts +48 -0
  219. package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +1 -0
  220. package/dist/schemas/nodes/inline/InlineSchema.js +436 -0
  221. package/dist/schemas/nodes/inline/InlineSchema.js.map +1 -0
  222. package/dist/schemas/nodes/inline/index.d.ts +7 -0
  223. package/dist/schemas/nodes/inline/index.d.ts.map +1 -0
  224. package/dist/schemas/nodes/inline/index.js +7 -0
  225. package/dist/schemas/nodes/inline/index.js.map +1 -0
  226. package/dist/schemas/nodes/macro/MacroSchema.d.ts +27 -0
  227. package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +1 -0
  228. package/dist/schemas/nodes/macro/MacroSchema.js +162 -0
  229. package/dist/schemas/nodes/macro/MacroSchema.js.map +1 -0
  230. package/dist/schemas/nodes/macro/index.d.ts +7 -0
  231. package/dist/schemas/nodes/macro/index.d.ts.map +1 -0
  232. package/dist/schemas/nodes/macro/index.js +7 -0
  233. package/dist/schemas/nodes/macro/index.js.map +1 -0
  234. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +24 -0
  235. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +1 -0
  236. package/dist/schemas/preprocessing/ConfluencePreprocessor.js +351 -0
  237. package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +1 -0
  238. package/dist/schemas/preprocessing/index.d.ts +8 -0
  239. package/dist/schemas/preprocessing/index.d.ts.map +1 -0
  240. package/dist/schemas/preprocessing/index.js +2 -0
  241. package/dist/schemas/preprocessing/index.js.map +1 -0
  242. package/dist/serializers/ConfluenceSerializer.d.ts +30 -0
  243. package/dist/serializers/ConfluenceSerializer.d.ts.map +1 -0
  244. package/dist/serializers/ConfluenceSerializer.js +551 -0
  245. package/dist/serializers/ConfluenceSerializer.js.map +1 -0
  246. package/dist/serializers/MarkdownSerializer.d.ts +34 -0
  247. package/dist/serializers/MarkdownSerializer.d.ts.map +1 -0
  248. package/dist/serializers/MarkdownSerializer.js +355 -0
  249. package/dist/serializers/MarkdownSerializer.js.map +1 -0
  250. package/dist/serializers/index.d.ts +8 -0
  251. package/dist/serializers/index.d.ts.map +1 -0
  252. package/dist/serializers/index.js +8 -0
  253. package/dist/serializers/index.js.map +1 -0
  254. package/package.json +27 -16
  255. package/src/ConfluenceAuth.ts +571 -0
  256. package/src/ConfluenceClient.ts +188 -156
  257. package/src/ConfluenceConfig.ts +63 -7
  258. package/src/ConfluenceError.ts +110 -14
  259. package/src/GitError.ts +92 -0
  260. package/src/GitService.ts +859 -0
  261. package/src/LocalFileSystem.ts +179 -9
  262. package/src/MarkdownConverter.ts +126 -122
  263. package/src/SchemaConverterError.ts +108 -0
  264. package/src/Schemas.ts +223 -6
  265. package/src/SyncEngine.ts +745 -162
  266. package/src/ast/BlockNode.ts +425 -0
  267. package/src/ast/Document.ts +90 -0
  268. package/src/ast/InlineNode.ts +323 -0
  269. package/src/ast/MacroNode.ts +245 -0
  270. package/src/ast/index.ts +83 -0
  271. package/src/bin.ts +50 -249
  272. package/src/commands/auth.ts +117 -0
  273. package/src/commands/clone.ts +145 -0
  274. package/src/commands/delete.ts +57 -0
  275. package/src/commands/errorHandler.ts +32 -0
  276. package/src/commands/git.ts +114 -0
  277. package/src/commands/index.ts +10 -0
  278. package/src/commands/layers.ts +211 -0
  279. package/src/commands/new.ts +99 -0
  280. package/src/commands/pageTree.ts +40 -0
  281. package/src/commands/shared.ts +35 -0
  282. package/src/commands/sync.ts +129 -0
  283. package/src/index.ts +21 -1
  284. package/src/internal/NodeLayers.ts +21 -0
  285. package/src/internal/frontmatter.ts +21 -0
  286. package/src/internal/gitCommands.ts +229 -0
  287. package/src/internal/hashUtils.ts +65 -3
  288. package/src/internal/oauthServer.ts +199 -0
  289. package/src/internal/pathUtils.ts +34 -17
  290. package/src/internal/tokenStorage.ts +240 -0
  291. package/src/internal/userCache.ts +90 -0
  292. package/src/parsers/ConfluenceParser.ts +950 -0
  293. package/src/parsers/MarkdownParser.ts +1198 -0
  294. package/src/parsers/index.ts +8 -0
  295. package/src/schemas/ConfluenceSchema.ts +56 -0
  296. package/src/schemas/ConversionSchema.ts +318 -0
  297. package/src/schemas/MarkdownSchema.ts +56 -0
  298. package/src/schemas/hast/HastFromHtml.ts +153 -0
  299. package/src/schemas/hast/HastSchema.ts +274 -0
  300. package/src/schemas/hast/index.ts +35 -0
  301. package/src/schemas/index.ts +20 -0
  302. package/src/schemas/mdast/MdastFromMarkdown.ts +118 -0
  303. package/src/schemas/mdast/MdastSchema.ts +566 -0
  304. package/src/schemas/mdast/index.ts +59 -0
  305. package/src/schemas/mdast/mdastToString.ts +102 -0
  306. package/src/schemas/nodes/block/BlockSchema.ts +773 -0
  307. package/src/schemas/nodes/block/index.ts +13 -0
  308. package/src/schemas/nodes/index.ts +20 -0
  309. package/src/schemas/nodes/inline/InlineSchema.ts +523 -0
  310. package/src/schemas/nodes/inline/index.ts +14 -0
  311. package/src/schemas/nodes/macro/MacroSchema.ts +226 -0
  312. package/src/schemas/nodes/macro/index.ts +6 -0
  313. package/src/schemas/preprocessing/ConfluencePreprocessor.ts +446 -0
  314. package/src/schemas/preprocessing/index.ts +8 -0
  315. package/src/serializers/ConfluenceSerializer.ts +717 -0
  316. package/src/serializers/MarkdownSerializer.ts +493 -0
  317. package/src/serializers/index.ts +8 -0
  318. package/test/GitService.test.ts +209 -0
  319. package/test/MarkdownConverter.test.ts +37 -3
  320. package/test/Schemas.test.ts +97 -2
  321. package/test/ast/BlockNode.test.ts +265 -0
  322. package/test/ast/Document.test.ts +126 -0
  323. package/test/ast/InlineNode.test.ts +161 -0
  324. package/test/fixtures/integration-test.html.fixture +103 -0
  325. package/test/fixtures/integration-test.md.expected +257 -0
  326. package/test/integration.test.ts +269 -0
  327. package/test/oauthServer.test.ts +50 -0
  328. package/test/parsers/ConfluenceParser.test.ts +283 -0
  329. package/test/schemas/ConfluencePreprocessor.test.ts +180 -0
  330. package/test/schemas/ConversionSchema.test.ts +159 -0
  331. package/test/schemas/HastSchema.test.ts +138 -0
  332. package/test/schemas/MdastSchema.test.ts +145 -0
  333. package/test/schemas/nodes/block/BlockSchema.test.ts +173 -0
  334. package/test/schemas/nodes/inline/InlineSchema.test.ts +198 -0
  335. package/test/schemas/nodes/macro/MacroSchema.test.ts +142 -0
  336. package/test/tokenStorage.test.ts +99 -0
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Git commands (commit, log, diff) for Confluence CLI.
3
+ */
4
+ import { Args, Command, Options } from "@effect/cli"
5
+ import * as Console from "effect/Console"
6
+ import * as Effect from "effect/Effect"
7
+ import * as Option from "effect/Option"
8
+ import { ConfluenceConfig } from "../ConfluenceConfig.js"
9
+ import { GitService } from "../GitService.js"
10
+
11
+ // === Commit command ===
12
+ const commitMessageOption = Options.text("message").pipe(
13
+ Options.withAlias("m"),
14
+ Options.withDescription("Commit message"),
15
+ Options.optional
16
+ )
17
+
18
+ export const commitCommand = Command.make(
19
+ "commit",
20
+ { message: commitMessageOption },
21
+ ({ message }) =>
22
+ Effect.gen(function*() {
23
+ const git = yield* GitService
24
+ const config = yield* ConfluenceConfig
25
+
26
+ // Sync from external docs path to .confluence/ (skips if docsPath is inside .confluence/)
27
+ yield* git.syncFromDocs(config.docsPath, config.trackedPaths)
28
+
29
+ yield* git.addAll()
30
+ const msg = Option.isSome(message) ? message.value : "Manual commit"
31
+ const hash = yield* git.commit({ message: msg })
32
+ yield* Console.log(`Committed: ${hash.substring(0, 7)}`)
33
+ })
34
+ ).pipe(Command.withDescription("Stage and commit current changes"))
35
+
36
+ // === Log command ===
37
+ const logLimitOption = Options.integer("limit").pipe(
38
+ Options.withAlias("n"),
39
+ Options.withDescription("Number of commits to show"),
40
+ Options.withDefault(10)
41
+ )
42
+
43
+ const logOnelineOption = Options.boolean("oneline").pipe(
44
+ Options.withDescription("Show compact one-line format")
45
+ )
46
+
47
+ const logSinceOption = Options.text("since").pipe(
48
+ Options.withDescription("Show commits since date (e.g., '2024-01-01')"),
49
+ Options.optional
50
+ )
51
+
52
+ const logFileArg = Args.text({ name: "file" }).pipe(Args.optional) as Args.Args<Option.Option<string>>
53
+
54
+ export const logCommand = Command.make(
55
+ "log",
56
+ { limit: logLimitOption, oneline: logOnelineOption, since: logSinceOption, file: logFileArg },
57
+ ({ file, limit, oneline, since }) =>
58
+ Effect.gen(function*() {
59
+ const git = yield* GitService
60
+ const opts = {
61
+ n: limit,
62
+ oneline,
63
+ ...(Option.isSome(since) ? { since: since.value } : {}),
64
+ ...(Option.isSome(file) ? { file: file.value } : {})
65
+ }
66
+ const commits = yield* git.log(opts)
67
+ if (commits.length === 0) {
68
+ yield* Console.log("No commits yet")
69
+ } else if (oneline) {
70
+ for (const commit of commits) {
71
+ yield* Console.log(`${commit.hash.substring(0, 7)} ${commit.message}`)
72
+ }
73
+ } else {
74
+ for (const commit of commits) {
75
+ yield* Console.log(`commit ${commit.hash}`)
76
+ yield* Console.log(`Author: ${commit.author} <${commit.email}>`)
77
+ yield* Console.log(`Date: ${commit.date.toISOString()}`)
78
+ yield* Console.log(`\n ${commit.message}\n`)
79
+ }
80
+ }
81
+ })
82
+ ).pipe(Command.withDescription("Show commit history"))
83
+
84
+ // === Diff command ===
85
+ const diffStagedOption = Options.boolean("staged").pipe(
86
+ Options.withDescription("Show staged changes")
87
+ )
88
+
89
+ const diffCommitOption = Options.text("commit").pipe(
90
+ Options.withDescription("Compare with specific commit"),
91
+ Options.optional
92
+ )
93
+
94
+ const diffFileArg = Args.text({ name: "file" }).pipe(Args.optional) as Args.Args<Option.Option<string>>
95
+
96
+ export const diffCommand = Command.make(
97
+ "diff",
98
+ { staged: diffStagedOption, commit: diffCommitOption, file: diffFileArg },
99
+ ({ commit, file, staged }) =>
100
+ Effect.gen(function*() {
101
+ const git = yield* GitService
102
+ const opts = {
103
+ staged,
104
+ ...(Option.isSome(commit) ? { commit: commit.value } : {}),
105
+ ...(Option.isSome(file) ? { file: file.value } : {})
106
+ }
107
+ const diff = yield* git.diff(opts)
108
+ if (diff === "") {
109
+ yield* Console.log("No changes")
110
+ } else {
111
+ yield* Console.log(diff)
112
+ }
113
+ })
114
+ ).pipe(Command.withDescription("Show changes in working directory"))
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CLI commands for confluence-to-markdown.
3
+ */
4
+ export { authCommand } from "./auth.js"
5
+ export { cloneCommand } from "./clone.js"
6
+ export { deleteCommand } from "./delete.js"
7
+ export { commitCommand, diffCommand, logCommand } from "./git.js"
8
+ export { newCommand } from "./new.js"
9
+ export { getAuth } from "./shared.js"
10
+ export { pullCommand, pushCommand, statusCommand } from "./sync.js"
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Layer definitions for CLI commands.
3
+ */
4
+ import * as NodeContext from "@effect/platform-node/NodeContext"
5
+ import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient"
6
+ import * as NodeTerminal from "@effect/platform-node/NodeTerminal"
7
+ import * as Effect from "effect/Effect"
8
+ import * as Layer from "effect/Layer"
9
+ import type { PageId } from "../Brand.js"
10
+ import { ConfluenceAuth, layer as ConfluenceAuthLayer } from "../ConfluenceAuth.js"
11
+ import { ConfluenceClient, type ConfluenceClientConfig, layer as ConfluenceClientLayer } from "../ConfluenceClient.js"
12
+ import {
13
+ ConfluenceConfig,
14
+ layer as ConfluenceConfigLayer,
15
+ layerFromValues as ConfluenceConfigLayerFromValues
16
+ } from "../ConfluenceConfig.js"
17
+ import { GitService, layer as GitServiceLayer } from "../GitService.js"
18
+ import { UserCacheLayer } from "../internal/userCache.js"
19
+ import { layer as LocalFileSystemLayer } from "../LocalFileSystem.js"
20
+ import { layer as MarkdownConverterLayer } from "../MarkdownConverter.js"
21
+ import { layer as SyncEngineLayer, SyncEngine } from "../SyncEngine.js"
22
+ import { getAuth } from "./shared.js"
23
+
24
+ // Dummy config layer for help/init
25
+ const DummyConfigLayer = ConfluenceConfigLayerFromValues({
26
+ rootPageId: "dummy" as PageId,
27
+ baseUrl: "https://dummy.atlassian.net",
28
+ docsPath: ".confluence/docs",
29
+ excludePatterns: [],
30
+ saveSource: false,
31
+ trackedPaths: ["**/*.md"]
32
+ })
33
+
34
+ // Dummy client layer for help/init (will fail if actually used)
35
+ const DummyConfluenceClientLayer = Layer.succeed(
36
+ ConfluenceClient,
37
+ ConfluenceClient.of({
38
+ getPage: () => Effect.dieMessage("Not configured"),
39
+ getChildren: () => Effect.dieMessage("Not configured"),
40
+ getAllChildren: () => Effect.dieMessage("Not configured"),
41
+ createPage: () => Effect.dieMessage("Not configured"),
42
+ updatePage: () => Effect.dieMessage("Not configured"),
43
+ deletePage: () => Effect.dieMessage("Not configured"),
44
+ getPageVersions: () => Effect.dieMessage("Not configured"),
45
+ getUser: () => Effect.dieMessage("Not configured"),
46
+ getSpaceId: () => Effect.dieMessage("Not configured"),
47
+ setEditorVersion: () => Effect.dieMessage("Not configured")
48
+ })
49
+ )
50
+
51
+ // Dummy sync engine that will fail if actually used
52
+ const DummySyncEngineLayer = Layer.succeed(
53
+ SyncEngine,
54
+ SyncEngine.of({
55
+ pull: () => Effect.dieMessage("Not configured - run 'confluence clone' first"),
56
+ push: (_options: { dryRun: boolean; message?: string }) =>
57
+ Effect.dieMessage("Not configured - run 'confluence clone' first"),
58
+ status: () => Effect.dieMessage("Not configured - run 'confluence clone' first")
59
+ })
60
+ )
61
+
62
+ // Dummy git layer for auth/minimal
63
+ const notConfigured = () => Effect.dieMessage("Not configured - run 'confluence clone' first")
64
+ const DummyGitServiceLayer = Layer.succeed(
65
+ GitService,
66
+ GitService.of({
67
+ validateGit: notConfigured,
68
+ init: notConfigured,
69
+ isInitialized: () => Effect.succeed(false),
70
+ status: notConfigured,
71
+ commit: notConfigured,
72
+ log: notConfigured,
73
+ diff: notConfigured,
74
+ addAll: notConfigured,
75
+ hasConflicts: () => Effect.succeed(false),
76
+ mergeContinue: notConfigured,
77
+ syncFromDocs: notConfigured,
78
+ syncToDocs: notConfigured,
79
+ getHead: notConfigured,
80
+ getCurrentBranch: notConfigured,
81
+ createBranch: notConfigured,
82
+ checkout: notConfigured,
83
+ reset: notConfigured,
84
+ deleteBranch: notConfigured,
85
+ getParent: notConfigured,
86
+ cherryPick: (_ref: string, _options?: { strategy?: "ours" | "theirs" }) => notConfigured(),
87
+ getChangedFiles: notConfigured,
88
+ showFile: notConfigured,
89
+ amend: notConfigured,
90
+ logRange: notConfigured,
91
+ branchExists: notConfigured,
92
+ updateBranch: notConfigured,
93
+ merge: notConfigured,
94
+ getDeletedFiles: notConfigured,
95
+ getFileContentAt: notConfigured
96
+ })
97
+ )
98
+
99
+ // Dummy auth layer for init/help
100
+ const DummyConfluenceAuthLayer = Layer.succeed(
101
+ ConfluenceAuth,
102
+ ConfluenceAuth.of({
103
+ configure: () => Effect.dieMessage("Not configured"),
104
+ isConfigured: () => Effect.succeed(false),
105
+ login: () => Effect.dieMessage("Not configured"),
106
+ logout: () => Effect.dieMessage("Not configured"),
107
+ getAccessToken: () => Effect.dieMessage("Not configured"),
108
+ getCloudId: () => Effect.dieMessage("Not configured"),
109
+ getCurrentUser: () => Effect.succeed(null),
110
+ isLoggedIn: () => Effect.succeed(false)
111
+ })
112
+ )
113
+
114
+ // Auth layer with HTTP client
115
+ const AuthLive = ConfluenceAuthLayer.pipe(Layer.provide(NodeHttpClient.layer))
116
+
117
+ // Build client layer dynamically based on auth
118
+ const ConfluenceClientLive = Layer.unwrapEffect(
119
+ Effect.gen(function*() {
120
+ const auth = yield* getAuth()
121
+ const config = yield* ConfluenceConfig
122
+
123
+ const clientConfig: ConfluenceClientConfig = {
124
+ baseUrl: config.baseUrl,
125
+ auth
126
+ }
127
+
128
+ return ConfluenceClientLayer(clientConfig)
129
+ })
130
+ )
131
+
132
+ /**
133
+ * Full app layer with all services.
134
+ */
135
+ export const AppLayer = SyncEngineLayer.pipe(
136
+ Layer.provideMerge(UserCacheLayer),
137
+ Layer.provideMerge(GitServiceLayer),
138
+ Layer.provideMerge(ConfluenceClientLive),
139
+ Layer.provideMerge(MarkdownConverterLayer),
140
+ Layer.provideMerge(LocalFileSystemLayer),
141
+ Layer.provideMerge(ConfluenceConfigLayer()),
142
+ Layer.provideMerge(AuthLive),
143
+ Layer.provideMerge(NodeHttpClient.layer),
144
+ Layer.provideMerge(NodeContext.layer)
145
+ )
146
+
147
+ /**
148
+ * Auth-only layer for login/logout commands.
149
+ */
150
+ export const AuthOnlyLayer = DummySyncEngineLayer.pipe(
151
+ Layer.provideMerge(UserCacheLayer),
152
+ Layer.provideMerge(DummyGitServiceLayer),
153
+ Layer.provideMerge(DummyConfluenceClientLayer),
154
+ Layer.provideMerge(AuthLive),
155
+ Layer.provideMerge(MarkdownConverterLayer),
156
+ Layer.provideMerge(LocalFileSystemLayer),
157
+ Layer.provideMerge(DummyConfigLayer),
158
+ Layer.provideMerge(NodeHttpClient.layer),
159
+ Layer.provideMerge(NodeContext.layer)
160
+ )
161
+
162
+ /**
163
+ * Minimal layer for help - uses real GitService for clone.
164
+ */
165
+ export const MinimalLayer = DummySyncEngineLayer.pipe(
166
+ Layer.provideMerge(UserCacheLayer),
167
+ Layer.provideMerge(GitServiceLayer),
168
+ Layer.provideMerge(DummyConfluenceClientLayer),
169
+ Layer.provideMerge(DummyConfluenceAuthLayer),
170
+ Layer.provideMerge(MarkdownConverterLayer),
171
+ Layer.provideMerge(LocalFileSystemLayer),
172
+ Layer.provideMerge(DummyConfigLayer),
173
+ Layer.provideMerge(NodeTerminal.layer),
174
+ Layer.provideMerge(NodeContext.layer)
175
+ )
176
+
177
+ /**
178
+ * Clone layer - needs auth + git but builds SyncEngine dynamically.
179
+ */
180
+ export const CloneLayer = DummySyncEngineLayer.pipe(
181
+ Layer.provideMerge(UserCacheLayer),
182
+ Layer.provideMerge(GitServiceLayer),
183
+ Layer.provideMerge(DummyConfluenceClientLayer),
184
+ Layer.provideMerge(AuthLive),
185
+ Layer.provideMerge(MarkdownConverterLayer),
186
+ Layer.provideMerge(LocalFileSystemLayer),
187
+ Layer.provideMerge(DummyConfigLayer),
188
+ Layer.provideMerge(NodeHttpClient.layer),
189
+ Layer.provideMerge(NodeTerminal.layer),
190
+ Layer.provideMerge(NodeContext.layer)
191
+ )
192
+
193
+ /**
194
+ * Determine which layer to use based on command.
195
+ */
196
+ export const getLayerType = (): "full" | "auth" | "clone" | "minimal" => {
197
+ const cmd = process.argv[2]
198
+ // auth commands need auth layer only
199
+ if (cmd === "auth") {
200
+ return "auth"
201
+ }
202
+ // clone needs auth + git but not config-dependent services
203
+ if (cmd === "clone") {
204
+ return "clone"
205
+ }
206
+ // --help, -h, --version don't need config
207
+ if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "--version") {
208
+ return "minimal"
209
+ }
210
+ return "full"
211
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * New page command for Confluence CLI.
3
+ */
4
+ import { Command, Prompt } from "@effect/cli"
5
+ import * as Path from "@effect/platform/Path"
6
+ import * as Console from "effect/Console"
7
+ import * as Effect from "effect/Effect"
8
+ import { ConfluenceConfig } from "../ConfluenceConfig.js"
9
+ import { LocalFileSystem } from "../LocalFileSystem.js"
10
+ import { flattenPageTree } from "./pageTree.js"
11
+
12
+ /** Slugify a title for use as filename */
13
+ const slugify = (title: string): string =>
14
+ title
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9\s-]/g, "")
17
+ .replace(/\s+/g, "-")
18
+ .replace(/-+/g, "-")
19
+ .replace(/^-|-$/g, "")
20
+
21
+ export const newCommand = Command.make("new", {}, () =>
22
+ Effect.gen(function*() {
23
+ const localFs = yield* LocalFileSystem
24
+ const config = yield* ConfluenceConfig
25
+ const pathService = yield* Path.Path
26
+
27
+ const docsPath = pathService.join(process.cwd(), config.docsPath)
28
+
29
+ // Build page tree
30
+ yield* Console.log("Scanning page structure...")
31
+ const tree = yield* localFs.buildPageTree(docsPath, config.rootPageId, "Root")
32
+
33
+ // Check if we have any pages
34
+ const hasPages = tree.children.length > 0 || tree.pageId !== null
35
+
36
+ if (!hasPages) {
37
+ yield* Console.log("No pages found. Run 'confluence clone' or 'confluence pull' first.")
38
+ return
39
+ }
40
+
41
+ // Flatten to choices
42
+ const choices = flattenPageTree(tree)
43
+
44
+ // Show parent selector
45
+ const parent = yield* Prompt.select({
46
+ message: "Select parent page for the new page:",
47
+ choices
48
+ })
49
+
50
+ // Prompt for title
51
+ const title = yield* Prompt.text({
52
+ message: "Enter page title:"
53
+ })
54
+
55
+ if (!title.trim()) {
56
+ yield* Console.log("Title cannot be empty")
57
+ return
58
+ }
59
+
60
+ // Generate filename
61
+ const filename = `${slugify(title.trim())}.md`
62
+
63
+ // Determine file path
64
+ // If parent is root (path === ""), create in docsPath
65
+ // If parent has children, create in parent's directory
66
+ let filePath: string
67
+ if (parent.path === "") {
68
+ // Root level
69
+ filePath = pathService.join(docsPath, filename)
70
+ } else {
71
+ // Under a page - check if parent directory exists
72
+ const parentBasename = pathService.basename(parent.path, ".md")
73
+ const parentDir = pathService.dirname(parent.path)
74
+ const targetDir = parentDir === "." ? parentBasename : pathService.join(parentDir, parentBasename)
75
+ filePath = pathService.join(docsPath, targetDir, filename)
76
+ }
77
+
78
+ // Check if file already exists
79
+ const exists = yield* localFs.exists(filePath)
80
+ if (exists) {
81
+ yield* Console.log(`File already exists: ${filePath}`)
82
+ return
83
+ }
84
+
85
+ // Write new page file with title-only front-matter
86
+ yield* localFs.writeNewPageFile(
87
+ filePath,
88
+ { title: title.trim() },
89
+ "\n<!-- Write your page content here -->\n"
90
+ )
91
+
92
+ const relativePath = pathService.relative(process.cwd(), filePath)
93
+ yield* Console.log(`Created new page: ${relativePath}`)
94
+ yield* Console.log("")
95
+ yield* Console.log("Next steps:")
96
+ yield* Console.log(" 1. Edit the file to add content")
97
+ yield* Console.log(" 2. Run 'confluence commit' to stage changes")
98
+ yield* Console.log(" 3. Run 'confluence push' to create on Confluence")
99
+ })).pipe(Command.withDescription("Create a new page to be pushed to Confluence"))
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared page tree utilities for CLI commands.
3
+ */
4
+ import type { PageTreeNode } from "../LocalFileSystem.js"
5
+
6
+ export interface PageChoice {
7
+ readonly title: string
8
+ readonly value: {
9
+ readonly path: string
10
+ readonly pageId: string | null
11
+ readonly nodeTitle: string
12
+ }
13
+ readonly description?: string
14
+ }
15
+
16
+ /**
17
+ * Flatten page tree to choices with indentation for interactive prompts.
18
+ */
19
+ export const flattenPageTree = (
20
+ node: PageTreeNode,
21
+ depth: number = 0
22
+ ): ReadonlyArray<PageChoice> => {
23
+ const indent = " ".repeat(depth)
24
+ const prefix = depth === 0 ? "" : "├─ "
25
+ const choices: Array<PageChoice> = []
26
+
27
+ choices.push({
28
+ title: `${indent}${prefix}${node.title}`,
29
+ value: { path: node.path, pageId: node.pageId, nodeTitle: node.title },
30
+ description: node.pageId ? `Page ID: ${node.pageId}` : "Root"
31
+ })
32
+
33
+ for (const child of node.children) {
34
+ for (const choice of flattenPageTree(child, depth + 1)) {
35
+ choices.push(choice)
36
+ }
37
+ }
38
+
39
+ return choices
40
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared utilities for CLI commands.
3
+ */
4
+ import * as Config from "effect/Config"
5
+ import * as Effect from "effect/Effect"
6
+ import * as Option from "effect/Option"
7
+ import { ConfluenceAuth } from "../ConfluenceAuth.js"
8
+
9
+ const AuthConfig = Config.all({
10
+ apiKey: Config.string("CONFLUENCE_API_KEY"),
11
+ email: Config.string("CONFLUENCE_EMAIL")
12
+ })
13
+
14
+ /**
15
+ * Get authentication config from env vars or OAuth.
16
+ */
17
+ export const getAuth = () =>
18
+ Effect.gen(function*() {
19
+ // 1. Try env vars first (backwards compat)
20
+ const envAuth = yield* AuthConfig.pipe(
21
+ Effect.map(({ apiKey, email }) => ({ type: "token" as const, email, token: apiKey })),
22
+ Effect.option
23
+ )
24
+
25
+ if (Option.isSome(envAuth)) {
26
+ return envAuth.value
27
+ }
28
+
29
+ // 2. Try OAuth token
30
+ const auth = yield* ConfluenceAuth
31
+ const accessToken = yield* auth.getAccessToken()
32
+ const cloudId = yield* auth.getCloudId()
33
+
34
+ return { type: "oauth2" as const, accessToken, cloudId }
35
+ })
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Sync commands (pull, push, status) for Confluence CLI.
3
+ */
4
+ import { Command, Options } from "@effect/cli"
5
+ import * as Console from "effect/Console"
6
+ import * as Effect from "effect/Effect"
7
+ import { GitService } from "../GitService.js"
8
+ import { SyncEngine } from "../SyncEngine.js"
9
+
10
+ // === Pull command ===
11
+ const forceOption = Options.boolean("force").pipe(
12
+ Options.withAlias("f"),
13
+ Options.withDescription("Overwrite local changes")
14
+ )
15
+
16
+ const replayHistoryOption = Options.boolean("replay-history").pipe(
17
+ Options.withDescription("Replay version history as individual git commits")
18
+ )
19
+
20
+ export const pullCommand = Command.make(
21
+ "pull",
22
+ { force: forceOption, replayHistory: replayHistoryOption },
23
+ ({ force, replayHistory }) =>
24
+ Effect.gen(function*() {
25
+ const engine = yield* SyncEngine
26
+ yield* Console.log("Pulling pages from Confluence...")
27
+ const onProgress = (current: number, total: number, message: string) => {
28
+ process.stdout.write(`\r Replaying history: ${current}/${total} - ${message}`)
29
+ }
30
+ const result = yield* engine.pull({
31
+ force,
32
+ replayHistory,
33
+ ...(replayHistory ? { onProgress } : {})
34
+ })
35
+ if (replayHistory) {
36
+ process.stdout.write("\r" + " ".repeat(80) + "\r")
37
+ }
38
+ yield* Console.log(`Pulled ${result.pulled} pages`)
39
+ if (result.commits > 0) {
40
+ yield* Console.log(`Created ${result.commits} git commits`)
41
+ }
42
+ if (result.errors.length > 0) {
43
+ yield* Console.error("Errors:", result.errors.join("\n"))
44
+ }
45
+ })
46
+ ).pipe(Command.withDescription("Download pages from Confluence to local markdown"))
47
+
48
+ // === Push command ===
49
+ const dryRunOption = Options.boolean("dry-run").pipe(
50
+ Options.withAlias("n"),
51
+ Options.withDescription("Show changes without applying")
52
+ )
53
+
54
+ export const pushCommand = Command.make(
55
+ "push",
56
+ { dryRun: dryRunOption },
57
+ ({ dryRun }) =>
58
+ Effect.gen(function*() {
59
+ const engine = yield* SyncEngine
60
+ const git = yield* GitService
61
+
62
+ // Check for uncommitted changes
63
+ const gitStatus = yield* git.status()
64
+ if (gitStatus.hasChanges) {
65
+ yield* Console.log("Uncommitted changes detected. Run 'confluence commit' first.")
66
+ return
67
+ }
68
+
69
+ yield* Console.log(dryRun ? "Dry run - showing changes..." : "Pushing changes to Confluence...")
70
+ const result = yield* engine.push({ dryRun })
71
+ if (result.pushed === 0 && result.created === 0 && result.deleted === 0) {
72
+ yield* Console.log("Nothing to push")
73
+ } else {
74
+ yield* Console.log(`Pushed: ${result.pushed}, Created: ${result.created}, Deleted: ${result.deleted}`)
75
+ }
76
+ if (result.errors.length > 0) {
77
+ yield* Console.error("Errors:", result.errors.join("\n"))
78
+ }
79
+ })
80
+ ).pipe(Command.withDescription("Upload local markdown changes to Confluence"))
81
+
82
+ // === Status command ===
83
+ export const statusCommand = Command.make("status", {}, () =>
84
+ Effect.gen(function*() {
85
+ const engine = yield* SyncEngine
86
+ const git = yield* GitService
87
+
88
+ // Show git status
89
+ const gitInit = yield* git.isInitialized()
90
+ if (gitInit) {
91
+ const gitStatus = yield* git.status()
92
+ const commitCount = yield* git.log({ n: 1 }).pipe(
93
+ Effect.map((commits) => commits.length > 0 ? "has commits" : "no commits"),
94
+ Effect.catchAll(() => Effect.succeed("unknown"))
95
+ )
96
+ yield* Console.log(`Git: initialized (${commitCount})`)
97
+ if (gitStatus.hasChanges) {
98
+ const staged = gitStatus.entries.filter((e) => e.staged).length
99
+ const unstaged = gitStatus.entries.filter((e) => !e.staged).length
100
+ yield* Console.log(` Changes: ${staged} staged, ${unstaged} unstaged`)
101
+ }
102
+ if (gitStatus.hasConflicts) {
103
+ yield* Console.log(` Conflicts: ${gitStatus.conflictedFiles.length} files`)
104
+ }
105
+ } else {
106
+ yield* Console.log("Git: not initialized (run 'confluence git init')")
107
+ }
108
+
109
+ const result = yield* engine.status()
110
+ yield* Console.log(`
111
+ Sync Status:
112
+ Synced: ${result.synced}
113
+ Local Modified: ${result.localModified}
114
+ Remote Modified: ${result.remoteModified}
115
+ Conflicts: ${result.conflicts}
116
+ Local Only: ${result.localOnly}
117
+ Remote Only: ${result.remoteOnly}
118
+ `)
119
+ if (result.files.length > 0 && result.synced < result.files.length) {
120
+ yield* Console.log("Changed files:")
121
+ for (const file of result.files) {
122
+ if (file._tag !== "Synced" && file._tag !== "RemoteOnly") {
123
+ yield* Console.log(` [${file._tag}] ${file.path}`)
124
+ } else if (file._tag === "RemoteOnly") {
125
+ yield* Console.log(` [${file._tag}] ${file.page.title}`)
126
+ }
127
+ }
128
+ }
129
+ })).pipe(Command.withDescription("Show sync status"))
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  export * from "./Brand.js"
10
+ export { ConfluenceAuth, type ConfluenceAuthService, layer as ConfluenceAuthLayer } from "./ConfluenceAuth.js"
10
11
  export {
11
12
  ConfluenceClient,
12
13
  type ConfluenceClientConfig,
@@ -26,10 +27,29 @@ export { layer as MarkdownConverterLayer, MarkdownConverter } from "./MarkdownCo
26
27
  export * from "./Schemas.js"
27
28
  export {
28
29
  layer as SyncEngineLayer,
30
+ type ProgressCallback,
31
+ type PullOptions,
29
32
  type PullResult,
30
33
  type PushResult,
31
34
  type StatusResult,
32
35
  SyncEngine,
33
- type SyncResult,
34
36
  type SyncStatus
35
37
  } from "./SyncEngine.js"
38
+
39
+ // AST types
40
+ export * from "./ast/index.js"
41
+
42
+ // Parsers
43
+ export { parseConfluenceHtml } from "./parsers/ConfluenceParser.js"
44
+ export { parseMarkdown } from "./parsers/MarkdownParser.js"
45
+
46
+ // Serializers
47
+ export { serializeToConfluence } from "./serializers/ConfluenceSerializer.js"
48
+ export { serializeToMarkdown } from "./serializers/MarkdownSerializer.js"
49
+
50
+ // Bi-directional schemas
51
+ export { DocumentFromConfluence } from "./schemas/ConfluenceSchema.js"
52
+ export { DocumentFromMarkdown } from "./schemas/MarkdownSchema.js"
53
+
54
+ // Schema converter errors
55
+ export { MigrationError, ParseError, SerializeError } from "./SchemaConverterError.js"