@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.
- package/README.md +41 -0
- package/cbb/dev-standards/rules/cbb-ai-behavior.md +104 -0
- package/cbb/dev-standards/rules/cbb-coding-rule.md +50 -0
- package/cbb/dev-standards/rules/cbb-priority.md +56 -0
- package/cbb/dev-standards/skills/architecture-specs/SKILL.md +129 -0
- package/cbb/dev-standards/skills/coding-specs/SKILL.md +376 -0
- package/cbb/dev-standards/skills/coding-specs/references/concurrency.md +53 -0
- package/cbb/dev-standards/skills/coding-specs/references/config-center.md +16 -0
- package/cbb/dev-standards/skills/coding-specs/references/distributed.md +42 -0
- package/cbb/dev-standards/skills/coding-specs/references/es-coding.md +60 -0
- package/cbb/dev-standards/skills/coding-specs/references/scheduled-task.md +25 -0
- package/cbb/dev-standards/skills/coding-specs/references/security.md +11 -0
- package/cbb/dev-standards/skills/coding-specs/references/unit-testing.md +43 -0
- package/cbb/dev-standards/skills/es-design-specs/SKILL.md +104 -0
- package/cbb/dev-standards/skills/mysql-design-specs/SKILL.md +89 -0
- package/cbb/lib/install/claude-code.js +20 -0
- package/cbb/lib/install/cleanup.js +64 -0
- package/cbb/lib/install/init.js +1875 -0
- package/cbb/lib/install/qoder.js +20 -0
- package/cbb/lib/install/workspaces.js +232 -0
- package/cbb/lib/openspec/index.js +554 -0
- package/cbb/lib/superpowers/index.js +265 -0
- package/cbb/lib/utils/check-update.js +147 -0
- package/cbb/lib/utils/checkbox.js +383 -0
- package/cbb/lib/utils/gitignore.js +69 -0
- package/cbb/lib/utils/output.js +64 -0
- package/cbb/lib/utils/settings.js +119 -0
- package/cbb/lib/utils/version.js +135 -0
- package/cbb/lib/wiki/api-client.js +358 -0
- package/cbb/lib/wiki/cli.js +427 -0
- package/cbb/lib/wiki/convert.js +464 -0
- package/cbb/lib/wiki/index.js +218 -0
- package/cbb/lib/wiki/mermaid-guard.js +103 -0
- package/cbb/lib/wiki/split.js +131 -0
- package/cbb/tools/cbb-decompile-jar/SKILL.md +220 -0
- package/cbb/tools/cbb-decompile-jar/scripts/decompile.py +863 -0
- package/cbb/tools/cbb-design-to-wiki/SKILL.md +180 -0
- package/cbb/tools/cbb-mvn-guide/SKILL.md +281 -0
- package/cbb/tools/cbb-mvn-guide/scripts/mvn_jdk_manager.py +378 -0
- package/cbb/tools/cbb-mvn-guide/scripts/mvn_pom_jdk_reader.py +197 -0
- package/cbb/tools/cbb-plantuml-authoring/SKILL.md +448 -0
- package/cbb/tools/cbb-plantuml-authoring/references/drawing-templates.md +479 -0
- package/cbb/tools/cbb-wiki-ops/SKILL.md +134 -0
- package/cbb/tools/cbb-wiki-ops/scripts/check-auth.js +44 -0
- package/cbb/worktrees/_shared/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/_shared/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/_shared/scripts/push-core.js +136 -0
- package/cbb/worktrees/_shared/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/commands/close.md +64 -0
- package/cbb/worktrees/commands/extend.md +65 -0
- package/cbb/worktrees/commands/init.md +55 -0
- package/cbb/worktrees/commands/push.md +42 -0
- package/cbb/worktrees/skills/openspec-close-worktree/SKILL.md +449 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-env.js +76 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-unarchived.js +48 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/delete-branches.js +136 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/discover-apps.js +76 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/remove-worktrees.js +124 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/safety-check.js +174 -0
- package/cbb/worktrees/skills/openspec-close-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +390 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +95 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +98 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +135 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +150 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +88 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +93 -0
- package/cbb/worktrees/skills/openspec-init-worktree/SKILL.md +539 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/auto-open.js +136 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env-deep.js +87 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env.js +90 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-repos.js +171 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-branches.js +103 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-worktrees.js +154 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +93 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/install-ai.js +177 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/parse-config.js +67 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-branches.js +101 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/silence-popup.js +23 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/sync-repos.js +95 -0
- package/cbb/worktrees/skills/openspec-init-worktree/scripts/update-gitignore.js +134 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/SKILL.md +307 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/commit-worktrees.js +269 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-target-worktree.js +96 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-workspace-root.js +67 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-core.js +136 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-worktrees.js +159 -0
- package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +23 -0
- package/config/cbb.yaml +6 -0
- package/config/config.sample.json +16 -0
- package/config/openspec/config.yaml +28 -0
- package/config/openspec/schemas/spec-driven/schema.yaml +247 -0
- package/config/openspec/schemas/spec-driven/templates/design.md +475 -0
- package/config/openspec/schemas/spec-driven/templates/proposal.md +58 -0
- package/config/openspec/schemas/spec-driven/templates/spec.md +8 -0
- package/config/openspec/schemas/spec-driven/templates/tasks.md +9 -0
- package/config/workspaces.json +15 -0
- package/openspec/.version +6 -0
- package/openspec/commands/apply.md +182 -0
- package/openspec/commands/archive.md +223 -0
- package/openspec/commands/bulk-archive.md +334 -0
- package/openspec/commands/continue.md +112 -0
- package/openspec/commands/explore.md +206 -0
- package/openspec/commands/ff.md +111 -0
- package/openspec/commands/new.md +70 -0
- package/openspec/commands/onboard.md +555 -0
- package/openspec/commands/propose.md +157 -0
- package/openspec/commands/sync.md +256 -0
- package/openspec/commands/update.md +85 -0
- package/openspec/commands/verify.md +169 -0
- package/openspec/skills/openspec-apply-change/SKILL.md +187 -0
- package/openspec/skills/openspec-archive-change/SKILL.md +181 -0
- package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -0
- package/openspec/skills/openspec-continue-change/SKILL.md +117 -0
- package/openspec/skills/openspec-explore/SKILL.md +342 -0
- package/openspec/skills/openspec-ff-change/SKILL.md +116 -0
- package/openspec/skills/openspec-new-change/SKILL.md +76 -0
- package/openspec/skills/openspec-onboard/SKILL.md +560 -0
- package/openspec/skills/openspec-propose/SKILL.md +162 -0
- package/openspec/skills/openspec-sync-specs/SKILL.md +261 -0
- package/openspec/skills/openspec-update-change/SKILL.md +90 -0
- package/openspec/skills/openspec-verify-change/SKILL.md +174 -0
- package/package.json +46 -0
- package/superpowers/.version +6 -0
- package/superpowers/skills/brainstorming/SKILL.md +250 -0
- package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
- package/superpowers/skills/brainstorming/scripts/helper.js +167 -0
- package/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
- package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
- package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
- package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/superpowers/skills/brainstorming/visual-companion.md +299 -0
- package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -0
- package/superpowers/skills/executing-plans/SKILL.md +64 -0
- package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -0
- package/superpowers/skills/receiving-code-review/SKILL.md +205 -0
- package/superpowers/skills/requesting-code-review/SKILL.md +95 -0
- package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -0
- package/superpowers/skills/subagent-driven-development/SKILL.md +568 -0
- package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -0
- package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -0
- package/superpowers/skills/subagent-driven-development/scripts/review-package +46 -0
- package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +40 -0
- package/superpowers/skills/subagent-driven-development/scripts/task-brief +41 -0
- package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
- package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/superpowers/skills/systematic-debugging/SKILL.md +283 -0
- package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -0
- package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/superpowers/skills/systematic-debugging/test-academic.md +14 -0
- package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/superpowers/skills/test-driven-development/SKILL.md +320 -0
- package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -0
- package/superpowers/skills/using-git-worktrees/SKILL.md +167 -0
- package/superpowers/skills/using-superpowers/SKILL.md +63 -0
- package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
- package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -0
- package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -0
- package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -0
- package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
- package/superpowers/skills/verification-before-completion/SKILL.md +120 -0
- package/superpowers/skills/writing-plans/SKILL.md +171 -0
- package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
- package/superpowers/skills/writing-skills/SKILL.md +679 -0
- package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
- package/superpowers/skills/writing-skills/render-graphs.js +169 -0
- 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 };
|