openyida 2026.7.18 → 2026.7.21
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 +37 -2
- package/bin/yida.js +113 -18
- package/docs/capabilities.md +202 -0
- package/lib/agent-center/agent-center.js +2 -3
- package/lib/app/app-list.js +3 -4
- package/lib/app/build-page.js +13 -6
- package/lib/app/check-page.js +16 -6
- package/lib/app/compile.js +17 -7
- package/lib/app/create-app.js +14 -2
- package/lib/app/create-form/api-path.js +25 -0
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form/commands.js +4 -0
- package/lib/app/create-form/definition-reader.js +23 -23
- package/lib/app/create-form/field-normalizers.js +26 -7
- package/lib/app/create-form/schema-patch.js +4 -1
- package/lib/app/create-form.js +155 -68
- package/lib/app/create-page.js +47 -10
- package/lib/app/generate-page.js +20 -1
- package/lib/app/get-form-config.js +2 -1
- package/lib/app/get-schema.js +67 -15
- package/lib/app/import-app.js +94 -42
- package/lib/app/list-forms.js +4 -8
- package/lib/app/page-ir.js +140 -0
- package/lib/app/publish.js +289 -556
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +22 -9
- package/lib/app/update-form-config.js +4 -2
- package/lib/asset/asset-cmd.js +19 -6
- package/lib/auth/oauth-loopback.js +376 -15
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/basic-info/basic-info.js +2 -1
- package/lib/bridge/bridge.js +43 -18
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-errors.js +38 -0
- package/lib/core/command-manifest.js +59 -1
- package/lib/core/copy.js +12 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/i18n.js +66 -8
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +38 -46
- package/lib/core/locales/zh.js +30 -46
- package/lib/core/sample.js +12 -2
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +108 -5
- package/lib/corp-efficiency/corp-efficiency.js +2 -2
- package/lib/corp-manager/corp-manager.js +3 -3
- package/lib/formula/evaluate.js +11 -68
- package/lib/formula/field-refs.js +83 -0
- package/lib/i18n-management/i18n-management.js +2 -3
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/preview-process.js +20 -8
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
- package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
- package/lib/samples/yida-custom-page/design-tokens.js +2 -2
- package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
- package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
- package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +10 -8
- package/scripts/check-release-risks.js +254 -0
- package/scripts/generate-command-docs.js +6 -1
- package/scripts/i18n-baseline.json +11 -11
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-ci.sh +15 -11
- package/scripts/validate-i18n.js +30 -9
- package/scripts/validate-package-size.js +5 -2
- package/scripts/validate-skills.js +4 -0
- package/scripts/validate-structure.js +15 -0
- package/yida-skills/SKILL.md +117 -30
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +59 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +78 -17
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +50 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
- package/yida-skills/skills/yida-report/SKILL.md +9 -235
- package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
- package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
- package/yida-skills/skills-index.json +238 -54
- package/lib/core/locales/ar.js +0 -834
- package/lib/core/locales/de.js +0 -834
- package/lib/core/locales/es.js +0 -834
- package/lib/core/locales/fr.js +0 -834
- package/lib/core/locales/hi.js +0 -834
- package/lib/core/locales/ja.js +0 -1227
- package/lib/core/locales/ko.js +0 -836
- package/lib/core/locales/pt.js +0 -834
- package/lib/core/locales/vi.js +0 -834
- package/lib/core/locales/zh-HK.js +0 -1263
- package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
- package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
- package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
- package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
- package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
- package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
- package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
- package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
- package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* check-release-risks.js
|
|
6
|
+
*
|
|
7
|
+
* 发布前静态风险扫描,专注「跨平台浏览器/URL 拉起」这一类在 macOS 本地
|
|
8
|
+
* 测试里查不出、却会在 Windows/Linux 用户侧炸掉的历史坑:
|
|
9
|
+
*
|
|
10
|
+
* - `cmd /c start <url>`:cmd.exe 把 URL 里的 `&` 当命令分隔符,截断
|
|
11
|
+
* OAuth/bridge URL,丢失 client_id/state 或 bridge 配对参数(见 ce7efdd)。
|
|
12
|
+
* - `open -n <url>`:macOS 下不会真正开新窗口,只是在默认浏览器里开新
|
|
13
|
+
* 标签页,属于「假装开新窗口」的反模式。
|
|
14
|
+
*
|
|
15
|
+
* HARD 反模式(error)→ 退出码 1,阻断发布。
|
|
16
|
+
* SOFT 提示(warning)→ 退出码 0,仅提醒发布人做人工跨端验证。
|
|
17
|
+
*
|
|
18
|
+
* 该脚本无第三方依赖,纯静态扫描 lib/ 源码;核心分析函数导出供单测使用。
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
|
|
24
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
25
|
+
const SCAN_DIRS = ['lib'];
|
|
26
|
+
|
|
27
|
+
// HARD 反模式:命中即 error,阻断发布。
|
|
28
|
+
const HARD_RULES = [
|
|
29
|
+
{
|
|
30
|
+
id: 'cmd-c-start-url',
|
|
31
|
+
pattern: /cmd\s*\/c\s*start/i,
|
|
32
|
+
message:
|
|
33
|
+
'cmd /c start 会把 URL 中的 & 当作命令分隔符截断参数(丢失 client_id/state 或 bridge 配对参数)。请改用 rundll32 url.dll,FileProtocolHandler,并复用 resolveBrowserLauncher。',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'cmd-c-start-argv',
|
|
37
|
+
pattern: /['"]cmd['"]\s*,\s*\[\s*['"]\/c['"]\s*,\s*['"]start['"]/i,
|
|
38
|
+
message:
|
|
39
|
+
'spawn("cmd", ["/c", "start", ...]) 与 cmd /c start 同源风险:& 处截断 URL。请改用 rundll32 或平台专用浏览器拉起命令。',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'open-n-url-new-tab',
|
|
43
|
+
pattern: /\[\s*(['"])-n\1\s*,\s*url\s*\]/,
|
|
44
|
+
message:
|
|
45
|
+
'open -n <url> 在 macOS 上不会开新窗口,只会在默认浏览器新开标签页(假装开窗口)。要真正开新窗口须指定浏览器 App 并传其 --new-window/-new-window,检测不到默认浏览器时回退纯 open <url>。',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
// SOFT 提示:命中不阻断,只提醒发布人补人工跨端验证。
|
|
50
|
+
const SOFT_LAUNCH_PRIMITIVES =
|
|
51
|
+
/rundll32|xdg-open|osascript|FileProtocolHandler|--new-window|-new-window|command\s*:\s*['"]open['"]|spawn(?:Sync)?\(\s*['"]open['"]/;
|
|
52
|
+
|
|
53
|
+
// 把注释内容替换成等长空白(保留换行以维持行号),避免把「解释为何避免
|
|
54
|
+
// cmd /c start」这类说明性注释误判成真实反模式。会跟踪字符串/模板字面量,
|
|
55
|
+
// 不会把字符串里的 // 或 /* 当注释。
|
|
56
|
+
function stripComments(content) {
|
|
57
|
+
const src = String(content);
|
|
58
|
+
let out = '';
|
|
59
|
+
let i = 0;
|
|
60
|
+
const n = src.length;
|
|
61
|
+
let state = 'code'; // code | line | block | sq | dq | tpl
|
|
62
|
+
while (i < n) {
|
|
63
|
+
const ch = src[i];
|
|
64
|
+
const next = src[i + 1];
|
|
65
|
+
if (state === 'code') {
|
|
66
|
+
if (ch === '/' && next === '/') {
|
|
67
|
+
state = 'line';
|
|
68
|
+
out += ' ';
|
|
69
|
+
i += 2;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (ch === '/' && next === '*') {
|
|
73
|
+
state = 'block';
|
|
74
|
+
out += ' ';
|
|
75
|
+
i += 2;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (ch === "'") {
|
|
79
|
+
state = 'sq';
|
|
80
|
+
} else if (ch === '"') {
|
|
81
|
+
state = 'dq';
|
|
82
|
+
} else if (ch === '`') {
|
|
83
|
+
state = 'tpl';
|
|
84
|
+
}
|
|
85
|
+
out += ch;
|
|
86
|
+
i += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (state === 'line') {
|
|
90
|
+
if (ch === '\n') {
|
|
91
|
+
state = 'code';
|
|
92
|
+
out += ch;
|
|
93
|
+
} else {
|
|
94
|
+
out += ' ';
|
|
95
|
+
}
|
|
96
|
+
i += 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (state === 'block') {
|
|
100
|
+
if (ch === '*' && next === '/') {
|
|
101
|
+
state = 'code';
|
|
102
|
+
out += ' ';
|
|
103
|
+
i += 2;
|
|
104
|
+
} else {
|
|
105
|
+
out += ch === '\n' ? '\n' : ' ';
|
|
106
|
+
i += 1;
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// string / template states: copy verbatim, honor escapes, exit on matching quote
|
|
111
|
+
out += ch;
|
|
112
|
+
if (ch === '\\') {
|
|
113
|
+
out += next !== undefined ? next : '';
|
|
114
|
+
i += 2;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (
|
|
118
|
+
(state === 'sq' && ch === "'") ||
|
|
119
|
+
(state === 'dq' && ch === '"') ||
|
|
120
|
+
(state === 'tpl' && ch === '`')
|
|
121
|
+
) {
|
|
122
|
+
state = 'code';
|
|
123
|
+
}
|
|
124
|
+
i += 1;
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function analyzeContent(relPath, content) {
|
|
130
|
+
const findings = [];
|
|
131
|
+
const scannable = stripComments(content);
|
|
132
|
+
const lines = scannable.split(/\r?\n/);
|
|
133
|
+
|
|
134
|
+
for (const rule of HARD_RULES) {
|
|
135
|
+
lines.forEach((line, index) => {
|
|
136
|
+
if (rule.pattern.test(line)) {
|
|
137
|
+
findings.push({
|
|
138
|
+
file: relPath,
|
|
139
|
+
line: index + 1,
|
|
140
|
+
severity: 'error',
|
|
141
|
+
ruleId: rule.id,
|
|
142
|
+
message: rule.message,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (SOFT_LAUNCH_PRIMITIVES.test(scannable)) {
|
|
149
|
+
findings.push({
|
|
150
|
+
file: relPath,
|
|
151
|
+
line: 0,
|
|
152
|
+
severity: 'warning',
|
|
153
|
+
ruleId: 'cross-platform-launch-touched',
|
|
154
|
+
message:
|
|
155
|
+
'涉及浏览器/URL 拉起代码。CI 只跑纯函数单测,不覆盖真实系统拉起——发布前请在 Windows / macOS / Linux 各自实测 login 与 bridge 页面唤起。',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return findings;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function analyzeFiles(files) {
|
|
163
|
+
const findings = [];
|
|
164
|
+
for (const f of files) {
|
|
165
|
+
findings.push(...analyzeContent(f.path, f.content));
|
|
166
|
+
}
|
|
167
|
+
const errorCount = findings.filter((x) => x.severity === 'error').length;
|
|
168
|
+
const warnCount = findings.filter((x) => x.severity === 'warning').length;
|
|
169
|
+
return { findings, errorCount, warnCount };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function collectSourceFiles(root = REPO_ROOT, dirs = SCAN_DIRS) {
|
|
173
|
+
const out = [];
|
|
174
|
+
const walk = (abs) => {
|
|
175
|
+
let entries = [];
|
|
176
|
+
try {
|
|
177
|
+
entries = fs.readdirSync(abs, { withFileTypes: true });
|
|
178
|
+
} catch {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
for (const entry of entries) {
|
|
182
|
+
const full = path.join(abs, entry.name);
|
|
183
|
+
if (entry.isDirectory()) {
|
|
184
|
+
if (entry.name === 'node_modules' || entry.name === '.git') {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
walk(full);
|
|
188
|
+
} else if (entry.isFile() && entry.name.endsWith('.js')) {
|
|
189
|
+
out.push({
|
|
190
|
+
path: path.relative(root, full),
|
|
191
|
+
content: fs.readFileSync(full, 'utf8'),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
for (const dir of dirs) {
|
|
197
|
+
walk(path.join(root, dir));
|
|
198
|
+
}
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function formatFindings({ findings, errorCount, warnCount }) {
|
|
203
|
+
const lines = [];
|
|
204
|
+
const errors = findings.filter((x) => x.severity === 'error');
|
|
205
|
+
const warnings = findings.filter((x) => x.severity === 'warning');
|
|
206
|
+
|
|
207
|
+
if (errors.length) {
|
|
208
|
+
lines.push('发布风险检查:发现 HARD 反模式(阻断发布)');
|
|
209
|
+
for (const f of errors) {
|
|
210
|
+
lines.push(` ✗ [${f.ruleId}] ${f.file}:${f.line}`);
|
|
211
|
+
lines.push(` ${f.message}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (warnings.length) {
|
|
216
|
+
lines.push('发布风险检查:跨端人工验证提醒(不阻断)');
|
|
217
|
+
const byFile = new Set(warnings.map((w) => w.file));
|
|
218
|
+
for (const file of byFile) {
|
|
219
|
+
lines.push(` ⚠ ${file}`);
|
|
220
|
+
}
|
|
221
|
+
lines.push(
|
|
222
|
+
' 涉及浏览器/URL 拉起:请在 Windows / macOS / Linux 各自实测 openyida login 与 bridge 页面唤起。'
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
lines.push('');
|
|
227
|
+
lines.push(`发布风险检查完成:error=${errorCount}, warning=${warnCount}`);
|
|
228
|
+
return lines.join('\n');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function main() {
|
|
232
|
+
const result = analyzeFiles(collectSourceFiles());
|
|
233
|
+
process.stdout.write(`${formatFindings(result)}\n`);
|
|
234
|
+
if (result.errorCount > 0) {
|
|
235
|
+
process.stdout.write(
|
|
236
|
+
'\n存在阻断发布的 HARD 反模式,请修复后重试(详见 .qoder/skills 跨端发布风险技能)。\n'
|
|
237
|
+
);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
process.exit(0);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (require.main === module) {
|
|
244
|
+
main();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
HARD_RULES,
|
|
249
|
+
SOFT_LAUNCH_PRIMITIVES,
|
|
250
|
+
analyzeContent,
|
|
251
|
+
analyzeFiles,
|
|
252
|
+
collectSourceFiles,
|
|
253
|
+
formatFindings,
|
|
254
|
+
};
|
|
@@ -49,7 +49,12 @@ function getByPath(object, keyPath) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function translate(locale, key) {
|
|
52
|
-
|
|
52
|
+
const value = getByPath(locale, key);
|
|
53
|
+
if (!value) {
|
|
54
|
+
console.warn('[generate-command-docs] 缺失翻译,已回退为 key:' + key);
|
|
55
|
+
return key;
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
function escapeTableCell(value) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"base": "zh",
|
|
3
|
-
"basePathCount":
|
|
3
|
+
"basePathCount": 1392,
|
|
4
4
|
"locales": {
|
|
5
5
|
"ar": {
|
|
6
|
-
"missing":
|
|
6
|
+
"missing": 697,
|
|
7
7
|
"typeMismatch": 0
|
|
8
8
|
},
|
|
9
9
|
"de": {
|
|
10
|
-
"missing":
|
|
10
|
+
"missing": 697,
|
|
11
11
|
"typeMismatch": 0
|
|
12
12
|
},
|
|
13
13
|
"en": {
|
|
@@ -15,35 +15,35 @@
|
|
|
15
15
|
"typeMismatch": 0
|
|
16
16
|
},
|
|
17
17
|
"es": {
|
|
18
|
-
"missing":
|
|
18
|
+
"missing": 697,
|
|
19
19
|
"typeMismatch": 0
|
|
20
20
|
},
|
|
21
21
|
"fr": {
|
|
22
|
-
"missing":
|
|
22
|
+
"missing": 697,
|
|
23
23
|
"typeMismatch": 0
|
|
24
24
|
},
|
|
25
25
|
"hi": {
|
|
26
|
-
"missing":
|
|
26
|
+
"missing": 697,
|
|
27
27
|
"typeMismatch": 0
|
|
28
28
|
},
|
|
29
29
|
"ja": {
|
|
30
|
-
"missing":
|
|
30
|
+
"missing": 396,
|
|
31
31
|
"typeMismatch": 0
|
|
32
32
|
},
|
|
33
33
|
"ko": {
|
|
34
|
-
"missing":
|
|
34
|
+
"missing": 696,
|
|
35
35
|
"typeMismatch": 0
|
|
36
36
|
},
|
|
37
37
|
"pt": {
|
|
38
|
-
"missing":
|
|
38
|
+
"missing": 697,
|
|
39
39
|
"typeMismatch": 0
|
|
40
40
|
},
|
|
41
41
|
"vi": {
|
|
42
|
-
"missing":
|
|
42
|
+
"missing": 697,
|
|
43
43
|
"typeMismatch": 0
|
|
44
44
|
},
|
|
45
45
|
"zh-HK": {
|
|
46
|
-
"missing":
|
|
46
|
+
"missing": 356,
|
|
47
47
|
"typeMismatch": 0
|
|
48
48
|
}
|
|
49
49
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -224,28 +224,24 @@ npm install -g openyida@latest
|
|
|
224
224
|
若登录态无效,执行:
|
|
225
225
|
|
|
226
226
|
\`\`\`bash
|
|
227
|
-
openyida login
|
|
227
|
+
openyida login
|
|
228
228
|
\`\`\`
|
|
229
229
|
|
|
230
|
-
登录完成后再次运行 \`openyida login --check-only --json\`
|
|
230
|
+
登录完成后再次运行 \`openyida login --check-only --json\` 验证 token session,再继续真实资源操作。
|
|
231
231
|
|
|
232
232
|
## Codex Browser 边界
|
|
233
233
|
|
|
234
234
|
Codex App 的 in-app browser / \`@Browser\` 适合打开本地开发服务器、file-backed preview 和无需登录的公开页面,用于截图、点击和检查渲染状态。
|
|
235
235
|
|
|
236
|
-
不要把 Codex in-app browser 用作宜搭登录 Cookie
|
|
236
|
+
不要把 Codex in-app browser 用作宜搭登录 Cookie 来源:OpenYida CLI 登录使用 OAuth loopback + token session,不需要导出或手写 Cookie。
|
|
237
237
|
|
|
238
|
-
需要登录并获得 CLI
|
|
238
|
+
需要登录并获得 CLI token session 时,优先运行:
|
|
239
239
|
|
|
240
240
|
\`\`\`bash
|
|
241
|
-
openyida login
|
|
241
|
+
openyida login
|
|
242
242
|
\`\`\`
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
在 Codex 中如果 \`openyida login --codex-poll\` 返回 \`need_corp_selection\`,优先调用 OpenYida MCP 工具
|
|
247
|
-
\`select_yida_login_organization\`,传入返回值里的 \`session_file\`。该工具会通过 MCP \`elicitation/create\`
|
|
248
|
-
展示 Codex 原生组织单选控件,并在用户选择后完成 \`openyida login --codex-select\`。
|
|
244
|
+
\`openyida login\` 会通过 OAuth loopback 打开常规本地浏览器;如需抑制自动打开浏览器,可设置环境变量 \`OPENYIDA_NO_BROWSER=1\`。只有在需要纯浏览器预览或检查公开页面时才使用 \`@Browser\`。
|
|
249
245
|
|
|
250
246
|
## 工作目录
|
|
251
247
|
|
|
@@ -279,8 +275,8 @@ fast_build 页面源码默认不得使用 \`this.dataSourceMap.*\`,除非本
|
|
|
279
275
|
| \`yida-skills/analytics\` | 报表、统计、图表、ECharts、看板、驾驶舱 | \`yida-report\`, \`yida-chart\`, \`yida-dashboard\` |
|
|
280
276
|
| \`yida-skills/integration\` | 连接器、外部 API、数据源、集成自动化 | \`yida-integration\`, \`yida-connector\`, \`yida-connector-safe-actions\`, \`yida-data-source-connectors\` |
|
|
281
277
|
| \`yida-skills/access\` | 平台/应用/表单/页面权限、公开访问、分享 | \`yida-corp-manager\`, \`yida-app-permission\`, \`yida-form-permission\`, \`yida-page-config\` |
|
|
282
|
-
| \`yida-skills/ops\` |
|
|
283
|
-
| \`yida-skills/agent\` |
|
|
278
|
+
| \`yida-skills/ops\` | Sequence、VOC | \`yida-db-seq-fix\`, \`yida-voc\` |
|
|
279
|
+
| \`yida-skills/agent\` | 导出对话、会议纪要/闪记转 PRD | \`yida-export-conversation\`, \`yida-flash-note-to-prd\` |
|
|
284
280
|
|
|
285
281
|
## 执行规则
|
|
286
282
|
|
package/scripts/validate-ci.sh
CHANGED
|
@@ -17,25 +17,25 @@ echo "=== Step 2: Validate project structure ==="
|
|
|
17
17
|
npm run check:structure
|
|
18
18
|
|
|
19
19
|
echo ""
|
|
20
|
-
echo "=== Step 3:
|
|
20
|
+
echo "=== Step 3: Build Wukong skills package ==="
|
|
21
|
+
npm run build:skills
|
|
22
|
+
|
|
23
|
+
echo ""
|
|
24
|
+
echo "=== Step 4: Validate skills ==="
|
|
21
25
|
npm run check:skills
|
|
22
26
|
|
|
23
27
|
echo ""
|
|
24
|
-
echo "=== Step
|
|
28
|
+
echo "=== Step 5: Validate command manifest ==="
|
|
25
29
|
npm run check:commands
|
|
26
30
|
|
|
27
31
|
echo ""
|
|
28
|
-
echo "=== Step
|
|
32
|
+
echo "=== Step 6: Validate generated command docs ==="
|
|
29
33
|
npm run check:docs
|
|
30
34
|
|
|
31
35
|
echo ""
|
|
32
|
-
echo "=== Step
|
|
36
|
+
echo "=== Step 7: Validate i18n locale parity (ratchet) ==="
|
|
33
37
|
npm run check:i18n
|
|
34
38
|
|
|
35
|
-
echo ""
|
|
36
|
-
echo "=== Step 7: Build Wukong skills package ==="
|
|
37
|
-
npm run build:skills
|
|
38
|
-
|
|
39
39
|
echo ""
|
|
40
40
|
echo "=== Step 8: Check JavaScript syntax ==="
|
|
41
41
|
npm run check:syntax
|
|
@@ -45,15 +45,19 @@ echo "=== Step 9: Run lint ==="
|
|
|
45
45
|
npm run lint
|
|
46
46
|
|
|
47
47
|
echo ""
|
|
48
|
-
echo "=== Step 10:
|
|
48
|
+
echo "=== Step 10: Scan cross-platform release risks ==="
|
|
49
|
+
npm run check:release-risks
|
|
50
|
+
|
|
51
|
+
echo ""
|
|
52
|
+
echo "=== Step 11: Run tests ==="
|
|
49
53
|
npm run test:unit -- --runInBand
|
|
50
54
|
|
|
51
55
|
echo ""
|
|
52
|
-
echo "=== Step
|
|
56
|
+
echo "=== Step 12: Validate npm package size budget ==="
|
|
53
57
|
npm run check:package-size
|
|
54
58
|
|
|
55
59
|
echo ""
|
|
56
|
-
echo "=== Step
|
|
60
|
+
echo "=== Step 13: Validate npm package contents ==="
|
|
57
61
|
npm run check:package
|
|
58
62
|
|
|
59
63
|
echo ""
|
package/scripts/validate-i18n.js
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* i18n 语言包一致性校验
|
|
7
7
|
*
|
|
8
|
-
* 以 zh
|
|
8
|
+
* 以 zh(源语言)为基准,校验核心语言包和 locales-extra/core 下可选语言包的 key 是否对齐:
|
|
9
9
|
* - 基准中存在但目标语言缺失的 key -> 错误(会 fallback 到其它语言,用户可见)
|
|
10
10
|
* - 目标语言多出的 key -> 警告(可能是残留 / 拼写错误)
|
|
11
11
|
* - 叶子/分支类型不一致(string vs object)-> 错误
|
|
12
12
|
*
|
|
13
13
|
* 用法:
|
|
14
14
|
* node scripts/validate-i18n.js # 严格模式:任意缺失则退出码 1(本地全量审计)
|
|
15
|
-
* node scripts/validate-i18n.js --check #
|
|
15
|
+
* node scripts/validate-i18n.js --check # 棘轮模式:核心语言漂移超过基线时失败(CI 用)
|
|
16
16
|
* node scripts/validate-i18n.js --update-baseline # 将当前漂移写入基线
|
|
17
17
|
* node scripts/validate-i18n.js --json # 输出机器可读结果
|
|
18
18
|
*/
|
|
@@ -22,22 +22,42 @@ const path = require('path');
|
|
|
22
22
|
|
|
23
23
|
const ROOT = path.resolve(__dirname, '..');
|
|
24
24
|
const LOCALES_DIR = path.join(ROOT, 'lib', 'core', 'locales');
|
|
25
|
+
const EXTRA_LOCALES_DIR = path.join(ROOT, 'locales-extra', 'core');
|
|
25
26
|
const BASELINE_FILE = path.join(__dirname, 'i18n-baseline.json');
|
|
26
27
|
const BASE_LOCALE = 'zh';
|
|
28
|
+
const CORE_CHECK_LOCALES = new Set(['en']);
|
|
29
|
+
|
|
30
|
+
function resolveLocaleFile(name) {
|
|
31
|
+
const coreFile = path.join(LOCALES_DIR, `${name}.js`);
|
|
32
|
+
if (fs.existsSync(coreFile)) {
|
|
33
|
+
return coreFile;
|
|
34
|
+
}
|
|
35
|
+
const extraFile = path.join(EXTRA_LOCALES_DIR, `${name}.js`);
|
|
36
|
+
if (fs.existsSync(extraFile)) {
|
|
37
|
+
return extraFile;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
27
41
|
|
|
28
42
|
function loadLocale(name) {
|
|
29
43
|
// 清除 require 缓存,保证多次运行结果稳定
|
|
30
|
-
const file =
|
|
44
|
+
const file = resolveLocaleFile(name);
|
|
45
|
+
if (!file) {
|
|
46
|
+
throw new Error(`Locale not found: ${name}`);
|
|
47
|
+
}
|
|
31
48
|
delete require.cache[require.resolve(file)];
|
|
32
49
|
return require(file);
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
function listLocales() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
.
|
|
40
|
-
|
|
53
|
+
const localeNames = new Set();
|
|
54
|
+
[LOCALES_DIR, EXTRA_LOCALES_DIR].forEach((dir) => {
|
|
55
|
+
if (!fs.existsSync(dir)) { return; }
|
|
56
|
+
fs.readdirSync(dir)
|
|
57
|
+
.filter((f) => f.endsWith('.js'))
|
|
58
|
+
.forEach((f) => localeNames.add(f.replace(/\.js$/, '')));
|
|
59
|
+
});
|
|
60
|
+
return [...localeNames].sort();
|
|
41
61
|
}
|
|
42
62
|
|
|
43
63
|
/**
|
|
@@ -147,6 +167,7 @@ function main() {
|
|
|
147
167
|
}
|
|
148
168
|
const regressions = [];
|
|
149
169
|
Object.keys(report).forEach((name) => {
|
|
170
|
+
if (!CORE_CHECK_LOCALES.has(name)) { return; }
|
|
150
171
|
const base = baseline.locales[name] || { missing: 0, typeMismatch: 0 };
|
|
151
172
|
if (report[name].missing.length > base.missing) {
|
|
152
173
|
regressions.push(`${name} 缺失 ${base.missing} → ${report[name].missing.length}`);
|
|
@@ -160,7 +181,7 @@ function main() {
|
|
|
160
181
|
console.error('(存量缺失作为跟踪项,补齐后运行 --update-baseline 收紧基线)');
|
|
161
182
|
process.exit(1);
|
|
162
183
|
}
|
|
163
|
-
console.log('\n[i18n]
|
|
184
|
+
console.log('\n[i18n] 棘轮校验通过:核心语言无新增漂移 ✓(可选语言同步参与结构校验)');
|
|
164
185
|
return;
|
|
165
186
|
}
|
|
166
187
|
|
|
@@ -12,7 +12,7 @@ const path = require('path');
|
|
|
12
12
|
// per-file cap stays fixed to catch accidental large-blob embeds.
|
|
13
13
|
const MAX_TARBALL_BYTES = 1792 * 1024;
|
|
14
14
|
const MAX_UNPACKED_BYTES = 5632 * 1024;
|
|
15
|
-
const MAX_ENTRY_COUNT =
|
|
15
|
+
const MAX_ENTRY_COUNT = 433;
|
|
16
16
|
const MAX_SINGLE_FILE_BYTES = 512 * 1024;
|
|
17
17
|
|
|
18
18
|
function formatBytes(bytes) {
|
|
@@ -32,7 +32,10 @@ function fail(message) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function resolveNpmBin() {
|
|
35
|
-
|
|
35
|
+
if (process.env.OPENYIDA_NPM_BIN) {
|
|
36
|
+
return process.env.OPENYIDA_NPM_BIN;
|
|
37
|
+
}
|
|
38
|
+
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
function runNpmPackDryRun() {
|
|
@@ -41,6 +41,21 @@ if (!nodeEngine) {
|
|
|
41
41
|
}
|
|
42
42
|
console.log('engines.node: ' + nodeEngine);
|
|
43
43
|
|
|
44
|
+
if (fs.existsSync('package-lock.json')) {
|
|
45
|
+
const packageLock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8'));
|
|
46
|
+
const lockVersions = [
|
|
47
|
+
['package-lock.json version', packageLock.version],
|
|
48
|
+
['package-lock root package version', packageLock.packages && packageLock.packages[''] && packageLock.packages[''].version],
|
|
49
|
+
];
|
|
50
|
+
for (const pair of lockVersions) {
|
|
51
|
+
if (pair[1] !== packageJson.version) {
|
|
52
|
+
console.error(`${pair[0]} (${pair[1] || 'missing'}) does not match package.json version (${packageJson.version})`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
console.log('package-lock version: ' + packageLock.version);
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
const skillsDir = 'yida-skills/skills';
|
|
45
60
|
if (fs.existsSync(skillsDir)) {
|
|
46
61
|
const skills = fs.readdirSync(skillsDir).filter(function(name) {
|