@jspg-ai/coding-bb 0.0.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 (183) hide show
  1. package/README.md +41 -0
  2. package/cbb/dev-standards/rules/cbb-ai-behavior.md +104 -0
  3. package/cbb/dev-standards/rules/cbb-coding-rule.md +50 -0
  4. package/cbb/dev-standards/rules/cbb-priority.md +56 -0
  5. package/cbb/dev-standards/skills/architecture-specs/SKILL.md +129 -0
  6. package/cbb/dev-standards/skills/coding-specs/SKILL.md +376 -0
  7. package/cbb/dev-standards/skills/coding-specs/references/concurrency.md +53 -0
  8. package/cbb/dev-standards/skills/coding-specs/references/config-center.md +16 -0
  9. package/cbb/dev-standards/skills/coding-specs/references/distributed.md +42 -0
  10. package/cbb/dev-standards/skills/coding-specs/references/es-coding.md +60 -0
  11. package/cbb/dev-standards/skills/coding-specs/references/scheduled-task.md +25 -0
  12. package/cbb/dev-standards/skills/coding-specs/references/security.md +11 -0
  13. package/cbb/dev-standards/skills/coding-specs/references/unit-testing.md +43 -0
  14. package/cbb/dev-standards/skills/es-design-specs/SKILL.md +104 -0
  15. package/cbb/dev-standards/skills/mysql-design-specs/SKILL.md +89 -0
  16. package/cbb/lib/install/claude-code.js +20 -0
  17. package/cbb/lib/install/cleanup.js +64 -0
  18. package/cbb/lib/install/init.js +1875 -0
  19. package/cbb/lib/install/qoder.js +20 -0
  20. package/cbb/lib/install/workspaces.js +232 -0
  21. package/cbb/lib/openspec/index.js +554 -0
  22. package/cbb/lib/superpowers/index.js +265 -0
  23. package/cbb/lib/utils/check-update.js +147 -0
  24. package/cbb/lib/utils/checkbox.js +383 -0
  25. package/cbb/lib/utils/gitignore.js +69 -0
  26. package/cbb/lib/utils/output.js +64 -0
  27. package/cbb/lib/utils/settings.js +119 -0
  28. package/cbb/lib/utils/version.js +135 -0
  29. package/cbb/lib/wiki/api-client.js +358 -0
  30. package/cbb/lib/wiki/cli.js +427 -0
  31. package/cbb/lib/wiki/convert.js +464 -0
  32. package/cbb/lib/wiki/index.js +218 -0
  33. package/cbb/lib/wiki/mermaid-guard.js +103 -0
  34. package/cbb/lib/wiki/split.js +131 -0
  35. package/cbb/tools/cbb-decompile-jar/SKILL.md +220 -0
  36. package/cbb/tools/cbb-decompile-jar/scripts/decompile.py +863 -0
  37. package/cbb/tools/cbb-design-to-wiki/SKILL.md +180 -0
  38. package/cbb/tools/cbb-mvn-guide/SKILL.md +281 -0
  39. package/cbb/tools/cbb-mvn-guide/scripts/mvn_jdk_manager.py +378 -0
  40. package/cbb/tools/cbb-mvn-guide/scripts/mvn_pom_jdk_reader.py +197 -0
  41. package/cbb/tools/cbb-plantuml-authoring/SKILL.md +448 -0
  42. package/cbb/tools/cbb-plantuml-authoring/references/drawing-templates.md +479 -0
  43. package/cbb/tools/cbb-wiki-ops/SKILL.md +134 -0
  44. package/cbb/tools/cbb-wiki-ops/scripts/check-auth.js +44 -0
  45. package/cbb/worktrees/_shared/scripts/find-target-worktree.js +96 -0
  46. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +67 -0
  47. package/cbb/worktrees/_shared/scripts/push-core.js +136 -0
  48. package/cbb/worktrees/_shared/scripts/silence-popup.js +23 -0
  49. package/cbb/worktrees/commands/close.md +64 -0
  50. package/cbb/worktrees/commands/extend.md +65 -0
  51. package/cbb/worktrees/commands/init.md +55 -0
  52. package/cbb/worktrees/commands/push.md +42 -0
  53. package/cbb/worktrees/skills/openspec-close-worktree/SKILL.md +449 -0
  54. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-env.js +76 -0
  55. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-unarchived.js +48 -0
  56. package/cbb/worktrees/skills/openspec-close-worktree/scripts/delete-branches.js +136 -0
  57. package/cbb/worktrees/skills/openspec-close-worktree/scripts/discover-apps.js +76 -0
  58. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +96 -0
  59. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-workspace-root.js +67 -0
  60. package/cbb/worktrees/skills/openspec-close-worktree/scripts/remove-worktrees.js +124 -0
  61. package/cbb/worktrees/skills/openspec-close-worktree/scripts/safety-check.js +174 -0
  62. package/cbb/worktrees/skills/openspec-close-worktree/scripts/silence-popup.js +23 -0
  63. package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +390 -0
  64. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +95 -0
  65. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +98 -0
  66. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +135 -0
  67. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-target-worktree.js +96 -0
  68. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-workspace-root.js +67 -0
  69. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +150 -0
  70. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +88 -0
  71. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/push-core.js +136 -0
  72. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/silence-popup.js +23 -0
  73. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +93 -0
  74. package/cbb/worktrees/skills/openspec-init-worktree/SKILL.md +539 -0
  75. package/cbb/worktrees/skills/openspec-init-worktree/scripts/auto-open.js +136 -0
  76. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env-deep.js +87 -0
  77. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env.js +90 -0
  78. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-repos.js +171 -0
  79. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-branches.js +103 -0
  80. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-worktrees.js +154 -0
  81. package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +67 -0
  82. package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +93 -0
  83. package/cbb/worktrees/skills/openspec-init-worktree/scripts/install-ai.js +177 -0
  84. package/cbb/worktrees/skills/openspec-init-worktree/scripts/parse-config.js +67 -0
  85. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-branches.js +101 -0
  86. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +136 -0
  87. package/cbb/worktrees/skills/openspec-init-worktree/scripts/silence-popup.js +23 -0
  88. package/cbb/worktrees/skills/openspec-init-worktree/scripts/sync-repos.js +95 -0
  89. package/cbb/worktrees/skills/openspec-init-worktree/scripts/update-gitignore.js +134 -0
  90. package/cbb/worktrees/skills/openspec-push-worktrees/SKILL.md +307 -0
  91. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/commit-worktrees.js +269 -0
  92. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-target-worktree.js +96 -0
  93. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-workspace-root.js +67 -0
  94. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-core.js +136 -0
  95. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-worktrees.js +159 -0
  96. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +23 -0
  97. package/config/cbb.yaml +6 -0
  98. package/config/config.sample.json +16 -0
  99. package/config/openspec/config.yaml +28 -0
  100. package/config/openspec/schemas/spec-driven/schema.yaml +247 -0
  101. package/config/openspec/schemas/spec-driven/templates/design.md +475 -0
  102. package/config/openspec/schemas/spec-driven/templates/proposal.md +58 -0
  103. package/config/openspec/schemas/spec-driven/templates/spec.md +8 -0
  104. package/config/openspec/schemas/spec-driven/templates/tasks.md +9 -0
  105. package/config/workspaces.json +15 -0
  106. package/openspec/.version +6 -0
  107. package/openspec/commands/apply.md +182 -0
  108. package/openspec/commands/archive.md +223 -0
  109. package/openspec/commands/bulk-archive.md +334 -0
  110. package/openspec/commands/continue.md +112 -0
  111. package/openspec/commands/explore.md +206 -0
  112. package/openspec/commands/ff.md +111 -0
  113. package/openspec/commands/new.md +70 -0
  114. package/openspec/commands/onboard.md +555 -0
  115. package/openspec/commands/propose.md +157 -0
  116. package/openspec/commands/sync.md +256 -0
  117. package/openspec/commands/update.md +85 -0
  118. package/openspec/commands/verify.md +169 -0
  119. package/openspec/skills/openspec-apply-change/SKILL.md +187 -0
  120. package/openspec/skills/openspec-archive-change/SKILL.md +181 -0
  121. package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  122. package/openspec/skills/openspec-continue-change/SKILL.md +117 -0
  123. package/openspec/skills/openspec-explore/SKILL.md +342 -0
  124. package/openspec/skills/openspec-ff-change/SKILL.md +116 -0
  125. package/openspec/skills/openspec-new-change/SKILL.md +76 -0
  126. package/openspec/skills/openspec-onboard/SKILL.md +560 -0
  127. package/openspec/skills/openspec-propose/SKILL.md +162 -0
  128. package/openspec/skills/openspec-sync-specs/SKILL.md +261 -0
  129. package/openspec/skills/openspec-update-change/SKILL.md +90 -0
  130. package/openspec/skills/openspec-verify-change/SKILL.md +174 -0
  131. package/package.json +46 -0
  132. package/superpowers/.version +6 -0
  133. package/superpowers/skills/brainstorming/SKILL.md +250 -0
  134. package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
  135. package/superpowers/skills/brainstorming/scripts/helper.js +167 -0
  136. package/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
  137. package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
  138. package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
  139. package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  140. package/superpowers/skills/brainstorming/visual-companion.md +299 -0
  141. package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -0
  142. package/superpowers/skills/executing-plans/SKILL.md +64 -0
  143. package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -0
  144. package/superpowers/skills/receiving-code-review/SKILL.md +205 -0
  145. package/superpowers/skills/requesting-code-review/SKILL.md +95 -0
  146. package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -0
  147. package/superpowers/skills/subagent-driven-development/SKILL.md +568 -0
  148. package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -0
  149. package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -0
  150. package/superpowers/skills/subagent-driven-development/scripts/review-package +46 -0
  151. package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +40 -0
  152. package/superpowers/skills/subagent-driven-development/scripts/task-brief +41 -0
  153. package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
  154. package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  155. package/superpowers/skills/systematic-debugging/SKILL.md +283 -0
  156. package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  157. package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  158. package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  159. package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -0
  160. package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  161. package/superpowers/skills/systematic-debugging/test-academic.md +14 -0
  162. package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  163. package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  164. package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  165. package/superpowers/skills/test-driven-development/SKILL.md +320 -0
  166. package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -0
  167. package/superpowers/skills/using-git-worktrees/SKILL.md +167 -0
  168. package/superpowers/skills/using-superpowers/SKILL.md +63 -0
  169. package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
  170. package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -0
  171. package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -0
  172. package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -0
  173. package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
  174. package/superpowers/skills/verification-before-completion/SKILL.md +120 -0
  175. package/superpowers/skills/writing-plans/SKILL.md +171 -0
  176. package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  177. package/superpowers/skills/writing-skills/SKILL.md +679 -0
  178. package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  179. package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  180. package/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  181. package/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  182. package/superpowers/skills/writing-skills/render-graphs.js +169 -0
  183. package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * cbb wiki 子命令 — Wiki 查询与管理。
5
+ *
6
+ * 用法:
7
+ * cbb wiki get <pageId> [--expand=...] [--full]
8
+ * cbb wiki children <pageId> [--limit=50] [--start=0]
9
+ * cbb wiki search "<cql>" [--limit=20] [--excerpt=highlight] [--order=lastmodified desc]
10
+ * cbb wiki spaces [--limit=100] [--type=global]
11
+ * cbb wiki comments <pageId> [--limit=50]
12
+ * cbb wiki user [--current] [--account-id=<id>] [--username=<name>]
13
+ * cbb wiki versions <pageId> [--limit=20]
14
+ * cbb wiki attachments <pageId> list [--limit=50]
15
+ * cbb wiki attachments <pageId> upload --file=<path> [--comment="..."]
16
+ * cbb wiki attachments <pageId> delete --attachment-id=<id>
17
+ * cbb wiki comment <pageId> --body-file=<path> [--parent=<parentCommentId>]
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const { markdownToXhtml } = require('./convert');
23
+ const api = require('./api-client');
24
+
25
+ // ── 工具 ──────────────────────────────────────────────
26
+
27
+ function out(msg) {
28
+ process.stdout.write(Buffer.from(msg + '\n', 'utf8'));
29
+ }
30
+
31
+ function err(msg) {
32
+ process.stderr.write(Buffer.from(msg + '\n', 'utf8'));
33
+ }
34
+
35
+ // 已知带值选项:允许 --flag value 与 --flag=value 两种写法。
36
+ // 出现未在此列出的选项时,按布尔处理(保持旧版行为,便于未知选项平滑升级)。
37
+ const VALUED_OPTIONS = new Set([
38
+ 'parent-id', 'title', 'file', 'page-id', 'body-file',
39
+ 'attachment-id', 'account-id', 'username', 'parent',
40
+ 'comment', 'limit', 'start', 'excerpt', 'order',
41
+ 'expand', 'type',
42
+ ]);
43
+ // 已知布尔选项:显式声明为开关,避免与同名带值选项(如 --type、--expand)冲突时误吞参数
44
+ const BOOLEAN_OPTIONS = new Set(['full', 'current', 'minor-edit']);
45
+
46
+ function parseArgs(argv) {
47
+ const pos = [];
48
+ const opts = {};
49
+ for (let i = 0; i < argv.length; i++) {
50
+ const a = argv[i];
51
+ if (a.startsWith('--')) {
52
+ const eq = a.indexOf('=');
53
+ let key;
54
+ let value;
55
+ if (eq > 0) {
56
+ // --flag=value 形式
57
+ key = a.slice(2, eq);
58
+ value = a.slice(eq + 1);
59
+ } else {
60
+ key = a.slice(2);
61
+ if (VALUED_OPTIONS.has(key)) {
62
+ // --flag value 形式:消耗下一个参数作为值
63
+ value = argv[++i];
64
+ if (value === undefined) {
65
+ err(`选项 --${key} 需要一个值(用法: --${key} <value> 或 --${key}=<value>)`);
66
+ process.exit(1);
67
+ }
68
+ } else {
69
+ // 未知 / 已知布尔选项 → 视为 true
70
+ value = true;
71
+ }
72
+ }
73
+ opts[key] = value;
74
+ } else {
75
+ pos.push(a);
76
+ }
77
+ }
78
+ return { pos, opts };
79
+ }
80
+
81
+ function showHelp() {
82
+ out(`cbb wiki — Wiki 操作(查询 + 发布 + 管理)
83
+
84
+ 参数格式:
85
+ 本工具同时支持两种写法,请按习惯任选其一:
86
+ --flag <value> GNU 风格(推荐,shell 提示更友好)
87
+ --flag=<value> 等号风格
88
+
89
+ 子命令:
90
+ create --parent-id <id> --title "..." --file <md> 创建新页面
91
+ create --parent-id=<id> --title="..." --file=<md> 等价写法
92
+ update --page-id <id> --file <md> 更新已有页面
93
+ update --page-id=<id> --file=<md> 等价写法
94
+ get <pageId> [--expand=...] [--full] 读页面(--full 输出正文)
95
+ children <pageId> [--limit=50] [--start=0] 列子页
96
+ search "<cql>" [--limit=20] [--excerpt=highlight] CQL 搜索
97
+ spaces [--limit=100] [--type=global] 列空间
98
+ comments <pageId> [--limit=50] 列评论
99
+ user [--current] [--account-id=<id>] [--username=<name>] 查用户
100
+ versions <pageId> [--limit=20] 列历史版本
101
+ attachments <pageId> list [--limit=50] 列附件
102
+ attachments <pageId> upload --file=<path> 上传附件
103
+ attachments <pageId> delete --attachment-id=<id> 删除附件
104
+ comment <pageId> --body-file=<path> 创建评论
105
+
106
+ 示例:
107
+ cbb wiki create --parent-id 123456 --title "方案" --file design.md
108
+ cbb wiki get 123456 --full
109
+ cbb wiki search 'type=page AND title~"freight"'
110
+
111
+ 认证:环境变量 CBB_WIKI_EMAIL + CBB_WIKI_TOKEN,或 ~/.cbb/wiki-config.json
112
+ 令牌获取: https://wiki.amh-group.com/plugins/tokens/view.action`);
113
+ }
114
+
115
+ // ── 子命令实现 ────────────────────────────────────────
116
+
117
+ async function cmdGet({ pos, opts }) {
118
+ if (!pos[0]) { err('用法: cbb wiki get <pageId> [--expand=...] [--full]'); process.exit(1); }
119
+ const result = await api.getPage(pos[0], { includeBody: opts.full });
120
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
121
+
122
+ const d = result.data;
123
+ out('# Wiki 页面信息');
124
+ out('');
125
+ out(`- **内容ID**: ${d.id}`);
126
+ out(`- **内容标题**: ${d.title}`);
127
+ out(`- **所属空间Key**: ${d.spaceKey}`);
128
+ out(`- **所属空间名称**: ${d.spaceName}`);
129
+ out(`- **版本**: ${d.version}`);
130
+ if (d.bodyStorage) {
131
+ if (opts.full) {
132
+ out('');
133
+ out('## 内容正文 (XHTML)');
134
+ out('```html');
135
+ out(d.bodyStorage);
136
+ out('```');
137
+ } else {
138
+ out(`- **正文字节数**: ${d.bodyStorage.length}(加 --full 查看全文)`);
139
+ }
140
+ }
141
+ }
142
+
143
+ async function cmdChildren({ pos, opts }) {
144
+ if (!pos[0]) { err('用法: cbb wiki children <pageId> [--limit=50] [--start=0]'); process.exit(1); }
145
+ const result = await api.getChildren(pos[0], { limit: Number(opts.limit) || 50, start: Number(opts.start) || 0 });
146
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
147
+
148
+ const d = result.data;
149
+ const results = d.results || [];
150
+ out('# Wiki 子页面列表');
151
+ out(`- **父页面ID**: ${pos[0]}`);
152
+ out(`- **本页数量**: ${results.length}`);
153
+ out('');
154
+ if (results.length === 0) { out('(无子页面)'); return; }
155
+ results.forEach((p, i) => {
156
+ out(`### ${i + 1}. ${p.title}`);
157
+ out(`- **页面ID**: ${p.id}`);
158
+ out(`- **版本**: ${p.version && p.version.number}`);
159
+ if (p.version && p.version.when) out(`- **最后修改**: ${p.version.when}`);
160
+ out('');
161
+ });
162
+ }
163
+
164
+ async function cmdSearch({ pos, opts }) {
165
+ if (!pos[0]) { err('用法: cbb wiki search "<cql>" [--limit=20] [--excerpt=highlight] [--order=lastmodified desc]'); process.exit(1); }
166
+ const result = await api.search(pos[0], {
167
+ limit: Number(opts.limit) || 20,
168
+ excerpt: opts.excerpt,
169
+ order: opts.order,
170
+ });
171
+ if (!result.success) { err(`搜索失败: ${result.error}`); process.exit(1); }
172
+
173
+ const d = result.data;
174
+ const results = d.results || [];
175
+ out('# Wiki 搜索结果');
176
+ out(`- **CQL**: ${pos[0]}`);
177
+ out(`- **命中数量**: ${d.totalSize != null ? d.totalSize : results.length}`);
178
+ out('');
179
+ if (results.length === 0) { out('(无结果)'); return; }
180
+ results.forEach((r, i) => {
181
+ out(`### ${i + 1}. ${r.content && r.content.title || r.title || '(未知)'}`);
182
+ out(`- **页面ID**: ${r.content && r.content.id || r.entityId}`);
183
+ if (r.excerpt) out(`- **摘要**: ${r.excerpt}`);
184
+ out('');
185
+ });
186
+ }
187
+
188
+ async function cmdSpaces({ opts }) {
189
+ const result = await api.getSpaces({ limit: Number(opts.limit) || 100, type: opts.type });
190
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
191
+
192
+ const d = result.data;
193
+ const results = d.results || [];
194
+ out('# Wiki 空间列表');
195
+ out(`- **本页数量**: ${results.length}`);
196
+ out('');
197
+ if (results.length === 0) { out('(无空间)'); return; }
198
+ results.forEach((s, i) => {
199
+ out(`### ${i + 1}. ${s.name}`);
200
+ out(`- **空间Key**: ${s.key}`);
201
+ out(`- **类型**: ${s.type}`);
202
+ out('');
203
+ });
204
+ }
205
+
206
+ async function cmdComments({ pos, opts }) {
207
+ if (!pos[0]) { err('用法: cbb wiki comments <pageId> [--limit=50]'); process.exit(1); }
208
+ const result = await api.getComments(pos[0], { limit: Number(opts.limit) || 50 });
209
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
210
+
211
+ const d = result.data;
212
+ const results = d.results || [];
213
+ out('# Wiki 评论列表');
214
+ out(`- **页面ID**: ${pos[0]}`);
215
+ out(`- **评论数量**: ${results.length}`);
216
+ out('');
217
+ if (results.length === 0) { out('(无评论)'); return; }
218
+ results.forEach((c, i) => {
219
+ out(`### 评论 ${i + 1}`);
220
+ out(`- **评论ID**: ${c.id}`);
221
+ if (c.version && c.version.by && c.version.by.displayName) out(`- **作者**: ${c.version.by.displayName}`);
222
+ if (c.version && c.version.when) out(`- **时间**: ${c.version.when}`);
223
+ if (c.body && c.body.storage) {
224
+ const text = c.body.storage.value.replace(/<[^>]+>/g, '').slice(0, 200);
225
+ out(`- **内容**: ${text}${c.body.storage.value.length > 200 ? '...' : ''}`);
226
+ }
227
+ out('');
228
+ });
229
+ }
230
+
231
+ async function cmdUser({ opts }) {
232
+ const result = await api.getUser({
233
+ current: opts.current,
234
+ accountId: opts['account-id'],
235
+ username: opts.username,
236
+ });
237
+ if (!result.success) { err(`查询失败: ${result.error}`); process.exit(1); }
238
+
239
+ const d = result.data;
240
+ out('# Wiki 用户信息');
241
+ if (d.accountId) out(`- **accountId**: ${d.accountId}`);
242
+ if (d.username) out(`- **用户名**: ${d.username}`);
243
+ if (d.displayName) out(`- **显示名**: ${d.displayName}`);
244
+ if (d.email) out(`- **邮箱**: ${d.email}`);
245
+ if (d.accountType) out(`- **账户类型**: ${d.accountType}`);
246
+ }
247
+
248
+ async function cmdVersions({ pos, opts }) {
249
+ if (!pos[0]) { err('用法: cbb wiki versions <pageId> [--limit=20]'); process.exit(1); }
250
+ const result = await api.getVersions(pos[0], { limit: Number(opts.limit) || 20 });
251
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
252
+
253
+ const d = result.data;
254
+ const results = d.results || [];
255
+ out('# Wiki 历史版本');
256
+ out(`- **页面ID**: ${pos[0]}`);
257
+ out(`- **版本数量**: ${results.length}`);
258
+ out('');
259
+ if (results.length === 0) { out('(无版本记录)'); return; }
260
+ results.forEach((v, i) => {
261
+ out(`### 版本 ${v.number}`);
262
+ if (v.by && v.by.displayName) out(`- **修改人**: ${v.by.displayName}`);
263
+ if (v.when) out(`- **时间**: ${v.when}`);
264
+ if (v.message) out(`- **说明**: ${v.message}`);
265
+ out('');
266
+ });
267
+ }
268
+
269
+ async function cmdAttachments({ pos, opts }) {
270
+ if (!pos[0] || !pos[1]) { err('用法: cbb wiki attachments <pageId> <list|upload|delete> [选项]'); process.exit(1); }
271
+ const pageId = pos[0];
272
+ const action = pos[1];
273
+
274
+ if (action === 'list') {
275
+ const result = await api.getAttachments(pageId, { limit: Number(opts.limit) || 50 });
276
+ if (!result.success) { err(`获取失败: ${result.error}`); process.exit(1); }
277
+ const d = result.data;
278
+ const results = d.results || [];
279
+ out('# Wiki 附件列表');
280
+ out(`- **页面ID**: ${pageId}`);
281
+ out(`- **附件数量**: ${results.length}`);
282
+ out('');
283
+ if (results.length === 0) { out('(无附件)'); return; }
284
+ results.forEach((a, i) => {
285
+ out(`### 附件 ${i + 1}`);
286
+ out(`- **附件ID**: ${a.id}`);
287
+ out(`- **文件名**: ${a.title}`);
288
+ if (a.metadata && a.metadata.mediaType) out(`- **类型**: ${a.metadata.mediaType}`);
289
+ if (a.extensions && a.extensions.fileSize) out(`- **大小**: ${a.extensions.fileSize} bytes`);
290
+ if (a.version && a.version.when) out(`- **上传时间**: ${a.version.when}`);
291
+ out('');
292
+ });
293
+ return;
294
+ }
295
+
296
+ if (action === 'upload') {
297
+ if (!opts.file) { err('upload 需要 --file=<path>'); process.exit(1); }
298
+ const result = await api.uploadAttachment(pageId, opts.file, opts.comment);
299
+ if (!result.success) { err(`上传失败: ${result.error}`); process.exit(1); }
300
+ const att = (result.data.results && result.data.results[0]) || result.data;
301
+ out('# 附件上传成功');
302
+ out(`- **附件ID**: ${att.id}`);
303
+ out(`- **文件名**: ${att.title}`);
304
+ out(`- **页面ID**: ${pageId}`);
305
+ return;
306
+ }
307
+
308
+ if (action === 'delete') {
309
+ if (!opts['attachment-id']) { err('delete 需要 --attachment-id=<id>'); process.exit(1); }
310
+ const result = await api.deleteAttachment(opts['attachment-id']);
311
+ if (!result.success) { err(`删除失败: ${result.error}`); process.exit(1); }
312
+ out('# 附件删除成功');
313
+ out(`- **附件ID**: ${opts['attachment-id']}`);
314
+ return;
315
+ }
316
+
317
+ err(`未知操作: ${action}(支持 list/upload/delete)`);
318
+ process.exit(1);
319
+ }
320
+
321
+ async function cmdComment({ pos, opts }) {
322
+ if (!pos[0] || !opts['body-file']) {
323
+ err('用法: cbb wiki comment <pageId> --body-file=<path> [--parent=<parentCommentId>]');
324
+ process.exit(1);
325
+ }
326
+ const body = fs.readFileSync(opts['body-file'], 'utf8');
327
+ const result = await api.createComment(pos[0], body, opts.parent);
328
+ if (!result.success) { err(`创建失败: ${result.error}`); process.exit(1); }
329
+ out('# 评论创建成功');
330
+ out(`- **评论ID**: ${result.data.id}`);
331
+ out(`- **页面ID**: ${pos[0]}`);
332
+ if (opts.parent) out(`- **回复目标**: ${opts.parent}`);
333
+ }
334
+
335
+ // ── 发布命令 ─────────────────────────────────────────
336
+
337
+ function readAndConvert(filePath) {
338
+ const resolved = path.resolve(filePath);
339
+ if (!fs.existsSync(resolved)) { err(`文件不存在: ${resolved}`); process.exit(1); }
340
+ const markdown = fs.readFileSync(resolved, 'utf-8');
341
+ if (!markdown.trim()) { err(`文件为空: ${resolved}`); process.exit(1); }
342
+ err('转换 Markdown → Confluence Storage XHTML...');
343
+ const xhtml = markdownToXhtml(markdown);
344
+ err(`转换完成,${xhtml.length} 字符`);
345
+ return xhtml;
346
+ }
347
+
348
+ async function cmdCreate({ pos, opts }) {
349
+ if (!opts['parent-id'] || !opts.title || !opts.file) {
350
+ err('用法: cbb wiki create --parent-id <id> --title "..." --file <md>');
351
+ process.exit(1);
352
+ }
353
+ const xhtml = readAndConvert(opts.file);
354
+ err(`创建页面 "${opts.title}" 在父页面 ${opts['parent-id']} 下...`);
355
+ const result = await api.createPage(opts.title, opts['parent-id'], xhtml);
356
+ if (!result.success) {
357
+ err(`创建失败: ${result.error}`);
358
+ if (result.statusCode === 401 || result.statusCode === 403) {
359
+ err('认证失败。请检查 CBB_WIKI_EMAIL / CBB_WIKI_TOKEN 或 ~/.cbb/wiki-config.json。');
360
+ } else if (result.statusCode === 409) {
361
+ err('版本冲突,请重试。');
362
+ }
363
+ process.exit(1);
364
+ }
365
+ const url = api.buildPageUrl(result.data);
366
+ err(`创建成功!页面 ID: ${result.data.id}`);
367
+ err(`访问: ${url}`);
368
+ }
369
+
370
+ async function cmdUpdate({ pos, opts }) {
371
+ if (!opts['page-id'] || !opts.file) {
372
+ err('用法: cbb wiki update --page-id <id> --file <md>');
373
+ process.exit(1);
374
+ }
375
+ const xhtml = readAndConvert(opts.file);
376
+ err(`获取页面 ${opts['page-id']} 信息...`);
377
+ const pageInfo = await api.getPage(opts['page-id']);
378
+ if (!pageInfo.success) { err(`获取页面失败: ${pageInfo.error}`); process.exit(1); }
379
+ err(`更新页面: ${pageInfo.data.title} (v${pageInfo.data.version} → v${pageInfo.data.version + 1})`);
380
+ const result = await api.updatePage(opts['page-id'], pageInfo.data.version, pageInfo.data.title, xhtml);
381
+ if (!result.success) {
382
+ err(`更新失败: ${result.error}`);
383
+ if (result.statusCode === 401 || result.statusCode === 403) {
384
+ err('认证失败。请检查 CBB_WIKI_EMAIL / CBB_WIKI_TOKEN 或 ~/.cbb/wiki-config.json。');
385
+ } else if (result.statusCode === 409) {
386
+ err('版本冲突,页面可能已被他人修改,请重试。');
387
+ }
388
+ process.exit(1);
389
+ }
390
+ const url = api.buildPageUrl(result.data);
391
+ err(`更新成功!页面 ID: ${result.data.id}`);
392
+ err(`访问: ${url}`);
393
+ }
394
+
395
+ // ── 路由 ──────────────────────────────────────────────
396
+
397
+ const commands = {
398
+ create: cmdCreate,
399
+ update: cmdUpdate,
400
+ get: cmdGet,
401
+ children: cmdChildren,
402
+ search: cmdSearch,
403
+ spaces: cmdSpaces,
404
+ comments: cmdComments,
405
+ user: cmdUser,
406
+ versions: cmdVersions,
407
+ attachments: cmdAttachments,
408
+ comment: cmdComment,
409
+ };
410
+
411
+ async function run(argv) {
412
+ const sub = argv[0];
413
+ if (!sub || sub === '-h' || sub === '--help') {
414
+ showHelp();
415
+ return;
416
+ }
417
+ const handler = commands[sub];
418
+ if (!handler) {
419
+ err(`未知子命令: ${sub}`);
420
+ showHelp();
421
+ process.exit(1);
422
+ }
423
+ const args = parseArgs(argv.slice(1));
424
+ await handler(args);
425
+ }
426
+
427
+ module.exports = { run, parseArgs, VALUED_OPTIONS };