listpage_cli 0.0.303 → 0.0.305

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.
@@ -174,6 +174,12 @@ function printHelp() {
174
174
  " 说明: 使用 docker.remote + docker.container 执行部署,支持 ports[] 与 envFile/env 合并",
175
175
  ` 备注: ${helpColor("默认会清理并拉取镜像;传入 --skip-image 时只执行容器相关步骤(假定镜像已是最新且已存在)", "yellow")}`,
176
176
  ` ${helpColor("参数优先级为 CLI > profile > base", "yellow")}`,
177
+ "",
178
+ ` ${helpColor("lark", "green")}`,
179
+ ` 用法: ${helpColor("listpage_cli lark read <doc_token>", "dim")}`,
180
+ ` ${helpColor("listpage_cli lark check-todo <doc_token> <todo_index>", "dim")}`,
181
+ ` ${helpColor("listpage_cli lark update-block <doc_token> <emoji_id> <markdown_content_path>", "dim")}`,
182
+ " 说明: 飞书文档相关操作(读取文档、勾选TODO、更新高亮块)",
177
183
  ].join("\n");
178
184
  console.log(h);
179
185
  }
@@ -9,6 +9,7 @@ const KNOWN_COMMANDS = new Set([
9
9
  "build-project",
10
10
  "release-project",
11
11
  "deploy-project",
12
+ "lark",
12
13
  ]);
13
14
  function parseArgs(argv) {
14
15
  const rawArgs = [...argv];
package/bin/cli.js CHANGED
@@ -9,6 +9,7 @@ const install_skill_command_1 = require("./commands/install-skill-command");
9
9
  const build_project_command_1 = require("./commands/build-project-command");
10
10
  const release_project_command_1 = require("./commands/release-project-command");
11
11
  const deploy_project_command_1 = require("./commands/deploy-project-command");
12
+ const lark_command_1 = require("./commands/lark-command");
12
13
  const node_fs_adapter_1 = require("./adapters/node-fs-adapter");
13
14
  const filesystem_capability_service_1 = require("./services/filesystem-capability-service");
14
15
  const fsAdapter = (0, node_fs_adapter_1.createNodeFsAdapter)();
@@ -41,6 +42,9 @@ const releaseProjectCommandHandler = (0, release_project_command_1.createRelease
41
42
  const deployProjectCommandHandler = (0, deploy_project_command_1.createDeployProjectCommandHandler)({
42
43
  fs: fsAdapter,
43
44
  });
45
+ const larkCommandHandler = (0, lark_command_1.createLarkCommandHandler)({
46
+ fs: fsAdapter,
47
+ });
44
48
  async function main() {
45
49
  const result = await (0, execute_1.executeCommand)(process.argv.slice(2), {
46
50
  printHelp: cli_interaction_1.printHelp,
@@ -51,6 +55,7 @@ async function main() {
51
55
  "build-project": buildProjectCommandHandler,
52
56
  "release-project": releaseProjectCommandHandler,
53
57
  "deploy-project": deployProjectCommandHandler,
58
+ lark: larkCommandHandler,
54
59
  },
55
60
  });
56
61
  applyCommandResult(result);
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleCheckTodoCommand = handleCheckTodoCommand;
4
+ const command_result_1 = require("../../domain/command-result");
5
+ async function handleCheckTodoCommand(input, client, fs) {
6
+ const docToken = input.positionals[1];
7
+ const todoIndex = input.positionals[2];
8
+ if (!docToken || !todoIndex) {
9
+ return (0, command_result_1.commandError)("错误: 参数缺失。用法: listpage_cli lark check-todo <doc_token> <todo_index>", "missing_args", 1);
10
+ }
11
+ const index = parseInt(todoIndex, 10);
12
+ if (isNaN(index) || index < 1) {
13
+ return (0, command_result_1.commandError)("错误: todo_index 必须为大于 0 的整数", "invalid_index", 1);
14
+ }
15
+ try {
16
+ // 1. 获取所有 block,寻找 emoji_id 为 "rocket" 的高亮块
17
+ // (参考用户需求,check_todo 默认在 rocket 块下操作,或者后续可扩展为参数)
18
+ const targetEmojiId = "rocket";
19
+ const blocksRes = await client.docx.documentBlock.list({
20
+ path: { document_id: docToken },
21
+ });
22
+ if (blocksRes.code !== 0 || !blocksRes.data?.items) {
23
+ return (0, command_result_1.commandError)(`获取文档 blocks 失败: ${blocksRes.msg}`, "get_blocks_failed", 1);
24
+ }
25
+ let targetBlockId;
26
+ for (const block of blocksRes.data.items) {
27
+ // block_type 14 是 Callout (高亮块)
28
+ if (block.block_type === 19 &&
29
+ block.callout?.emoji_id === targetEmojiId) {
30
+ targetBlockId = block.block_id;
31
+ break;
32
+ }
33
+ }
34
+ if (!targetBlockId) {
35
+ return (0, command_result_1.commandError)(`未在文档中找到 emoji_id 为 "${targetEmojiId}" 的高亮块`, "block_not_found", 1);
36
+ }
37
+ // 2. 获取该高亮块下的子节点 (Todo List)
38
+ const childrenRes = await client.docx.documentBlockChildren.get({
39
+ path: {
40
+ document_id: docToken,
41
+ block_id: targetBlockId,
42
+ },
43
+ });
44
+ if (childrenRes.code !== 0 || !childrenRes.data?.items) {
45
+ return (0, command_result_1.commandError)(`获取高亮块子节点失败: ${childrenRes.msg}`, "get_children_failed", 1);
46
+ }
47
+ const todoItems = childrenRes.data.items;
48
+ // index 从 1 开始,所以需要 -1
49
+ const todoBlock = todoItems[index - 1];
50
+ if (!todoBlock) {
51
+ return (0, command_result_1.commandError)(`未找到第 ${index} 个待办事项 (总数: ${todoItems.length})`, "todo_not_found", 1);
52
+ }
53
+ // 检查是否为 Todo Block (block_type 11 是 Todo)
54
+ if (todoBlock.block_type !== 11) {
55
+ // 如果不是 TODO 类型,可能是文本或其他,视情况处理
56
+ // 这里简单判断,如果不是 TODO 块,可能 index 指向了非 TODO 元素
57
+ console.warn(`警告: 第 ${index} 个子节点类型为 ${todoBlock.block_type},可能不是待办事项。尝试继续操作...`);
58
+ }
59
+ // 3. 检查是否已完成
60
+ if (todoBlock.todo?.style?.done === true) {
61
+ console.log(`待办事项 (ID: ${todoBlock.block_id}) 已经是完成状态。`);
62
+ return (0, command_result_1.commandOk)();
63
+ }
64
+ // 4. 更新 Todo 状态
65
+ const todoElements = todoBlock.todo?.elements;
66
+ const firstTextRun = todoElements?.find((e) => e.text_run)?.text_run;
67
+ const todoContent = firstTextRun?.content || "";
68
+ console.log(`正在勾选待办事项: "${todoContent}" (ID: ${todoBlock.block_id})`);
69
+ const updateRes = await client.docx.documentBlock.patch({
70
+ path: {
71
+ document_id: docToken,
72
+ block_id: todoBlock.block_id,
73
+ },
74
+ params: {
75
+ document_revision_id: -1,
76
+ },
77
+ data: {
78
+ update_text: {
79
+ style: {
80
+ done: true,
81
+ },
82
+ fields: [2],
83
+ elements: [
84
+ {
85
+ text_run: {
86
+ content: todoContent,
87
+ },
88
+ },
89
+ ],
90
+ },
91
+ },
92
+ });
93
+ if (updateRes.code !== 0) {
94
+ return (0, command_result_1.commandError)(`更新待办事项失败: ${updateRes.msg}`, "update_todo_failed", 1);
95
+ }
96
+ console.log("飞书文档 TODO 勾选成功!");
97
+ return (0, command_result_1.commandOk)();
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ return (0, command_result_1.commandError)(`Check Todo 执行异常: ${message}`, "check_todo_exception", 1);
102
+ }
103
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readLarkConfig = readLarkConfig;
4
+ const command_result_1 = require("../../domain/command-result");
5
+ const json_with_comments_1 = require("../../shared/json-with-comments");
6
+ function readLarkConfig(fs) {
7
+ const cwd = fs.cwd();
8
+ const configPath = fs.resolve(cwd, "listpage.config.json");
9
+ if (!fs.exists(configPath)) {
10
+ return (0, command_result_1.commandError)("错误: 当前目录下未找到 listpage.config.json。请确保在项目根目录下执行该命令。", "config_not_found", 1);
11
+ }
12
+ try {
13
+ const configContent = fs.readText(configPath);
14
+ const config = (0, json_with_comments_1.parseJsonWithComments)(configContent);
15
+ const appId = config.lark?.APP_ID;
16
+ const appSecret = config.lark?.APP_SECRET;
17
+ if (!appId || !appSecret) {
18
+ return (0, command_result_1.commandError)("错误: listpage.config.json 中缺失 lark.APP_ID 或 lark.APP_SECRET 配置。", "missing_lark_config", 1);
19
+ }
20
+ return { appId, appSecret };
21
+ }
22
+ catch (error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ return (0, command_result_1.commandError)(`错误: 解析 listpage.config.json 失败: ${message}`, "config_parse_error", 1);
25
+ }
26
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleReadCommand = handleReadCommand;
4
+ const command_result_1 = require("../../domain/command-result");
5
+ async function handleReadCommand(input, client, fs) {
6
+ const docToken = input.positionals[1];
7
+ if (!docToken) {
8
+ return (0, command_result_1.commandError)("错误: 请提供飞书文档的 doc_token。用法: listpage_cli lark read <doc_token>", "missing_doc_token", 1);
9
+ }
10
+ console.log(`正在读取飞书文档内容,doc_token: ${docToken}`);
11
+ const response = await client.docx.document.rawContent({
12
+ path: {
13
+ document_id: docToken,
14
+ },
15
+ params: {
16
+ lang: 0,
17
+ },
18
+ });
19
+ if (response.code !== 0) {
20
+ return (0, command_result_1.commandError)(`读取飞书文档失败,错误码: ${response.code}, 错误信息: ${response.msg}`, "read_doc_failed", 1);
21
+ }
22
+ const docContent = response.data?.content || "";
23
+ const outputPath = fs.resolve(fs.cwd(), `.listpage/lark/${docToken}.md`);
24
+ fs.writeText(outputPath, docContent);
25
+ console.log(`飞书文档读取成功!内容已保存至: ${outputPath}`);
26
+ return (0, command_result_1.commandOk)();
27
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleUpdateBlockCommand = handleUpdateBlockCommand;
4
+ const command_result_1 = require("../../domain/command-result");
5
+ async function handleUpdateBlockCommand(input, client, fs) {
6
+ const docToken = input.positionals[1];
7
+ const emojiId = input.positionals[2];
8
+ const markdownContentPath = input.positionals[3];
9
+ if (!docToken || !emojiId || !markdownContentPath) {
10
+ return (0, command_result_1.commandError)("错误: 参数缺失。用法: listpage_cli lark update-block <doc_token> <emoji_id> <markdown_content_path>", "missing_args", 1);
11
+ }
12
+ console.log(`正在更新高亮块文本,doc_token: ${docToken}, emojiId: ${emojiId}, path: ${markdownContentPath}`);
13
+ try {
14
+ // 1. 读取本地 Markdown 文件
15
+ const absolutePath = fs.resolve(fs.cwd(), markdownContentPath);
16
+ if (!fs.exists(absolutePath)) {
17
+ return (0, command_result_1.commandError)(`错误: 找不到文件 ${absolutePath}`, "file_not_found", 1);
18
+ }
19
+ const markdownContent = fs.readText(absolutePath);
20
+ // 2. 获取文档的所有 Block,寻找匹配 emojiId 的高亮块
21
+ const blocksRes = await client.docx.documentBlock.list({
22
+ path: { document_id: docToken },
23
+ params: {
24
+ page_size: 500,
25
+ document_revision_id: -1,
26
+ },
27
+ });
28
+ if (blocksRes.code !== 0 || !blocksRes.data?.items) {
29
+ return (0, command_result_1.commandError)(`获取文档 blocks 失败: ${blocksRes.msg}`, "get_blocks_failed", 1);
30
+ }
31
+ // 假设高亮块是一个 callout (高亮块),并且其 emoji_id 匹配用户输入
32
+ // 你需要根据实际的飞书 Block 结构调整寻找逻辑
33
+ const blocks = blocksRes.data.items || [];
34
+ const targetBlock = blocks.find((b) => b.block_type === 19 && b.callout?.emoji_id === emojiId);
35
+ if (!targetBlock?.block_id) {
36
+ return (0, command_result_1.commandError)(`未在文档中找到 emoji_id 为 ${emojiId} 的高亮块`, "block_not_found", 1);
37
+ }
38
+ // 3. 获取目标块的子节点数量,以便进行批量删除
39
+ const childrenCounts = targetBlock.children?.length || 0;
40
+ // 4. 清空原有内容
41
+ if (childrenCounts > 1) {
42
+ console.log(`清空高亮块中原有的 ${childrenCounts} 个子节点...`);
43
+ await client.docx.documentBlockChildren.batchDelete({
44
+ params: {
45
+ document_revision_id: -1,
46
+ },
47
+ data: {
48
+ start_index: 1,
49
+ end_index: childrenCounts,
50
+ },
51
+ path: {
52
+ document_id: docToken,
53
+ block_id: targetBlock.block_id,
54
+ },
55
+ });
56
+ }
57
+ // 5. 将 Markdown 内容转换为 Blocks
58
+ const convertRes = await client.docx.document.convert({
59
+ data: {
60
+ content: markdownContent,
61
+ content_type: "markdown",
62
+ },
63
+ });
64
+ if (convertRes.code !== 0) {
65
+ return (0, command_result_1.commandError)(`转换 Markdown 失败: ${convertRes.msg}`, "convert_failed", 1);
66
+ }
67
+ const newBlocks = convertRes.data?.blocks || [];
68
+ // 6. 添加新内容
69
+ if (newBlocks.length > 0) {
70
+ console.log("插入新的内容到高亮块...");
71
+ await client.docx.documentBlockChildren.create({
72
+ path: {
73
+ document_id: docToken,
74
+ block_id: targetBlock.block_id,
75
+ },
76
+ data: {
77
+ children: newBlocks,
78
+ index: -1,
79
+ },
80
+ });
81
+ }
82
+ console.log("飞书文档高亮块更新成功!");
83
+ return (0, command_result_1.commandOk)();
84
+ }
85
+ catch (error) {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ return (0, command_result_1.commandError)(`更新高亮块时发生异常: ${message}`, "update_block_exception", 1);
88
+ }
89
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLarkCommandHandler = createLarkCommandHandler;
4
+ const command_result_1 = require("../domain/command-result");
5
+ const node_sdk_1 = require("@larksuiteoapi/node-sdk");
6
+ const lark_config_1 = require("./lark/lark-config");
7
+ const read_command_1 = require("./lark/read-command");
8
+ const check_todo_command_1 = require("./lark/check-todo-command");
9
+ const update_block_command_1 = require("./lark/update-block-command");
10
+ function createLarkCommandHandler(deps) {
11
+ return async function larkCommand(input) {
12
+ try {
13
+ // 尝试读取 lark 配置
14
+ const configResult = (0, lark_config_1.readLarkConfig)(deps.fs);
15
+ if ("ok" in configResult) {
16
+ // 如果返回的是 CommandResult,说明读取失败,直接返回错误
17
+ return configResult;
18
+ }
19
+ const { appId, appSecret } = configResult;
20
+ const client = new node_sdk_1.Client({
21
+ appId,
22
+ appSecret,
23
+ disableTokenCache: false,
24
+ });
25
+ // 解析 lark 后面的参数
26
+ const subCommand = input.positionals[0];
27
+ switch (subCommand) {
28
+ case "read":
29
+ return await (0, read_command_1.handleReadCommand)(input, client, deps.fs);
30
+ case "check-todo":
31
+ return await (0, check_todo_command_1.handleCheckTodoCommand)(input, client, deps.fs);
32
+ case "update-block":
33
+ return await (0, update_block_command_1.handleUpdateBlockCommand)(input, client, deps.fs);
34
+ default:
35
+ return (0, command_result_1.commandError)("错误: 未知的子命令。目前仅支持: read, check-todo, update-block", "invalid_subcommand", 1);
36
+ }
37
+ }
38
+ catch (error) {
39
+ const message = error instanceof Error ? error.message : String(error);
40
+ return (0, command_result_1.commandError)(`Lark 命令执行失败: ${message}`, "lark_command_failed", 1);
41
+ }
42
+ };
43
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createReadFeishuCommandHandler = createReadFeishuCommandHandler;
4
+ const command_result_1 = require("../domain/command-result");
5
+ function createReadFeishuCommandHandler(deps) {
6
+ return async function readFeishuCommand(input) {
7
+ try {
8
+ // 提取命令行参数,例如:listpage_cli read-feishu <docUrl>
9
+ const docUrl = input.positionals[0];
10
+ if (!docUrl) {
11
+ return (0, command_result_1.commandError)("错误: 请提供飞书文档 URL 或标识符", "invalid_argument", 1);
12
+ }
13
+ console.log(`正在读取飞书文档: ${docUrl}`);
14
+ // TODO: 在这里实现具体的读取飞书文档内容的功能
15
+ // const docContent = await fetchFeishuDoc(docUrl);
16
+ // TODO: 在这里实现具体的写入本地文件的功能
17
+ // await deps.fs.writeFile("feishu-doc.md", docContent);
18
+ console.log("飞书文档读取成功!");
19
+ return (0, command_result_1.commandOk)();
20
+ }
21
+ catch (error) {
22
+ const message = error instanceof Error ? error.message : String(error);
23
+ return (0, command_result_1.commandError)(`读取飞书文档失败: ${message}`, "read_feishu_failed", 1);
24
+ }
25
+ };
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "listpage_cli",
3
- "version": "0.0.303",
3
+ "version": "0.0.305",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "listpage_cli": "bin/cli.js"
@@ -26,6 +26,7 @@
26
26
  "dependencies": {
27
27
  "@types/dockerode": "^4.0.1",
28
28
  "dockerode": "^4.0.9",
29
- "enquirer": "^2.4.1"
29
+ "enquirer": "^2.4.1",
30
+ "@larksuiteoapi/node-sdk": "~1.59.0"
30
31
  }
31
32
  }
@@ -25,7 +25,7 @@
25
25
  "class-transformer": "^0.5.1",
26
26
  "class-validator": "~0.14.2",
27
27
  "rxjs": "^7.8.1",
28
- "listpage-next-nest": "~0.0.303"
28
+ "listpage-next-nest": "~0.0.305"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@nestjs/schematics": "^11.0.0",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "react": "^19.2.0",
14
14
  "react-dom": "^19.2.0",
15
- "listpage-next": "~0.0.303",
15
+ "listpage-next": "~0.0.305",
16
16
  "react-router-dom": ">=6.0.0",
17
17
  "@ant-design/v5-patch-for-react-19": "~1.0.3",
18
18
  "ahooks": "^3.9.5",
@@ -23,7 +23,7 @@
23
23
  "styled-components": "^6.1.19",
24
24
  "mobx": "~6.15.0",
25
25
  "@ant-design/icons": "~6.0.2",
26
- "listpage-components": "~0.0.303",
26
+ "listpage-components": "~0.0.305",
27
27
  "lucide-react": "~0.575.0"
28
28
  "mobx-react-lite": "~4.1.1"
29
29
  },
@@ -65,7 +65,11 @@ export interface ClientOptions {
65
65
  port?: number;
66
66
  publicPath?: string;
67
67
  };
68
- onError?: (code: number, message: string) => void;
68
+ onError?: (
69
+ code: number,
70
+ message: string,
71
+ options?: { quiet?: boolean }
72
+ ) => void;
69
73
  }
70
74
  ```
71
75
 
@@ -87,6 +91,7 @@ export interface RequestOptions {
87
91
  key?: string;
88
92
  time?: number; // 缓存时间(ms)
89
93
  };
94
+ quiet?: boolean; // 为 true 时表示本次请求静默错误,不在 onError 中弹通用提示
90
95
  }
91
96
  ```
92
97