larkcc 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -12
- package/README.md +188 -27
- package/dist/agent.d.ts +2 -1
- package/dist/agent.js +189 -38
- package/dist/agent.js.map +1 -1
- package/dist/app.js +14 -5
- package/dist/app.js.map +1 -1
- package/dist/cardkit.d.ts +125 -0
- package/dist/cardkit.js +448 -0
- package/dist/cardkit.js.map +1 -0
- package/dist/config.d.ts +23 -3
- package/dist/config.js +43 -47
- package/dist/config.js.map +1 -1
- package/dist/feishu.d.ts +50 -4
- package/dist/feishu.js +287 -97
- package/dist/feishu.js.map +1 -1
- package/dist/format/builder.d.ts +126 -37
- package/dist/format/builder.js +276 -116
- package/dist/format/builder.js.map +1 -1
- package/dist/format/card-optimize.d.ts +42 -0
- package/dist/format/card-optimize.js +74 -0
- package/dist/format/card-optimize.js.map +1 -0
- package/dist/format/constants.d.ts +80 -9
- package/dist/format/constants.js +140 -53
- package/dist/format/constants.js.map +1 -1
- package/dist/format/document.d.ts +4 -2
- package/dist/format/document.js +57 -35
- package/dist/format/document.js.map +1 -1
- package/dist/format/duration.d.ts +24 -0
- package/dist/format/duration.js +72 -0
- package/dist/format/duration.js.map +1 -0
- package/dist/format/guide.d.ts +19 -0
- package/dist/format/guide.js +201 -0
- package/dist/format/guide.js.map +1 -0
- package/dist/format/image-resolver.d.ts +31 -0
- package/dist/format/image-resolver.js +202 -0
- package/dist/format/image-resolver.js.map +1 -0
- package/dist/format/index.d.ts +8 -3
- package/dist/format/index.js +8 -2
- package/dist/format/index.js.map +1 -1
- package/dist/format/parser.d.ts +16 -0
- package/dist/format/parser.js +26 -12
- package/dist/format/parser.js.map +1 -1
- package/dist/format/sanitize.d.ts +3 -0
- package/dist/format/sanitize.js +16 -7
- package/dist/format/sanitize.js.map +1 -1
- package/dist/format/thinking.d.ts +29 -0
- package/dist/format/thinking.js +50 -0
- package/dist/format/thinking.js.map +1 -0
- package/dist/resources/format-guide.md +109 -0
- package/dist/streaming.d.ts +83 -0
- package/dist/streaming.js +301 -0
- package/dist/streaming.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -4
package/dist/format/document.js
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
* 飞书文档处理模块
|
|
3
3
|
* 将 Markdown 转换为飞书文档块
|
|
4
4
|
*/
|
|
5
|
-
import { buildTextBlock, buildHeadingBlock, buildCodeBlock, buildBulletBlock, buildOrderedBlock, buildQuoteBlock, buildTodoBlock, buildEquationBlock, buildCalloutBlock, buildDividerBlock, buildTableBlock, parseInlineText, } from "./builder.js";
|
|
6
|
-
import { parseTable, parseTodo, parseBlockEquation, parseCallout, parseHeading, isCodeBlockStart, isCodeBlockEnd, isDivider, isBulletList, isOrderedList, } from "./parser.js";
|
|
5
|
+
import { buildTextBlock, buildHeadingBlock, buildCodeBlock, buildBulletBlock, buildOrderedBlock, buildQuoteBlock, buildTodoBlock, buildEquationBlock, buildCalloutBlock, buildDividerBlock, buildImageBlock, buildTableBlock, parseInlineText, } from "./builder.js";
|
|
6
|
+
import { parseTable, parseTodo, parseBlockEquation, parseCallout, parseHeading, isCodeBlockStart, isCodeBlockEnd, isDivider, isBulletList, isOrderedList, parseBulletList, parseOrderedList, } from "./parser.js";
|
|
7
7
|
import { sanitizeContent } from "./sanitize.js";
|
|
8
8
|
import { BlockType } from "./constants.js";
|
|
9
9
|
// ── 主转换函数 ───────────────────────────────────────────────────
|
|
10
10
|
/**
|
|
11
11
|
* 将 Markdown 文本转换为飞书文档块
|
|
12
|
+
*
|
|
13
|
+
* 返回 DocumentBlockItem[] 保持原始顺序,区分简单块和需要 Descendants API 的复杂块
|
|
12
14
|
*/
|
|
13
15
|
export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
14
|
-
const
|
|
16
|
+
const items = [];
|
|
15
17
|
// 1. 内容清理
|
|
16
18
|
const { content: sanitizedMarkdown, warnings } = sanitizeContent(markdown);
|
|
17
19
|
if (warnings.length > 0) {
|
|
@@ -27,7 +29,7 @@ export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
|
27
29
|
if (currentPara.length > 0) {
|
|
28
30
|
const content = currentPara.join("\n").trim();
|
|
29
31
|
if (content) {
|
|
30
|
-
|
|
32
|
+
items.push({ type: "simple", block: buildTextBlock(content) });
|
|
31
33
|
}
|
|
32
34
|
currentPara = [];
|
|
33
35
|
}
|
|
@@ -37,7 +39,7 @@ export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
|
37
39
|
// --- 代码块处理 ---
|
|
38
40
|
if (inCodeBlock) {
|
|
39
41
|
if (isCodeBlockEnd(line)) {
|
|
40
|
-
|
|
42
|
+
items.push({ type: "simple", block: buildCodeBlock(codeContent.join("\n"), codeLang) });
|
|
41
43
|
inCodeBlock = false;
|
|
42
44
|
codeContent = [];
|
|
43
45
|
codeLang = "";
|
|
@@ -59,24 +61,27 @@ export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
|
59
61
|
const equationResult = parseBlockEquation(lines, i);
|
|
60
62
|
if (equationResult) {
|
|
61
63
|
flushPara();
|
|
62
|
-
|
|
64
|
+
items.push({ type: "simple", block: buildEquationBlock(equationResult.result.latex) });
|
|
63
65
|
i = equationResult.endIndex;
|
|
64
66
|
continue;
|
|
65
67
|
}
|
|
66
|
-
// ---
|
|
68
|
+
// --- 高亮块(需要 Descendants API) ---
|
|
67
69
|
const calloutResult = parseCallout(lines, i);
|
|
68
70
|
if (calloutResult) {
|
|
69
71
|
flushPara();
|
|
70
72
|
const { type, content } = calloutResult.result;
|
|
71
|
-
|
|
73
|
+
items.push({ type: "callout", data: buildCalloutBlock(type, content.join("\n")) });
|
|
72
74
|
i = calloutResult.endIndex;
|
|
73
75
|
continue;
|
|
74
76
|
}
|
|
75
|
-
// ---
|
|
77
|
+
// --- 表格(需要 Descendants API) ---
|
|
76
78
|
const tableResult = parseTable(lines, i);
|
|
77
79
|
if (tableResult) {
|
|
78
80
|
flushPara();
|
|
79
|
-
|
|
81
|
+
const tableBlock = buildTableBlock(tableResult.data);
|
|
82
|
+
// 保留原始 Markdown,用于表格写入失败时的降级显示
|
|
83
|
+
tableBlock.rawMarkdown = lines.slice(i, tableResult.endIndex).join("\n");
|
|
84
|
+
items.push({ type: "table", data: tableBlock });
|
|
80
85
|
i = tableResult.endIndex;
|
|
81
86
|
continue;
|
|
82
87
|
}
|
|
@@ -84,7 +89,7 @@ export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
|
84
89
|
const todoResult = parseTodo(line);
|
|
85
90
|
if (todoResult) {
|
|
86
91
|
flushPara();
|
|
87
|
-
|
|
92
|
+
items.push({ type: "simple", block: buildTodoBlock(todoResult.content, todoResult.checked) });
|
|
88
93
|
continue;
|
|
89
94
|
}
|
|
90
95
|
// --- 标题 ---
|
|
@@ -92,64 +97,78 @@ export function markdownToBlocks(markdown, originalMessage, meta) {
|
|
|
92
97
|
if (headingLevel > 0) {
|
|
93
98
|
flushPara();
|
|
94
99
|
const content = line.slice(headingLevel + 1).trim();
|
|
95
|
-
|
|
100
|
+
items.push({ type: "simple", block: buildHeadingBlock(headingLevel, content) });
|
|
96
101
|
continue;
|
|
97
102
|
}
|
|
98
103
|
// --- 分割线 ---
|
|
99
104
|
if (isDivider(line)) {
|
|
100
105
|
flushPara();
|
|
101
|
-
|
|
106
|
+
items.push({ type: "simple", block: buildDividerBlock() });
|
|
102
107
|
continue;
|
|
103
108
|
}
|
|
104
109
|
// --- 引用块 ---
|
|
105
110
|
if (line.trim().startsWith("> ")) {
|
|
106
111
|
flushPara();
|
|
107
112
|
const quoteContent = line.trim().slice(2);
|
|
108
|
-
// 检查是否是高亮块语法(已在上面处理)
|
|
109
113
|
if (!quoteContent.match(/^\[!\w+\]/)) {
|
|
110
|
-
|
|
114
|
+
items.push({ type: "simple", block: buildQuoteBlock(quoteContent) });
|
|
111
115
|
}
|
|
112
116
|
continue;
|
|
113
117
|
}
|
|
114
|
-
// ---
|
|
118
|
+
// --- 无序列表(支持嵌套层级) ---
|
|
115
119
|
if (isBulletList(line)) {
|
|
116
120
|
flushPara();
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
|
|
121
|
+
const parsed = parseBulletList(line);
|
|
122
|
+
if (parsed) {
|
|
123
|
+
items.push({ type: "simple", block: buildBulletBlock(parsed.content, parsed.level) });
|
|
120
124
|
}
|
|
121
125
|
continue;
|
|
122
126
|
}
|
|
123
|
-
// ---
|
|
127
|
+
// --- 有序列表(支持嵌套层级) ---
|
|
124
128
|
if (isOrderedList(line)) {
|
|
125
129
|
flushPara();
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
|
|
130
|
+
const parsed = parseOrderedList(line);
|
|
131
|
+
if (parsed) {
|
|
132
|
+
items.push({ type: "simple", block: buildOrderedBlock(parsed.content, parsed.level) });
|
|
129
133
|
}
|
|
130
134
|
continue;
|
|
131
135
|
}
|
|
136
|
+
// --- 图片(img_xxx 格式,已由 ImageResolver 处理) ---
|
|
137
|
+
const imgMatch = line.trim().match(/^!\[([^\]]*)\]\((img_[^)]+)\)$/i);
|
|
138
|
+
if (imgMatch) {
|
|
139
|
+
flushPara();
|
|
140
|
+
items.push({ type: "simple", block: buildImageBlock(imgMatch[2]) });
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// --- 空行(段落分隔符) ---
|
|
144
|
+
if (line.trim() === "") {
|
|
145
|
+
flushPara();
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
132
148
|
// --- 普通段落 ---
|
|
133
149
|
currentPara.push(line);
|
|
134
150
|
}
|
|
135
151
|
// 处理剩余段落
|
|
136
152
|
flushPara();
|
|
137
153
|
// 3. 添加元数据头部
|
|
138
|
-
const
|
|
139
|
-
return {
|
|
154
|
+
const headerItems = buildDocumentHeader(originalMessage, meta);
|
|
155
|
+
return { items: [...headerItems, ...items], warnings };
|
|
140
156
|
}
|
|
141
157
|
// ── 文档头部构建 ───────────────────────────────────────────────────
|
|
142
158
|
function buildDocumentHeader(originalMessage, meta) {
|
|
143
|
-
const
|
|
159
|
+
const items = [];
|
|
144
160
|
// 引用块显示用户原始消息
|
|
145
161
|
if (originalMessage) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
items.push({
|
|
163
|
+
type: "simple",
|
|
164
|
+
block: {
|
|
165
|
+
block_type: BlockType.QUOTE,
|
|
166
|
+
quote: { elements: parseInlineText(originalMessage) },
|
|
167
|
+
},
|
|
149
168
|
});
|
|
150
169
|
}
|
|
151
170
|
// 分割线
|
|
152
|
-
|
|
171
|
+
items.push({ type: "simple", block: buildDividerBlock() });
|
|
153
172
|
// 元数据(每行一个 text block,确保换行)
|
|
154
173
|
const metaLines = [
|
|
155
174
|
`📁 工作目录: ${meta.cwd}`,
|
|
@@ -158,13 +177,16 @@ function buildDocumentHeader(originalMessage, meta) {
|
|
|
158
177
|
`📅 时间: ${meta.datetime}`,
|
|
159
178
|
];
|
|
160
179
|
for (const line of metaLines) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
items.push({
|
|
181
|
+
type: "simple",
|
|
182
|
+
block: {
|
|
183
|
+
block_type: BlockType.TEXT,
|
|
184
|
+
text: { elements: [{ text_run: { content: line } }] },
|
|
185
|
+
},
|
|
164
186
|
});
|
|
165
187
|
}
|
|
166
188
|
// 分割线
|
|
167
|
-
|
|
168
|
-
return
|
|
189
|
+
items.push({ type: "simple", block: buildDividerBlock() });
|
|
190
|
+
return items;
|
|
169
191
|
}
|
|
170
192
|
//# sourceMappingURL=document.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/format/document.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,aAAa,
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/format/document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 时间格式化 & Thinking 卡片元素构建
|
|
3
|
+
*
|
|
4
|
+
* 统一 CardKit 和 Update 模式的 thinking 折叠面板,
|
|
5
|
+
* 对齐 openclaw-lark 的 collapsible_panel 方案。
|
|
6
|
+
*/
|
|
7
|
+
/** Thinking 内容截断阈值(字符数) */
|
|
8
|
+
export declare const THINKING_OVERFLOW_TRUNCATE = 3000;
|
|
9
|
+
/** 秒 → "3.2s" / "1m 23s" */
|
|
10
|
+
export declare function formatDuration(seconds: number): string;
|
|
11
|
+
/** 毫秒 → "3.2s" / "1m 23s" */
|
|
12
|
+
export declare function formatReasoningDuration(ms: number): string;
|
|
13
|
+
interface ThinkingPanelOptions {
|
|
14
|
+
thinking: string;
|
|
15
|
+
reasoningElapsedMs?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 构建 thinking 折叠面板元素(collapsible_panel)
|
|
19
|
+
*
|
|
20
|
+
* 返回 [collapsible_panel, hr],可直接展开到卡片 elements 数组。
|
|
21
|
+
* CardKit 和 Update 模式共用此函数,避免重复。
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildThinkingPanel(options: ThinkingPanelOptions): any[];
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 时间格式化 & Thinking 卡片元素构建
|
|
3
|
+
*
|
|
4
|
+
* 统一 CardKit 和 Update 模式的 thinking 折叠面板,
|
|
5
|
+
* 对齐 openclaw-lark 的 collapsible_panel 方案。
|
|
6
|
+
*/
|
|
7
|
+
// ── 常量 ──────────────────────────────────────────────────
|
|
8
|
+
/** Thinking 内容截断阈值(字符数) */
|
|
9
|
+
export const THINKING_OVERFLOW_TRUNCATE = 3000;
|
|
10
|
+
// ── 时间格式化 ─────────────────────────────────────────────
|
|
11
|
+
/** 秒 → "3.2s" / "1m 23s" */
|
|
12
|
+
export function formatDuration(seconds) {
|
|
13
|
+
if (seconds < 60)
|
|
14
|
+
return `${seconds.toFixed(1)}s`;
|
|
15
|
+
const minutes = Math.floor(seconds / 60);
|
|
16
|
+
const remainSec = Math.round(seconds % 60);
|
|
17
|
+
return `${minutes}m ${remainSec}s`;
|
|
18
|
+
}
|
|
19
|
+
/** 毫秒 → "3.2s" / "1m 23s" */
|
|
20
|
+
export function formatReasoningDuration(ms) {
|
|
21
|
+
return formatDuration(ms / 1000);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 构建 thinking 折叠面板元素(collapsible_panel)
|
|
25
|
+
*
|
|
26
|
+
* 返回 [collapsible_panel, hr],可直接展开到卡片 elements 数组。
|
|
27
|
+
* CardKit 和 Update 模式共用此函数,避免重复。
|
|
28
|
+
*/
|
|
29
|
+
export function buildThinkingPanel(options) {
|
|
30
|
+
const truncatedThinking = options.thinking.length > THINKING_OVERFLOW_TRUNCATE
|
|
31
|
+
? options.thinking.slice(0, THINKING_OVERFLOW_TRUNCATE) + "\n..."
|
|
32
|
+
: options.thinking;
|
|
33
|
+
const durLabel = options.reasoningElapsedMs
|
|
34
|
+
? ` ${formatReasoningDuration(options.reasoningElapsedMs)}`
|
|
35
|
+
: "";
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
tag: "collapsible_panel",
|
|
39
|
+
expanded: false,
|
|
40
|
+
header: {
|
|
41
|
+
title: {
|
|
42
|
+
tag: "markdown",
|
|
43
|
+
content: `💭 Thought${durLabel}`,
|
|
44
|
+
i18n_content: {
|
|
45
|
+
zh_cn: `💭 思考${durLabel}`,
|
|
46
|
+
en_us: `💭 Thought${durLabel}`,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
vertical_align: "center",
|
|
50
|
+
icon: {
|
|
51
|
+
tag: "standard_icon",
|
|
52
|
+
token: "down-small-ccm_outlined",
|
|
53
|
+
size: "16px 16px",
|
|
54
|
+
},
|
|
55
|
+
icon_position: "follow_text",
|
|
56
|
+
icon_expanded_angle: -180,
|
|
57
|
+
},
|
|
58
|
+
border: { color: "grey", corner_radius: "5px" },
|
|
59
|
+
vertical_spacing: "8px",
|
|
60
|
+
padding: "8px 8px 8px 8px",
|
|
61
|
+
elements: [
|
|
62
|
+
{
|
|
63
|
+
tag: "markdown",
|
|
64
|
+
content: truncatedThinking,
|
|
65
|
+
text_size: "notation",
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
{ tag: "hr" },
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=duration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.js","sourceRoot":"","sources":["../../src/format/duration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,2DAA2D;AAE3D,2BAA2B;AAC3B,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAE/C,yDAAyD;AAEzD,4BAA4B;AAC5B,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IAC3C,OAAO,GAAG,OAAO,KAAK,SAAS,GAAG,CAAC;AACrC,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,uBAAuB,CAAC,EAAU;IAChD,OAAO,cAAc,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;AACnC,CAAC;AASD;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA6B;IAC9D,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,GAAG,0BAA0B;QAC5E,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,0BAA0B,CAAC,GAAG,OAAO;QACjE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAErB,MAAM,QAAQ,GAAG,OAAO,CAAC,kBAAkB;QACzC,CAAC,CAAC,IAAI,uBAAuB,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE;QAC3D,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;QACL;YACE,GAAG,EAAE,mBAAmB;YACxB,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE;gBACN,KAAK,EAAE;oBACL,GAAG,EAAE,UAAU;oBACf,OAAO,EAAE,aAAa,QAAQ,EAAE;oBAChC,YAAY,EAAE;wBACZ,KAAK,EAAE,QAAQ,QAAQ,EAAE;wBACzB,KAAK,EAAE,aAAa,QAAQ,EAAE;qBAC/B;iBACF;gBACD,cAAc,EAAE,QAAQ;gBACxB,IAAI,EAAE;oBACJ,GAAG,EAAE,eAAe;oBACpB,KAAK,EAAE,yBAAyB;oBAChC,IAAI,EAAE,WAAW;iBAClB;gBACD,aAAa,EAAE,aAAa;gBAC5B,mBAAmB,EAAE,CAAC,GAAG;aAC1B;YACD,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE;YAC/C,gBAAgB,EAAE,KAAK;YACvB,OAAO,EAAE,iBAAiB;YAC1B,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,UAAU;oBACf,OAAO,EAAE,iBAAiB;oBAC1B,SAAS,EAAE,UAAU;iBACtB;aACF;SACF;QACD,EAAE,GAAG,EAAE,IAAI,EAAE;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 飞书格式指导模块
|
|
3
|
+
*
|
|
4
|
+
* 从文件加载格式指导内容,注入到 Claude 的 system prompt 中。
|
|
5
|
+
*
|
|
6
|
+
* 文件优先级:
|
|
7
|
+
* 1. ~/.larkcc/format-guide.md(用户自定义)
|
|
8
|
+
* 2. resources/format-guide.md(随项目发布的默认文件)
|
|
9
|
+
* 3. 内置默认内容(代码内 fallback)
|
|
10
|
+
*
|
|
11
|
+
* 注入方式:通过 query() 的 options.systemPrompt.append
|
|
12
|
+
* 注入时机:每次调用 query() 时传入,整个会话生效
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* 获取格式指导内容(带缓存)
|
|
16
|
+
*
|
|
17
|
+
* 只在第一次调用时读取文件,后续返回缓存。
|
|
18
|
+
*/
|
|
19
|
+
export declare function getFormatGuideContent(): string;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 飞书格式指导模块
|
|
3
|
+
*
|
|
4
|
+
* 从文件加载格式指导内容,注入到 Claude 的 system prompt 中。
|
|
5
|
+
*
|
|
6
|
+
* 文件优先级:
|
|
7
|
+
* 1. ~/.larkcc/format-guide.md(用户自定义)
|
|
8
|
+
* 2. resources/format-guide.md(随项目发布的默认文件)
|
|
9
|
+
* 3. 内置默认内容(代码内 fallback)
|
|
10
|
+
*
|
|
11
|
+
* 注入方式:通过 query() 的 options.systemPrompt.append
|
|
12
|
+
* 注入时机:每次调用 query() 时传入,整个会话生效
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as os from "os";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
// ESM 兼容:__dirname 在 ESM 中不可用
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.dirname(__filename);
|
|
21
|
+
// ── 内置默认格式指导(fallback)────────────────────────────────
|
|
22
|
+
const DEFAULT_FORMAT_GUIDE = `# 飞书格式规范
|
|
23
|
+
|
|
24
|
+
你的回复会通过飞书展示。短内容显示为交互式卡片,长内容写入飞书云文档。
|
|
25
|
+
两者对 Markdown 的支持不同,请严格遵守以下规范。
|
|
26
|
+
|
|
27
|
+
## 一、通用规则(卡片和文档都适用)
|
|
28
|
+
|
|
29
|
+
### 代码块
|
|
30
|
+
- 必须标注语言:\`\`\`typescript、\`\`\`python、\`\`\`bash 等
|
|
31
|
+
- 不要使用无语言标记的代码块(\`\`\`)
|
|
32
|
+
- 不要在代码块外使用 | 开头的文字(会被误识别为表格)
|
|
33
|
+
|
|
34
|
+
### 图片
|
|
35
|
+
- 不要使用外部图片链接 
|
|
36
|
+
- 飞书只支持 img_xxx 格式的内部图片 key
|
|
37
|
+
|
|
38
|
+
### 段落
|
|
39
|
+
- 段落之间用空行分隔
|
|
40
|
+
- 不要用 <br> 或 HTML 标签控制换行
|
|
41
|
+
|
|
42
|
+
### 列表
|
|
43
|
+
- 嵌套不要超过 2 级
|
|
44
|
+
- 嵌套缩进统一用 2 个空格
|
|
45
|
+
|
|
46
|
+
### 不要使用
|
|
47
|
+
- HTML 标签(除了表格合并 <td colspan="2">,仅文档模式可用)
|
|
48
|
+
- 脚注 [^1]
|
|
49
|
+
- 折叠 <details>
|
|
50
|
+
- 任务列表外的复选框语法
|
|
51
|
+
|
|
52
|
+
## 二、卡片规则(短内容,显示为交互式卡片)
|
|
53
|
+
|
|
54
|
+
飞书卡片 Markdown 只支持有限的格式子集:
|
|
55
|
+
|
|
56
|
+
### 标题
|
|
57
|
+
- 只用 #### (H4) 和 ##### (H5)
|
|
58
|
+
- 不要使用 # ## ###(不会渲染为标题)
|
|
59
|
+
|
|
60
|
+
### 表格
|
|
61
|
+
- 列数不超过 5 列
|
|
62
|
+
- 不要使用 colspan/rowspan 合并(卡片不支持 HTML)
|
|
63
|
+
- 单元格内容尽量简短
|
|
64
|
+
|
|
65
|
+
### 不支持(不要在卡片内容中使用)
|
|
66
|
+
- > [!TYPE] Callout 语法
|
|
67
|
+
- $$ 数学公式
|
|
68
|
+
- 嵌套列表
|
|
69
|
+
- 删除线 ~~text~~
|
|
70
|
+
|
|
71
|
+
### 建议
|
|
72
|
+
- 代码块标注语言
|
|
73
|
+
- 使用 **粗体** 和 *斜体* 强调重点
|
|
74
|
+
- 使用 > 引用块
|
|
75
|
+
- 使用 --- 分割线
|
|
76
|
+
|
|
77
|
+
## 三、文档规则(长内容,写入飞书云文档)
|
|
78
|
+
|
|
79
|
+
飞书文档支持更丰富的格式:
|
|
80
|
+
|
|
81
|
+
### Callout 高亮块
|
|
82
|
+
使用 > [!TYPE] 语法,支持的类型和推荐 emoji:
|
|
83
|
+
|
|
84
|
+
| 类型 | 推荐 emoji | 用途 |
|
|
85
|
+
|------|-----------|------|
|
|
86
|
+
| > [!NOTE] | 💡 | 提示信息 |
|
|
87
|
+
| > [!TIP] | ✅ | 实用建议 |
|
|
88
|
+
| > [!WARNING] | ⚠️ | 注意事项 |
|
|
89
|
+
| > [!DANGER] | 🔴 | 危险操作 |
|
|
90
|
+
| > [!CAUTION] | 🟡 | 谨慎操作 |
|
|
91
|
+
| > [!INFO] | ℹ️ | 补充信息 |
|
|
92
|
+
|
|
93
|
+
示例:
|
|
94
|
+
> [!TIP] ✅
|
|
95
|
+
> 使用 async/await 可以避免回调地狱。
|
|
96
|
+
|
|
97
|
+
注意:
|
|
98
|
+
- Callout 中不要嵌套列表或表格(渲染会失败)
|
|
99
|
+
- 每条内容单独一行,用 > 开头
|
|
100
|
+
|
|
101
|
+
### 表格
|
|
102
|
+
- 列数建议不超过 6 列
|
|
103
|
+
- 单元格内容不超过 200 个字符
|
|
104
|
+
- 可以使用 <td colspan="N"> 合并列
|
|
105
|
+
- 不要在同一表格中混用合并单元格和普通单元格
|
|
106
|
+
- 表头和分隔符是必需的
|
|
107
|
+
|
|
108
|
+
### 数学公式
|
|
109
|
+
- 块级公式用 $$...$$
|
|
110
|
+
- 行内公式用 $...$
|
|
111
|
+
- 不要使用 \\\多行对齐(飞书不支持)
|
|
112
|
+
- 不要使用 \\begin{}...\\end{} 环境
|
|
113
|
+
|
|
114
|
+
### 代码块
|
|
115
|
+
- 必须标注语言(飞书会根据语言做语法高亮)
|
|
116
|
+
- 支持的语言:typescript, javascript, python, java, go, rust, bash, sql, json, yaml, xml, html, css, markdown, c, cpp, csharp, ruby, php, swift, kotlin, dart, r, matlab, scala, lua, perl, haskell, elixir, clojure, shell, powershell, dockerfile, makefile, toml, ini, diff, plaintext
|
|
117
|
+
|
|
118
|
+
### 标题
|
|
119
|
+
- 使用 H1-H6 完整层级
|
|
120
|
+
- 文档会保留原始标题级别
|
|
121
|
+
|
|
122
|
+
## 四、反面教材(这些会导致渲染失败或格式异常)
|
|
123
|
+
|
|
124
|
+
❌ 代码块外使用 | 开头 → 被误识别为表格
|
|
125
|
+
❌ Callout 中嵌套列表 → 渲染失败
|
|
126
|
+
❌ 数学公式使用多行对齐 → 公式显示异常
|
|
127
|
+
❌ 表格单元格内容超长 → 表格溢出文档宽度
|
|
128
|
+
❌ 超过 3 级的列表嵌套 → 只显示为 2 级
|
|
129
|
+
❌ 空的代码块(无语言标记且无内容)→ 创建失败
|
|
130
|
+
❌ 在段落之间不空行 → 段落粘连显示为一坨文字`;
|
|
131
|
+
// ── 文件路径 ───────────────────────────────────────────────────
|
|
132
|
+
function getUserGuidePath() {
|
|
133
|
+
return path.join(os.homedir(), ".larkcc", "format-guide.md");
|
|
134
|
+
}
|
|
135
|
+
function getBundledGuidePaths() {
|
|
136
|
+
return [
|
|
137
|
+
// 编译后 dist/format/guide.js → dist/resources/format-guide.md
|
|
138
|
+
path.join(__dirname, "..", "resources", "format-guide.md"),
|
|
139
|
+
// 开发时 src/format/guide.ts → resources/format-guide.md
|
|
140
|
+
path.join(__dirname, "..", "..", "resources", "format-guide.md"),
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
// ── 加载函数 ───────────────────────────────────────────────────
|
|
144
|
+
/**
|
|
145
|
+
* 加载格式指导内容
|
|
146
|
+
*
|
|
147
|
+
* 优先级:
|
|
148
|
+
* 1. ~/.larkcc/format-guide.md(用户自定义)
|
|
149
|
+
* 2. resources/format-guide.md(随项目发布的默认文件)
|
|
150
|
+
* 3. 内置默认内容(代码内 fallback)
|
|
151
|
+
*/
|
|
152
|
+
function loadFormatGuideContent() {
|
|
153
|
+
// 1. 用户自定义文件
|
|
154
|
+
const userPath = getUserGuidePath();
|
|
155
|
+
try {
|
|
156
|
+
if (fs.existsSync(userPath)) {
|
|
157
|
+
const content = fs.readFileSync(userPath, "utf8").trim();
|
|
158
|
+
if (content) {
|
|
159
|
+
console.error(`[GUIDE] Loaded user format guide: ${userPath}`);
|
|
160
|
+
return content;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
console.error(`[GUIDE] Failed to read user guide: ${error}`);
|
|
166
|
+
}
|
|
167
|
+
// 2. 随项目发布的默认文件(优先 dist/resources/,其次项目根 resources/)
|
|
168
|
+
const bundledPaths = getBundledGuidePaths();
|
|
169
|
+
for (const bundledPath of bundledPaths) {
|
|
170
|
+
try {
|
|
171
|
+
if (fs.existsSync(bundledPath)) {
|
|
172
|
+
const content = fs.readFileSync(bundledPath, "utf8").trim();
|
|
173
|
+
if (content) {
|
|
174
|
+
console.error(`[GUIDE] Loaded bundled format guide: ${bundledPath}`);
|
|
175
|
+
return content;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
console.error(`[GUIDE] Failed to read bundled guide ${bundledPath}: ${error}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// 3. 内置默认
|
|
184
|
+
console.error("[GUIDE] Using built-in default format guide");
|
|
185
|
+
return DEFAULT_FORMAT_GUIDE;
|
|
186
|
+
}
|
|
187
|
+
// ── 缓存 ───────────────────────────────────────────────────────
|
|
188
|
+
let cachedGuide = null;
|
|
189
|
+
/**
|
|
190
|
+
* 获取格式指导内容(带缓存)
|
|
191
|
+
*
|
|
192
|
+
* 只在第一次调用时读取文件,后续返回缓存。
|
|
193
|
+
*/
|
|
194
|
+
export function getFormatGuideContent() {
|
|
195
|
+
if (cachedGuide !== null) {
|
|
196
|
+
return cachedGuide;
|
|
197
|
+
}
|
|
198
|
+
cachedGuide = loadFormatGuideContent();
|
|
199
|
+
return cachedGuide;
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=guide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/format/guide.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片解析模块
|
|
3
|
+
*
|
|
4
|
+
* 将 Markdown 中的外部图片 URL 下载并上传到飞书,
|
|
5
|
+
* 替换为飞书内部的 img_xxx 格式 key。
|
|
6
|
+
*
|
|
7
|
+
* 处理流程:
|
|
8
|
+
* 1. 提取代码块(保护代码内容)
|
|
9
|
+
* 2. 扫描  模式
|
|
10
|
+
* 3. 串行下载 + 上传(避免触发速率限制)
|
|
11
|
+
* 4. 替换 URL → img_xxx
|
|
12
|
+
* 5. 恢复代码块
|
|
13
|
+
*
|
|
14
|
+
* 失败的图片保留原始 URL,由后续 sanitizeContent 降级为链接。
|
|
15
|
+
*/
|
|
16
|
+
export interface ImageResolveResult {
|
|
17
|
+
/** 替换后的 Markdown 内容 */
|
|
18
|
+
content: string;
|
|
19
|
+
/** 成功上传的图片数 */
|
|
20
|
+
uploaded: number;
|
|
21
|
+
/** 上传失败的图片数 */
|
|
22
|
+
failed: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 解析 Markdown 中的外部图片,下载并上传到飞书
|
|
26
|
+
*
|
|
27
|
+
* @param markdown 原始 Markdown 内容
|
|
28
|
+
* @param token tenant_access_token
|
|
29
|
+
* @returns 替换后的内容和统计信息
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveImages(markdown: string, token: string): Promise<ImageResolveResult>;
|