@vdfor/confluence-sync 0.1.0 → 0.3.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/README.md CHANGED
@@ -23,6 +23,9 @@ yarn global add @vdfor/confluence-sync
23
23
  # 必填:Confluence 服务地址
24
24
  export CONFLUENCE_BASE_URL="https://your-confluence-instance.com"
25
25
 
26
+ # 必填:Space Key
27
+ export CONFLUENCE_SPACE_KEY="YOUR_SPACE_KEY"
28
+
26
29
  # 认证方式(二选一)
27
30
  # 方式1(推荐):Personal Access Token
28
31
  export CONFLUENCE_PAT="your-personal-access-token"
@@ -37,6 +40,7 @@ export CONFLUENCE_API_TOKEN="your-api-token"
37
40
  ```bash
38
41
  confluence-sync upload --file test.md \
39
42
  --base-url https://your-confluence-instance.com \
43
+ --space-key YOUR_SPACE_KEY \
40
44
  --pat your-token
41
45
  ```
42
46
 
@@ -85,10 +89,11 @@ confluence-sync get-content --page-id <ID> [--markdown]
85
89
  | 参数 | 说明 |
86
90
  |------|------|
87
91
  | `--base-url` | Confluence 服务地址 |
92
+ | `--space-key` | Space Key |
88
93
  | `--pat` | Personal Access Token |
89
94
  | `--username` | Confluence 登录名 |
90
95
  | `--api-token` | API Token 或密码 |
91
- | `--space` | Space Key |
96
+ | `--space` | Space Key(覆盖默认值) |
92
97
  | `--file` | 本地文件路径 |
93
98
  | `--title` | 页面标题 |
94
99
  | `--page-id` | 页面 ID |
@@ -119,6 +124,25 @@ confluence-sync get-content --page-id 123456
119
124
  confluence-sync get-content --page-id 123456 --markdown
120
125
  ```
121
126
 
127
+ ## Skill 集成
128
+
129
+ 本项目包含 Trae Skill,安装后可被智能体调用。
130
+
131
+ ### 安装
132
+
133
+ ```bash
134
+ pnpm add -g @vdfor/confluence-sync
135
+ ```
136
+
137
+ ### 使用
138
+
139
+ 安装后,智能体可直接调用 `confluence-sync` 命令:
140
+
141
+ ```bash
142
+ confluence-sync upload --file README.md --title "项目文档" --space MYSPACE
143
+ confluence-sync get-content --page-id 123456 --markdown
144
+ ```
145
+
122
146
  ## License
123
147
 
124
148
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vdfor/confluence-sync",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "author": "vdfor",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "files": [
22
22
  "upload.mjs",
23
- "src/"
23
+ "src/",
24
+ "skills/"
24
25
  ],
25
26
  "engines": {
26
27
  "node": ">=18"
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: "confluence-sync"
3
+ description: "Confluence 文档同步 CLI 工具,支持将本地 Markdown 文件上传至 Confluence 并自动转换为 Confluence 页面格式。当用户需要上传、更新、获取 Confluence 页面内容或管理附件时调用。"
4
+ ---
5
+
6
+ # Confluence Sync
7
+
8
+ Confluence 文档同步 CLI 工具,支持将本地 Markdown 文件上传至 Confluence 并自动转换为 Confluence 页面格式。
9
+
10
+ ## 功能特性
11
+
12
+ - 上传 Markdown 文件为 Confluence 页面
13
+ - 更新已有页面内容
14
+ - 上传文件作为页面附件
15
+ - 列出空间页面和页面附件
16
+ - 获取页面内容(支持转换为 Markdown 格式)
17
+
18
+ ## 配置要求
19
+
20
+ 使用前需要配置以下环境变量或 CLI 参数:
21
+
22
+ ### 必填配置
23
+
24
+ - `CONFLUENCE_BASE_URL`: Confluence 服务地址
25
+ - `CONFLUENCE_SPACE_KEY`: Space Key
26
+ - 认证方式(二选一):
27
+ - `CONFLUENCE_PAT`: Personal Access Token(推荐)
28
+ - `CONFLUENCE_USERNAME` + `CONFLUENCE_API_TOKEN`: Basic Auth 认证
29
+
30
+ ### 可选配置
31
+
32
+ - `--space`: Space Key(覆盖默认值)
33
+
34
+ ## 命令列表
35
+
36
+ ### upload - 上传 Markdown 为新页面
37
+
38
+ ```bash
39
+ confluence-sync upload --file <path> [--title <标题>] [--space <key>] [--parent <ID或标题>] [--dry-run]
40
+ ```
41
+
42
+ ### update - 更新已有页面
43
+
44
+ ```bash
45
+ confluence-sync update --file <path> (--page-id <ID> | --title <标题>) [--space <key>] [--minor-edit]
46
+ ```
47
+
48
+ ### upload-file - 上传附件
49
+
50
+ ```bash
51
+ confluence-sync upload-file --page-id <ID> --file <path> [--name <文件名>]
52
+ ```
53
+
54
+ ### list-pages - 列出空间页面
55
+
56
+ ```bash
57
+ confluence-sync list-pages [--space <key>]
58
+ ```
59
+
60
+ ### list-files - 列出页面附件
61
+
62
+ ```bash
63
+ confluence-sync list-files --page-id <ID>
64
+ ```
65
+
66
+ ### get-content - 获取页面内容
67
+
68
+ ```bash
69
+ confluence-sync get-content --page-id <ID> [--markdown]
70
+ ```
71
+
72
+ 使用 `--markdown` 参数可将 Confluence 内容转换为 Markdown 格式输出。
73
+
74
+ ## 使用示例
75
+
76
+ ```bash
77
+ # 上传 Markdown 文件
78
+ confluence-sync upload --file README.md --title "项目文档" --space MYSPACE
79
+
80
+ # 更新已有页面
81
+ confluence-sync update --file README.md --page-id 123456
82
+
83
+ # 上传附件
84
+ confluence-sync upload-file --page-id 123456 --file image.png
85
+
86
+ # 列出空间所有页面
87
+ confluence-sync list-pages --space MYSPACE
88
+
89
+ # 获取页面内容
90
+ confluence-sync get-content --page-id 123456
91
+
92
+ # 获取页面内容并转换为 Markdown
93
+ confluence-sync get-content --page-id 123456 --markdown
94
+ ```
95
+
96
+ ## 注意事项
97
+
98
+ 1. 使用前请确保已正确配置认证信息
99
+ 2. Personal Access Token 需要在 Confluence 个人设置中生成
100
+ 3. 上传附件时,如果附件已存在会自动更新
101
+ 4. 使用 `--dry-run` 参数可以预览转换结果而不实际上传
@@ -1,13 +1,10 @@
1
1
  import axios from 'axios';
2
2
  import { marked } from 'marked';
3
- import { readFileSync } from 'node:fs';
4
3
  import { extname } from 'node:path';
5
4
 
6
5
  // ── 配置 ──────────────────────────────────────────────────────────────────────
7
- const config = JSON.parse(readFileSync(new URL('../config.json', import.meta.url), 'utf-8'));
8
- const { spaceKey: defaultSpaceKey } = config;
9
-
10
6
  let baseUrl = process.env.CONFLUENCE_BASE_URL;
7
+ let spaceKey = process.env.CONFLUENCE_SPACE_KEY;
11
8
  let pat = process.env.CONFLUENCE_PAT;
12
9
  let username = process.env.CONFLUENCE_USERNAME;
13
10
  let apiToken = process.env.CONFLUENCE_API_TOKEN;
@@ -17,12 +14,14 @@ let api;
17
14
  * 用 CLI 参数覆盖环境变量配置,需在其他函数调用前执行
18
15
  * @param {object} [opts]
19
16
  * @param {string} [opts.baseUrl]
17
+ * @param {string} [opts.spaceKey]
20
18
  * @param {string} [opts.pat]
21
19
  * @param {string} [opts.username]
22
20
  * @param {string} [opts.apiToken]
23
21
  */
24
22
  export function configure(opts = {}) {
25
23
  if (opts.baseUrl) baseUrl = opts.baseUrl;
24
+ if (opts.spaceKey) spaceKey = opts.spaceKey;
26
25
  if (opts.pat) pat = opts.pat;
27
26
  if (opts.username) username = opts.username;
28
27
  if (opts.apiToken) apiToken = opts.apiToken;
@@ -479,7 +478,8 @@ async function resolveParentId(parentIdentifier, spaceKey) {
479
478
  * @param {boolean} [opts.dryRun] - 仅打印转换结果
480
479
  */
481
480
  export async function uploadMarkdown(opts) {
482
- const { filePath, title: optTitle, spaceKey = defaultSpaceKey, parentId: parentRaw, dryRun = false } = opts;
481
+ const { filePath, title: optTitle, spaceKey: spaceKeyOpt, parentId: parentRaw, dryRun = false } = opts;
482
+ const effectiveSpaceKey = spaceKeyOpt || spaceKey;
483
483
  const fs = await import('node:fs');
484
484
  const path = await import('node:path');
485
485
 
@@ -490,16 +490,16 @@ export async function uploadMarkdown(opts) {
490
490
  if (dryRun) {
491
491
  console.log('── 转换结果(dry-run)────────────────────────');
492
492
  console.log(` 标题: ${title}`);
493
- console.log(` Space: ${spaceKey}`);
493
+ console.log(` Space: ${effectiveSpaceKey}`);
494
494
  console.log(' Body:\n' + bodyHtml);
495
495
  return null;
496
496
  }
497
497
 
498
498
  // 查找父页面
499
- const parentId = await resolveParentId(parentRaw, spaceKey);
499
+ const parentId = await resolveParentId(parentRaw, effectiveSpaceKey);
500
500
 
501
501
  // 检查是否已存在同名页面
502
- const existing = await getPageByTitle(spaceKey, title);
502
+ const existing = await getPageByTitle(effectiveSpaceKey, title);
503
503
  if (existing) {
504
504
  console.log(` 页面「${title}」已存在 (ID: ${existing.id}),将更新…`);
505
505
  const updated = await updatePage(existing.id, title, bodyHtml, existing.version.number);
@@ -507,7 +507,7 @@ export async function uploadMarkdown(opts) {
507
507
  return updated;
508
508
  }
509
509
 
510
- const page = await createPage(spaceKey, title, bodyHtml, parentId);
510
+ const page = await createPage(effectiveSpaceKey, title, bodyHtml, parentId);
511
511
  console.log(` ✅ 创建完成 → ${baseUrl}/pages/viewpage.action?pageId=${page.id}`);
512
512
  return page;
513
513
  }
@@ -516,7 +516,8 @@ export async function uploadMarkdown(opts) {
516
516
  * 更新指定页面(通过 ID 或 space+title 查找)
517
517
  */
518
518
  export async function updateMarkdown(opts) {
519
- const { pageId, title: searchTitle, filePath, spaceKey = defaultSpaceKey, minorEdit = false } = opts;
519
+ const { pageId, title: searchTitle, filePath, spaceKey: spaceKeyOpt, minorEdit = false } = opts;
520
+ const effectiveSpaceKey = spaceKeyOpt || spaceKey;
520
521
  const fs = await import('node:fs');
521
522
 
522
523
  const md = fs.readFileSync(filePath, 'utf-8');
@@ -526,8 +527,8 @@ export async function updateMarkdown(opts) {
526
527
  if (pageId) {
527
528
  page = await getPageById(pageId);
528
529
  } else if (searchTitle) {
529
- page = await getPageByTitle(spaceKey, searchTitle);
530
- if (!page) throw new Error(`未找到页面「${searchTitle}」(space: ${spaceKey})`);
530
+ page = await getPageByTitle(effectiveSpaceKey, searchTitle);
531
+ if (!page) throw new Error(`未找到页面「${searchTitle}」(space: ${effectiveSpaceKey})`);
531
532
  } else {
532
533
  throw new Error('必须指定 --page-id 或 --title 来定位目标页面');
533
534
  }
@@ -539,5 +540,5 @@ export async function updateMarkdown(opts) {
539
540
  }
540
541
 
541
542
  // ── 导出配置 ──────────────────────────────────────────────────────────────────
542
- export { defaultSpaceKey };
543
543
  export function getBaseUrl() { return baseUrl; }
544
+ export function getSpaceKey() { return spaceKey; }
package/upload.mjs CHANGED
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * 环境变量(或通过 CLI 参数配置):
6
6
  * 必填: CONFLUENCE_BASE_URL - Confluence 服务地址
7
+ * CONFLUENCE_SPACE_KEY - Space Key
7
8
  * 认证方式(二选一):
8
9
  * 方式1 PAT: CONFLUENCE_PAT - Personal Access Token
9
10
  * 方式2 Basic Auth: CONFLUENCE_USERNAME - Confluence 登录名(工号)
@@ -19,6 +20,7 @@
19
20
  *
20
21
  * 可选配置参数(优先于环境变量):
21
22
  * --base-url Confluence 服务地址
23
+ * --space-key Space Key
22
24
  * --pat Personal Access Token
23
25
  * --username Confluence 登录名
24
26
  * --api-token API Token 或密码
@@ -32,8 +34,8 @@ import {
32
34
  listAttachments,
33
35
  getPageContent,
34
36
  confluenceToMd,
35
- defaultSpaceKey,
36
37
  getBaseUrl,
38
+ getSpaceKey,
37
39
  configure,
38
40
  } from './src/confluence.mjs';
39
41
 
@@ -106,6 +108,7 @@ get-content 选项:
106
108
 
107
109
  配置参数(优先于环境变量):
108
110
  --base-url Confluence 服务地址
111
+ --space-key Space Key
109
112
  --pat Personal Access Token
110
113
  --username Confluence 登录名
111
114
  --api-token API Token 或密码
@@ -113,6 +116,7 @@ get-content 选项:
113
116
  环境变量:
114
117
  必填:
115
118
  CONFLUENCE_BASE_URL Confluence 服务地址
119
+ CONFLUENCE_SPACE_KEY Space Key
116
120
 
117
121
  认证方式(二选一):
118
122
  方式1 - Personal Access Token:
@@ -139,11 +143,13 @@ async function main() {
139
143
  // 用 CLI 参数覆盖环境变量配置
140
144
  configure({
141
145
  baseUrl: args['base-url'],
146
+ spaceKey: args['space-key'],
142
147
  pat: args['pat'],
143
148
  username: args['username'],
144
149
  apiToken: args['api-token'],
145
150
  });
146
151
  const baseUrl = getBaseUrl();
152
+ const spaceKey = getSpaceKey();
147
153
 
148
154
  try {
149
155
  switch (command) {
@@ -155,7 +161,7 @@ async function main() {
155
161
  const result = await uploadMarkdown({
156
162
  filePath: args.file,
157
163
  title: args.title,
158
- spaceKey: args.space || defaultSpaceKey,
164
+ spaceKey: args.space || spaceKey,
159
165
  parentId: args.parent,
160
166
  dryRun: args['dry-run'] === true,
161
167
  });
@@ -182,7 +188,7 @@ async function main() {
182
188
  pageId: args['page-id'],
183
189
  title: args.title,
184
190
  filePath: args.file,
185
- spaceKey: args.space || defaultSpaceKey,
191
+ spaceKey: args.space || spaceKey,
186
192
  minorEdit: args['minor-edit'] === true,
187
193
  });
188
194
  console.log('\n页面信息:');
@@ -210,7 +216,7 @@ async function main() {
210
216
  }
211
217
 
212
218
  case 'list-pages': {
213
- const space = args.space || defaultSpaceKey;
219
+ const space = args.space || spaceKey;
214
220
  console.log(`Space: ${space}\n`);
215
221
  const pages = await listPages(space);
216
222
  if (!pages.length) {