openyida 2026.7.26-beta.3 → 2026.7.27-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -414,6 +414,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
414
414
  | `openyida data <action> <resource> [args]` | Unified data management (form/process/task/subform) |
415
415
  | `openyida task-center <type> [options]` | Global task center (todo/processed/cc etc.) |
416
416
  | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, and domain settings |
417
+ | `openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]` | Fetch Markdown content from a DingTalk document |
418
+ | `openyida read-dingtalk-tingji <taskUuid> [--json]` | Fetch DingTalk Tingji details by task UUID |
417
419
  | `openyida get-permission <appType> <formUuid>` | Query form permission config |
418
420
  | `openyida save-permission <appType> <formUuid> ...` | Save form permission config |
419
421
  | `openyida corp-manager <search-user\|list\|add\|remove\|address-book> ...` | Manage platform admins and address book permissions |
package/bin/yida.js CHANGED
@@ -869,6 +869,18 @@ async function main() {
869
869
  break;
870
870
  }
871
871
 
872
+ case 'read-dingtalk-doc': {
873
+ const { run } = require('../lib/document/document-markdown');
874
+ await run(args);
875
+ break;
876
+ }
877
+
878
+ case 'read-dingtalk-tingji': {
879
+ const { run } = require('../lib/document/tingji');
880
+ await run(args);
881
+ break;
882
+ }
883
+
872
884
  case 'doctor': {
873
885
  const { run } = require('../lib/core/doctor');
874
886
  await run(args);
@@ -402,9 +402,17 @@ const COMMAND_SIDE_EFFECTS = new Map([
402
402
  'integration.list',
403
403
  'list-forms',
404
404
  'process.preview',
405
+ 'read-dingtalk-tingji',
405
406
  'verify-short-url',
406
407
  ], sideEffect('remote_read')),
407
408
 
409
+ ['read-dingtalk-doc', sideEffect('mixed', {
410
+ mutates_yida: false,
411
+ mutates_local: true,
412
+ read_actions: ['<docUrl>', '<docUrl> --json'],
413
+ mutating_actions: ['<docUrl> --output <file>', '<docUrl> -o <file>'],
414
+ })],
415
+
408
416
  ['asset', sideEffect('mixed', {
409
417
  mutates_yida: false,
410
418
  mutates_local: true,
@@ -620,11 +628,24 @@ const COMMAND_PERMISSIONS = new Map([
620
628
  'integration.list',
621
629
  'list-forms',
622
630
  'process.preview',
631
+ 'read-dingtalk-tingji',
623
632
  'verify-short-url',
624
633
  ], permission('allow', 'read', {
625
634
  reason: 'Read-only, diagnostic, validation, or manifest discovery command.',
626
635
  })),
627
636
 
637
+ ['read-dingtalk-doc', actionDependentPermission({
638
+ preauthorized_actions: [
639
+ '<docUrl> --output <file>',
640
+ '<docUrl> -o <file>',
641
+ ],
642
+ preauthorized_patterns: [{
643
+ type: 'argv_contains_any',
644
+ values: ['http://', 'https://'],
645
+ description: 'A valid document URL is present; optional output writes are non-destructive local operations.',
646
+ }],
647
+ })],
648
+
628
649
  ...permissionEntries([
629
650
  'eval',
630
651
  ], actionDependentPermission({
@@ -1038,6 +1059,12 @@ const COMMAND_GROUPS = [
1038
1059
  command('basic-info', ['basic-info'], 'basic-info <overview|commodity|grant|capacity|quota|abs-path|dataflow|i18n|domain>', 'help.cmd_basic_info', {
1039
1060
  output: 'json',
1040
1061
  }),
1062
+ command('read-dingtalk-doc', ['read-dingtalk-doc'], 'read-dingtalk-doc <docUrl> [--output <file>] [--json]', 'help.cmd_read_dingtalk_doc', {
1063
+ output: 'text|json',
1064
+ }),
1065
+ command('read-dingtalk-tingji', ['read-dingtalk-tingji'], 'read-dingtalk-tingji <taskUuid> [--json]', 'help.cmd_read_dingtalk_tingji', {
1066
+ output: 'json',
1067
+ }),
1041
1068
  command('get-permission', ['get-permission'], 'get-permission <appType> <formUuid>', 'help.cmd_get_permission'),
1042
1069
  command('save-permission', ['save-permission'], 'save-permission <appType> <formUuid> ...', 'help.cmd_save_permission'),
1043
1070
  command('corp-manager', ['corp-manager'], 'corp-manager <search-user|list|add|remove|address-book> ...', 'help.cmd_corp_manager', { output: 'json' }),
@@ -47,6 +47,8 @@ module.exports = {
47
47
  cmd_data: 'Unified data management (form/process/task/subform)',
48
48
  cmd_task_center: 'Global task center (todo/processed/cc etc.)',
49
49
  cmd_basic_info: 'Query organization basic info, capacity, quotas, and domain settings',
50
+ cmd_read_dingtalk_doc: 'Fetch Markdown content from a DingTalk document',
51
+ cmd_read_dingtalk_tingji: 'Fetch DingTalk Tingji details by task UUID',
50
52
  cmd_get_permission: 'Query form permission config',
51
53
  cmd_save_permission: 'Save form permission config',
52
54
  cmd_corp_manager: 'Manage platform admins and address book permissions',
@@ -47,6 +47,8 @@ module.exports = {
47
47
  cmd_data: '统一数据管理(表单/流程/任务/子表单)',
48
48
  cmd_task_center: '全局任务中心(待办/已处理/抄送等)',
49
49
  cmd_basic_info: '查询组织基本信息、容量、额度和域名设置',
50
+ cmd_read_dingtalk_doc: '获取钉钉文档的 Markdown 内容',
51
+ cmd_read_dingtalk_tingji: '按任务 UUID 获取钉钉听记详情',
50
52
  cmd_get_permission: '查询表单权限配置',
51
53
  cmd_save_permission: '保存表单权限配置',
52
54
  cmd_corp_manager: '管理平台管理员与通讯录权限',
package/lib/core/utils.js CHANGED
@@ -916,6 +916,18 @@ async function httpGet(baseUrl, requestPath, queryParams, cookiesOrOptions, mayb
916
916
  });
917
917
  return;
918
918
  }
919
+ if (optionsOverride.responseType === 'text') {
920
+ if (Number(res.statusCode) < 200 || Number(res.statusCode) >= 300) {
921
+ resolve({
922
+ success: false,
923
+ errorMsg: `HTTP ${res.statusCode}`,
924
+ __httpStatus: res.statusCode,
925
+ });
926
+ return;
927
+ }
928
+ resolve(data);
929
+ return;
930
+ }
919
931
  try {
920
932
  const parsed = JSON.parse(data);
921
933
  if (isLoginExpired(parsed)) {
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { createAuthRef, createYidaClient } = require('../core/yida-client');
6
+ const { throwUsage } = require('../core/command-errors');
7
+
8
+ const API_PATH = '/query/document/markdown.json';
9
+
10
+ function parseArgs(args) {
11
+ const parsed = { docUrl: '', output: '', json: false, help: false };
12
+ for (let index = 0; index < args.length; index++) {
13
+ const arg = args[index];
14
+ if (arg === '--help' || arg === '-h') {
15
+ parsed.help = true;
16
+ } else if (arg === '--json') {
17
+ parsed.json = true;
18
+ } else if ((arg === '--output' || arg === '-o') && args[index + 1]) {
19
+ parsed.output = args[++index];
20
+ } else if (!arg.startsWith('--') && !parsed.docUrl) {
21
+ parsed.docUrl = arg;
22
+ } else {
23
+ throwUsage('Usage: openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]');
24
+ }
25
+ }
26
+ return parsed;
27
+ }
28
+
29
+ function validateDocUrl(docUrl) {
30
+ if (!docUrl) {
31
+ throwUsage('Usage: openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]');
32
+ }
33
+ let parsed;
34
+ try {
35
+ parsed = new URL(docUrl);
36
+ } catch {
37
+ throw new Error('docUrl must be a valid HTTP(S) URL');
38
+ }
39
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
40
+ throw new Error('docUrl must be a valid HTTP(S) URL');
41
+ }
42
+ return parsed.toString();
43
+ }
44
+
45
+ function unwrapMarkdownResponse(response) {
46
+ if (typeof response !== 'string') {
47
+ const detail = response && (response.errorMsg || response.message);
48
+ throw new Error(detail || 'Failed to fetch document Markdown');
49
+ }
50
+
51
+ const trimmed = response.trim();
52
+ if (!trimmed.startsWith('{')) {
53
+ return response;
54
+ }
55
+
56
+ let parsed;
57
+ try {
58
+ parsed = JSON.parse(trimmed);
59
+ } catch {
60
+ return response;
61
+ }
62
+
63
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
64
+ return response;
65
+ }
66
+ if (parsed.success === false) {
67
+ throw new Error(parsed.errorMsg || parsed.message || 'Failed to fetch document Markdown');
68
+ }
69
+ if (typeof parsed.content === 'string') {
70
+ return parsed.content;
71
+ }
72
+ return response;
73
+ }
74
+
75
+ async function fetchDocumentMarkdown(docUrl, options = {}) {
76
+ const authRef = options.authRef || createAuthRef();
77
+ const client = options.client || createYidaClient({ authRef });
78
+ const response = await client.get(API_PATH, { docUrl: validateDocUrl(docUrl) }, {
79
+ responseType: 'text',
80
+ timeout: options.timeout || 300000,
81
+ });
82
+ return unwrapMarkdownResponse(response);
83
+ }
84
+
85
+ async function run(args) {
86
+ const parsed = parseArgs(args);
87
+ if (parsed.help) {
88
+ console.log('Usage: openyida read-dingtalk-doc <docUrl> [--output <file>] [--json]');
89
+ return { help: true };
90
+ }
91
+ const docUrl = validateDocUrl(parsed.docUrl);
92
+ const content = await fetchDocumentMarkdown(docUrl);
93
+ if (parsed.output) {
94
+ const outputPath = path.resolve(parsed.output);
95
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
96
+ fs.writeFileSync(outputPath, content, 'utf8');
97
+ const result = { success: true, docUrl, output: outputPath, length: content.length };
98
+ console.log(JSON.stringify(result, null, 2));
99
+ return result;
100
+ }
101
+ const result = { success: true, docUrl, content };
102
+ console.log(parsed.json ? JSON.stringify(result, null, 2) : content);
103
+ return result;
104
+ }
105
+
106
+ module.exports = {
107
+ API_PATH,
108
+ parseArgs,
109
+ validateDocUrl,
110
+ unwrapMarkdownResponse,
111
+ fetchDocumentMarkdown,
112
+ run,
113
+ };
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ const { createAuthRef, createYidaClient } = require('../core/yida-client');
4
+ const { throwUsage } = require('../core/command-errors');
5
+
6
+ const API_PATH = '/query/document/tingji.json';
7
+
8
+ function parseArgs(args) {
9
+ const parsed = { taskUuid: '', help: false };
10
+ for (const arg of args) {
11
+ if (arg === '--help' || arg === '-h') {
12
+ parsed.help = true;
13
+ } else if (arg === '--json') {
14
+ continue;
15
+ } else if (!arg.startsWith('--') && !parsed.taskUuid) {
16
+ parsed.taskUuid = arg;
17
+ } else {
18
+ throwUsage('Usage: openyida read-dingtalk-tingji <taskUuid> [--json]');
19
+ }
20
+ }
21
+ return parsed;
22
+ }
23
+
24
+ function validateTaskUuid(taskUuid) {
25
+ const normalized = String(taskUuid || '').trim();
26
+ if (!normalized) {
27
+ throwUsage('Usage: openyida read-dingtalk-tingji <taskUuid> [--json]');
28
+ }
29
+ if (normalized.length > 256 || /[\r\n]/.test(normalized)) {
30
+ throw new Error('taskUuid is invalid');
31
+ }
32
+ return normalized;
33
+ }
34
+
35
+ async function fetchTingjiDetail(taskUuid, options = {}) {
36
+ const authRef = options.authRef || createAuthRef();
37
+ const client = options.client || createYidaClient({ authRef });
38
+ const response = await client.get(API_PATH, { taskUuid: validateTaskUuid(taskUuid) }, {
39
+ timeout: options.timeout || 300000,
40
+ });
41
+ if (!response || response.success === false || response.__needLogin || response.__csrfExpired) {
42
+ const detail = response && (response.errorMsg || response.message);
43
+ throw new Error(detail || 'Failed to fetch Tingji detail');
44
+ }
45
+ return response.content !== undefined ? response.content : response;
46
+ }
47
+
48
+ async function run(args) {
49
+ const parsed = parseArgs(args);
50
+ if (parsed.help) {
51
+ console.log('Usage: openyida read-dingtalk-tingji <taskUuid> [--json]');
52
+ return { help: true };
53
+ }
54
+ const taskUuid = validateTaskUuid(parsed.taskUuid);
55
+ const detail = await fetchTingjiDetail(taskUuid);
56
+ const result = { success: true, taskUuid, detail };
57
+ console.log(JSON.stringify(result, null, 2));
58
+ return result;
59
+ }
60
+
61
+ module.exports = { API_PATH, parseArgs, validateTaskUuid, fetchTingjiDetail, run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.7.26-beta.3",
3
+ "version": "2026.7.27-beta.1",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -167,13 +167,15 @@ OpenYida builder 默认使用 `create-app / create-form / create-page / generate
167
167
  | `yida-skills/integration` | 连接器、外部 API、执行动作、设计器数据源、集成自动化、逻辑流 | `yida-integration`、`yida-connector`、`yida-connector-safe-actions`、`yida-data-source-connectors` |
168
168
  | `yida-skills/access` | 平台/应用/表单/页面权限、公开访问、分享 | `yida-corp-manager`、`yida-app-permission`、`yida-form-permission`、`yida-page-config` |
169
169
  | `yida-skills/ops` | Sequence、主键冲突、VOC 反馈 | `yida-db-seq-fix`、`yida-voc` |
170
- | `yida-skills/agent` | 导出对话、会议纪要/闪记转 PRD | `yida-export-conversation`、`yida-flash-note-to-prd` |
170
+ | `yida-skills/agent` | 导出对话、读取钉钉文档/听记、会议纪要/闪记转 PRD | `yida-export-conversation`、`yida-document-markdown`、`yida-tingji`、`yida-flash-note-to-prd` |
171
171
 
172
172
  ### 高频分歧
173
173
 
174
174
  | 用户意图 | 选哪个 |
175
175
  |------|------|
176
176
  | 从零搭一个完整应用/系统 | `yida-app`;默认 `fast_build`,不要自动升级到深度设计 |
177
+ | 读取钉钉在线文档正文 | `yida-document-markdown`,使用登录态接口获取 Markdown |
178
+ | 按 taskUuid 读取钉钉听记 | `yida-tingji`,将听记任务 ID 原样传入命令 |
177
179
  | 只创建应用壳并拿 appType | `yida-create-app` |
178
180
  | 创建自定义展示页资源 | `yida-create-page`,之后默认接 `yida-canvas-custom-page` 和 `yida-publish-page` |
179
181
  | 开发表单字段结构 / 增删改字段 | `yida-create-form-page` |
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: yida-document-markdown
3
+ description: 获取钉钉文档、钉钉在线文档或知识库文档的完整 Markdown 内容。用户提供文档链接并要求读取、提取、总结或继续处理文档内容时使用。
4
+ ---
5
+
6
+ # 获取钉钉文档 Markdown
7
+
8
+ ## 严格要求 (MUST DO)
9
+
10
+ - 使用 `openyida read-dingtalk-doc "<docUrl>"` 读取文档内容
11
+ - 将用户提供的钉钉文档 URL 原样传给 `docUrl` 参数
12
+ - 仅基于命令返回的 Markdown 执行总结、转 PRD 或其他下游任务
13
+
14
+ ## 命令
15
+
16
+ ```bash
17
+ openyida read-dingtalk-doc "<docUrl>"
18
+ openyida read-dingtalk-doc "<docUrl>" --json
19
+ openyida read-dingtalk-doc "<docUrl>" --output ./document.md
20
+ ```
21
+
22
+ | 参数 | 必填 | 说明 |
23
+ |------|------|------|
24
+ | `docUrl` | 是 | 可访问的钉钉文档 HTTP(S) 链接 |
25
+ | `--json` | 否 | 输出包含原始链接和 Markdown 的 JSON |
26
+ | `--output`, `-o` | 否 | 将 Markdown 写入指定文件;若文件已存在则覆盖 |
27
+
28
+ ## 执行流程
29
+
30
+ 1. 确认用户已提供文档链接。
31
+ 2. 默认运行 `openyida read-dingtalk-doc "<docUrl>"` 获取纯 Markdown;需要结构化结果时使用 `--json`。
32
+ 3. 仅在用户要求保存文件或后续任务需要文件输入时使用 `--output`,并明确告知写入路径。
33
+ 4. 检查命令成功结果,再按用户要求处理 Markdown。
34
+
35
+ ## 异常处理
36
+
37
+ | 场景 | 处理方式 |
38
+ |------|----------|
39
+ | 未登录或登录失效 | 运行 `openyida auth status`,必要时执行 `openyida login` |
40
+ | 400 | 检查 `docUrl` 是否为空或格式错误 |
41
+ | 文档无权限或不存在 | 请用户确认当前钉钉账号权限与链接有效性 |
42
+ | 请求超时 | 稍后重试;文档转换最长可能等待 300 秒 |
43
+
44
+ ## 完成标准
45
+
46
+ 命令成功返回非推测的 Markdown 内容,或成功写入用户指定文件。
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: yida-tingji
3
+ description: 按 taskUuid 获取钉钉听记、会议录音转写、会议纪要或 AI 听记的完整详情。用户提供听记任务 ID 并要求读取、整理、总结或转 PRD 时使用。
4
+ ---
5
+
6
+ # 获取钉钉听记详情
7
+
8
+ ## 严格要求 (MUST DO)
9
+
10
+ - 使用 `openyida read-dingtalk-tingji "<taskUuid>"` 读取听记详情
11
+ - 将用户提供的 `taskUuid` 原样传入,不自行转换或校验其格式
12
+ - 读取成功后,根据用户要求提取会议摘要、关键决策、行动项或生成 PRD
13
+ - 默认不要在回复中展示带签名参数的资源 URL;用户明确要求原始结果时再输出完整 JSON
14
+
15
+ ## 命令
16
+
17
+ ```bash
18
+ openyida read-dingtalk-tingji "<taskUuid>"
19
+ openyida read-dingtalk-tingji "<taskUuid>" --json
20
+ ```
21
+
22
+ | 参数 | 必填 | 说明 |
23
+ |------|------|------|
24
+ | `taskUuid` | 是 | 钉钉听记任务 ID,按原值传入 |
25
+ | `--json` | 否 | 显式声明 JSON 输出;当前命令默认即为 JSON |
26
+
27
+ ## 执行流程
28
+
29
+ 1. 从用户输入或听记链接上下文中取得准确的 `taskUuid`;无法确定时请用户补充。
30
+ 2. 运行 `openyida read-dingtalk-tingji "<taskUuid>" --json`。
31
+ 3. 检查成功结果,再按用户要求提取会议摘要、发言内容、决策或待办。
32
+
33
+ ## 异常处理
34
+
35
+ | 场景 | 处理方式 |
36
+ |------|----------|
37
+ | 未登录或登录失效 | 运行 `openyida auth status`,必要时执行 `openyida login` |
38
+ | 400 | 检查 `taskUuid` 是否为空 |
39
+ | 听记无权限或不存在 | 请用户确认当前钉钉账号权限和 `taskUuid` |
40
+ | 请求超时 | 稍后重试;接口最长可能等待 300 秒 |
41
+
42
+ ## 完成标准
43
+
44
+ 命令成功返回指定 `taskUuid` 对应的真实听记详情。
@@ -89,6 +89,30 @@
89
89
  "基础信息"
90
90
  ]
91
91
  },
92
+ {
93
+ "name": "yida-document-markdown",
94
+ "path": "skills/yida-document-markdown/SKILL.md",
95
+ "display_name": "钉钉文档 Markdown",
96
+ "description": "获取钉钉文档、钉钉在线文档或知识库文档的完整 Markdown 内容。用户提供文档链接并要求读取、提取、总结或继续处理文档内容时使用。",
97
+ "category": "yida-skills/agent",
98
+ "tags": ["钉钉文档", "Markdown", "文档链接", "内容提取"],
99
+ "aliases": ["读取钉钉文档", "文档转 Markdown"],
100
+ "command_ids": ["read-dingtalk-doc"],
101
+ "done_when": "命令成功返回真实 Markdown 内容,或成功写入指定文件。",
102
+ "requires_login": true
103
+ },
104
+ {
105
+ "name": "yida-tingji",
106
+ "path": "skills/yida-tingji/SKILL.md",
107
+ "display_name": "钉钉听记详情",
108
+ "description": "按 taskUuid 获取钉钉听记、会议录音转写、会议纪要或 AI 听记的完整详情。用户提供听记任务 ID 并要求读取、整理、总结或转 PRD 时使用。",
109
+ "category": "yida-skills/agent",
110
+ "tags": ["钉钉听记", "会议纪要", "taskUuid", "语音转写"],
111
+ "aliases": ["读取听记", "获取会议记录"],
112
+ "command_ids": ["read-dingtalk-tingji"],
113
+ "done_when": "命令成功返回指定 taskUuid 对应的真实听记详情。",
114
+ "requires_login": true
115
+ },
92
116
  {
93
117
  "name": "yida-business-rule",
94
118
  "path": "skills/yida-business-rule/SKILL.md",
@@ -1159,6 +1183,11 @@
1159
1183
  "description": "非宜搭业务资源本身的 agent 辅助能力:导出对话、会议/闪记转 PRD。",
1160
1184
  "signals": [
1161
1185
  "导出对话",
1186
+ "钉钉文档",
1187
+ "读取文档",
1188
+ "Markdown 内容",
1189
+ "钉钉听记",
1190
+ "taskUuid",
1162
1191
  "会议纪要",
1163
1192
  "闪记",
1164
1193
  "PRD"