@knpkv/confluence-to-markdown 0.5.0 → 0.7.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.
- package/CHANGELOG.md +61 -0
- package/README.md +58 -14
- package/dist/AdfPlaceholders.d.ts +42 -0
- package/dist/AdfPlaceholders.d.ts.map +1 -0
- package/dist/AdfPlaceholders.js +547 -0
- package/dist/AdfPlaceholders.js.map +1 -0
- package/dist/AdfSchemaValidator.d.ts +37 -0
- package/dist/AdfSchemaValidator.d.ts.map +1 -0
- package/dist/AdfSchemaValidator.js +37 -0
- package/dist/AdfSchemaValidator.js.map +1 -0
- package/dist/AdfWalker.d.ts +39 -0
- package/dist/AdfWalker.d.ts.map +1 -0
- package/dist/AdfWalker.js +527 -0
- package/dist/AdfWalker.js.map +1 -0
- package/dist/AtlaskitTransformers.d.ts +35 -0
- package/dist/AtlaskitTransformers.d.ts.map +1 -0
- package/dist/AtlaskitTransformers.js +48 -0
- package/dist/AtlaskitTransformers.js.map +1 -0
- package/dist/Brand.d.ts +6 -6
- package/dist/Brand.d.ts.map +1 -1
- package/dist/Brand.js +8 -6
- package/dist/Brand.js.map +1 -1
- package/dist/ConfluenceAuth.d.ts +4 -4
- package/dist/ConfluenceAuth.d.ts.map +1 -1
- package/dist/ConfluenceAuth.js +15 -27
- package/dist/ConfluenceAuth.js.map +1 -1
- package/dist/ConfluenceClient.d.ts +4 -4
- package/dist/ConfluenceClient.d.ts.map +1 -1
- package/dist/ConfluenceClient.js +21 -14
- package/dist/ConfluenceClient.js.map +1 -1
- package/dist/ConfluenceConfig.d.ts +3 -3
- package/dist/ConfluenceConfig.d.ts.map +1 -1
- package/dist/ConfluenceConfig.js +13 -11
- package/dist/ConfluenceConfig.js.map +1 -1
- package/dist/ConfluenceError.d.ts +56 -4
- package/dist/ConfluenceError.d.ts.map +1 -1
- package/dist/ConfluenceError.js +30 -1
- package/dist/ConfluenceError.js.map +1 -1
- package/dist/GitService.d.ts +11 -3
- package/dist/GitService.d.ts.map +1 -1
- package/dist/GitService.js +19 -27
- package/dist/GitService.js.map +1 -1
- package/dist/LocalFileSystem.d.ts +3 -3
- package/dist/LocalFileSystem.d.ts.map +1 -1
- package/dist/LocalFileSystem.js +6 -6
- package/dist/LocalFileSystem.js.map +1 -1
- package/dist/MarkdownConverter.d.ts +16 -65
- package/dist/MarkdownConverter.d.ts.map +1 -1
- package/dist/MarkdownConverter.js +64 -85
- package/dist/MarkdownConverter.js.map +1 -1
- package/dist/Schemas.d.ts +128 -141
- package/dist/Schemas.d.ts.map +1 -1
- package/dist/Schemas.js +21 -23
- package/dist/Schemas.js.map +1 -1
- package/dist/SyncEngine.d.ts +8 -5
- package/dist/SyncEngine.d.ts.map +1 -1
- package/dist/SyncEngine.js +189 -113
- package/dist/SyncEngine.js.map +1 -1
- package/dist/bin.js +23 -35
- package/dist/bin.js.map +1 -1
- package/dist/commands/auth.d.ts +2 -14
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +11 -16
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/clone.d.ts +4 -6
- package/dist/commands/clone.d.ts.map +1 -1
- package/dist/commands/clone.js +34 -32
- package/dist/commands/clone.js.map +1 -1
- package/dist/commands/delete.d.ts +2 -10
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +5 -4
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/errorHandler.d.ts +2 -1
- package/dist/commands/errorHandler.d.ts.map +1 -1
- package/dist/commands/errorHandler.js +22 -15
- package/dist/commands/errorHandler.js.map +1 -1
- package/dist/commands/fetch.d.ts +27 -0
- package/dist/commands/fetch.d.ts.map +1 -0
- package/dist/commands/fetch.js +48 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/git.d.ts +7 -10
- package/dist/commands/git.d.ts.map +1 -1
- package/dist/commands/git.js +6 -6
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/layers.d.ts +10 -9
- package/dist/commands/layers.d.ts.map +1 -1
- package/dist/commands/layers.js +41 -30
- package/dist/commands/layers.js.map +1 -1
- package/dist/commands/new.d.ts +2 -6
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +5 -4
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/pageInput.d.ts +19 -0
- package/dist/commands/pageInput.d.ts.map +1 -0
- package/dist/commands/pageInput.js +68 -0
- package/dist/commands/pageInput.js.map +1 -0
- package/dist/commands/root.d.ts +8 -0
- package/dist/commands/root.d.ts.map +1 -0
- package/dist/commands/root.js +29 -0
- package/dist/commands/root.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -9
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +5 -6
- package/dist/commands/sync.js.map +1 -1
- package/dist/index.d.ts +3 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -13
- package/dist/index.js.map +1 -1
- package/dist/internal/NodeLayers.d.ts.map +1 -1
- package/dist/internal/NodeLayers.js +1 -2
- package/dist/internal/NodeLayers.js.map +1 -1
- package/dist/internal/adfMetadata.d.ts +30 -0
- package/dist/internal/adfMetadata.d.ts.map +1 -0
- package/dist/internal/adfMetadata.js +126 -0
- package/dist/internal/adfMetadata.js.map +1 -0
- package/dist/internal/cleanMarkdown.d.ts +5 -0
- package/dist/internal/cleanMarkdown.d.ts.map +1 -0
- package/dist/internal/cleanMarkdown.js +13 -0
- package/dist/internal/cleanMarkdown.js.map +1 -0
- package/dist/internal/frontmatter.d.ts.map +1 -1
- package/dist/internal/frontmatter.js +41 -8
- package/dist/internal/frontmatter.js.map +1 -1
- package/dist/internal/gitCommands.d.ts +9 -3
- package/dist/internal/gitCommands.d.ts.map +1 -1
- package/dist/internal/gitCommands.js +18 -9
- package/dist/internal/gitCommands.js.map +1 -1
- package/dist/internal/hashUtils.d.ts +1 -1
- package/dist/internal/hashUtils.d.ts.map +1 -1
- package/dist/internal/hashUtils.js +1 -1
- package/dist/internal/hashUtils.js.map +1 -1
- package/dist/internal/oauthServer.d.ts +10 -5
- package/dist/internal/oauthServer.d.ts.map +1 -1
- package/dist/internal/oauthServer.js +19 -40
- package/dist/internal/oauthServer.js.map +1 -1
- package/dist/internal/pathUtils.d.ts +1 -1
- package/dist/internal/pathUtils.d.ts.map +1 -1
- package/dist/internal/pathUtils.js +1 -1
- package/dist/internal/pathUtils.js.map +1 -1
- package/dist/internal/process.d.ts +15 -0
- package/dist/internal/process.d.ts.map +1 -0
- package/dist/internal/process.js +10 -0
- package/dist/internal/process.js.map +1 -0
- package/dist/internal/stdio.d.ts +6 -0
- package/dist/internal/stdio.d.ts.map +1 -0
- package/dist/internal/stdio.js +15 -0
- package/dist/internal/stdio.js.map +1 -0
- package/dist/internal/tokenStorage.d.ts +3 -13
- package/dist/internal/tokenStorage.d.ts.map +1 -1
- package/dist/internal/tokenStorage.js +26 -24
- package/dist/internal/tokenStorage.js.map +1 -1
- package/dist/internal/userCache.d.ts +1 -1
- package/dist/internal/userCache.d.ts.map +1 -1
- package/dist/internal/userCache.js +1 -1
- package/dist/internal/userCache.js.map +1 -1
- package/package.json +29 -20
- package/skills/confluence/SKILL.md +143 -0
- package/skills/confluence/agents/openai.yaml +4 -0
- package/src/AdfPlaceholders.ts +563 -0
- package/src/AdfSchemaValidator.ts +65 -0
- package/src/AdfWalker.ts +591 -0
- package/src/AtlaskitTransformers.ts +70 -0
- package/src/Brand.ts +11 -16
- package/src/ConfluenceAuth.ts +22 -30
- package/src/ConfluenceClient.ts +28 -24
- package/src/ConfluenceConfig.ts +14 -14
- package/src/ConfluenceError.ts +65 -3
- package/src/GitService.ts +39 -49
- package/src/LocalFileSystem.ts +7 -9
- package/src/MarkdownConverter.ts +108 -143
- package/src/Schemas.ts +17 -16
- package/src/SyncEngine.ts +272 -127
- package/src/atlaskit-adf-schema.d.ts +3 -0
- package/src/bin.ts +30 -56
- package/src/commands/auth.ts +21 -18
- package/src/commands/clone.ts +46 -38
- package/src/commands/delete.ts +5 -4
- package/src/commands/errorHandler.ts +25 -18
- package/src/commands/fetch.ts +90 -0
- package/src/commands/git.ts +6 -6
- package/src/commands/index.ts +1 -0
- package/src/commands/layers.ts +64 -37
- package/src/commands/new.ts +5 -4
- package/src/commands/pageInput.ts +103 -0
- package/src/commands/root.ts +59 -0
- package/src/commands/sync.ts +7 -6
- package/src/index.ts +3 -18
- package/src/internal/NodeLayers.ts +1 -2
- package/src/internal/adfMetadata.ts +145 -0
- package/src/internal/cleanMarkdown.ts +15 -0
- package/src/internal/frontmatter.ts +45 -8
- package/src/internal/gitCommands.ts +23 -17
- package/src/internal/hashUtils.ts +2 -2
- package/src/internal/oauthServer.ts +84 -105
- package/src/internal/pathUtils.ts +1 -1
- package/src/internal/process.ts +15 -0
- package/src/internal/stdio.ts +22 -0
- package/src/internal/tokenStorage.ts +39 -29
- package/src/internal/userCache.ts +2 -2
- package/test/AdfPlaceholders.test.ts +508 -0
- package/test/AdfSchemaValidator.test.ts +34 -0
- package/test/AdfWalker.test.ts +676 -0
- package/test/AtlaskitTransformers.test.ts +25 -0
- package/test/Brand.test.ts +11 -11
- package/test/GitService.test.ts +6 -2
- package/test/MarkdownConverter.test.ts +121 -105
- package/test/RoundTrip.test.ts +521 -0
- package/test/Schemas.test.ts +40 -40
- package/test/adfMetadata.test.ts +110 -0
- package/test/cleanMarkdown.test.ts +36 -0
- package/test/commandHarness.test.ts +79 -0
- package/test/commandHarness.ts +147 -0
- package/test/fetch.test.ts +61 -0
- package/test/frontmatter.test.ts +41 -0
- package/test/integration.test.ts +569 -156
- package/test/layers.test.ts +12 -0
- package/test/oauthServer.test.ts +4 -5
- package/test/pageInput.test.ts +83 -0
- package/test/tokenStorage.test.ts +17 -17
- package/dist/SchemaConverterError.d.ts +0 -108
- package/dist/SchemaConverterError.d.ts.map +0 -1
- package/dist/SchemaConverterError.js +0 -84
- package/dist/SchemaConverterError.js.map +0 -1
- package/dist/ast/BlockNode.d.ts +0 -453
- package/dist/ast/BlockNode.d.ts.map +0 -1
- package/dist/ast/BlockNode.js +0 -310
- package/dist/ast/BlockNode.js.map +0 -1
- package/dist/ast/Document.d.ts +0 -216
- package/dist/ast/Document.d.ts.map +0 -1
- package/dist/ast/Document.js +0 -69
- package/dist/ast/Document.js.map +0 -1
- package/dist/ast/InlineNode.d.ts +0 -477
- package/dist/ast/InlineNode.d.ts.map +0 -1
- package/dist/ast/InlineNode.js +0 -263
- package/dist/ast/InlineNode.js.map +0 -1
- package/dist/ast/MacroNode.d.ts +0 -267
- package/dist/ast/MacroNode.d.ts.map +0 -1
- package/dist/ast/MacroNode.js +0 -164
- package/dist/ast/MacroNode.js.map +0 -1
- package/dist/ast/index.d.ts +0 -10
- package/dist/ast/index.d.ts.map +0 -1
- package/dist/ast/index.js +0 -14
- package/dist/ast/index.js.map +0 -1
- package/dist/parsers/ConfluenceParser.d.ts +0 -26
- package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
- package/dist/parsers/ConfluenceParser.js +0 -797
- package/dist/parsers/ConfluenceParser.js.map +0 -1
- package/dist/parsers/MarkdownParser.d.ts +0 -26
- package/dist/parsers/MarkdownParser.d.ts.map +0 -1
- package/dist/parsers/MarkdownParser.js +0 -982
- package/dist/parsers/MarkdownParser.js.map +0 -1
- package/dist/parsers/index.d.ts +0 -8
- package/dist/parsers/index.d.ts.map +0 -1
- package/dist/parsers/index.js +0 -8
- package/dist/parsers/index.js.map +0 -1
- package/dist/schemas/ConfluenceSchema.d.ts +0 -21
- package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
- package/dist/schemas/ConfluenceSchema.js +0 -38
- package/dist/schemas/ConfluenceSchema.js.map +0 -1
- package/dist/schemas/ConversionSchema.d.ts +0 -35
- package/dist/schemas/ConversionSchema.d.ts.map +0 -1
- package/dist/schemas/ConversionSchema.js +0 -208
- package/dist/schemas/ConversionSchema.js.map +0 -1
- package/dist/schemas/MarkdownSchema.d.ts +0 -21
- package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
- package/dist/schemas/MarkdownSchema.js +0 -38
- package/dist/schemas/MarkdownSchema.js.map +0 -1
- package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
- package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
- package/dist/schemas/hast/HastFromHtml.js +0 -107
- package/dist/schemas/hast/HastFromHtml.js.map +0 -1
- package/dist/schemas/hast/HastSchema.d.ts +0 -195
- package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
- package/dist/schemas/hast/HastSchema.js +0 -183
- package/dist/schemas/hast/HastSchema.js.map +0 -1
- package/dist/schemas/hast/index.d.ts +0 -9
- package/dist/schemas/hast/index.d.ts.map +0 -1
- package/dist/schemas/hast/index.js +0 -3
- package/dist/schemas/hast/index.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -14
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -16
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
- package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
- package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
- package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
- package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
- package/dist/schemas/mdast/MdastSchema.js +0 -266
- package/dist/schemas/mdast/MdastSchema.js.map +0 -1
- package/dist/schemas/mdast/index.d.ts +0 -10
- package/dist/schemas/mdast/index.d.ts.map +0 -1
- package/dist/schemas/mdast/index.js +0 -4
- package/dist/schemas/mdast/index.js.map +0 -1
- package/dist/schemas/mdast/mdastToString.d.ts +0 -13
- package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
- package/dist/schemas/mdast/mdastToString.js +0 -85
- package/dist/schemas/mdast/mdastToString.js.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
- package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/block/BlockSchema.js +0 -634
- package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
- package/dist/schemas/nodes/block/index.d.ts +0 -7
- package/dist/schemas/nodes/block/index.d.ts.map +0 -1
- package/dist/schemas/nodes/block/index.js +0 -7
- package/dist/schemas/nodes/block/index.js.map +0 -1
- package/dist/schemas/nodes/index.d.ts +0 -9
- package/dist/schemas/nodes/index.d.ts.map +0 -1
- package/dist/schemas/nodes/index.js +0 -12
- package/dist/schemas/nodes/index.js.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
- package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
- package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
- package/dist/schemas/nodes/inline/index.d.ts +0 -7
- package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
- package/dist/schemas/nodes/inline/index.js +0 -7
- package/dist/schemas/nodes/inline/index.js.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
- package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
- package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
- package/dist/schemas/nodes/macro/index.d.ts +0 -7
- package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
- package/dist/schemas/nodes/macro/index.js +0 -7
- package/dist/schemas/nodes/macro/index.js.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -24
- package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -359
- package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
- package/dist/schemas/preprocessing/index.d.ts +0 -8
- package/dist/schemas/preprocessing/index.d.ts.map +0 -1
- package/dist/schemas/preprocessing/index.js +0 -2
- package/dist/schemas/preprocessing/index.js.map +0 -1
- package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
- package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
- package/dist/serializers/ConfluenceSerializer.js +0 -560
- package/dist/serializers/ConfluenceSerializer.js.map +0 -1
- package/dist/serializers/MarkdownSerializer.d.ts +0 -34
- package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
- package/dist/serializers/MarkdownSerializer.js +0 -395
- package/dist/serializers/MarkdownSerializer.js.map +0 -1
- package/dist/serializers/index.d.ts +0 -8
- package/dist/serializers/index.d.ts.map +0 -1
- package/dist/serializers/index.js +0 -8
- package/dist/serializers/index.js.map +0 -1
- package/src/SchemaConverterError.ts +0 -108
- package/src/ast/BlockNode.ts +0 -469
- package/src/ast/Document.ts +0 -90
- package/src/ast/InlineNode.ts +0 -323
- package/src/ast/MacroNode.ts +0 -245
- package/src/ast/index.ts +0 -83
- package/src/parsers/ConfluenceParser.ts +0 -956
- package/src/parsers/MarkdownParser.ts +0 -1338
- package/src/parsers/index.ts +0 -8
- package/src/schemas/ConfluenceSchema.ts +0 -56
- package/src/schemas/ConversionSchema.ts +0 -318
- package/src/schemas/MarkdownSchema.ts +0 -56
- package/src/schemas/hast/HastFromHtml.ts +0 -153
- package/src/schemas/hast/HastSchema.ts +0 -274
- package/src/schemas/hast/index.ts +0 -35
- package/src/schemas/index.ts +0 -20
- package/src/schemas/mdast/MdastFromMarkdown.ts +0 -118
- package/src/schemas/mdast/MdastSchema.ts +0 -566
- package/src/schemas/mdast/index.ts +0 -59
- package/src/schemas/mdast/mdastToString.ts +0 -102
- package/src/schemas/nodes/block/BlockSchema.ts +0 -773
- package/src/schemas/nodes/block/index.ts +0 -13
- package/src/schemas/nodes/index.ts +0 -20
- package/src/schemas/nodes/inline/InlineSchema.ts +0 -523
- package/src/schemas/nodes/inline/index.ts +0 -14
- package/src/schemas/nodes/macro/MacroSchema.ts +0 -226
- package/src/schemas/nodes/macro/index.ts +0 -6
- package/src/schemas/preprocessing/ConfluencePreprocessor.ts +0 -455
- package/src/schemas/preprocessing/index.ts +0 -8
- package/src/serializers/ConfluenceSerializer.ts +0 -737
- package/src/serializers/MarkdownSerializer.ts +0 -543
- package/src/serializers/index.ts +0 -8
- package/test/ast/BlockNode.test.ts +0 -265
- package/test/ast/Document.test.ts +0 -126
- package/test/ast/InlineNode.test.ts +0 -161
- package/test/fixtures/integration-test.html.fixture +0 -103
- package/test/fixtures/integration-test.md.expected +0 -257
- package/test/parsers/ConfluenceParser.test.ts +0 -452
- package/test/schemas/ConfluencePreprocessor.test.ts +0 -180
- package/test/schemas/ConversionSchema.test.ts +0 -159
- package/test/schemas/HastSchema.test.ts +0 -138
- package/test/schemas/MdastSchema.test.ts +0 -145
- package/test/schemas/nodes/block/BlockSchema.test.ts +0 -173
- package/test/schemas/nodes/inline/InlineSchema.test.ts +0 -198
- package/test/schemas/nodes/macro/MacroSchema.test.ts +0 -142
package/src/commands/layers.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layer definitions for CLI commands.
|
|
3
3
|
*/
|
|
4
|
-
import * as NodeContext from "@effect/platform-node/NodeContext"
|
|
5
4
|
import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient"
|
|
5
|
+
import * as NodeServices from "@effect/platform-node/NodeServices"
|
|
6
6
|
import * as NodeTerminal from "@effect/platform-node/NodeTerminal"
|
|
7
7
|
import * as Effect from "effect/Effect"
|
|
8
8
|
import * as Layer from "effect/Layer"
|
|
9
|
+
import { layer as AdfSchemaValidatorLayer } from "../AdfSchemaValidator.js"
|
|
10
|
+
import { layer as AtlaskitTransformersLayer } from "../AtlaskitTransformers.js"
|
|
9
11
|
import type { PageId } from "../Brand.js"
|
|
10
12
|
import { ConfluenceAuth, layer as ConfluenceAuthLayer } from "../ConfluenceAuth.js"
|
|
11
13
|
import { ConfluenceClient, type ConfluenceClientConfig, layer as ConfluenceClientLayer } from "../ConfluenceClient.js"
|
|
@@ -21,6 +23,11 @@ import { layer as MarkdownConverterLayer } from "../MarkdownConverter.js"
|
|
|
21
23
|
import { layer as SyncEngineLayer, SyncEngine } from "../SyncEngine.js"
|
|
22
24
|
import { getAuth } from "./shared.js"
|
|
23
25
|
|
|
26
|
+
const ConverterPipeline = MarkdownConverterLayer.pipe(
|
|
27
|
+
Layer.provide(AtlaskitTransformersLayer),
|
|
28
|
+
Layer.provide(AdfSchemaValidatorLayer)
|
|
29
|
+
)
|
|
30
|
+
|
|
24
31
|
// Dummy config layer for help/init
|
|
25
32
|
const DummyConfigLayer = ConfluenceConfigLayerFromValues({
|
|
26
33
|
rootPageId: "dummy" as PageId,
|
|
@@ -35,16 +42,16 @@ const DummyConfigLayer = ConfluenceConfigLayerFromValues({
|
|
|
35
42
|
const DummyConfluenceClientLayer = Layer.succeed(
|
|
36
43
|
ConfluenceClient,
|
|
37
44
|
ConfluenceClient.of({
|
|
38
|
-
getPage: () => Effect.
|
|
39
|
-
getChildren: () => Effect.
|
|
40
|
-
getAllChildren: () => Effect.
|
|
41
|
-
createPage: () => Effect.
|
|
42
|
-
updatePage: () => Effect.
|
|
43
|
-
deletePage: () => Effect.
|
|
44
|
-
getPageVersions: () => Effect.
|
|
45
|
-
getUser: () => Effect.
|
|
46
|
-
getSpaceId: () => Effect.
|
|
47
|
-
setEditorVersion: () => Effect.
|
|
45
|
+
getPage: () => Effect.die("Not configured"),
|
|
46
|
+
getChildren: () => Effect.die("Not configured"),
|
|
47
|
+
getAllChildren: () => Effect.die("Not configured"),
|
|
48
|
+
createPage: () => Effect.die("Not configured"),
|
|
49
|
+
updatePage: () => Effect.die("Not configured"),
|
|
50
|
+
deletePage: () => Effect.die("Not configured"),
|
|
51
|
+
getPageVersions: () => Effect.die("Not configured"),
|
|
52
|
+
getUser: () => Effect.die("Not configured"),
|
|
53
|
+
getSpaceId: () => Effect.die("Not configured"),
|
|
54
|
+
setEditorVersion: () => Effect.die("Not configured")
|
|
48
55
|
})
|
|
49
56
|
)
|
|
50
57
|
|
|
@@ -52,15 +59,15 @@ const DummyConfluenceClientLayer = Layer.succeed(
|
|
|
52
59
|
const DummySyncEngineLayer = Layer.succeed(
|
|
53
60
|
SyncEngine,
|
|
54
61
|
SyncEngine.of({
|
|
55
|
-
pull: () => Effect.
|
|
62
|
+
pull: () => Effect.die("Not configured - run 'confluence clone' first"),
|
|
56
63
|
push: (_options: { dryRun: boolean; message?: string }) =>
|
|
57
|
-
Effect.
|
|
58
|
-
status: () => Effect.
|
|
64
|
+
Effect.die("Not configured - run 'confluence clone' first"),
|
|
65
|
+
status: () => Effect.die("Not configured - run 'confluence clone' first")
|
|
59
66
|
})
|
|
60
67
|
)
|
|
61
68
|
|
|
62
69
|
// Dummy git layer for auth/minimal
|
|
63
|
-
const notConfigured = () => Effect.
|
|
70
|
+
const notConfigured = () => Effect.die("Not configured - run 'confluence clone' first")
|
|
64
71
|
const DummyGitServiceLayer = Layer.succeed(
|
|
65
72
|
GitService,
|
|
66
73
|
GitService.of({
|
|
@@ -100,22 +107,22 @@ const DummyGitServiceLayer = Layer.succeed(
|
|
|
100
107
|
const DummyConfluenceAuthLayer = Layer.succeed(
|
|
101
108
|
ConfluenceAuth,
|
|
102
109
|
ConfluenceAuth.of({
|
|
103
|
-
configure: () => Effect.
|
|
110
|
+
configure: () => Effect.die("Not configured"),
|
|
104
111
|
isConfigured: () => Effect.succeed(false),
|
|
105
|
-
login: () => Effect.
|
|
106
|
-
logout: () => Effect.
|
|
107
|
-
getAccessToken: () => Effect.
|
|
108
|
-
getCloudId: () => Effect.
|
|
112
|
+
login: () => Effect.die("Not configured"),
|
|
113
|
+
logout: () => Effect.die("Not configured"),
|
|
114
|
+
getAccessToken: () => Effect.die("Not configured"),
|
|
115
|
+
getCloudId: () => Effect.die("Not configured"),
|
|
109
116
|
getCurrentUser: () => Effect.succeed(null),
|
|
110
117
|
isLoggedIn: () => Effect.succeed(false)
|
|
111
118
|
})
|
|
112
119
|
)
|
|
113
120
|
|
|
114
121
|
// Auth layer with HTTP client
|
|
115
|
-
const AuthLive = ConfluenceAuthLayer.pipe(Layer.provide(NodeHttpClient.
|
|
122
|
+
const AuthLive = ConfluenceAuthLayer.pipe(Layer.provide(NodeHttpClient.layerFetch))
|
|
116
123
|
|
|
117
124
|
// Build client layer dynamically based on auth
|
|
118
|
-
const ConfluenceClientLive = Layer.
|
|
125
|
+
const ConfluenceClientLive = Layer.unwrap(
|
|
119
126
|
Effect.gen(function*() {
|
|
120
127
|
const auth = yield* getAuth()
|
|
121
128
|
const config = yield* ConfluenceConfig
|
|
@@ -136,12 +143,12 @@ export const AppLayer = SyncEngineLayer.pipe(
|
|
|
136
143
|
Layer.provideMerge(UserCacheLayer),
|
|
137
144
|
Layer.provideMerge(GitServiceLayer),
|
|
138
145
|
Layer.provideMerge(ConfluenceClientLive),
|
|
139
|
-
Layer.provideMerge(
|
|
146
|
+
Layer.provideMerge(ConverterPipeline),
|
|
140
147
|
Layer.provideMerge(LocalFileSystemLayer),
|
|
141
148
|
Layer.provideMerge(ConfluenceConfigLayer()),
|
|
142
149
|
Layer.provideMerge(AuthLive),
|
|
143
|
-
Layer.provideMerge(NodeHttpClient.
|
|
144
|
-
Layer.provideMerge(
|
|
150
|
+
Layer.provideMerge(NodeHttpClient.layerFetch),
|
|
151
|
+
Layer.provideMerge(NodeServices.layer)
|
|
145
152
|
)
|
|
146
153
|
|
|
147
154
|
/**
|
|
@@ -152,11 +159,11 @@ export const AuthOnlyLayer = DummySyncEngineLayer.pipe(
|
|
|
152
159
|
Layer.provideMerge(DummyGitServiceLayer),
|
|
153
160
|
Layer.provideMerge(DummyConfluenceClientLayer),
|
|
154
161
|
Layer.provideMerge(AuthLive),
|
|
155
|
-
Layer.provideMerge(
|
|
162
|
+
Layer.provideMerge(ConverterPipeline),
|
|
156
163
|
Layer.provideMerge(LocalFileSystemLayer),
|
|
157
164
|
Layer.provideMerge(DummyConfigLayer),
|
|
158
|
-
Layer.provideMerge(NodeHttpClient.
|
|
159
|
-
Layer.provideMerge(
|
|
165
|
+
Layer.provideMerge(NodeHttpClient.layerFetch),
|
|
166
|
+
Layer.provideMerge(NodeServices.layer)
|
|
160
167
|
)
|
|
161
168
|
|
|
162
169
|
/**
|
|
@@ -167,11 +174,11 @@ export const MinimalLayer = DummySyncEngineLayer.pipe(
|
|
|
167
174
|
Layer.provideMerge(GitServiceLayer),
|
|
168
175
|
Layer.provideMerge(DummyConfluenceClientLayer),
|
|
169
176
|
Layer.provideMerge(DummyConfluenceAuthLayer),
|
|
170
|
-
Layer.provideMerge(
|
|
177
|
+
Layer.provideMerge(ConverterPipeline),
|
|
171
178
|
Layer.provideMerge(LocalFileSystemLayer),
|
|
172
179
|
Layer.provideMerge(DummyConfigLayer),
|
|
173
180
|
Layer.provideMerge(NodeTerminal.layer),
|
|
174
|
-
Layer.provideMerge(
|
|
181
|
+
Layer.provideMerge(NodeServices.layer)
|
|
175
182
|
)
|
|
176
183
|
|
|
177
184
|
/**
|
|
@@ -182,19 +189,35 @@ export const CloneLayer = DummySyncEngineLayer.pipe(
|
|
|
182
189
|
Layer.provideMerge(GitServiceLayer),
|
|
183
190
|
Layer.provideMerge(DummyConfluenceClientLayer),
|
|
184
191
|
Layer.provideMerge(AuthLive),
|
|
185
|
-
Layer.provideMerge(
|
|
192
|
+
Layer.provideMerge(ConverterPipeline),
|
|
193
|
+
Layer.provideMerge(LocalFileSystemLayer),
|
|
194
|
+
Layer.provideMerge(DummyConfigLayer),
|
|
195
|
+
Layer.provideMerge(NodeHttpClient.layerFetch),
|
|
196
|
+
Layer.provideMerge(NodeTerminal.layer),
|
|
197
|
+
Layer.provideMerge(NodeServices.layer)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Fetch layer - needs auth + converter but no config, sync engine, or git workspace.
|
|
202
|
+
*/
|
|
203
|
+
export const FetchLayer = DummySyncEngineLayer.pipe(
|
|
204
|
+
Layer.provideMerge(UserCacheLayer),
|
|
205
|
+
Layer.provideMerge(DummyGitServiceLayer),
|
|
206
|
+
Layer.provideMerge(DummyConfluenceClientLayer),
|
|
207
|
+
Layer.provideMerge(AuthLive),
|
|
208
|
+
Layer.provideMerge(ConverterPipeline),
|
|
186
209
|
Layer.provideMerge(LocalFileSystemLayer),
|
|
187
210
|
Layer.provideMerge(DummyConfigLayer),
|
|
188
|
-
Layer.provideMerge(NodeHttpClient.
|
|
211
|
+
Layer.provideMerge(NodeHttpClient.layerFetch),
|
|
189
212
|
Layer.provideMerge(NodeTerminal.layer),
|
|
190
|
-
Layer.provideMerge(
|
|
213
|
+
Layer.provideMerge(NodeServices.layer)
|
|
191
214
|
)
|
|
192
215
|
|
|
193
216
|
/**
|
|
194
217
|
* Determine which layer to use based on command.
|
|
195
218
|
*/
|
|
196
|
-
export const getLayerType = (): "full" | "auth" | "clone" | "minimal" => {
|
|
197
|
-
const cmd =
|
|
219
|
+
export const getLayerType = (argv: ReadonlyArray<string>): "full" | "auth" | "clone" | "fetch" | "minimal" => {
|
|
220
|
+
const cmd = argv[0]
|
|
198
221
|
// auth commands need auth layer only
|
|
199
222
|
if (cmd === "auth") {
|
|
200
223
|
return "auth"
|
|
@@ -203,8 +226,12 @@ export const getLayerType = (): "full" | "auth" | "clone" | "minimal" => {
|
|
|
203
226
|
if (cmd === "clone") {
|
|
204
227
|
return "clone"
|
|
205
228
|
}
|
|
206
|
-
//
|
|
207
|
-
if (
|
|
229
|
+
// fetch needs auth + converter but no existing config
|
|
230
|
+
if (cmd === "fetch") {
|
|
231
|
+
return "fetch"
|
|
232
|
+
}
|
|
233
|
+
// skills/help/version don't need config
|
|
234
|
+
if (!cmd || cmd === "skills" || cmd === "--help" || cmd === "-h" || cmd === "--version") {
|
|
208
235
|
return "minimal"
|
|
209
236
|
}
|
|
210
237
|
return "full"
|
package/src/commands/new.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* New page command for Confluence CLI.
|
|
3
3
|
*/
|
|
4
|
-
import { Command, Prompt } from "@effect/cli"
|
|
5
|
-
import * as Path from "@effect/platform/Path"
|
|
6
4
|
import * as Console from "effect/Console"
|
|
7
5
|
import * as Effect from "effect/Effect"
|
|
6
|
+
import * as Path from "effect/Path"
|
|
7
|
+
import { Command, Prompt } from "effect/unstable/cli"
|
|
8
8
|
import { ConfluenceConfig } from "../ConfluenceConfig.js"
|
|
9
9
|
import { LocalFileSystem } from "../LocalFileSystem.js"
|
|
10
10
|
import { flattenPageTree } from "./pageTree.js"
|
|
@@ -24,7 +24,8 @@ export const newCommand = Command.make("new", {}, () =>
|
|
|
24
24
|
const config = yield* ConfluenceConfig
|
|
25
25
|
const pathService = yield* Path.Path
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const cwd = pathService.resolve(".")
|
|
28
|
+
const docsPath = pathService.join(cwd, config.docsPath)
|
|
28
29
|
|
|
29
30
|
// Build page tree
|
|
30
31
|
yield* Console.log("Scanning page structure...")
|
|
@@ -89,7 +90,7 @@ export const newCommand = Command.make("new", {}, () =>
|
|
|
89
90
|
"\n<!-- Write your page content here -->\n"
|
|
90
91
|
)
|
|
91
92
|
|
|
92
|
-
const relativePath = pathService.relative(
|
|
93
|
+
const relativePath = pathService.relative(cwd, filePath)
|
|
93
94
|
yield* Console.log(`Created new page: ${relativePath}`)
|
|
94
95
|
yield* Console.log("")
|
|
95
96
|
yield* Console.log("Next steps:")
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared page input parsing for commands that accept Confluence page IDs.
|
|
3
|
+
*/
|
|
4
|
+
import * as Effect from "effect/Effect"
|
|
5
|
+
import { ConfigError } from "../ConfluenceError.js"
|
|
6
|
+
|
|
7
|
+
export interface PageInput {
|
|
8
|
+
readonly url?: string | undefined
|
|
9
|
+
readonly pageId?: string | undefined
|
|
10
|
+
readonly baseUrl?: string | undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResolvedPageInput {
|
|
14
|
+
readonly pageId: string
|
|
15
|
+
readonly baseUrl: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const isSupportedHost = (host: string): boolean => /^[a-z0-9-]+\.atlassian\.(?:net|com)$/.test(host)
|
|
19
|
+
|
|
20
|
+
const isNumericPageId = (segment: string): boolean => /^[0-9]+$/.test(segment)
|
|
21
|
+
|
|
22
|
+
export const validatePageId = (input: string): Effect.Effect<string, ConfigError> => {
|
|
23
|
+
const pageId = input.trim()
|
|
24
|
+
return pageId.length > 0 && isNumericPageId(pageId)
|
|
25
|
+
? Effect.succeed(pageId)
|
|
26
|
+
: Effect.fail(new ConfigError({ message: `Invalid Confluence page ID: ${input}` }))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const validateBaseUrl = (input: string): Effect.Effect<string, ConfigError> =>
|
|
30
|
+
Effect.gen(function*() {
|
|
31
|
+
const url = yield* Effect.try({
|
|
32
|
+
try: () => new URL(input.trim()),
|
|
33
|
+
catch: () => new ConfigError({ message: `Invalid Confluence URL: ${input}` })
|
|
34
|
+
})
|
|
35
|
+
if (url.protocol !== "https:" || url.pathname !== "/" || !isSupportedHost(url.host)) {
|
|
36
|
+
return yield* Effect.fail(
|
|
37
|
+
new ConfigError({
|
|
38
|
+
message: `Invalid Confluence URL: ${input}. Expected format: https://yoursite.atlassian.net`
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
return `${url.protocol}//${url.host}`
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
export const parseConfluencePageUrl = (input: string): Effect.Effect<ResolvedPageInput, ConfigError> =>
|
|
46
|
+
Effect.gen(function*() {
|
|
47
|
+
const url = yield* Effect.try({
|
|
48
|
+
try: () => new URL(input.trim()),
|
|
49
|
+
catch: () => new ConfigError({ message: `Invalid Confluence page URL: ${input}` })
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (url.protocol !== "https:" || !isSupportedHost(url.host)) {
|
|
53
|
+
return yield* Effect.fail(
|
|
54
|
+
new ConfigError({
|
|
55
|
+
message: `Unsupported Confluence page URL: ${input}. Expected an https Atlassian Cloud URL.`
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const segments = url.pathname.split("/").filter((segment) => segment.length > 0)
|
|
61
|
+
const pagesIndex = segments.indexOf("pages")
|
|
62
|
+
const pageIdFromPages = pagesIndex >= 0 ? segments[pagesIndex + 1] : undefined
|
|
63
|
+
const pageId = pagesIndex >= 0
|
|
64
|
+
? pageIdFromPages && isNumericPageId(pageIdFromPages) ? pageIdFromPages : undefined
|
|
65
|
+
: segments.find(isNumericPageId)
|
|
66
|
+
|
|
67
|
+
if (!pageId) {
|
|
68
|
+
return yield* Effect.fail(new ConfigError({ message: `Could not find a page ID in URL: ${input}` }))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
pageId,
|
|
73
|
+
baseUrl: `${url.protocol}//${url.host}`
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
export const resolvePageInput = (input: PageInput): Effect.Effect<ResolvedPageInput, ConfigError> =>
|
|
78
|
+
Effect.gen(function*() {
|
|
79
|
+
const url = input.url?.trim()
|
|
80
|
+
const pageId = input.pageId?.trim()
|
|
81
|
+
const baseUrl = input.baseUrl?.trim()
|
|
82
|
+
|
|
83
|
+
if (url && (pageId || baseUrl)) {
|
|
84
|
+
return yield* Effect.fail(
|
|
85
|
+
new ConfigError({ message: "Use either --url or --page-id/--base-url, not both." })
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (url) {
|
|
90
|
+
return yield* parseConfluencePageUrl(url)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!pageId || !baseUrl) {
|
|
94
|
+
return yield* Effect.fail(
|
|
95
|
+
new ConfigError({ message: "Both --page-id and --base-url are required when --url is not provided." })
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
pageId: yield* validatePageId(pageId),
|
|
101
|
+
baseUrl: yield* validateBaseUrl(baseUrl)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root CLI command composition.
|
|
3
|
+
*/
|
|
4
|
+
import { makeInstallCommand } from "@knpkv/agent-skills"
|
|
5
|
+
import * as Console from "effect/Console"
|
|
6
|
+
import { Command } from "effect/unstable/cli"
|
|
7
|
+
import {
|
|
8
|
+
authCommand,
|
|
9
|
+
cloneCommand,
|
|
10
|
+
commitCommand,
|
|
11
|
+
deleteCommand,
|
|
12
|
+
diffCommand,
|
|
13
|
+
fetchCommand,
|
|
14
|
+
logCommand,
|
|
15
|
+
newCommand,
|
|
16
|
+
pullCommand,
|
|
17
|
+
pushCommand,
|
|
18
|
+
statusCommand
|
|
19
|
+
} from "./index.js"
|
|
20
|
+
|
|
21
|
+
export interface ConfluenceCommandOptions {
|
|
22
|
+
readonly fetch?: typeof fetchCommand
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const skillsInstall = makeInstallCommand({
|
|
26
|
+
description: "Install the Confluence agent skill",
|
|
27
|
+
name: "install",
|
|
28
|
+
skills: ["confluence"]
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const skillsCommand = Command.make(
|
|
32
|
+
"skills",
|
|
33
|
+
{},
|
|
34
|
+
() => Console.log("Usage: confluence skills install")
|
|
35
|
+
).pipe(
|
|
36
|
+
Command.withDescription("Agent skill commands"),
|
|
37
|
+
Command.withSubcommands([skillsInstall])
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
export const makeConfluenceCommand = (options: ConfluenceCommandOptions = {}) =>
|
|
41
|
+
Command.make("confluence").pipe(
|
|
42
|
+
Command.withDescription("Sync Confluence pages to local markdown"),
|
|
43
|
+
Command.withSubcommands([
|
|
44
|
+
cloneCommand,
|
|
45
|
+
authCommand,
|
|
46
|
+
pullCommand,
|
|
47
|
+
pushCommand,
|
|
48
|
+
statusCommand,
|
|
49
|
+
commitCommand,
|
|
50
|
+
logCommand,
|
|
51
|
+
diffCommand,
|
|
52
|
+
options.fetch ?? fetchCommand,
|
|
53
|
+
newCommand,
|
|
54
|
+
deleteCommand,
|
|
55
|
+
skillsCommand
|
|
56
|
+
])
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
export const confluenceCommand = makeConfluenceCommand()
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sync commands (pull, push, status) for Confluence CLI.
|
|
3
3
|
*/
|
|
4
|
-
import { Command, Options } from "@effect/cli"
|
|
5
4
|
import * as Console from "effect/Console"
|
|
6
5
|
import * as Effect from "effect/Effect"
|
|
6
|
+
import { Command, Flag as Options } from "effect/unstable/cli"
|
|
7
7
|
import { GitService } from "../GitService.js"
|
|
8
|
+
import { writeStdout } from "../internal/stdio.js"
|
|
9
|
+
import type { ProgressCallback } from "../SyncEngine.js"
|
|
8
10
|
import { SyncEngine } from "../SyncEngine.js"
|
|
9
11
|
|
|
10
12
|
// === Pull command ===
|
|
@@ -24,16 +26,15 @@ export const pullCommand = Command.make(
|
|
|
24
26
|
Effect.gen(function*() {
|
|
25
27
|
const engine = yield* SyncEngine
|
|
26
28
|
yield* Console.log("Pulling pages from Confluence...")
|
|
27
|
-
const onProgress = (current
|
|
28
|
-
|
|
29
|
-
}
|
|
29
|
+
const onProgress: ProgressCallback = (current, total, message) =>
|
|
30
|
+
writeStdout(`\r Replaying history: ${current}/${total} - ${message}`)
|
|
30
31
|
const result = yield* engine.pull({
|
|
31
32
|
force,
|
|
32
33
|
replayHistory,
|
|
33
34
|
...(replayHistory ? { onProgress } : {})
|
|
34
35
|
})
|
|
35
36
|
if (replayHistory) {
|
|
36
|
-
|
|
37
|
+
yield* writeStdout("\r" + " ".repeat(80) + "\r")
|
|
37
38
|
}
|
|
38
39
|
yield* Console.log(`Pulled ${result.pulled} pages`)
|
|
39
40
|
if (result.commits > 0) {
|
|
@@ -91,7 +92,7 @@ export const statusCommand = Command.make("status", {}, () =>
|
|
|
91
92
|
const gitStatus = yield* git.status()
|
|
92
93
|
const commitCount = yield* git.log({ n: 1 }).pipe(
|
|
93
94
|
Effect.map((commits) => commits.length > 0 ? "has commits" : "no commits"),
|
|
94
|
-
Effect.
|
|
95
|
+
Effect.catchIf(() => true, () => Effect.succeed("unknown"))
|
|
95
96
|
)
|
|
96
97
|
yield* Console.log(`Git: initialized (${commitCount})`)
|
|
97
98
|
if (gitStatus.hasChanges) {
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* @packageDocumentation
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
export { AdfSchemaValidator, layer as AdfSchemaValidatorLayer } from "./AdfSchemaValidator.js"
|
|
10
|
+
export { type WalkerWarning, type WalkResult } from "./AdfWalker.js"
|
|
11
|
+
export { AtlaskitTransformers, layer as AtlaskitTransformersLayer, type Transformers } from "./AtlaskitTransformers.js"
|
|
9
12
|
export * from "./Brand.js"
|
|
10
13
|
export { ConfluenceAuth, type ConfluenceAuthService, layer as ConfluenceAuthLayer } from "./ConfluenceAuth.js"
|
|
11
14
|
export {
|
|
@@ -35,21 +38,3 @@ export {
|
|
|
35
38
|
SyncEngine,
|
|
36
39
|
type SyncStatus
|
|
37
40
|
} 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"
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Node.js-specific layer implementations.
|
|
3
3
|
*
|
|
4
|
-
* This
|
|
5
|
-
* All other code should use Effect platform abstractions.
|
|
4
|
+
* This file wires package-specific Node runtime layers.
|
|
6
5
|
*
|
|
7
6
|
* @module
|
|
8
7
|
* @internal
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External sidecar storage for ADF placeholder metadata.
|
|
3
|
+
*
|
|
4
|
+
* Markdown stays readable by replacing large `attrs={...}` / `node={...}`
|
|
5
|
+
* blobs with `ref=./page.adf.json#id`; the sidecar stores decoded JSON.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import * as Schema from "effect/Schema"
|
|
10
|
+
|
|
11
|
+
export type AdfMetadataKind = "attrs" | "marks" | "node"
|
|
12
|
+
|
|
13
|
+
export const AdfMetadataEntrySchema = Schema.Struct({
|
|
14
|
+
kind: Schema.Literals(["attrs", "marks", "node"]),
|
|
15
|
+
value: Schema.Unknown
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export const AdfMetadataSidecarSchema = Schema.Struct({
|
|
19
|
+
version: Schema.Literal(1),
|
|
20
|
+
entries: Schema.Record(Schema.String, AdfMetadataEntrySchema)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export type AdfMetadataEntry = typeof AdfMetadataEntrySchema.Type
|
|
24
|
+
export type AdfMetadataSidecar = typeof AdfMetadataSidecarSchema.Type
|
|
25
|
+
|
|
26
|
+
const stableStringify = (v: unknown): string => {
|
|
27
|
+
if (Array.isArray(v)) return `[${v.map(stableStringify).join(",")}]`
|
|
28
|
+
if (v !== null && typeof v === "object") {
|
|
29
|
+
const entries = Object.entries(v as Record<string, unknown>)
|
|
30
|
+
.filter(([, value]) => value !== undefined)
|
|
31
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
32
|
+
.map(([k, value]) => `${JSON.stringify(k)}:${stableStringify(value)}`)
|
|
33
|
+
return `{${entries.join(",")}}`
|
|
34
|
+
}
|
|
35
|
+
return JSON.stringify(v) ?? "null"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const markerKinds: ReadonlyArray<AdfMetadataKind> = ["node", "attrs", "marks"]
|
|
39
|
+
|
|
40
|
+
const markerType = (line: string): string => {
|
|
41
|
+
const match = /<!--\s*adf:([A-Za-z][A-Za-z0-9]*)/.exec(line)
|
|
42
|
+
return match?.[1] ?? "metadata"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const fromBase64 = (b64: string): string => {
|
|
46
|
+
const bin = atob(b64)
|
|
47
|
+
return new TextDecoder().decode(Uint8Array.from(bin, (c) => c.charCodeAt(0)))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const parseMetadataValue = (raw: string): unknown | null => {
|
|
51
|
+
const trimmed = raw.trim()
|
|
52
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(trimmed) as unknown
|
|
55
|
+
} catch {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const decoded = fromBase64(trimmed)
|
|
62
|
+
if (!decoded.startsWith("{") && !decoded.startsWith("[")) return null
|
|
63
|
+
return JSON.parse(decoded) as unknown
|
|
64
|
+
} catch {
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const externalizeLine = (
|
|
70
|
+
line: string,
|
|
71
|
+
sidecarHref: string,
|
|
72
|
+
nextId: (type: string) => string,
|
|
73
|
+
entries: Record<string, AdfMetadataEntry>
|
|
74
|
+
): string => {
|
|
75
|
+
if (!line.includes("<!-- adf:") || line.includes("<!-- adf:/")) return line
|
|
76
|
+
const end = line.lastIndexOf("-->")
|
|
77
|
+
if (end === -1) return line
|
|
78
|
+
|
|
79
|
+
for (const kind of markerKinds) {
|
|
80
|
+
const needle = ` ${kind}=`
|
|
81
|
+
const keyStart = line.indexOf(needle)
|
|
82
|
+
if (keyStart === -1 || keyStart > end) continue
|
|
83
|
+
|
|
84
|
+
const valueStart = keyStart + needle.length
|
|
85
|
+
const raw = line.slice(valueStart, end).trim()
|
|
86
|
+
const value = parseMetadataValue(raw)
|
|
87
|
+
if (value === null) return line
|
|
88
|
+
|
|
89
|
+
const id = nextId(markerType(line))
|
|
90
|
+
entries[id] = { kind, value }
|
|
91
|
+
return `${line.slice(0, keyStart)} ref=${sidecarHref}#${id} ${line.slice(end)}`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return line
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const externalizeAdfMetadata = (
|
|
98
|
+
markdown: string,
|
|
99
|
+
sidecarHref: string
|
|
100
|
+
): { readonly markdown: string; readonly sidecar: AdfMetadataSidecar | null } => {
|
|
101
|
+
const entries: Record<string, AdfMetadataEntry> = {}
|
|
102
|
+
let counter = 0
|
|
103
|
+
const nextId = (type: string): string => `${type}-${++counter}`
|
|
104
|
+
const lines = markdown.split("\n").map((line) => externalizeLine(line, sidecarHref, nextId, entries))
|
|
105
|
+
return {
|
|
106
|
+
markdown: lines.join("\n"),
|
|
107
|
+
sidecar: Object.keys(entries).length > 0 ? { version: 1, entries } : null
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const collectAdfMetadataHrefs = (markdown: string): ReadonlySet<string> => {
|
|
112
|
+
const hrefs = new Set<string>()
|
|
113
|
+
for (const line of markdown.split("\n")) {
|
|
114
|
+
if (!line.includes("<!-- adf:") || !line.includes(" ref=")) continue
|
|
115
|
+
const end = line.lastIndexOf("-->")
|
|
116
|
+
const refStart = line.indexOf(" ref=")
|
|
117
|
+
if (end === -1 || refStart === -1 || refStart > end) continue
|
|
118
|
+
const rawRef = line.slice(refStart + " ref=".length, end).trim()
|
|
119
|
+
const href = rawRef.includes("#") ? rawRef.slice(0, rawRef.lastIndexOf("#")) : rawRef
|
|
120
|
+
if (href.length > 0) hrefs.add(href)
|
|
121
|
+
}
|
|
122
|
+
return hrefs
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const hydrateLine = (line: string, sidecars: ReadonlyMap<string, AdfMetadataSidecar>): string => {
|
|
126
|
+
if (!line.includes("<!-- adf:") || !line.includes(" ref=")) return line
|
|
127
|
+
const end = line.lastIndexOf("-->")
|
|
128
|
+
const refStart = line.indexOf(" ref=")
|
|
129
|
+
if (end === -1 || refStart === -1 || refStart > end) return line
|
|
130
|
+
|
|
131
|
+
const rawRef = line.slice(refStart + " ref=".length, end).trim()
|
|
132
|
+
const href = rawRef.includes("#") ? rawRef.slice(0, rawRef.lastIndexOf("#")) : rawRef
|
|
133
|
+
const id = rawRef.includes("#") ? rawRef.slice(rawRef.lastIndexOf("#") + 1) : rawRef
|
|
134
|
+
const sidecar = sidecars.get(href)
|
|
135
|
+
if (!sidecar) return line
|
|
136
|
+
const entry = sidecar.entries[id]
|
|
137
|
+
if (!entry) return line
|
|
138
|
+
|
|
139
|
+
return `${line.slice(0, refStart)} ${entry.kind}=${stableStringify(entry.value)} ${line.slice(end)}`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const hydrateAdfMetadata = (
|
|
143
|
+
markdown: string,
|
|
144
|
+
sidecars: ReadonlyMap<string, AdfMetadataSidecar>
|
|
145
|
+
): string => markdown.split("\n").map((line) => hydrateLine(line, sidecars)).join("\n")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove Confluence round-trip metadata from markdown intended for reading.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const ADF_COMMENT_PATTERN = /<!--\s*adf:[\s\S]*?-->/g
|
|
6
|
+
|
|
7
|
+
export const cleanMarkdown = (markdown: string): string => {
|
|
8
|
+
const cleaned = markdown
|
|
9
|
+
.replace(ADF_COMMENT_PATTERN, "")
|
|
10
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
11
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
12
|
+
.trim()
|
|
13
|
+
|
|
14
|
+
return cleaned.length > 0 ? `${cleaned}\n` : ""
|
|
15
|
+
}
|