lark-docx2md 0.5.3-beta.0 → 0.5.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,7 +42,7 @@ npx -y lark-docx2md@latest download <url>
42
42
  | `--app-id <id>` | 飞书应用 App ID | `LARK_DOCX2MD_APP_ID` | — |
43
43
  | `--app-secret <secret>` | 飞书应用 App Secret | `LARK_DOCX2MD_APP_SECRET` | — |
44
44
  | `-o, --output <dir>` | 输出目录 | `LARK_DOCX2MD_OUTPUT` | `./larkDocx2mdOutput` |
45
- | `--agent [mode]` | Agent 模式:日志 ERROR。不传值(或 `=true`)为在线模式,Markdown 输出到 stdout;传 `local` 则落盘后输出引导 AI 读取的提示词 | `LARK_DOCX2MD_AGENT=true\|local` | `false` |
45
+ | `--agent [mode]` | Agent 模式:日志 ERROR。不传值(或 `=stdout`)为在线模式,Markdown 输出到 stdout;传 `local` 则落盘后输出引导 AI 读取的提示词 | `LARK_DOCX2MD_AGENT=stdout\|local` | `false` |
46
46
  | `--image-mode <mode>` | 图片处理模式:`local`(下载到本地)或 `online`(24h 临时链接) | `LARK_DOCX2MD_IMAGE_MODE` | `local` |
47
47
  | `--filter-title <title>` | 按标题过滤:仅转换匹配标题及其下级内容(匹配到同级或更高级标题时截止) | — | — |
48
48
  | `--filter-title-block-id <id>` | 按 heading 块 id 精确过滤(无同名歧义),通常配合 `get-titles` 子命令获取;与 `--filter-title` 互斥 | — | — |
@@ -57,6 +57,7 @@ npx -y lark-docx2md@latest download <url>
57
57
  > - 非 agent 模式下 `--wb-format yaml` 时:`--wb-image-mode` 强制为 `online`。
58
58
  > - `--filter-title`:按标题文本精确匹配(忽略前后空格),收集该标题及其所有子级块,遇到同级或更高级标题时停止。同名标题取首个;未匹配时错误信息附全文标题 yaml 清单。
59
59
  > - `--filter-title-block-id`:按 heading 块 id 严格相等匹配,适用于同名标题或脚本化场景;通常先用 `get-titles` 查出目标 `blockId` 再传入。与 `--filter-title` 互斥。
60
+ > - **命中深层标题时自动注入父级标题(仅 heading 块本身)**:两个过滤参数均会按文档顺序补齐包含路径上的顶层→该标题的所有祖先标题,以保留章节层级上下文;不会引入旁支兄弟或伪造跳级。
60
61
 
61
62
  ## 子命令:`get-titles`
62
63
 
@@ -73,7 +74,7 @@ npx -y lark-docx2md@latest get-titles --agent <url>
73
74
  | `--format <format>` | 输出格式:`yaml`(扁平) \| `yaml-tree`(嵌套) \| `json` \| `tree`(json 嵌套) \| `text`(缩进的 markdown 标题) | `yaml` |
74
75
  | `--agent [mode]` | 同 `dl`,降低日志级别 | — |
75
76
 
76
- 输出包含 `blockId` / `index` / `level` / `text` / `path`,可被 AI 直接消费用于选择目标章节。
77
+ 输出包含 `blockId` / `level` / `text`,可被 AI 直接消费用于选择目标章节(嵌套关系由 `yaml-tree` / `tree` 格式天然表达)。
77
78
 
78
79
  ## 功能
79
80
 
@@ -100,7 +101,7 @@ npx -y lark-docx2md@latest get-titles --agent <url>
100
101
  | Callout | 高亮块 | `>[!TIP]` + 子块 |
101
102
  | Divider | 分割线 | `---` |
102
103
  | Image | 图片 | `![图片](url)` |
103
- | Table / TableCell | 表格 | `<table>` HTML(支持合并单元格) |
104
+ | Table / TableCell | 表格 | GFM 管道表格(合并单元格按值展开) |
104
105
  | QuoteContainer | 引用容器 | `> 子块内容` |
105
106
  | Grid / GridColumn | 分栏布局 | 展平为子块内容 |
106
107
  | Sheet | 电子表格 | GFM 表格(合并单元格自动展开) |
package/dist/cli.js CHANGED
@@ -1,27 +1,56 @@
1
1
  #!/usr/bin/env node
2
- import { i as getTitles, n as convert, o as setLogLevel, r as formatTitlesAsText, s as serializeYaml, t as buildTitleTree } from "./converter-D1nCzDJF.js";
2
+ import { a as setLogLevel, n as buildTitleTree, o as serializeYaml, r as getTitles, t as convert } from "./converter-C2dAcaTO.js";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
3
5
  import { Command } from "commander";
4
6
  import { LoggerLevel } from "@larksuiteoapi/node-sdk";
5
7
  //#region src/cli.ts
6
8
  const program = new Command();
7
9
  program.name("larkDocx2md").description("Download Lark/Feishu documents to markdown");
8
- program.command("download").alias("dl").description("Download a wiki document to markdown").option("--app-id <id>", "Feishu app ID (or read from LARK_DOCX2MD_APP_ID)").option("--app-secret <secret>", "Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)").option("-o, --output <dir>", "Output directory (or LARK_DOCX2MD_OUTPUT)").option("--agent [mode]", "Enable agent mode: ERROR log level, and AI-oriented stdout. Pass \"local\" to save markdown/images/whiteboards to disk and print a read-file prompt (or LARK_DOCX2MD_AGENT=true|local)").option("--wb-format <format>", "Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)").option("--wb-bg <style>", "Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)").option("--wb-image-mode <mode>", "Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)").option("--image-mode <mode>", "Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)").option("--filter-title <title>", "Only convert the section matching this heading title (single title, first match wins on duplicates)").option("--filter-title-block-id <id>", "Only convert the section whose heading block id matches (most precise; obtain from get-titles)").argument("<url>", "Feishu wiki document URL: https://*.feishu.cn/wiki/*").action(async (url, opts) => {
10
+ /**
11
+ * 把 commander 解析出的 --agent 原值(undefined | true | string)与
12
+ * LARK_DOCX2MD_AGENT 环境变量统一收敛为精确的 AgentMode | false。
13
+ *
14
+ * 优先级:显式 --agent > 环境变量 > 默认 false。
15
+ * 非法取值返回错误信息字符串,由调用方决定如何上报。
16
+ */
17
+ function resolveAgentMode(raw) {
18
+ if (raw === void 0) {
19
+ const env = process.env.LARK_DOCX2MD_AGENT;
20
+ if (env === "stdout" || env === "local") return { value: env };
21
+ if (env !== void 0 && env !== "") return {
22
+ value: false,
23
+ error: `Invalid LARK_DOCX2MD_AGENT="${env}", must be "stdout" or "local"`
24
+ };
25
+ return { value: false };
26
+ }
27
+ if (raw === true) return { value: "stdout" };
28
+ if (raw === "stdout" || raw === "local") return { value: raw };
29
+ return {
30
+ value: false,
31
+ error: `Invalid --agent value "${raw}", must be "stdout" or "local"`
32
+ };
33
+ }
34
+ program.command("download").alias("dl").description("Download a wiki document to markdown").option("--app-id <id>", "Feishu app ID (or read from LARK_DOCX2MD_APP_ID)").option("--app-secret <secret>", "Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)").option("-o, --output <dir>", "Output directory (or LARK_DOCX2MD_OUTPUT)").option("--agent [mode]", "Enable agent mode: ERROR log level, and AI-oriented stdout. Modes: \"stdout\" (default, print markdown to stdout) or \"local\" (save markdown/images/whiteboards to disk and print a read-file prompt). Or LARK_DOCX2MD_AGENT=stdout|local").option("--wb-format <format>", "Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)").option("--wb-bg <style>", "Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)").option("--wb-image-mode <mode>", "Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)").option("--image-mode <mode>", "Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)").option("--filter-title <title>", "Only convert the section matching this heading title (single title, first match wins on duplicates)").option("--filter-title-block-id <id>", "Only convert the section whose heading block id matches (most precise; obtain from get-titles)").argument("<url>", "Feishu wiki document URL: https://*.feishu.cn/wiki/*").action(async (url, opts) => {
9
35
  opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;
10
36
  opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;
11
37
  opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? "./larkDocx2mdOutput";
12
- if (opts.agent === void 0) {
13
- const envAgent = process.env.LARK_DOCX2MD_AGENT;
14
- if (envAgent === "true") opts.agent = true;
15
- else if (envAgent === "local") opts.agent = "local";
16
- else opts.agent = false;
17
- } else if (typeof opts.agent === "string" && opts.agent !== "local") program.error(`Invalid --agent value "${opts.agent}", only "local" is supported (or omit the value)`);
18
- const agentEnabled = opts.agent === true || opts.agent === "local";
38
+ const agentResolved = resolveAgentMode(opts.agent);
39
+ if (agentResolved.error) {
40
+ program.error(agentResolved.error);
41
+ return;
42
+ }
43
+ opts.agent = agentResolved.value;
44
+ const agentEnabled = opts.agent === "stdout" || opts.agent === "local";
19
45
  const agentLocal = opts.agent === "local";
46
+ const agentStdout = opts.agent === "stdout";
20
47
  opts.imageMode = opts.imageMode ?? process.env.LARK_DOCX2MD_IMAGE_MODE ?? "local";
21
48
  opts.wbFormat = opts.wbFormat ?? process.env.LARK_DOCX2MD_WB_FORMAT;
22
49
  opts.wbBg = opts.wbBg ?? process.env.LARK_DOCX2MD_WB_BG ?? "none";
23
50
  opts.wbImageMode = opts.wbImageMode ?? process.env.LARK_DOCX2MD_WB_IMAGE_MODE ?? "local";
24
- if (!opts.wbFormat) opts.wbFormat = agentEnabled ? "yaml" : "svg";
51
+ if (!opts.wbFormat) if (agentLocal) opts.wbFormat = "inline-svg";
52
+ else if (agentStdout) opts.wbFormat = "yaml";
53
+ else opts.wbFormat = "svg";
25
54
  if (agentEnabled) {
26
55
  setLogLevel(LoggerLevel.error);
27
56
  if (agentLocal) {
@@ -58,33 +87,28 @@ program.command("download").alias("dl").description("Download a wiki document to
58
87
  wbImageMode: opts.wbImageMode,
59
88
  wbBg: opts.wbBg,
60
89
  wbFormat: opts.wbFormat,
61
- agent: agentLocal ? "local" : opts.agent === true,
90
+ agent: opts.agent,
62
91
  filterTitle: opts.filterTitle?.trim(),
63
92
  filterTitleBlockId: opts.filterTitleBlockId?.trim()
64
93
  });
65
94
  if (agentLocal) process.stdout.write(`**The Feishu document has been downloaded to the following absolute path:**\n\n\`${result.filePath}\`\n\n**Read this file to access the full markdown content.**\n`);
66
- else if (opts.agent === true) process.stdout.write(result.markdown);
95
+ else if (agentStdout) process.stdout.write(result.markdown);
67
96
  });
68
- program.command("get-titles").description("Print all headings (level 1~9) of a wiki/docx document. Useful before --filter-title-block-id.").option("--app-id <id>", "Feishu app ID (or read from LARK_DOCX2MD_APP_ID)").option("--app-secret <secret>", "Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)").option("--max-level <n>", "Only output headings whose level <= n (1~9)", "9").option("--format <format>", "Output format: \"yaml\" (flat, default) | \"yaml-tree\" (nested) | \"json\" (flat) | \"tree\" (json nested) | \"text\" (indented markdown headings)", "yaml").option("--agent [mode]", "Enable agent mode: ERROR log level, AI-oriented stdout (or LARK_DOCX2MD_AGENT=true|local)").argument("<url>", "Feishu wiki/docx URL: https://*.feishu.cn/{wiki,docx,docs}/*").action(async (url, opts) => {
97
+ program.command("get-titles").description("Print all headings (level 1~9) of a wiki/docx document as a nested yaml tree. Useful before --filter-title-block-id.").option("--app-id <id>", "Feishu app ID (or read from LARK_DOCX2MD_APP_ID)").option("--app-secret <secret>", "Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)").option("-o, --output <dir>", "Output directory used by --agent local (or LARK_DOCX2MD_OUTPUT)").option("--max-level <n>", "Only output headings whose level <= n (1~9)", "9").option("--agent [mode]", "Enable agent mode: ERROR log level, AI-oriented stdout. Modes: \"stdout\" (default, print titles to stdout) or \"local\" (save titles to disk and print a read-file prompt). Or LARK_DOCX2MD_AGENT=stdout|local").argument("<url>", "Feishu wiki/docx URL: https://*.feishu.cn/{wiki,docx,docs}/*").action(async (url, opts) => {
69
98
  opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;
70
99
  opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;
71
- if (opts.agent === void 0) {
72
- const envAgent = process.env.LARK_DOCX2MD_AGENT;
73
- if (envAgent === "true") opts.agent = true;
74
- else if (envAgent === "local") opts.agent = "local";
75
- else opts.agent = false;
76
- } else if (typeof opts.agent === "string" && opts.agent !== "local") program.error(`Invalid --agent value "${opts.agent}", only "local" is supported (or omit the value)`);
77
- if (opts.agent === true || opts.agent === "local") setLogLevel(LoggerLevel.error);
100
+ opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? "./larkDocx2mdOutput";
101
+ const agentResolved = resolveAgentMode(opts.agent);
102
+ if (agentResolved.error) {
103
+ program.error(agentResolved.error);
104
+ return;
105
+ }
106
+ opts.agent = agentResolved.value;
107
+ const agentEnabled = opts.agent === "stdout" || opts.agent === "local";
108
+ const agentLocal = opts.agent === "local";
109
+ if (agentEnabled) setLogLevel(LoggerLevel.error);
78
110
  const maxLevel = parseInt(opts.maxLevel ?? "9", 10);
79
111
  if (!Number.isInteger(maxLevel) || maxLevel < 1 || maxLevel > 9) program.error(`Invalid --max-level "${opts.maxLevel}", must be an integer in [1, 9]`);
80
- const format = opts.format ?? "yaml";
81
- if (![
82
- "yaml",
83
- "yaml-tree",
84
- "json",
85
- "tree",
86
- "text"
87
- ].includes(format)) program.error(`Invalid --format "${format}", must be "yaml" | "yaml-tree" | "json" | "tree" | "text"`);
88
112
  const appId = opts.appId;
89
113
  const appSecret = opts.appSecret;
90
114
  if (!appId || !appSecret) program.error("Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET");
@@ -92,34 +116,20 @@ program.command("get-titles").description("Print all headings (level 1~9) of a w
92
116
  appId,
93
117
  appSecret,
94
118
  url,
95
- agent: opts.agent === "local" ? "local" : opts.agent === true
119
+ agent: opts.agent
96
120
  });
97
- const filtered = result.titles.filter((t) => t.level <= maxLevel);
98
- if (format === "yaml") process.stdout.write(serializeYaml({
121
+ const tree = buildTitleTree(result.titles.filter((t) => t.level <= maxLevel));
122
+ const content = serializeYaml({
99
123
  url: result.url,
100
124
  docToken: result.docToken,
101
- titles: filtered
102
- }));
103
- else if (format === "yaml-tree") {
104
- const tree = buildTitleTree(filtered);
105
- process.stdout.write(serializeYaml({
106
- url: result.url,
107
- docToken: result.docToken,
108
- titles: tree
109
- }));
110
- } else if (format === "json") process.stdout.write(JSON.stringify({
111
- url: result.url,
112
- docToken: result.docToken,
113
- titles: filtered
114
- }, null, 2) + "\n");
115
- else if (format === "tree") {
116
- const tree = buildTitleTree(filtered);
117
- process.stdout.write(JSON.stringify({
118
- url: result.url,
119
- docToken: result.docToken,
120
- titles: tree
121
- }, null, 2) + "\n");
122
- } else process.stdout.write(formatTitlesAsText(filtered) + "\n");
125
+ titles: tree
126
+ });
127
+ if (agentLocal) {
128
+ fs.mkdirSync(opts.output, { recursive: true });
129
+ const filePath = path.resolve(opts.output, `${result.docToken}.titles.yaml`);
130
+ fs.writeFileSync(filePath, content);
131
+ process.stdout.write(`**The Feishu document titles have been downloaded to the following absolute path:**\n\n\`${filePath}\`\n\n**Read this file to access the full titles list.**\n`);
132
+ } else process.stdout.write(content);
123
133
  });
124
134
  program.parse();
125
135
  //#endregion
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { LoggerLevel } from '@larksuiteoapi/node-sdk';\nimport { buildTitleTree, convert, formatTitlesAsText, getTitles } from './converter.js';\nimport { setLogLevel } from './logger.js';\nimport { serializeYaml } from './whiteboard/yaml/serialize.js';\nimport type { SvgBackground, WbFormat, WbImageMode } from './types.js';\n\nconst program = new Command();\nprogram.name('larkDocx2md').description('Download Lark/Feishu documents to markdown');\n\nprogram\n .command('download')\n .alias('dl')\n .description('Download a wiki document to markdown')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('-o, --output <dir>', 'Output directory (or LARK_DOCX2MD_OUTPUT)')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, and AI-oriented stdout. Pass \"local\" to save markdown/images/whiteboards to disk and print a read-file prompt (or LARK_DOCX2MD_AGENT=true|local)')\n .option('--wb-format <format>', 'Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)')\n .option('--wb-bg <style>', 'Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)')\n .option('--wb-image-mode <mode>', 'Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)')\n .option('--image-mode <mode>', 'Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)')\n .option('--filter-title <title>', 'Only convert the section matching this heading title (single title, first match wins on duplicates)')\n .option('--filter-title-block-id <id>', 'Only convert the section whose heading block id matches (most precise; obtain from get-titles)')\n .argument('<url>', 'Feishu wiki document URL: https://*.feishu.cn/wiki/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; output?: string; agent?: boolean | string; imageMode?: string; wbImageMode?: string; wbBg?: SvgBackground; wbFormat?: string; filterTitle?: string; filterTitleBlockId?: string }) => {\n // ─── 环境变量默认值(直接指定 > 环境变量 > 内置默认值)────────────────\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? './larkDocx2mdOutput';\n // 解析 --agent:可能为 undefined | true | 'local' | 其他字符串\n if (opts.agent === undefined) {\n const envAgent = process.env.LARK_DOCX2MD_AGENT;\n if (envAgent === 'true') opts.agent = true;\n else if (envAgent === 'local') opts.agent = 'local';\n else opts.agent = false;\n } else if (typeof opts.agent === 'string' && opts.agent !== 'local') {\n program.error(`Invalid --agent value \"${opts.agent}\", only \"local\" is supported (or omit the value)`);\n }\n const agentEnabled = opts.agent === true || opts.agent === 'local';\n const agentLocal = opts.agent === 'local';\n\n opts.imageMode = opts.imageMode ?? process.env.LARK_DOCX2MD_IMAGE_MODE ?? 'local';\n opts.wbFormat = opts.wbFormat ?? process.env.LARK_DOCX2MD_WB_FORMAT;\n opts.wbBg = opts.wbBg ?? process.env.LARK_DOCX2MD_WB_BG ?? 'none';\n opts.wbImageMode = opts.wbImageMode ?? process.env.LARK_DOCX2MD_WB_IMAGE_MODE ?? 'local';\n\n // 设置 wb-format 默认值:--agent local 默认 inline-svg(兼容本地画板图片),--agent(在线)默认 yaml,其余 svg\n if (!opts.wbFormat) {\n opts.wbFormat = agentEnabled ? 'yaml' : 'svg';\n }\n\n if (agentEnabled) {\n setLogLevel(LoggerLevel.error);\n if (agentLocal) {\n // --agent local:图片/画板图片均落盘\n opts.imageMode = 'local';\n opts.wbImageMode = 'local';\n } else {\n // --agent(在线):一律在线,且画板仅支持内嵌形式\n opts.imageMode = 'online';\n opts.wbImageMode = 'online';\n }\n if (!['inline-svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Agent mode only supports \"inline-svg\" or \"yaml\" for --wb-format`);\n }\n } else {\n // yaml 格式图片仅支持 online\n if (opts.wbFormat === 'yaml') {\n opts.wbImageMode = 'online';\n }\n }\n\n if (opts.imageMode && !['local', 'online'].includes(opts.imageMode)) {\n program.error(`Invalid --image-mode \"${opts.imageMode}\", must be \"local\" or \"online\"`);\n }\n if (!['base64', 'inline-svg', 'svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Invalid --wb-format \"${opts.wbFormat}\", must be \"base64\", \"inline-svg\", \"svg\", or \"yaml\"`);\n }\n if (!['online', 'base64', 'local'].includes(opts.wbImageMode)) {\n program.error(`Invalid --wb-image-mode \"${opts.wbImageMode}\", must be \"online\", \"base64\", or \"local\"`);\n }\n if (opts.filterTitle && opts.filterTitleBlockId) {\n program.error('--filter-title and --filter-title-block-id are mutually exclusive; choose one');\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await convert({\n appId,\n appSecret,\n url,\n output: opts.output,\n imageMode: opts.imageMode as 'local' | 'online',\n wbImageMode: opts.wbImageMode as WbImageMode,\n wbBg: opts.wbBg,\n wbFormat: opts.wbFormat as WbFormat,\n agent: agentLocal ? 'local' : (opts.agent === true),\n filterTitle: opts.filterTitle?.trim(),\n filterTitleBlockId: opts.filterTitleBlockId?.trim(),\n });\n\n if (agentLocal) {\n // 本地模式:输出引导 AI 读取文件的提示词(绝对路径)\n process.stdout.write(\n `**The Feishu document has been downloaded to the following absolute path:**\\n\\n` +\n `\\`${result.filePath}\\`\\n\\n` +\n `**Read this file to access the full markdown content.**\\n`,\n );\n } else if (opts.agent === true) {\n process.stdout.write(result.markdown);\n }\n });\n\nprogram\n .command('get-titles')\n .description('Print all headings (level 1~9) of a wiki/docx document. Useful before --filter-title-block-id.')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('--max-level <n>', 'Only output headings whose level <= n (1~9)', '9')\n .option('--format <format>', 'Output format: \"yaml\" (flat, default) | \"yaml-tree\" (nested) | \"json\" (flat) | \"tree\" (json nested) | \"text\" (indented markdown headings)', 'yaml')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, AI-oriented stdout (or LARK_DOCX2MD_AGENT=true|local)')\n .argument('<url>', 'Feishu wiki/docx URL: https://*.feishu.cn/{wiki,docx,docs}/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; maxLevel?: string; format?: string; agent?: boolean | string }) => {\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n if (opts.agent === undefined) {\n const envAgent = process.env.LARK_DOCX2MD_AGENT;\n if (envAgent === 'true') opts.agent = true;\n else if (envAgent === 'local') opts.agent = 'local';\n else opts.agent = false;\n } else if (typeof opts.agent === 'string' && opts.agent !== 'local') {\n program.error(`Invalid --agent value \"${opts.agent}\", only \"local\" is supported (or omit the value)`);\n }\n const agentEnabled = opts.agent === true || opts.agent === 'local';\n if (agentEnabled) setLogLevel(LoggerLevel.error);\n\n const maxLevel = parseInt(opts.maxLevel ?? '9', 10);\n if (!Number.isInteger(maxLevel) || maxLevel < 1 || maxLevel > 9) {\n program.error(`Invalid --max-level \"${opts.maxLevel}\", must be an integer in [1, 9]`);\n }\n const format = opts.format ?? 'yaml';\n if (!['yaml', 'yaml-tree', 'json', 'tree', 'text'].includes(format)) {\n program.error(`Invalid --format \"${format}\", must be \"yaml\" | \"yaml-tree\" | \"json\" | \"tree\" | \"text\"`);\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await getTitles({\n appId,\n appSecret,\n url,\n agent: opts.agent === 'local' ? 'local' : (opts.agent === true),\n });\n const filtered = result.titles.filter(t => t.level <= maxLevel);\n\n if (format === 'yaml') {\n process.stdout.write(serializeYaml({ url: result.url, docToken: result.docToken, titles: filtered }));\n } else if (format === 'yaml-tree') {\n const tree = buildTitleTree(filtered);\n process.stdout.write(serializeYaml({ url: result.url, docToken: result.docToken, titles: tree }));\n } else if (format === 'json') {\n process.stdout.write(JSON.stringify({ url: result.url, docToken: result.docToken, titles: filtered }, null, 2) + '\\n');\n } else if (format === 'tree') {\n const tree = buildTitleTree(filtered);\n process.stdout.write(JSON.stringify({ url: result.url, docToken: result.docToken, titles: tree }, null, 2) + '\\n');\n } else {\n process.stdout.write(formatTitlesAsText(filtered) + '\\n');\n }\n });\n\nprogram.parse();\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { Command } from 'commander';\nimport { LoggerLevel } from '@larksuiteoapi/node-sdk';\nimport { convert } from './converter.js';\nimport { buildTitleTree, getTitles } from './get-titles.js';\nimport { setLogLevel } from './logger.js';\nimport { serializeYaml } from './whiteboard/yaml/serialize.js';\nimport type { SvgBackground, WbFormat, WbImageMode, AgentMode } from './types.js';\n\nconst program = new Command();\nprogram.name('larkDocx2md').description('Download Lark/Feishu documents to markdown');\n\n/**\n * 把 commander 解析出的 --agent 原值(undefined | true | string)与\n * LARK_DOCX2MD_AGENT 环境变量统一收敛为精确的 AgentMode | false。\n *\n * 优先级:显式 --agent > 环境变量 > 默认 false。\n * 非法取值返回错误信息字符串,由调用方决定如何上报。\n */\nfunction resolveAgentMode (raw: boolean | string | undefined): { value: AgentMode | false; error?: string } {\n if (raw === undefined) {\n const env = process.env.LARK_DOCX2MD_AGENT;\n if (env === 'stdout' || env === 'local') return { value: env };\n if (env !== undefined && env !== '') {\n return { value: false, error: `Invalid LARK_DOCX2MD_AGENT=\"${env}\", must be \"stdout\" or \"local\"` };\n }\n return { value: false };\n }\n // --agent 不带值:默认 stdout\n if (raw === true) return { value: 'stdout' };\n if (raw === 'stdout' || raw === 'local') return { value: raw };\n return { value: false, error: `Invalid --agent value \"${raw}\", must be \"stdout\" or \"local\"` };\n}\n\nprogram\n .command('download')\n .alias('dl')\n .description('Download a wiki document to markdown')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('-o, --output <dir>', 'Output directory (or LARK_DOCX2MD_OUTPUT)')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, and AI-oriented stdout. Modes: \"stdout\" (default, print markdown to stdout) or \"local\" (save markdown/images/whiteboards to disk and print a read-file prompt). Or LARK_DOCX2MD_AGENT=stdout|local')\n .option('--wb-format <format>', 'Whiteboard output format: \"base64\", \"inline-svg\", \"svg\", or \"yaml\" (or LARK_DOCX2MD_WB_FORMAT)')\n .option('--wb-bg <style>', 'Whiteboard SVG background: \"none\", \"dot\", or a color like \"#fff\" (or LARK_DOCX2MD_WB_BG)')\n .option('--wb-image-mode <mode>', 'Whiteboard image mode: \"online\", \"base64\", or \"local\" (or LARK_DOCX2MD_WB_IMAGE_MODE)')\n .option('--image-mode <mode>', 'Image handling mode: \"local\" or \"online\" (or LARK_DOCX2MD_IMAGE_MODE)')\n .option('--filter-title <title>', 'Only convert the section matching this heading title (single title, first match wins on duplicates)')\n .option('--filter-title-block-id <id>', 'Only convert the section whose heading block id matches (most precise; obtain from get-titles)')\n .argument('<url>', 'Feishu wiki document URL: https://*.feishu.cn/wiki/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; output?: string; agent?: boolean | string; imageMode?: string; wbImageMode?: string; wbBg?: SvgBackground; wbFormat?: string; filterTitle?: string; filterTitleBlockId?: string }) => {\n // ─── 环境变量默认值(直接指定 > 环境变量 > 内置默认值)────────────────\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? './larkDocx2mdOutput';\n // 解析 --agent:可能为 undefined | true | 'stdout' | 'local' | 其他字符串\n const agentResolved = resolveAgentMode(opts.agent);\n if (agentResolved.error) {\n program.error(agentResolved.error);\n return;\n }\n opts.agent = agentResolved.value;\n const agentEnabled = opts.agent === 'stdout' || opts.agent === 'local';\n const agentLocal = opts.agent === 'local';\n const agentStdout = opts.agent === 'stdout';\n\n opts.imageMode = opts.imageMode ?? process.env.LARK_DOCX2MD_IMAGE_MODE ?? 'local';\n opts.wbFormat = opts.wbFormat ?? process.env.LARK_DOCX2MD_WB_FORMAT;\n opts.wbBg = opts.wbBg ?? process.env.LARK_DOCX2MD_WB_BG ?? 'none';\n opts.wbImageMode = opts.wbImageMode ?? process.env.LARK_DOCX2MD_WB_IMAGE_MODE ?? 'local';\n\n // 设置 wb-format 默认值:--agent local 默认 inline-svg(兼容本地画板图片),--agent stdout 默认 yaml,其余 svg\n if (!opts.wbFormat) {\n if (agentLocal) opts.wbFormat = 'inline-svg';\n else if (agentStdout) opts.wbFormat = 'yaml';\n else opts.wbFormat = 'svg';\n }\n\n if (agentEnabled) {\n setLogLevel(LoggerLevel.error);\n if (agentLocal) {\n // --agent local:图片/画板图片均落盘\n opts.imageMode = 'local';\n opts.wbImageMode = 'local';\n } else {\n // --agent stdout:一律在线,且画板仅支持内嵌形式\n opts.imageMode = 'online';\n opts.wbImageMode = 'online';\n }\n if (!['inline-svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Agent mode only supports \"inline-svg\" or \"yaml\" for --wb-format`);\n }\n } else {\n // yaml 格式图片仅支持 online\n if (opts.wbFormat === 'yaml') {\n opts.wbImageMode = 'online';\n }\n }\n\n if (opts.imageMode && !['local', 'online'].includes(opts.imageMode)) {\n program.error(`Invalid --image-mode \"${opts.imageMode}\", must be \"local\" or \"online\"`);\n }\n if (!['base64', 'inline-svg', 'svg', 'yaml'].includes(opts.wbFormat)) {\n program.error(`Invalid --wb-format \"${opts.wbFormat}\", must be \"base64\", \"inline-svg\", \"svg\", or \"yaml\"`);\n }\n if (!['online', 'base64', 'local'].includes(opts.wbImageMode)) {\n program.error(`Invalid --wb-image-mode \"${opts.wbImageMode}\", must be \"online\", \"base64\", or \"local\"`);\n }\n if (opts.filterTitle && opts.filterTitleBlockId) {\n program.error('--filter-title and --filter-title-block-id are mutually exclusive; choose one');\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await convert({\n appId,\n appSecret,\n url,\n output: opts.output,\n imageMode: opts.imageMode as 'local' | 'online',\n wbImageMode: opts.wbImageMode as WbImageMode,\n wbBg: opts.wbBg,\n wbFormat: opts.wbFormat as WbFormat,\n agent: opts.agent as AgentMode | false,\n filterTitle: opts.filterTitle?.trim(),\n filterTitleBlockId: opts.filterTitleBlockId?.trim(),\n });\n\n if (agentLocal) {\n // 本地模式:输出引导 AI 读取文件的提示词(绝对路径)\n process.stdout.write(\n `**The Feishu document has been downloaded to the following absolute path:**\\n\\n` +\n `\\`${result.filePath}\\`\\n\\n` +\n `**Read this file to access the full markdown content.**\\n`,\n );\n } else if (agentStdout) {\n process.stdout.write(result.markdown);\n }\n });\n\nprogram\n .command('get-titles')\n .description('Print all headings (level 1~9) of a wiki/docx document as a nested yaml tree. Useful before --filter-title-block-id.')\n .option('--app-id <id>', 'Feishu app ID (or read from LARK_DOCX2MD_APP_ID)')\n .option('--app-secret <secret>', 'Feishu app secret (or read from LARK_DOCX2MD_APP_SECRET)')\n .option('-o, --output <dir>', 'Output directory used by --agent local (or LARK_DOCX2MD_OUTPUT)')\n .option('--max-level <n>', 'Only output headings whose level <= n (1~9)', '9')\n .option('--agent [mode]', 'Enable agent mode: ERROR log level, AI-oriented stdout. Modes: \"stdout\" (default, print titles to stdout) or \"local\" (save titles to disk and print a read-file prompt). Or LARK_DOCX2MD_AGENT=stdout|local')\n .argument('<url>', 'Feishu wiki/docx URL: https://*.feishu.cn/{wiki,docx,docs}/*')\n .action(async (url: string, opts: { appId?: string; appSecret?: string; output?: string; maxLevel?: string; agent?: boolean | string }) => {\n opts.appId = opts.appId ?? process.env.LARK_DOCX2MD_APP_ID;\n opts.appSecret = opts.appSecret ?? process.env.LARK_DOCX2MD_APP_SECRET;\n opts.output = opts.output ?? process.env.LARK_DOCX2MD_OUTPUT ?? './larkDocx2mdOutput';\n const agentResolved = resolveAgentMode(opts.agent);\n if (agentResolved.error) {\n program.error(agentResolved.error);\n return;\n }\n opts.agent = agentResolved.value;\n const agentEnabled = opts.agent === 'stdout' || opts.agent === 'local';\n const agentLocal = opts.agent === 'local';\n if (agentEnabled) setLogLevel(LoggerLevel.error);\n\n const maxLevel = parseInt(opts.maxLevel ?? '9', 10);\n if (!Number.isInteger(maxLevel) || maxLevel < 1 || maxLevel > 9) {\n program.error(`Invalid --max-level \"${opts.maxLevel}\", must be an integer in [1, 9]`);\n }\n\n const appId = opts.appId!;\n const appSecret = opts.appSecret!;\n if (!appId || !appSecret) {\n program.error('Missing credentials: pass --app-id/--app-secret or set LARK_DOCX2MD_APP_ID/LARK_DOCX2MD_APP_SECRET');\n }\n\n const result = await getTitles({\n appId,\n appSecret,\n url,\n agent: opts.agent as AgentMode | false,\n });\n const filtered = result.titles.filter(t => t.level <= maxLevel);\n const tree = buildTitleTree(filtered);\n const content = serializeYaml({ url: result.url, docToken: result.docToken, titles: tree });\n\n if (agentLocal) {\n // 本地模式:落盘 + 输出引导 AI 读取文件的提示词(绝对路径)\n fs.mkdirSync(opts.output, { recursive: true });\n const filePath = path.resolve(opts.output, `${result.docToken}.titles.yaml`);\n fs.writeFileSync(filePath, content);\n process.stdout.write(\n `**The Feishu document titles have been downloaded to the following absolute path:**\\n\\n` +\n `\\`${filePath}\\`\\n\\n` +\n `**Read this file to access the full titles list.**\\n`,\n );\n } else {\n process.stdout.write(content);\n }\n });\n\nprogram.parse();\n"],"mappings":"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"}