claude-code-workflow 6.3.24 → 6.3.26
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/.claude/commands/issue/discover-by-prompt.md +764 -0
- package/.claude/skills/text-formatter/SKILL.md +196 -0
- package/.claude/skills/text-formatter/phases/01-input-collection.md +111 -0
- package/.claude/skills/text-formatter/phases/02-content-analysis.md +248 -0
- package/.claude/skills/text-formatter/phases/03-format-transform.md +245 -0
- package/.claude/skills/text-formatter/phases/04-output-preview.md +183 -0
- package/.claude/skills/text-formatter/specs/callout-types.md +293 -0
- package/.claude/skills/text-formatter/specs/element-mapping.md +226 -0
- package/.claude/skills/text-formatter/specs/format-rules.md +273 -0
- package/.claude/skills/text-formatter/templates/bbcode-template.md +350 -0
- package/ccw/dist/core/routes/help-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/help-routes.js +43 -7
- package/ccw/dist/core/routes/help-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.js +31 -5
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -1
- package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/memory-routes.js +73 -0
- package/ccw/dist/core/routes/memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/status-routes.js +36 -4
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +58 -0
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/core/services/api-key-tester.d.ts.map +1 -1
- package/ccw/dist/core/services/api-key-tester.js +8 -3
- package/ccw/dist/core/services/api-key-tester.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +7 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +11 -1
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-executor-core.d.ts +11 -0
- package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-core.js +89 -2
- package/ccw/dist/tools/cli-executor-core.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +2 -1
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +51 -8
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/index.d.ts.map +1 -1
- package/ccw/dist/tools/index.js +2 -0
- package/ccw/dist/tools/index.js.map +1 -1
- package/ccw/dist/tools/litellm-client.d.ts +6 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-client.js +22 -1
- package/ccw/dist/tools/litellm-client.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +2 -2
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/tools/memory-update-queue.d.ts +172 -0
- package/ccw/dist/tools/memory-update-queue.d.ts.map +1 -0
- package/ccw/dist/tools/memory-update-queue.js +431 -0
- package/ccw/dist/tools/memory-update-queue.js.map +1 -0
- package/ccw/src/core/routes/help-routes.ts +46 -7
- package/ccw/src/core/routes/litellm-api-routes.ts +35 -4
- package/ccw/src/core/routes/memory-routes.ts +84 -0
- package/ccw/src/core/routes/status-routes.ts +39 -4
- package/ccw/src/core/server.ts +62 -0
- package/ccw/src/core/services/api-key-tester.ts +9 -3
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +45 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +36 -5
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +42 -81
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +170 -28
- package/ccw/src/templates/dashboard-js/components/notifications.js +14 -4
- package/ccw/src/templates/dashboard-js/i18n.js +26 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +72 -2
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +11 -1
- package/ccw/src/tools/claude-cli-tools.ts +17 -1
- package/ccw/src/tools/cli-executor-core.ts +103 -2
- package/ccw/src/tools/codex-lens.ts +63 -8
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +25 -3
- package/ccw/src/tools/litellm-executor.ts +2 -2
- package/ccw/src/tools/memory-update-queue.js +499 -0
- package/package.json +91 -91
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Phase 3: Format Transform
|
|
2
|
+
|
|
3
|
+
将内容转换为 BBCode + Markdown 混合格式(论坛优化)。
|
|
4
|
+
|
|
5
|
+
## Objective
|
|
6
|
+
|
|
7
|
+
- 根据分析结果转换内容
|
|
8
|
+
- 应用像素级字号规则
|
|
9
|
+
- 处理 Callout/标注语法
|
|
10
|
+
- 生成论坛兼容的输出
|
|
11
|
+
|
|
12
|
+
## Input
|
|
13
|
+
|
|
14
|
+
- 依赖: `input-config.json`, `analysis.json`
|
|
15
|
+
- 规范: `specs/format-rules.md`, `specs/element-mapping.md`
|
|
16
|
+
|
|
17
|
+
## Format Specification
|
|
18
|
+
|
|
19
|
+
### Size Hierarchy (Pixels)
|
|
20
|
+
|
|
21
|
+
| Element | Size | Color | Usage |
|
|
22
|
+
|---------|------|-------|-------|
|
|
23
|
+
| **H1** | 150 | #2196F3 | 文档主标题 |
|
|
24
|
+
| **H2** | 120 | #2196F3 | 章节标题 |
|
|
25
|
+
| **H3** | 100 | #333 | 子标题 |
|
|
26
|
+
| **H4+** | (默认) | - | 仅加粗 |
|
|
27
|
+
| **Notes** | 80 | gray | 备注/元数据 |
|
|
28
|
+
|
|
29
|
+
### Unsupported Tags (禁止使用)
|
|
30
|
+
|
|
31
|
+
| Tag | Reason | Alternative |
|
|
32
|
+
|-----|--------|-------------|
|
|
33
|
+
| `[align]` | 不渲染 | 删除,使用默认左对齐 |
|
|
34
|
+
| `[hr]` | 显示为文本 | 使用 Markdown `---` |
|
|
35
|
+
| `[table]` | 支持有限 | 转为列表或代码块 |
|
|
36
|
+
| HTML tags | 不支持 | 仅使用 BBCode |
|
|
37
|
+
|
|
38
|
+
## Execution Steps
|
|
39
|
+
|
|
40
|
+
### Step 1: 加载配置和分析
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
|
44
|
+
const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
|
|
45
|
+
const content = config.original_content;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Step 2: Callout 配置
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// Callout 类型映射(像素级字号)
|
|
52
|
+
const CALLOUT_CONFIG = {
|
|
53
|
+
// 信息类
|
|
54
|
+
note: { icon: '📝', color: '#2196F3', label: '注意' },
|
|
55
|
+
info: { icon: 'ℹ️', color: '#2196F3', label: '信息' },
|
|
56
|
+
abstract: { icon: '📄', color: '#2196F3', label: '摘要' },
|
|
57
|
+
summary: { icon: '📄', color: '#2196F3', label: '摘要' },
|
|
58
|
+
tldr: { icon: '📄', color: '#2196F3', label: '摘要' },
|
|
59
|
+
|
|
60
|
+
// 成功/提示类
|
|
61
|
+
tip: { icon: '💡', color: '#4CAF50', label: '提示' },
|
|
62
|
+
hint: { icon: '💡', color: '#4CAF50', label: '提示' },
|
|
63
|
+
success: { icon: '✅', color: '#4CAF50', label: '成功' },
|
|
64
|
+
check: { icon: '✅', color: '#4CAF50', label: '完成' },
|
|
65
|
+
done: { icon: '✅', color: '#4CAF50', label: '完成' },
|
|
66
|
+
|
|
67
|
+
// 警告类
|
|
68
|
+
warning: { icon: '⚠️', color: '#FF9800', label: '警告' },
|
|
69
|
+
caution: { icon: '⚠️', color: '#FF9800', label: '注意' },
|
|
70
|
+
attention: { icon: '⚠️', color: '#FF9800', label: '注意' },
|
|
71
|
+
question: { icon: '❓', color: '#FF9800', label: '问题' },
|
|
72
|
+
help: { icon: '❓', color: '#FF9800', label: '帮助' },
|
|
73
|
+
faq: { icon: '❓', color: '#FF9800', label: 'FAQ' },
|
|
74
|
+
todo: { icon: '📋', color: '#FF9800', label: '待办' },
|
|
75
|
+
|
|
76
|
+
// 错误/危险类
|
|
77
|
+
danger: { icon: '❌', color: '#F44336', label: '危险' },
|
|
78
|
+
error: { icon: '❌', color: '#F44336', label: '错误' },
|
|
79
|
+
bug: { icon: '🐛', color: '#F44336', label: 'Bug' },
|
|
80
|
+
important: { icon: '⭐', color: '#F44336', label: '重要' },
|
|
81
|
+
|
|
82
|
+
// 其他
|
|
83
|
+
example: { icon: '📋', color: '#9C27B0', label: '示例' },
|
|
84
|
+
quote: { icon: '💬', color: 'gray', label: '引用' },
|
|
85
|
+
cite: { icon: '💬', color: 'gray', label: '引用' }
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Callout 检测正则 (支持 +/- 折叠标记)
|
|
89
|
+
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\][+-]?(?:\s+(.+))?$/;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Step 3: Callout 解析器
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
function parseCallouts(text) {
|
|
96
|
+
const lines = text.split('\n');
|
|
97
|
+
const result = [];
|
|
98
|
+
let i = 0;
|
|
99
|
+
|
|
100
|
+
while (i < lines.length) {
|
|
101
|
+
const match = lines[i].match(CALLOUT_PATTERN);
|
|
102
|
+
if (match) {
|
|
103
|
+
const type = match[1].toLowerCase();
|
|
104
|
+
const title = match[2] || null;
|
|
105
|
+
const content = [];
|
|
106
|
+
i++;
|
|
107
|
+
|
|
108
|
+
// 收集 Callout 内容行
|
|
109
|
+
while (i < lines.length && lines[i].startsWith('>')) {
|
|
110
|
+
content.push(lines[i].replace(/^>\s*/, ''));
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
result.push({
|
|
115
|
+
isCallout: true,
|
|
116
|
+
type,
|
|
117
|
+
title,
|
|
118
|
+
content: content.join('\n')
|
|
119
|
+
});
|
|
120
|
+
} else {
|
|
121
|
+
result.push({ isCallout: false, line: lines[i] });
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Step 4: BBCode+MD 转换器
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
function formatBBCodeMD(text) {
|
|
134
|
+
let result = text;
|
|
135
|
+
|
|
136
|
+
// ===== 标题转换 (像素级字号) =====
|
|
137
|
+
result = result.replace(/^######\s*(.+)$/gm, '[b]$1[/b]');
|
|
138
|
+
result = result.replace(/^#####\s*(.+)$/gm, '[b]$1[/b]');
|
|
139
|
+
result = result.replace(/^####\s*(.+)$/gm, '[b]$1[/b]');
|
|
140
|
+
result = result.replace(/^###\s*(.+)$/gm, '[size=100][color=#333][b]$1[/b][/color][/size]');
|
|
141
|
+
result = result.replace(/^##\s*(.+)$/gm, '[size=120][color=#2196F3][b]$1[/b][/color][/size]');
|
|
142
|
+
result = result.replace(/^#\s*(.+)$/gm, '[size=150][color=#2196F3][b]$1[/b][/color][/size]');
|
|
143
|
+
|
|
144
|
+
// ===== 文本样式 =====
|
|
145
|
+
result = result.replace(/\*\*\*(.+?)\*\*\*/g, '[b][i]$1[/i][/b]');
|
|
146
|
+
result = result.replace(/\*\*(.+?)\*\*/g, '[b]$1[/b]');
|
|
147
|
+
result = result.replace(/__(.+?)__/g, '[b]$1[/b]');
|
|
148
|
+
result = result.replace(/\*(.+?)\*/g, '[i]$1[/i]');
|
|
149
|
+
result = result.replace(/_(.+?)_/g, '[i]$1[/i]');
|
|
150
|
+
result = result.replace(/~~(.+?)~~/g, '[s]$1[/s]');
|
|
151
|
+
result = result.replace(/==(.+?)==/g, '[color=yellow]$1[/color]');
|
|
152
|
+
|
|
153
|
+
// ===== HTML 转 BBCode =====
|
|
154
|
+
result = result.replace(/<mark>(.+?)<\/mark>/g, '[color=yellow]$1[/color]');
|
|
155
|
+
result = result.replace(/<u>(.+?)<\/u>/g, '[u]$1[/u]');
|
|
156
|
+
result = result.replace(/<details>\s*<summary>(.+?)<\/summary>\s*([\s\S]*?)<\/details>/g,
|
|
157
|
+
'[spoiler=$1]$2[/spoiler]');
|
|
158
|
+
|
|
159
|
+
// ===== 代码 =====
|
|
160
|
+
result = result.replace(/```(\w*)\n([\s\S]*?)```/g, '[code]$2[/code]');
|
|
161
|
+
// 行内代码保持原样 (部分论坛不支持 font=monospace)
|
|
162
|
+
|
|
163
|
+
// ===== 链接和图片 =====
|
|
164
|
+
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[url=$2]$1[/url]');
|
|
165
|
+
result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[img]$2[/img]');
|
|
166
|
+
|
|
167
|
+
// ===== 引用 (非 Callout) =====
|
|
168
|
+
result = result.replace(/^>\s+(.+)$/gm, '[quote]$1[/quote]');
|
|
169
|
+
|
|
170
|
+
// ===== 列表 (使用 • 符号) =====
|
|
171
|
+
result = result.replace(/^[-*+]\s+(.+)$/gm, '• $1');
|
|
172
|
+
|
|
173
|
+
// ===== 分隔线 (保持 Markdown 语法) =====
|
|
174
|
+
// `---` 在混合格式中通常可用,不转换为 [hr]
|
|
175
|
+
|
|
176
|
+
return result.trim();
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Step 5: Callout 转换
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
function convertCallouts(text) {
|
|
184
|
+
const parsed = parseCallouts(text);
|
|
185
|
+
|
|
186
|
+
return parsed.map(item => {
|
|
187
|
+
if (item.isCallout) {
|
|
188
|
+
const cfg = CALLOUT_CONFIG[item.type] || CALLOUT_CONFIG.note;
|
|
189
|
+
const displayTitle = item.title || cfg.label;
|
|
190
|
+
|
|
191
|
+
// 使用 [quote] 包裹,标题使用 size=100
|
|
192
|
+
return `[quote]
|
|
193
|
+
[size=100][color=${cfg.color}][b]${cfg.icon} ${displayTitle}[/b][/color][/size]
|
|
194
|
+
|
|
195
|
+
${item.content}
|
|
196
|
+
[/quote]`;
|
|
197
|
+
}
|
|
198
|
+
return item.line;
|
|
199
|
+
}).join('\n');
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Step 6: 执行转换
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
// 1. 先处理 Callouts
|
|
207
|
+
let formattedContent = convertCallouts(content);
|
|
208
|
+
|
|
209
|
+
// 2. 再进行通用 BBCode+MD 转换
|
|
210
|
+
formattedContent = formatBBCodeMD(formattedContent);
|
|
211
|
+
|
|
212
|
+
// 3. 清理多余空行
|
|
213
|
+
formattedContent = formattedContent.replace(/\n{3,}/g, '\n\n');
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Step 7: 保存转换结果
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
const outputFile = 'output.bbcode.txt';
|
|
220
|
+
Write(`${workDir}/${outputFile}`, formattedContent);
|
|
221
|
+
|
|
222
|
+
// 更新配置
|
|
223
|
+
config.output_file = outputFile;
|
|
224
|
+
config.formatted_content = formattedContent;
|
|
225
|
+
Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Output
|
|
229
|
+
|
|
230
|
+
- **File**: `output.bbcode.txt`
|
|
231
|
+
- **Format**: BBCode + Markdown 混合格式
|
|
232
|
+
|
|
233
|
+
## Quality Checklist
|
|
234
|
+
|
|
235
|
+
- [ ] 标题使用像素值 (150/120/100)
|
|
236
|
+
- [ ] 未使用 `[align]` 标签
|
|
237
|
+
- [ ] 未使用 `[hr]` 标签
|
|
238
|
+
- [ ] 分隔线使用 `---`
|
|
239
|
+
- [ ] Callout 正确转换为 [quote]
|
|
240
|
+
- [ ] 颜色值使用 hex 格式
|
|
241
|
+
- [ ] 内容完整无丢失
|
|
242
|
+
|
|
243
|
+
## Next Phase
|
|
244
|
+
|
|
245
|
+
→ [Phase 4: Output & Preview](04-output-preview.md)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Phase 4: Output & Preview
|
|
2
|
+
|
|
3
|
+
输出最终结果并提供预览。
|
|
4
|
+
|
|
5
|
+
## Objective
|
|
6
|
+
|
|
7
|
+
- 保存格式化后的内容到文件
|
|
8
|
+
- 提供预览功能
|
|
9
|
+
- 显示转换统计信息
|
|
10
|
+
|
|
11
|
+
## Input
|
|
12
|
+
|
|
13
|
+
- 依赖: `input-config.json`, `output.*`
|
|
14
|
+
- 配置: `{workDir}/input-config.json`
|
|
15
|
+
|
|
16
|
+
## Execution Steps
|
|
17
|
+
|
|
18
|
+
### Step 1: 加载结果
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
|
22
|
+
const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
|
|
23
|
+
const outputFile = `${workDir}/${config.output_file}`;
|
|
24
|
+
const formattedContent = Read(outputFile);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Step 2: 生成统计摘要
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const summary = {
|
|
31
|
+
input: {
|
|
32
|
+
method: config.input_method,
|
|
33
|
+
original_length: config.original_content.length,
|
|
34
|
+
word_count: config.original_content.split(/\s+/).length
|
|
35
|
+
},
|
|
36
|
+
output: {
|
|
37
|
+
format: config.target_format,
|
|
38
|
+
file: outputFile,
|
|
39
|
+
length: formattedContent.length
|
|
40
|
+
},
|
|
41
|
+
elements: analysis.stats,
|
|
42
|
+
reading_time: analysis.semantics?.estimated_reading_time || 1
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
console.log(`
|
|
46
|
+
╔════════════════════════════════════════════════════════════════╗
|
|
47
|
+
║ Text Formatter Summary ║
|
|
48
|
+
╠════════════════════════════════════════════════════════════════╣
|
|
49
|
+
║ Input: ${summary.input.word_count} words (${summary.input.original_length} chars)
|
|
50
|
+
║ Output: ${summary.output.format} → ${summary.output.file}
|
|
51
|
+
║ Elements Converted:
|
|
52
|
+
║ • Headings: ${summary.elements.headings}
|
|
53
|
+
║ • Paragraphs: ${summary.elements.paragraphs}
|
|
54
|
+
║ • Lists: ${summary.elements.lists}
|
|
55
|
+
║ • Code Blocks: ${summary.elements.code_blocks}
|
|
56
|
+
║ • Links: ${summary.elements.links}
|
|
57
|
+
║ Estimated Reading Time: ${summary.reading_time} min
|
|
58
|
+
╚════════════════════════════════════════════════════════════════╝
|
|
59
|
+
`);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Step 3: HTML 预览(如适用)
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
if (config.target_format === 'HTML') {
|
|
66
|
+
// 生成完整 HTML 文件用于预览
|
|
67
|
+
const previewHtml = `<!DOCTYPE html>
|
|
68
|
+
<html lang="zh-CN">
|
|
69
|
+
<head>
|
|
70
|
+
<meta charset="UTF-8">
|
|
71
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
72
|
+
<title>Text Formatter Preview</title>
|
|
73
|
+
<style>
|
|
74
|
+
body {
|
|
75
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
76
|
+
line-height: 1.6;
|
|
77
|
+
max-width: 800px;
|
|
78
|
+
margin: 0 auto;
|
|
79
|
+
padding: 2rem;
|
|
80
|
+
background: #f5f5f5;
|
|
81
|
+
}
|
|
82
|
+
.content {
|
|
83
|
+
background: white;
|
|
84
|
+
padding: 2rem;
|
|
85
|
+
border-radius: 8px;
|
|
86
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
87
|
+
}
|
|
88
|
+
h1, h2, h3, h4, h5, h6 { color: #333; margin-top: 1.5em; }
|
|
89
|
+
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; }
|
|
90
|
+
pre { background: #282c34; color: #abb2bf; padding: 1rem; border-radius: 6px; overflow-x: auto; }
|
|
91
|
+
pre code { background: none; padding: 0; }
|
|
92
|
+
blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 1rem; color: #666; }
|
|
93
|
+
a { color: #0066cc; }
|
|
94
|
+
img { max-width: 100%; }
|
|
95
|
+
hr { border: none; border-top: 1px solid #ddd; margin: 2rem 0; }
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<div class="content">
|
|
100
|
+
${formattedContent}
|
|
101
|
+
</div>
|
|
102
|
+
</body>
|
|
103
|
+
</html>`;
|
|
104
|
+
|
|
105
|
+
Write(`${workDir}/preview.html`, previewHtml);
|
|
106
|
+
|
|
107
|
+
// 可选:在浏览器中打开预览
|
|
108
|
+
// Bash(`start "${workDir}/preview.html"`); // Windows
|
|
109
|
+
// Bash(`open "${workDir}/preview.html"`); // macOS
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Step 4: 显示输出内容
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// 显示格式化后的内容
|
|
117
|
+
console.log('\n=== Formatted Content ===\n');
|
|
118
|
+
console.log(formattedContent);
|
|
119
|
+
console.log('\n=========================\n');
|
|
120
|
+
|
|
121
|
+
// 提示用户
|
|
122
|
+
console.log(`
|
|
123
|
+
📁 Output saved to: ${outputFile}
|
|
124
|
+
${config.target_format === 'HTML' ? '🌐 Preview available: ' + workDir + '/preview.html' : ''}
|
|
125
|
+
|
|
126
|
+
💡 Tips:
|
|
127
|
+
- Copy the content above for immediate use
|
|
128
|
+
- Or access the saved file at the path shown
|
|
129
|
+
`);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Step 5: 询问后续操作
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const nextAction = await AskUserQuestion({
|
|
136
|
+
questions: [
|
|
137
|
+
{
|
|
138
|
+
question: "需要执行什么操作?",
|
|
139
|
+
header: "后续操作",
|
|
140
|
+
multiSelect: false,
|
|
141
|
+
options: [
|
|
142
|
+
{ label: "完成", description: "结束格式化流程" },
|
|
143
|
+
{ label: "转换为其他格式", description: "选择另一种输出格式" },
|
|
144
|
+
{ label: "重新编辑", description: "修改原始内容后重新格式化" }
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (nextAction["后续操作"] === "转换为其他格式") {
|
|
151
|
+
// 返回 Phase 1 选择新格式
|
|
152
|
+
console.log('请重新运行 /text-formatter 选择其他格式');
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Output
|
|
157
|
+
|
|
158
|
+
- **File**: `output.{ext}` (最终输出)
|
|
159
|
+
- **File**: `preview.html` (HTML 预览,仅 HTML 格式)
|
|
160
|
+
- **Console**: 统计摘要和格式化内容
|
|
161
|
+
|
|
162
|
+
## Final Output Structure
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
{workDir}/
|
|
166
|
+
├── input-config.json # 配置信息
|
|
167
|
+
├── analysis.json # 分析结果
|
|
168
|
+
├── output.md # Markdown 输出(如选择)
|
|
169
|
+
├── output.bbcode.txt # BBCode 输出(如选择)
|
|
170
|
+
├── output.html # HTML 输出(如选择)
|
|
171
|
+
└── preview.html # HTML 预览页面
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Quality Checklist
|
|
175
|
+
|
|
176
|
+
- [ ] 输出文件已保存
|
|
177
|
+
- [ ] 统计信息正确显示
|
|
178
|
+
- [ ] 预览功能可用(HTML)
|
|
179
|
+
- [ ] 用户可访问输出内容
|
|
180
|
+
|
|
181
|
+
## Completion
|
|
182
|
+
|
|
183
|
+
此为最终阶段,格式化流程完成。
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Callout Types
|
|
2
|
+
|
|
3
|
+
Obsidian 风格的 Callout/Admonition 类型定义和转换规则。
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
| Phase | Usage | Section |
|
|
8
|
+
|-------|-------|---------|
|
|
9
|
+
| Phase 2 | 检测 Callout | Detection patterns |
|
|
10
|
+
| Phase 3 | 格式转换 | Conversion rules |
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Callout 语法
|
|
15
|
+
|
|
16
|
+
### Obsidian 原生语法
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
> [!TYPE] 可选标题
|
|
20
|
+
> 内容行1
|
|
21
|
+
> 内容行2
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 支持的类型
|
|
25
|
+
|
|
26
|
+
| Type | Alias | Icon | Color | 用途 |
|
|
27
|
+
|------|-------|------|-------|------|
|
|
28
|
+
| `note` | - | 📝 | blue | 普通提示 |
|
|
29
|
+
| `info` | - | ℹ️ | blue | 信息说明 |
|
|
30
|
+
| `tip` | `hint` | 💡 | green | 技巧提示 |
|
|
31
|
+
| `success` | `check`, `done` | ✅ | green | 成功状态 |
|
|
32
|
+
| `warning` | `caution`, `attention` | ⚠️ | orange | 警告信息 |
|
|
33
|
+
| `danger` | `error` | ❌ | red | 危险/错误 |
|
|
34
|
+
| `bug` | - | 🐛 | red | Bug 说明 |
|
|
35
|
+
| `example` | - | 📋 | purple | 示例内容 |
|
|
36
|
+
| `quote` | `cite` | 💬 | gray | 引用内容 |
|
|
37
|
+
| `abstract` | `summary`, `tldr` | 📄 | cyan | 摘要 |
|
|
38
|
+
| `question` | `help`, `faq` | ❓ | yellow | 问题/FAQ |
|
|
39
|
+
| `todo` | - | 📌 | orange | 待办事项 |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 检测 Pattern
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// Callout 检测正则
|
|
47
|
+
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
|
|
48
|
+
|
|
49
|
+
// 检测函数
|
|
50
|
+
function detectCallout(line) {
|
|
51
|
+
const match = line.match(CALLOUT_PATTERN);
|
|
52
|
+
if (match) {
|
|
53
|
+
return {
|
|
54
|
+
type: match[1].toLowerCase(),
|
|
55
|
+
title: match[2] || null
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 解析完整 Callout 块
|
|
62
|
+
function parseCalloutBlock(lines, startIndex) {
|
|
63
|
+
const firstLine = lines[startIndex];
|
|
64
|
+
const calloutInfo = detectCallout(firstLine);
|
|
65
|
+
|
|
66
|
+
if (!calloutInfo) return null;
|
|
67
|
+
|
|
68
|
+
const content = [];
|
|
69
|
+
let i = startIndex + 1;
|
|
70
|
+
|
|
71
|
+
while (i < lines.length && lines[i].startsWith('>')) {
|
|
72
|
+
content.push(lines[i].replace(/^>\s*/, ''));
|
|
73
|
+
i++;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...calloutInfo,
|
|
78
|
+
content: content.join('\n'),
|
|
79
|
+
endIndex: i - 1
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 转换规则
|
|
87
|
+
|
|
88
|
+
### BBCode 转换
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const CALLOUT_BBCODE = {
|
|
92
|
+
note: {
|
|
93
|
+
icon: '📝',
|
|
94
|
+
color: '#2196F3',
|
|
95
|
+
label: '注意'
|
|
96
|
+
},
|
|
97
|
+
info: {
|
|
98
|
+
icon: 'ℹ️',
|
|
99
|
+
color: '#2196F3',
|
|
100
|
+
label: '信息'
|
|
101
|
+
},
|
|
102
|
+
tip: {
|
|
103
|
+
icon: '💡',
|
|
104
|
+
color: '#4CAF50',
|
|
105
|
+
label: '提示'
|
|
106
|
+
},
|
|
107
|
+
success: {
|
|
108
|
+
icon: '✅',
|
|
109
|
+
color: '#4CAF50',
|
|
110
|
+
label: '成功'
|
|
111
|
+
},
|
|
112
|
+
warning: {
|
|
113
|
+
icon: '⚠️',
|
|
114
|
+
color: '#FF9800',
|
|
115
|
+
label: '警告'
|
|
116
|
+
},
|
|
117
|
+
danger: {
|
|
118
|
+
icon: '❌',
|
|
119
|
+
color: '#F44336',
|
|
120
|
+
label: '危险'
|
|
121
|
+
},
|
|
122
|
+
bug: {
|
|
123
|
+
icon: '🐛',
|
|
124
|
+
color: '#F44336',
|
|
125
|
+
label: 'Bug'
|
|
126
|
+
},
|
|
127
|
+
example: {
|
|
128
|
+
icon: '📋',
|
|
129
|
+
color: '#9C27B0',
|
|
130
|
+
label: '示例'
|
|
131
|
+
},
|
|
132
|
+
quote: {
|
|
133
|
+
icon: '💬',
|
|
134
|
+
color: '#9E9E9E',
|
|
135
|
+
label: '引用'
|
|
136
|
+
},
|
|
137
|
+
question: {
|
|
138
|
+
icon: '❓',
|
|
139
|
+
color: '#FFEB3B',
|
|
140
|
+
label: '问题'
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function calloutToBBCode(type, title, content, style = 'forum') {
|
|
145
|
+
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
|
146
|
+
const displayTitle = title || config.label;
|
|
147
|
+
|
|
148
|
+
if (style === 'compact') {
|
|
149
|
+
return `[quote][b]${config.icon} ${displayTitle}[/b]
|
|
150
|
+
${content}[/quote]`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Forum style - more visual
|
|
154
|
+
return `[quote]
|
|
155
|
+
[color=${config.color}][size=4][b]${config.icon} ${displayTitle}[/b][/size][/color]
|
|
156
|
+
|
|
157
|
+
${content}
|
|
158
|
+
[/quote]`;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### HTML 转换
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
function calloutToHTML(type, title, content) {
|
|
166
|
+
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
|
167
|
+
const displayTitle = title || config.label;
|
|
168
|
+
|
|
169
|
+
return `<div class="callout callout-${type}">
|
|
170
|
+
<div class="callout-title">
|
|
171
|
+
<span class="callout-icon">${config.icon}</span>
|
|
172
|
+
<span class="callout-title-text">${displayTitle}</span>
|
|
173
|
+
</div>
|
|
174
|
+
<div class="callout-content">
|
|
175
|
+
${content}
|
|
176
|
+
</div>
|
|
177
|
+
</div>`;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Hybrid 转换
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
function calloutToHybrid(type, title, content) {
|
|
185
|
+
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
|
186
|
+
const displayTitle = title || config.label;
|
|
187
|
+
|
|
188
|
+
// HTML container + BBCode styling + MD content
|
|
189
|
+
return `<div class="callout ${type}">
|
|
190
|
+
|
|
191
|
+
[color=${config.color}][b]${config.icon} ${displayTitle}[/b][/color]
|
|
192
|
+
|
|
193
|
+
${content}
|
|
194
|
+
|
|
195
|
+
</div>`;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Callout CSS 样式
|
|
202
|
+
|
|
203
|
+
```css
|
|
204
|
+
/* Base callout styles */
|
|
205
|
+
.callout {
|
|
206
|
+
padding: 1rem;
|
|
207
|
+
margin: 1rem 0;
|
|
208
|
+
border-left: 4px solid;
|
|
209
|
+
border-radius: 4px;
|
|
210
|
+
background: #f8f9fa;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.callout-title {
|
|
214
|
+
display: flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
gap: 0.5rem;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
margin-bottom: 0.5rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.callout-icon {
|
|
222
|
+
font-size: 1.2em;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* Type-specific colors */
|
|
226
|
+
.callout-note, .callout-info {
|
|
227
|
+
border-color: #2196F3;
|
|
228
|
+
background: #E3F2FD;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.callout-tip, .callout-success {
|
|
232
|
+
border-color: #4CAF50;
|
|
233
|
+
background: #E8F5E9;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.callout-warning {
|
|
237
|
+
border-color: #FF9800;
|
|
238
|
+
background: #FFF3E0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.callout-danger, .callout-bug {
|
|
242
|
+
border-color: #F44336;
|
|
243
|
+
background: #FFEBEE;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.callout-example {
|
|
247
|
+
border-color: #9C27B0;
|
|
248
|
+
background: #F3E5F5;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.callout-quote {
|
|
252
|
+
border-color: #9E9E9E;
|
|
253
|
+
background: #FAFAFA;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.callout-question {
|
|
257
|
+
border-color: #FFC107;
|
|
258
|
+
background: #FFFDE7;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 折叠 Callout
|
|
265
|
+
|
|
266
|
+
支持可折叠的 Callout 语法:
|
|
267
|
+
|
|
268
|
+
```markdown
|
|
269
|
+
> [!NOTE]+ 默认展开
|
|
270
|
+
> 内容
|
|
271
|
+
|
|
272
|
+
> [!NOTE]- 默认折叠
|
|
273
|
+
> 内容
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### BBCode 折叠
|
|
277
|
+
|
|
278
|
+
```bbcode
|
|
279
|
+
[collapse=📝 注意]
|
|
280
|
+
内容
|
|
281
|
+
[/collapse]
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### HTML 折叠
|
|
285
|
+
|
|
286
|
+
```html
|
|
287
|
+
<details class="callout callout-note">
|
|
288
|
+
<summary>📝 注意</summary>
|
|
289
|
+
<div class="callout-content">
|
|
290
|
+
内容
|
|
291
|
+
</div>
|
|
292
|
+
</details>
|
|
293
|
+
```
|