yidaconnector 2026.6.11

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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +383 -0
  3. package/bin/yida.js +670 -0
  4. package/lib/app/form-navigation.js +58 -0
  5. package/lib/app/get-schema.js +538 -0
  6. package/lib/auth/auth.js +294 -0
  7. package/lib/auth/cdp-browser-login.js +390 -0
  8. package/lib/auth/codex-login.js +71 -0
  9. package/lib/auth/login.js +475 -0
  10. package/lib/auth/org.js +363 -0
  11. package/lib/auth/qr-login.js +1563 -0
  12. package/lib/core/chalk.js +384 -0
  13. package/lib/core/check-update.js +82 -0
  14. package/lib/core/cli-error.js +39 -0
  15. package/lib/core/command-manifest.js +106 -0
  16. package/lib/core/env-cmd.js +545 -0
  17. package/lib/core/env-manager.js +601 -0
  18. package/lib/core/env.js +287 -0
  19. package/lib/core/i18n.js +177 -0
  20. package/lib/core/locales/ar.js +805 -0
  21. package/lib/core/locales/de.js +805 -0
  22. package/lib/core/locales/en.js +1623 -0
  23. package/lib/core/locales/es.js +805 -0
  24. package/lib/core/locales/fr.js +805 -0
  25. package/lib/core/locales/hi.js +805 -0
  26. package/lib/core/locales/ja.js +1197 -0
  27. package/lib/core/locales/ko.js +807 -0
  28. package/lib/core/locales/pt.js +805 -0
  29. package/lib/core/locales/vi.js +805 -0
  30. package/lib/core/locales/zh-HK.js +1233 -0
  31. package/lib/core/locales/zh.js +1584 -0
  32. package/lib/core/query-data.js +781 -0
  33. package/lib/core/redact.js +100 -0
  34. package/lib/core/utils.js +799 -0
  35. package/lib/core/yida-client.js +117 -0
  36. package/package.json +94 -0
  37. package/project/config.json +4 -0
  38. package/project/pages/src/demo-birthday-game.oyd.jsx +832 -0
  39. package/project/pages/src/demo-chip-insight.oyd.jsx +983 -0
  40. package/project/pages/src/demo-compat-smoke.oyd.jsx +58 -0
  41. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +805 -0
  42. package/project/pages/src/demo-crm-dashboard.oyd.jsx +677 -0
  43. package/project/pages/src/demo-future-vision-2026.oyd.jsx +1102 -0
  44. package/project/pages/src/demo-ppt.oyd.jsx +1192 -0
  45. package/project/pages/src/demo-salary-calculator.oyd.jsx +904 -0
  46. package/project/pages/src/yidaconnector-knowledge-doc.oyd.jsx +1714 -0
  47. package/project/prd/demo-birthday-game.md +39 -0
  48. package/project/prd/demo-crm.md +463 -0
  49. package/project/prd/demo-dingtalk-ai-solution-center.md +425 -0
  50. package/project/prd/demo-future-vision-2026.md +78 -0
  51. package/project/prd/demo-salary-calculator.md +101 -0
  52. package/scripts/build-skills-package.js +406 -0
  53. package/scripts/check-syntax.js +59 -0
  54. package/scripts/demo-dws.sh +106 -0
  55. package/scripts/e2e-real/cleanup.js +67 -0
  56. package/scripts/e2e-real/fixtures/form-fields.json +18 -0
  57. package/scripts/e2e-real/full-runner.js +1566 -0
  58. package/scripts/e2e-real/runner.js +293 -0
  59. package/scripts/e2e-real/skill-coverage.js +115 -0
  60. package/scripts/generate-command-docs.js +109 -0
  61. package/scripts/nightly-smoke.js +134 -0
  62. package/scripts/postinstall.js +545 -0
  63. package/scripts/solution-center-runner.js +368 -0
  64. package/scripts/validate-ci.sh +50 -0
  65. package/scripts/validate-command-manifest.js +119 -0
  66. package/scripts/validate-package-size.js +78 -0
  67. package/scripts/validate-skills.js +247 -0
  68. package/scripts/validate-structure.js +66 -0
  69. package/yida-skills/SKILL.md +163 -0
  70. package/yida-skills/references/yida-api.md +1309 -0
  71. package/yida-skills/skills/large-file-write/SKILL.md +91 -0
  72. package/yida-skills/skills/large-file-write/references/write-patterns.md +149 -0
  73. package/yida-skills/skills/large-file-write/scripts/write.js +157 -0
  74. package/yida-skills/skills/yida-data-management/SKILL.md +252 -0
  75. package/yida-skills/skills/yida-data-management/references/api-matrix.md +49 -0
  76. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +159 -0
  77. package/yida-skills/skills/yida-data-management/references/verified-endpoints.md +62 -0
  78. package/yida-skills/skills/yida-login/SKILL.md +159 -0
  79. package/yida-skills/skills/yida-logout/SKILL.md +67 -0
@@ -0,0 +1,406 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const zlib = require('zlib');
8
+
9
+ const ROOT = path.resolve(__dirname, '..');
10
+ const SOURCE_ROOT = path.join(ROOT, 'yida-skills');
11
+ const SOURCE_SUBSKILLS_ROOT = path.join(SOURCE_ROOT, 'skills');
12
+ const DEFAULT_OUTPUT_ROOT = path.join(ROOT, 'dist', 'skills', 'yidaconnector');
13
+ const DEFAULT_ZIP_OUT = path.join(ROOT, 'yidaconnector-skills.zip');
14
+
15
+ function parseArgs(argv) {
16
+ const options = {
17
+ out: DEFAULT_OUTPUT_ROOT,
18
+ zipOut: DEFAULT_ZIP_OUT,
19
+ zip: true,
20
+ };
21
+
22
+ for (let i = 0; i < argv.length; i++) {
23
+ const arg = argv[i];
24
+ if (arg === '--out') {
25
+ options.out = path.resolve(ROOT, argv[++i]);
26
+ } else if (arg === '--zip-out') {
27
+ options.zipOut = path.resolve(ROOT, argv[++i]);
28
+ options.zip = true;
29
+ } else if (arg === '--no-zip') {
30
+ options.zip = false;
31
+ }
32
+ }
33
+
34
+ return options;
35
+ }
36
+
37
+ function copyDirRecursive(src, dest) {
38
+ if (!fs.existsSync(src)) {
39
+ return 0;
40
+ }
41
+
42
+ fs.mkdirSync(dest, { recursive: true });
43
+
44
+ let count = 0;
45
+ const entries = fs.readdirSync(src, { withFileTypes: true });
46
+ for (const entry of entries) {
47
+ const srcPath = path.join(src, entry.name);
48
+ const destPath = path.join(dest, entry.name);
49
+
50
+ if (entry.isDirectory()) {
51
+ count += copyDirRecursive(srcPath, destPath);
52
+ } else if (entry.isFile()) {
53
+ fs.copyFileSync(srcPath, destPath);
54
+ count++;
55
+ }
56
+ }
57
+
58
+ return count;
59
+ }
60
+
61
+ function readRequiredFile(src) {
62
+ if (!fs.existsSync(src)) {
63
+ throw new Error('Missing required file: ' + path.relative(ROOT, src));
64
+ }
65
+
66
+ return fs.readFileSync(src, 'utf8');
67
+ }
68
+
69
+ function writeRootSkill(src, dest) {
70
+ const content = readRequiredFile(src)
71
+ .replace(/skills\/([a-z0-9-]+)\/SKILL\.md/g, 'references/subskills/$1/README.md')
72
+ .replace(/详见 SKILL\.md/g, '详见 README.md')
73
+ .replace('| 技能 | SKILL.md 路径 | 用途 | 典型命令 |', '| 技能 | README 路径 | 用途 | 典型命令 |')
74
+ .replace('> 每个子技能均有独立的 SKILL.md。执行时先选定一个最匹配的子技能,只读取该子技能文档;references 按文档提示按需读取,避免一次性加载全量文档。',
75
+ '> 悟空上传包只暴露一个根 SKILL.md;原子技能已打包到 references/subskills/,执行时先选定一个最匹配的子技能,只读取对应 README.md;references 按文档提示按需读取,避免一次性加载全量文档。');
76
+
77
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
78
+ fs.writeFileSync(dest, content, 'utf8');
79
+ return 1;
80
+ }
81
+
82
+ function transformSubskillReference(content) {
83
+ return content
84
+ .replace(/^---\n[\s\S]*?\n---\n?/, '')
85
+ .replace(/yida-skills\/SKILL\.md/g, '../../../SKILL.md')
86
+ .replace(/skills\/([a-z0-9-]+)\/SKILL\.md/g, '../$1/README.md')
87
+ .replace(/\.\.\/([a-z0-9-]+)\/SKILL\.md/g, '../$1/README.md')
88
+ .replace(/详见 SKILL\.md/g, '详见 README.md');
89
+ }
90
+
91
+ function copySubskillAsReference(skillDirName, outputRoot) {
92
+ const sourceDir = path.join(SOURCE_SUBSKILLS_ROOT, skillDirName);
93
+ const destDir = path.join(outputRoot, 'references', 'subskills', skillDirName);
94
+
95
+ if (!fs.existsSync(path.join(sourceDir, 'SKILL.md'))) {
96
+ return 0;
97
+ }
98
+
99
+ fs.mkdirSync(destDir, { recursive: true });
100
+ let count = 0;
101
+ const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
102
+ for (const entry of entries) {
103
+ const sourcePath = path.join(sourceDir, entry.name);
104
+ const destName = entry.name === 'SKILL.md' ? 'README.md' : entry.name;
105
+ const destPath = path.join(destDir, destName);
106
+
107
+ if (entry.isDirectory()) {
108
+ count += copyDirRecursive(sourcePath, destPath);
109
+ } else if (entry.isFile()) {
110
+ if (entry.name === 'SKILL.md') {
111
+ fs.writeFileSync(destPath, transformSubskillReference(readRequiredFile(sourcePath)), 'utf8');
112
+ } else {
113
+ fs.copyFileSync(sourcePath, destPath);
114
+ }
115
+ count++;
116
+ }
117
+ }
118
+
119
+ return count;
120
+ }
121
+
122
+ function copySubskillsAsReferences(outputRoot) {
123
+ if (!fs.existsSync(SOURCE_SUBSKILLS_ROOT)) {
124
+ return 0;
125
+ }
126
+
127
+ const skillDirNames = fs.readdirSync(SOURCE_SUBSKILLS_ROOT).filter(function(name) {
128
+ return fs.statSync(path.join(SOURCE_SUBSKILLS_ROOT, name)).isDirectory();
129
+ }).sort();
130
+
131
+ let count = 0;
132
+ for (const skillDirName of skillDirNames) {
133
+ count += copySubskillAsReference(skillDirName, outputRoot);
134
+ }
135
+
136
+ return count;
137
+ }
138
+
139
+ function collectSkillFiles(dir, files) {
140
+ if (!fs.existsSync(dir)) {
141
+ return;
142
+ }
143
+
144
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
145
+ for (const entry of entries) {
146
+ const fullPath = path.join(dir, entry.name);
147
+ if (entry.isDirectory()) {
148
+ collectSkillFiles(fullPath, files);
149
+ } else if (entry.isFile() && entry.name === 'SKILL.md') {
150
+ files.push(fullPath);
151
+ }
152
+ }
153
+ }
154
+
155
+ function collectMarkdownFiles(dir, files) {
156
+ if (!fs.existsSync(dir)) {
157
+ return;
158
+ }
159
+
160
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
161
+ for (const entry of entries) {
162
+ const fullPath = path.join(dir, entry.name);
163
+ if (entry.isDirectory()) {
164
+ collectMarkdownFiles(fullPath, files);
165
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
166
+ files.push(fullPath);
167
+ }
168
+ }
169
+ }
170
+
171
+ function assertSingleWukongSkill(outputRoot) {
172
+ const skillFiles = [];
173
+ collectSkillFiles(outputRoot, skillFiles);
174
+ if (skillFiles.length !== 1 || skillFiles[0] !== path.join(outputRoot, 'SKILL.md')) {
175
+ throw new Error('Wukong skill package must contain exactly one root SKILL.md');
176
+ }
177
+ }
178
+
179
+ function assertWukongFrontmatter(outputRoot) {
180
+ const skillText = readRequiredFile(path.join(outputRoot, 'SKILL.md'));
181
+ const frontmatterMatch = skillText.match(/^---\n([\s\S]*?)\n---/);
182
+ if (!frontmatterMatch) {
183
+ throw new Error('Wukong root SKILL.md must start with YAML frontmatter');
184
+ }
185
+
186
+ const keys = frontmatterMatch[1].split(/\r?\n/).filter(function(line) {
187
+ return /^[a-zA-Z0-9_-]+:\s*/.test(line);
188
+ }).map(function(line) {
189
+ return line.split(':')[0];
190
+ });
191
+
192
+ const invalidKeys = keys.filter(function(key) {
193
+ return key !== 'name' && key !== 'description';
194
+ });
195
+ if (invalidKeys.length > 0) {
196
+ throw new Error('Wukong root SKILL.md frontmatter must only contain name and description');
197
+ }
198
+ }
199
+
200
+ function assertNoSourceSkillLinks(outputRoot) {
201
+ const markdownFiles = [];
202
+ collectMarkdownFiles(outputRoot, markdownFiles);
203
+
204
+ for (const markdownFile of markdownFiles) {
205
+ const text = readRequiredFile(markdownFile);
206
+ if (/skills\/[a-z0-9-]+\/SKILL\.md|yida-skills\/SKILL\.md/.test(text)) {
207
+ throw new Error('Generated Wukong package contains source skill path: ' + path.relative(ROOT, markdownFile));
208
+ }
209
+ }
210
+ }
211
+
212
+ function buildSkillsPackage(outputRoot) {
213
+ if (!fs.existsSync(SOURCE_ROOT)) {
214
+ throw new Error('Missing source skills directory: yida-skills');
215
+ }
216
+
217
+ fs.rmSync(outputRoot, { recursive: true, force: true });
218
+ fs.mkdirSync(outputRoot, { recursive: true });
219
+
220
+ let count = 0;
221
+ count += writeRootSkill(
222
+ path.join(SOURCE_ROOT, 'SKILL.md'),
223
+ path.join(outputRoot, 'SKILL.md'),
224
+ );
225
+ count += copyDirRecursive(
226
+ path.join(SOURCE_ROOT, 'references'),
227
+ path.join(outputRoot, 'references'),
228
+ );
229
+ count += copySubskillsAsReferences(outputRoot);
230
+
231
+ assertSingleWukongSkill(outputRoot);
232
+ assertWukongFrontmatter(outputRoot);
233
+ assertNoSourceSkillLinks(outputRoot);
234
+
235
+ return count;
236
+ }
237
+
238
+ function buildZipPackage(outputRoot, zipOut) {
239
+ if (!fs.existsSync(outputRoot)) {
240
+ throw new Error('Missing generated skills package directory: ' + path.relative(ROOT, outputRoot));
241
+ }
242
+
243
+ fs.mkdirSync(path.dirname(zipOut), { recursive: true });
244
+ fs.rmSync(zipOut, { force: true });
245
+
246
+ const zipBuffer = createZipBuffer(outputRoot);
247
+ fs.writeFileSync(zipOut, zipBuffer);
248
+
249
+ const stat = fs.statSync(zipOut);
250
+ if (!stat.size) {
251
+ throw new Error('Created Wukong zip package is empty: ' + path.relative(ROOT, zipOut));
252
+ }
253
+
254
+ return stat.size;
255
+ }
256
+
257
+ const CRC32_TABLE = (() => {
258
+ const table = new Uint32Array(256);
259
+ for (let i = 0; i < 256; i++) {
260
+ let crc = i;
261
+ for (let j = 0; j < 8; j++) {
262
+ crc = (crc & 1) ? (0xEDB88320 ^ (crc >>> 1)) : (crc >>> 1);
263
+ }
264
+ table[i] = crc >>> 0;
265
+ }
266
+ return table;
267
+ })();
268
+
269
+ function crc32(buffer) {
270
+ let crc = 0xFFFFFFFF;
271
+ for (let i = 0; i < buffer.length; i++) {
272
+ crc = CRC32_TABLE[(crc ^ buffer[i]) & 0xFF] ^ (crc >>> 8);
273
+ }
274
+ return (crc ^ 0xFFFFFFFF) >>> 0;
275
+ }
276
+
277
+ function toDosDateTime(date) {
278
+ const year = Math.max(1980, date.getFullYear());
279
+ const month = date.getMonth() + 1;
280
+ const day = date.getDate();
281
+ const hours = date.getHours();
282
+ const minutes = date.getMinutes();
283
+ const seconds = Math.floor(date.getSeconds() / 2);
284
+ return {
285
+ time: ((hours << 11) | (minutes << 5) | seconds) & 0xFFFF,
286
+ date: (((year - 1980) << 9) | (month << 5) | day) & 0xFFFF,
287
+ };
288
+ }
289
+
290
+ function collectZipEntries(absPath, entryName, entries) {
291
+ const stat = fs.statSync(absPath);
292
+ if (stat.isDirectory()) {
293
+ const dirName = entryName.endsWith('/') ? entryName : entryName + '/';
294
+ entries.push({ absPath, entryName: dirName, stat, isDirectory: true });
295
+ const names = fs.readdirSync(absPath).filter(function(name) {
296
+ return name !== '.DS_Store';
297
+ }).sort();
298
+ for (const name of names) {
299
+ collectZipEntries(path.join(absPath, name), dirName + name, entries);
300
+ }
301
+ } else if (stat.isFile() && path.basename(absPath) !== '.DS_Store') {
302
+ entries.push({ absPath, entryName, stat, isDirectory: false });
303
+ }
304
+ }
305
+
306
+ function writeLocalHeader(entry, nameBuffer, compressed, uncompressed, crc, method) {
307
+ const { time, date } = toDosDateTime(entry.stat.mtime);
308
+ const header = Buffer.alloc(30);
309
+ header.writeUInt32LE(0x04034b50, 0);
310
+ header.writeUInt16LE(20, 4);
311
+ header.writeUInt16LE(0x0800, 6);
312
+ header.writeUInt16LE(method, 8);
313
+ header.writeUInt16LE(time, 10);
314
+ header.writeUInt16LE(date, 12);
315
+ header.writeUInt32LE(crc, 14);
316
+ header.writeUInt32LE(compressed.length, 18);
317
+ header.writeUInt32LE(uncompressed.length, 22);
318
+ header.writeUInt16LE(nameBuffer.length, 26);
319
+ header.writeUInt16LE(0, 28);
320
+ return header;
321
+ }
322
+
323
+ function writeCentralHeader(entry, nameBuffer, compressed, uncompressed, crc, method, localOffset) {
324
+ const { time, date } = toDosDateTime(entry.stat.mtime);
325
+ const header = Buffer.alloc(46);
326
+ header.writeUInt32LE(0x02014b50, 0);
327
+ header.writeUInt16LE(0x031E, 4);
328
+ header.writeUInt16LE(20, 6);
329
+ header.writeUInt16LE(0x0800, 8);
330
+ header.writeUInt16LE(method, 10);
331
+ header.writeUInt16LE(time, 12);
332
+ header.writeUInt16LE(date, 14);
333
+ header.writeUInt32LE(crc, 16);
334
+ header.writeUInt32LE(compressed.length, 20);
335
+ header.writeUInt32LE(uncompressed.length, 24);
336
+ header.writeUInt16LE(nameBuffer.length, 28);
337
+ header.writeUInt16LE(0, 30);
338
+ header.writeUInt16LE(0, 32);
339
+ header.writeUInt16LE(0, 34);
340
+ header.writeUInt16LE(0, 36);
341
+ const unixMode = entry.isDirectory ? 0o40755 : 0o100644;
342
+ const dosAttributes = entry.isDirectory ? 0x10 : 0;
343
+ header.writeUInt32LE(((unixMode << 16) | dosAttributes) >>> 0, 38);
344
+ header.writeUInt32LE(localOffset, 42);
345
+ return header;
346
+ }
347
+
348
+ function createZipBuffer(outputRoot) {
349
+ const entries = [];
350
+ collectZipEntries(outputRoot, path.basename(outputRoot), entries);
351
+
352
+ const chunks = [];
353
+ const centralChunks = [];
354
+ let offset = 0;
355
+
356
+ for (const entry of entries) {
357
+ const nameBuffer = Buffer.from(entry.entryName.replace(/\\/g, '/'), 'utf8');
358
+ const uncompressed = entry.isDirectory ? Buffer.alloc(0) : fs.readFileSync(entry.absPath);
359
+ const method = entry.isDirectory ? 0 : 8;
360
+ const compressed = entry.isDirectory ? Buffer.alloc(0) : zlib.deflateRawSync(uncompressed);
361
+ const crc = entry.isDirectory ? 0 : crc32(uncompressed);
362
+ const localOffset = offset;
363
+
364
+ const localHeader = writeLocalHeader(entry, nameBuffer, compressed, uncompressed, crc, method);
365
+ chunks.push(localHeader, nameBuffer, compressed);
366
+ offset += localHeader.length + nameBuffer.length + compressed.length;
367
+
368
+ const centralHeader = writeCentralHeader(entry, nameBuffer, compressed, uncompressed, crc, method, localOffset);
369
+ centralChunks.push(centralHeader, nameBuffer);
370
+ }
371
+
372
+ const centralOffset = offset;
373
+ const centralSize = centralChunks.reduce(function(sum, chunk) {
374
+ return sum + chunk.length;
375
+ }, 0);
376
+ const end = Buffer.alloc(22);
377
+ end.writeUInt32LE(0x06054b50, 0);
378
+ end.writeUInt16LE(0, 4);
379
+ end.writeUInt16LE(0, 6);
380
+ end.writeUInt16LE(entries.length, 8);
381
+ end.writeUInt16LE(entries.length, 10);
382
+ end.writeUInt32LE(centralSize, 12);
383
+ end.writeUInt32LE(centralOffset, 16);
384
+ end.writeUInt16LE(0, 20);
385
+
386
+ return Buffer.concat(chunks.concat(centralChunks, end));
387
+ }
388
+
389
+ function formatBytes(size) {
390
+ if (size < 1024) {return size + ' B';}
391
+ if (size < 1024 * 1024) {return (size / 1024).toFixed(1) + ' KB';}
392
+ return (size / 1024 / 1024).toFixed(1) + ' MB';
393
+ }
394
+
395
+ function run() {
396
+ const options = parseArgs(process.argv.slice(2));
397
+ const count = buildSkillsPackage(options.out);
398
+ console.log('Built YidaConnector skills package: ' + path.relative(ROOT, options.out));
399
+ console.log('Files copied: ' + count);
400
+ if (options.zip) {
401
+ const zipSize = buildZipPackage(options.out, options.zipOut);
402
+ console.log('Built Wukong upload zip: ' + path.relative(ROOT, options.zipOut) + ' (' + formatBytes(zipSize) + ')');
403
+ }
404
+ }
405
+
406
+ run();
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { spawnSync } = require('child_process');
8
+
9
+ const ROOT = path.resolve(__dirname, '..');
10
+ const TARGET_DIRS = ['bin', 'lib', 'scripts', 'tests'];
11
+
12
+ function collectJsFiles(dir, files) {
13
+ if (!fs.existsSync(dir)) {
14
+ return;
15
+ }
16
+
17
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
18
+ for (const entry of entries) {
19
+ const fullPath = path.join(dir, entry.name);
20
+ if (entry.isDirectory()) {
21
+ if (entry.name === 'node_modules' || entry.name === 'coverage') {
22
+ continue;
23
+ }
24
+ collectJsFiles(fullPath, files);
25
+ } else if (entry.isFile() && entry.name.endsWith('.js')) {
26
+ files.push(fullPath);
27
+ }
28
+ }
29
+ }
30
+
31
+ function run() {
32
+ const files = [];
33
+ for (const dir of TARGET_DIRS) {
34
+ collectJsFiles(path.join(ROOT, dir), files);
35
+ }
36
+
37
+ files.sort();
38
+
39
+ for (const file of files) {
40
+ const result = spawnSync(process.execPath, ['--check', file], {
41
+ cwd: ROOT,
42
+ encoding: 'utf8',
43
+ stdio: 'pipe',
44
+ });
45
+
46
+ const relativePath = path.relative(ROOT, file);
47
+ if (result.status !== 0) {
48
+ process.stderr.write(result.stderr || result.stdout);
49
+ process.stderr.write(`Syntax check failed: ${relativePath}\n`);
50
+ process.exit(result.status || 1);
51
+ }
52
+
53
+ process.stdout.write(` ok ${relativePath}\n`);
54
+ }
55
+
56
+ process.stdout.write(`All ${files.length} JavaScript files passed syntax check\n`);
57
+ }
58
+
59
+ run();
@@ -0,0 +1,106 @@
1
+ #!/bin/bash
2
+ # 钉钉 CLI 集成演示脚本
3
+
4
+ set -e
5
+
6
+ echo "========================================"
7
+ echo " YidaConnector 钉钉 CLI 集成演示"
8
+ echo "========================================"
9
+ echo ""
10
+
11
+ # 颜色定义
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ CYAN='\033[0;36m'
15
+ NC='\033[0m' # No Color
16
+
17
+ echo -e "${CYAN}1. 查看 dws 命令帮助${NC}"
18
+ echo "----------------------------------------"
19
+ node bin/yida.js dws --help | head -20
20
+ echo ""
21
+ echo "按回车继续..."
22
+ read
23
+
24
+ echo -e "${CYAN}2. 检查钉钉 CLI 安装状态${NC}"
25
+ echo "----------------------------------------"
26
+ if command -v dws &> /dev/null; then
27
+ echo -e "${GREEN}✓ 钉钉 CLI 已安装${NC}"
28
+ node bin/yida.js dws version
29
+ else
30
+ echo -e "${YELLOW}⚠ 钉钉 CLI 未安装${NC}"
31
+ echo "可以使用以下命令安装:"
32
+ echo " yidaconnector dws install"
33
+ fi
34
+ echo ""
35
+ echo "按回车继续..."
36
+ read
37
+
38
+ echo -e "${CYAN}3. 查看主帮助中的 dws 命令${NC}"
39
+ echo "----------------------------------------"
40
+ node bin/yida.js --help | grep -A 2 "dws"
41
+ echo ""
42
+ echo "按回车继续..."
43
+ read
44
+
45
+ echo -e "${CYAN}4. 常用命令示例${NC}"
46
+ echo "----------------------------------------"
47
+ echo ""
48
+ echo "搜索联系人:"
49
+ echo " ${GREEN}yidaconnector dws contact user search --keyword \"悟空\"${NC}"
50
+ echo ""
51
+ echo "创建待办事项:"
52
+ echo " ${GREEN}yidaconnector dws todo task create --title \"任务\" --executors \"userId\"${NC}"
53
+ echo ""
54
+ echo "列出日历事件:"
55
+ echo " ${GREEN}yidaconnector dws calendar event list${NC}"
56
+ echo ""
57
+ echo "查询考勤记录:"
58
+ echo " ${GREEN}yidaconnector dws attendance record list${NC}"
59
+ echo ""
60
+ echo "发送机器人消息:"
61
+ echo " ${GREEN}yidaconnector dws chat robot send --content \"消息内容\"${NC}"
62
+ echo ""
63
+ echo "按回车继续..."
64
+ read
65
+
66
+ echo -e "${CYAN}5. 输出格式示例${NC}"
67
+ echo "----------------------------------------"
68
+ echo ""
69
+ echo "表格输出(默认):"
70
+ echo " yidaconnector dws contact user search --keyword \"张三\" ${GREEN}-f table${NC}"
71
+ echo ""
72
+ echo "JSON 输出(适合 AI Agent):"
73
+ echo " yidaconnector dws contact user search --keyword \"张三\" ${GREEN}-f json${NC}"
74
+ echo ""
75
+ echo "原始 API 响应:"
76
+ echo " yidaconnector dws contact user search --keyword \"张三\" ${GREEN}-f raw${NC}"
77
+ echo ""
78
+ echo "按回车继续..."
79
+ read
80
+
81
+ echo -e "${CYAN}6. 特殊命令${NC}"
82
+ echo "----------------------------------------"
83
+ echo ""
84
+ echo "一键安装钉钉 CLI:"
85
+ echo " ${GREEN}yidaconnector dws install${NC}"
86
+ echo ""
87
+ echo "预览操作(不执行):"
88
+ echo " ${GREEN}yidaconnector dws <command> --dry-run${NC}"
89
+ echo ""
90
+ echo "输出到文件:"
91
+ echo " ${GREEN}yidaconnector dws <command> -o result.json${NC}"
92
+ echo ""
93
+ echo "按回车继续..."
94
+ read
95
+
96
+ echo "========================================"
97
+ echo " 演示完成!"
98
+ echo "========================================"
99
+ echo ""
100
+ echo "更多信息请查看文档:"
101
+ echo " - docs/dws-cli-guide.md (完整指南)"
102
+ echo " - docs/dws-quick-start.md (快速开始)"
103
+ echo " - docs/dws-integration-changelog.md (更新说明)"
104
+ echo ""
105
+ echo "准备就绪,可以开始使用钉钉 CLI 了!"
106
+ echo ""
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const ROOT = path.resolve(__dirname, '..', '..');
9
+ const DEFAULT_REGISTRY_DIR = path.join(ROOT, 'project', '.cache', 'e2e-real');
10
+
11
+ function getRegistryDir(env = process.env) {
12
+ return env.YIDACONNECTOR_E2E_REGISTRY_DIR || DEFAULT_REGISTRY_DIR;
13
+ }
14
+
15
+ function listRegistries(registryDir = getRegistryDir()) {
16
+ if (!fs.existsSync(registryDir)) {return [];}
17
+ return fs.readdirSync(registryDir)
18
+ .filter((file) => file.endsWith('.json'))
19
+ .map((file) => {
20
+ const registryPath = path.join(registryDir, file);
21
+ const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
22
+ return { registryPath, registry };
23
+ })
24
+ .sort((a, b) => String(a.registry.startedAt || '').localeCompare(String(b.registry.startedAt || '')));
25
+ }
26
+
27
+ function printSummary(items) {
28
+ if (items.length === 0) {
29
+ console.log('No real E2E registries found.');
30
+ return;
31
+ }
32
+
33
+ for (const item of items) {
34
+ const registry = item.registry;
35
+ console.log(`\n${registry.runId || path.basename(item.registryPath)} [${registry.status || 'unknown'}]`);
36
+ console.log(`Registry: ${item.registryPath}`);
37
+ for (const resource of registry.resources || []) {
38
+ const id = resource.appType || resource.formUuid || resource.pageId || 'unknown';
39
+ const secondary = resource.formUuid || resource.pageId || '';
40
+ console.log(`- ${resource.type}: ${id}${secondary && secondary !== id ? ` / ${secondary}` : ''} ${resource.name || ''}`);
41
+ }
42
+ }
43
+
44
+ console.log('\nYidaConnector does not yet expose a safe app/form deletion command, so this script lists disposable resources recorded by real E2E runs for manual cleanup.');
45
+ }
46
+
47
+ function run(options = {}) {
48
+ const registryDir = options.registryDir || getRegistryDir(options.env || process.env);
49
+ const items = listRegistries(registryDir);
50
+ printSummary(items);
51
+ return items;
52
+ }
53
+
54
+ if (require.main === module) {
55
+ try {
56
+ run();
57
+ } catch (error) {
58
+ console.error(error.message);
59
+ process.exit(1);
60
+ }
61
+ }
62
+
63
+ module.exports = {
64
+ getRegistryDir,
65
+ listRegistries,
66
+ run,
67
+ };
@@ -0,0 +1,18 @@
1
+ [
2
+ {
3
+ "type": "TextField",
4
+ "label": "E2E Text",
5
+ "required": true,
6
+ "placeholder": "Created by YidaConnector real E2E"
7
+ },
8
+ {
9
+ "type": "NumberField",
10
+ "label": "E2E Number",
11
+ "placeholder": "123"
12
+ },
13
+ {
14
+ "type": "SelectField",
15
+ "label": "E2E Status",
16
+ "options": ["New", "Done"]
17
+ }
18
+ ]