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.
Files changed (200) hide show
  1. package/README.md +37 -2
  2. package/bin/yida.js +113 -18
  3. package/docs/capabilities.md +202 -0
  4. package/lib/agent-center/agent-center.js +2 -3
  5. package/lib/app/app-list.js +3 -4
  6. package/lib/app/build-page.js +13 -6
  7. package/lib/app/check-page.js +16 -6
  8. package/lib/app/compile.js +17 -7
  9. package/lib/app/create-app.js +14 -2
  10. package/lib/app/create-form/api-path.js +25 -0
  11. package/lib/app/create-form/args.js +13 -0
  12. package/lib/app/create-form/commands.js +4 -0
  13. package/lib/app/create-form/definition-reader.js +23 -23
  14. package/lib/app/create-form/field-normalizers.js +26 -7
  15. package/lib/app/create-form/schema-patch.js +4 -1
  16. package/lib/app/create-form.js +155 -68
  17. package/lib/app/create-page.js +47 -10
  18. package/lib/app/generate-page.js +20 -1
  19. package/lib/app/get-form-config.js +2 -1
  20. package/lib/app/get-schema.js +67 -15
  21. package/lib/app/import-app.js +94 -42
  22. package/lib/app/list-forms.js +4 -8
  23. package/lib/app/page-ir.js +140 -0
  24. package/lib/app/publish.js +289 -556
  25. package/lib/app/schema-field-resolution.js +370 -0
  26. package/lib/app/services/app-reader.js +85 -0
  27. package/lib/app/services/app-service.js +235 -0
  28. package/lib/app/services/canvas-page-compiler.js +91 -0
  29. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  30. package/lib/app/services/field-bindings.js +68 -0
  31. package/lib/app/services/form-compiler.js +1922 -0
  32. package/lib/app/services/form-mode-service.js +182 -0
  33. package/lib/app/services/form-schema-patcher.js +333 -0
  34. package/lib/app/services/form-schema-reader.js +59 -0
  35. package/lib/app/services/form-service.js +379 -0
  36. package/lib/app/services/form-validation.js +562 -0
  37. package/lib/app/services/native-page-compiler.js +92 -0
  38. package/lib/app/services/native-page-schema-builder.js +428 -0
  39. package/lib/app/services/page-resource-service.js +185 -0
  40. package/lib/app/update-app.js +22 -9
  41. package/lib/app/update-form-config.js +4 -2
  42. package/lib/asset/asset-cmd.js +19 -6
  43. package/lib/auth/oauth-loopback.js +376 -15
  44. package/lib/auth/token-auth.js +34 -3
  45. package/lib/auth/token-store.js +22 -4
  46. package/lib/basic-info/basic-info.js +2 -1
  47. package/lib/bridge/bridge.js +43 -18
  48. package/lib/core/agent-capabilities.js +5 -3
  49. package/lib/core/command-errors.js +38 -0
  50. package/lib/core/command-manifest.js +59 -1
  51. package/lib/core/copy.js +12 -0
  52. package/lib/core/doctor.js +15 -4
  53. package/lib/core/env-cmd.js +1 -1
  54. package/lib/core/env.js +7 -6
  55. package/lib/core/i18n.js +66 -8
  56. package/lib/core/legacy-schema-guard.js +408 -0
  57. package/lib/core/locales/en.js +38 -46
  58. package/lib/core/locales/zh.js +30 -46
  59. package/lib/core/sample.js +12 -2
  60. package/lib/core/utils.js +334 -66
  61. package/lib/core/yida-client.js +108 -5
  62. package/lib/corp-efficiency/corp-efficiency.js +2 -2
  63. package/lib/corp-manager/corp-manager.js +3 -3
  64. package/lib/formula/evaluate.js +11 -68
  65. package/lib/formula/field-refs.js +83 -0
  66. package/lib/i18n-management/i18n-management.js +2 -3
  67. package/lib/process/configure-process.js +44 -1992
  68. package/lib/process/create-process.js +54 -87
  69. package/lib/process/preview-process.js +20 -8
  70. package/lib/process/services/process-compiler.js +2056 -0
  71. package/lib/process/services/process-reader.js +232 -0
  72. package/lib/process/services/process-resource-service.js +571 -0
  73. package/lib/process/services/process-service.js +122 -0
  74. package/lib/process/services/process-stage-checkpoint.js +246 -0
  75. package/lib/report/append.js +7 -26
  76. package/lib/report/http.js +31 -5
  77. package/lib/report/index.js +10 -2
  78. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  79. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  80. package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
  81. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  82. package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
  83. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
  84. package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
  85. package/lib/samples/yida-custom-page/design-tokens.js +2 -2
  86. package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
  87. package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
  88. package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
  89. package/lib/schema/adapters/app-adapter.js +210 -0
  90. package/lib/schema/adapters/form-adapter.js +1362 -0
  91. package/lib/schema/adapters/keys.js +19 -0
  92. package/lib/schema/adapters/page-adapter.js +566 -0
  93. package/lib/schema/adapters/process-adapter.js +519 -0
  94. package/lib/schema/applier.js +1878 -0
  95. package/lib/schema/apply-store.js +1083 -0
  96. package/lib/schema/command.js +645 -0
  97. package/lib/schema/dependency-graph.js +83 -0
  98. package/lib/schema/errors.js +481 -0
  99. package/lib/schema/hash.js +9 -0
  100. package/lib/schema/manifest-limits.js +177 -0
  101. package/lib/schema/manifest-loader.js +309 -0
  102. package/lib/schema/manifest-schema-v1.json +193 -0
  103. package/lib/schema/normalize-manifest.js +281 -0
  104. package/lib/schema/page-canvas-foundation.js +447 -0
  105. package/lib/schema/page-data-source-builder.js +561 -0
  106. package/lib/schema/page-foundation.js +556 -0
  107. package/lib/schema/page-source-loader.js +314 -0
  108. package/lib/schema/planner.js +691 -0
  109. package/lib/schema/remote-dispatch-boundary.js +39 -0
  110. package/lib/schema/remote-missing.js +21 -0
  111. package/lib/schema/remote-reader.js +189 -0
  112. package/lib/schema/resource-registry.js +157 -0
  113. package/lib/schema/server-revision.js +71 -0
  114. package/lib/schema/sort.js +28 -0
  115. package/lib/schema/state-store.js +589 -0
  116. package/package.json +10 -8
  117. package/scripts/check-release-risks.js +254 -0
  118. package/scripts/generate-command-docs.js +6 -1
  119. package/scripts/i18n-baseline.json +11 -11
  120. package/scripts/postinstall.js +8 -12
  121. package/scripts/validate-ci.sh +15 -11
  122. package/scripts/validate-i18n.js +30 -9
  123. package/scripts/validate-package-size.js +5 -2
  124. package/scripts/validate-skills.js +4 -0
  125. package/scripts/validate-structure.js +15 -0
  126. package/yida-skills/SKILL.md +117 -30
  127. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  128. package/yida-skills/references/setup-and-env.md +59 -59
  129. package/yida-skills/references/task-retrospective.md +6 -6
  130. package/yida-skills/skills/yida-app/SKILL.md +78 -17
  131. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
  132. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  133. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
  134. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  135. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  136. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  137. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  138. package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
  139. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  140. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  141. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  142. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  143. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  144. package/yida-skills/skills/yida-login/SKILL.md +50 -99
  145. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  146. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  147. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  148. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  149. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  150. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  151. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  152. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  153. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  154. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  155. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  156. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  157. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  158. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  159. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  160. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  161. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  162. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  163. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  164. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  165. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  166. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  167. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  168. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  169. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  170. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  171. package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
  172. package/yida-skills/skills/yida-report/SKILL.md +9 -235
  173. package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
  174. package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
  175. package/yida-skills/skills-index.json +238 -54
  176. package/lib/core/locales/ar.js +0 -834
  177. package/lib/core/locales/de.js +0 -834
  178. package/lib/core/locales/es.js +0 -834
  179. package/lib/core/locales/fr.js +0 -834
  180. package/lib/core/locales/hi.js +0 -834
  181. package/lib/core/locales/ja.js +0 -1227
  182. package/lib/core/locales/ko.js +0 -836
  183. package/lib/core/locales/pt.js +0 -834
  184. package/lib/core/locales/vi.js +0 -834
  185. package/lib/core/locales/zh-HK.js +0 -1263
  186. package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
  187. package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
  188. package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
  189. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
  190. package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
  191. package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
  192. package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
  193. package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
  194. package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
  195. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  196. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  197. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  198. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  199. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  200. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
@@ -0,0 +1,589 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const crypto = require('crypto');
6
+ const { schemaError } = require('./errors');
7
+ const { createDefaultRegistry } = require('./resource-registry');
8
+ const { compareCodePoints } = require('./sort');
9
+ const { canonicalizeKey, stableStringify } = require('./normalize-manifest');
10
+
11
+ const STATE_KIND = 'openyida_resource_state';
12
+ const STATE_CONTRACT_VERSION = 1;
13
+ const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
14
+ const ATOMIC_NONCE_PATTERN = /^[a-f0-9]{24}$/;
15
+ const ENVIRONMENT_SCOPE_TOKEN = 'openyida-schema-unscoped-internal';
16
+
17
+ const SENSITIVE_STATE_KEY_CANONICALS = new Set([
18
+ 'apikey',
19
+ 'authorization',
20
+ 'clientsecret',
21
+ 'cookie',
22
+ 'cookies',
23
+ 'credential',
24
+ 'credentials',
25
+ 'csrf',
26
+ 'csrftoken',
27
+ 'header',
28
+ 'headers',
29
+ 'internalpath',
30
+ 'internalurl',
31
+ 'password',
32
+ 'refreshtoken',
33
+ 'secret',
34
+ 'token',
35
+ ]);
36
+
37
+ const REAL_ID_KEY_CANONICALS = new Set([
38
+ 'apptype',
39
+ 'fieldid',
40
+ 'formuuid',
41
+ 'nodeid',
42
+ 'processcode',
43
+ 'processid',
44
+ 'processversion',
45
+ ]);
46
+
47
+ function resolveDefaultStatePath(cwd) {
48
+ return path.join(cwd || process.cwd(), '.cache', 'openyida', 'state.v1.json');
49
+ }
50
+
51
+ function createSha256(value) {
52
+ return 'sha256:' + crypto
53
+ .createHash('sha256')
54
+ .update(String(value === undefined || value === null ? '' : value))
55
+ .digest('hex');
56
+ }
57
+
58
+ function hashStable(value) {
59
+ return createSha256(stableStringify(value));
60
+ }
61
+
62
+ function createEnvironmentIdentity(input = {}, options = {}) {
63
+ if (input && input.environmentKey && input.corpIdHash) {
64
+ assertHash(input.environmentKey, 'environmentKey', '/environment/environmentKey');
65
+ assertHash(input.corpIdHash, 'corpIdHash', '/environment/corpIdHash');
66
+ return {
67
+ environmentKey: input.environmentKey,
68
+ corpIdHash: input.corpIdHash,
69
+ };
70
+ }
71
+
72
+ if (options.allowUnscopedEnvironment === true) {
73
+ return {
74
+ environmentKey: createSha256(`${ENVIRONMENT_SCOPE_TOKEN}:environment`),
75
+ corpIdHash: createSha256(`${ENVIRONMENT_SCOPE_TOKEN}:corp`),
76
+ };
77
+ }
78
+
79
+ const endpoint = input && (input.endpoint !== undefined ? input.endpoint : input.baseUrl);
80
+ const corpId = input && input.corpId;
81
+ if (!hasNonEmptyString(endpoint) || !hasNonEmptyString(corpId)) {
82
+ throw schemaError('SCHEMA_STATE_ENVIRONMENT_REQUIRED', 'State operations require endpoint/environmentKey and corpId/corpIdHash.', {
83
+ path: '/environment',
84
+ });
85
+ }
86
+
87
+ return {
88
+ environmentKey: createSha256(normalizeEndpoint(endpoint)),
89
+ corpIdHash: createSha256(corpId),
90
+ };
91
+ }
92
+
93
+ function createEmptyState(environmentInput, options = {}) {
94
+ const environment = createEnvironmentIdentity(environmentInput, options);
95
+ const state = {
96
+ kind: STATE_KIND,
97
+ contractVersion: STATE_CONTRACT_VERSION,
98
+ revision: 0,
99
+ environment,
100
+ resources: {},
101
+ };
102
+ if (options.manifestHash !== undefined) {
103
+ assertHash(options.manifestHash, 'manifestHash', '/manifestHash');
104
+ state.manifestHash = options.manifestHash;
105
+ }
106
+ validateStateShape(state, {
107
+ registry: options.registry,
108
+ });
109
+ return state;
110
+ }
111
+
112
+ function readState(statePath, options = {}) {
113
+ const fsImpl = options.fsImpl || fs;
114
+ const environment = createEnvironmentIdentity(options.environment, options);
115
+
116
+ let exists;
117
+ try {
118
+ exists = fsImpl.existsSync(statePath);
119
+ } catch (error) {
120
+ throw schemaError('SCHEMA_STATE_READ_FAILED', 'State file could not be read.', {
121
+ details: { operation: 'exists' },
122
+ });
123
+ }
124
+
125
+ if (!exists) {
126
+ return createEmptyState(environment, {
127
+ manifestHash: options.manifestHash,
128
+ registry: options.registry,
129
+ });
130
+ }
131
+
132
+ let raw;
133
+ try {
134
+ raw = fsImpl.readFileSync(statePath, 'utf8');
135
+ } catch (error) {
136
+ throw schemaError('SCHEMA_STATE_READ_FAILED', 'State file could not be read.', {
137
+ details: { operation: 'read' },
138
+ });
139
+ }
140
+
141
+ let parsed;
142
+ try {
143
+ parsed = JSON.parse(raw);
144
+ } catch (error) {
145
+ throw schemaError('SCHEMA_STATE_INVALID', 'State file is not valid JSON.', {
146
+ details: { reason: 'invalid_json' },
147
+ });
148
+ }
149
+
150
+ validateState(parsed, {
151
+ environment,
152
+ registry: options.registry,
153
+ });
154
+ return parsed;
155
+ }
156
+
157
+ function writeStateAtomic(statePath, state, options = {}) {
158
+ const fsImpl = options.fsImpl || fs;
159
+ const environment = createEnvironmentIdentity(options.environment, options);
160
+ const nextState = prepareStateForWrite(state, {
161
+ environment,
162
+ incrementRevision: options.incrementRevision,
163
+ registry: options.registry,
164
+ });
165
+ const dir = path.dirname(statePath);
166
+ const data = stableStringify(nextState) + '\n';
167
+ let fd;
168
+ let tmpPath;
169
+ let tempCreated = false;
170
+
171
+ try {
172
+ tmpPath = createAtomicTempPath(statePath, options);
173
+ fsImpl.mkdirSync(dir, { recursive: true, mode: 0o700 });
174
+ fd = fsImpl.openSync(tmpPath, 'wx', 0o600);
175
+ tempCreated = true;
176
+ fsImpl.writeFileSync(fd, data, 'utf8');
177
+ if (typeof fsImpl.fsyncSync === 'function') {
178
+ fsImpl.fsyncSync(fd);
179
+ }
180
+ fsImpl.closeSync(fd);
181
+ fd = undefined;
182
+ fsImpl.renameSync(tmpPath, statePath);
183
+ fsyncDirectoryBestEffort(fsImpl, dir);
184
+ return nextState;
185
+ } catch (error) {
186
+ if (fd !== undefined) {
187
+ try {
188
+ fsImpl.closeSync(fd);
189
+ } catch (closeError) {
190
+ // Best effort cleanup.
191
+ }
192
+ }
193
+ try {
194
+ if (tempCreated && tmpPath && fsImpl.existsSync(tmpPath)) {
195
+ fsImpl.unlinkSync(tmpPath);
196
+ }
197
+ } catch (unlinkError) {
198
+ // Best effort cleanup.
199
+ }
200
+ throw schemaError('SCHEMA_STATE_WRITE_FAILED', 'State file could not be written atomically.', {
201
+ details: { operation: 'atomic_write' },
202
+ });
203
+ }
204
+ }
205
+
206
+ function createAtomicTempPath(targetPath, options = {}) {
207
+ const dir = path.dirname(targetPath);
208
+ const base = path.basename(targetPath);
209
+ const pid = options.atomicProcessId === undefined ? process.pid : options.atomicProcessId;
210
+ const now = options.atomicNow === undefined ? Date.now() : options.atomicNow;
211
+ const nonce = options.atomicNonce || crypto.randomBytes(12).toString('hex');
212
+ if (
213
+ !Number.isInteger(pid) || pid <= 0 ||
214
+ !Number.isSafeInteger(now) || now < 0 ||
215
+ !ATOMIC_NONCE_PATTERN.test(nonce)
216
+ ) {
217
+ throw new Error('invalid atomic temp identity');
218
+ }
219
+ return path.join(dir, `.${base}.${pid}.${now}.${nonce}.tmp`);
220
+ }
221
+
222
+ function prepareStateForWrite(state, options = {}) {
223
+ const nextState = clonePlain(state);
224
+ validateState(nextState, {
225
+ environment: options.environment,
226
+ registry: options.registry,
227
+ });
228
+ nextState.revision += options.incrementRevision === false ? 0 : 1;
229
+ validateState(nextState, {
230
+ environment: options.environment,
231
+ registry: options.registry,
232
+ });
233
+ return nextState;
234
+ }
235
+
236
+ function validateState(state, options = {}) {
237
+ const environment = options.environment
238
+ ? createEnvironmentIdentity(options.environment, options)
239
+ : createEnvironmentIdentity(options.environmentInput, options);
240
+ validateStateShape(state, {
241
+ registry: options.registry,
242
+ });
243
+ assertEnvironmentMatches(state.environment, environment);
244
+ }
245
+
246
+ function validateStateShape(state, options = {}) {
247
+ const registry = options.registry || createDefaultRegistry();
248
+ if (!state || typeof state !== 'object' || Array.isArray(state)) {
249
+ throw schemaError('SCHEMA_STATE_INVALID', 'State file must be a JSON object.');
250
+ }
251
+ validateForbiddenStateKeys(state);
252
+ assertAllowedKeys(state, ['kind', 'contractVersion', 'revision', 'environment', 'manifestHash', 'resources'], '/');
253
+
254
+ if (state.kind !== STATE_KIND) {
255
+ throw schemaError('SCHEMA_STATE_INVALID', 'State kind must be "openyida_resource_state".', {
256
+ path: '/kind',
257
+ });
258
+ }
259
+ if (state.contractVersion !== STATE_CONTRACT_VERSION) {
260
+ throw schemaError('SCHEMA_STATE_VERSION_UNSUPPORTED', 'State contractVersion is not supported.', {
261
+ path: '/contractVersion',
262
+ details: { contractVersion: state.contractVersion },
263
+ });
264
+ }
265
+ if (!Number.isInteger(state.revision) || state.revision < 0) {
266
+ throw schemaError('SCHEMA_STATE_INVALID', 'State revision must be a non-negative integer.', {
267
+ path: '/revision',
268
+ });
269
+ }
270
+ validateEnvironmentShape(state.environment);
271
+ if (state.manifestHash !== undefined) {
272
+ assertHash(state.manifestHash, 'manifestHash', '/manifestHash');
273
+ }
274
+ validateResourcesShape(state.resources, registry);
275
+ }
276
+
277
+ function upsertResourceState(state, resourceState, options = {}) {
278
+ const nextState = clonePlain(state);
279
+ validateStateShape(nextState, { registry: options.registry });
280
+
281
+ const resourceType = resourceState && resourceState.resourceType;
282
+ const key = resourceState && resourceState.key;
283
+ if (!resourceType || !key) {
284
+ throw schemaError('SCHEMA_STATE_INVALID', 'Resource state must include resourceType and key.');
285
+ }
286
+ if (!nextState.resources[resourceType]) {
287
+ nextState.resources[resourceType] = {};
288
+ }
289
+ nextState.resources[resourceType][key] = buildPersistedResourceState(resourceState);
290
+ validateStateShape(nextState, { registry: options.registry });
291
+ return nextState;
292
+ }
293
+
294
+ function getResourceState(state, resourceType, key) {
295
+ return state &&
296
+ state.resources &&
297
+ state.resources[resourceType] &&
298
+ state.resources[resourceType][key] || null;
299
+ }
300
+
301
+ function buildPersistedResourceState(resourceState) {
302
+ const persisted = {
303
+ adapterVersion: resourceState.adapterVersion,
304
+ bindings: clonePlain(resourceState.bindings || {}),
305
+ };
306
+ if (resourceState.lastAppliedHash !== undefined) {
307
+ assertHash(resourceState.lastAppliedHash, 'lastAppliedHash');
308
+ persisted.lastAppliedHash = resourceState.lastAppliedHash;
309
+ }
310
+ if (resourceState.observedManagedHash !== undefined) {
311
+ assertHash(resourceState.observedManagedHash, 'observedManagedHash');
312
+ persisted.observedManagedHash = resourceState.observedManagedHash;
313
+ }
314
+ if (resourceState.remoteSchemaHash !== undefined) {
315
+ assertHash(resourceState.remoteSchemaHash, 'remoteSchemaHash');
316
+ persisted.remoteSchemaHash = resourceState.remoteSchemaHash;
317
+ }
318
+ if (resourceState.lastApplied !== undefined) {
319
+ persisted.lastApplied = clonePlain(resourceState.lastApplied);
320
+ }
321
+ return persisted;
322
+ }
323
+
324
+ function validateResourcesShape(resources, registry) {
325
+ if (!resources || typeof resources !== 'object' || Array.isArray(resources)) {
326
+ throw schemaError('SCHEMA_STATE_INVALID', 'State resources must be an object.', {
327
+ path: '/resources',
328
+ });
329
+ }
330
+
331
+ for (const resourceType of Object.keys(resources)) {
332
+ const adapter = registry.get(resourceType);
333
+ const resourceMap = resources[resourceType];
334
+ const resourceMapPath = `/resources/${escapePointer(resourceType)}`;
335
+ if (!resourceMap || typeof resourceMap !== 'object' || Array.isArray(resourceMap)) {
336
+ throw schemaError('SCHEMA_STATE_INVALID', 'State resource type entries must be objects.', {
337
+ path: resourceMapPath,
338
+ });
339
+ }
340
+ for (const key of Object.keys(resourceMap)) {
341
+ validateResourceEntry(resourceMap[key], {
342
+ adapter,
343
+ key,
344
+ path: `${resourceMapPath}/${escapePointer(key)}`,
345
+ resourceType,
346
+ });
347
+ }
348
+ }
349
+ }
350
+
351
+ function validateResourceEntry(entry, context) {
352
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
353
+ throw schemaError('SCHEMA_STATE_INVALID', 'State resource entry must be an object.', {
354
+ path: context.path,
355
+ });
356
+ }
357
+ assertAllowedKeys(entry, [
358
+ 'adapterVersion',
359
+ 'bindings',
360
+ 'lastAppliedHash',
361
+ 'observedManagedHash',
362
+ 'remoteSchemaHash',
363
+ 'lastApplied',
364
+ ], context.path);
365
+
366
+ if (!Number.isInteger(entry.adapterVersion) || entry.adapterVersion < 1) {
367
+ throw schemaError('SCHEMA_STATE_INVALID', 'State resource adapterVersion must be a supported integer.', {
368
+ path: `${context.path}/adapterVersion`,
369
+ });
370
+ }
371
+ if (entry.adapterVersion !== context.adapter.adapterVersion) {
372
+ throw schemaError('SCHEMA_STATE_ADAPTER_VERSION_UNSUPPORTED', 'State resource adapterVersion is not supported by the current adapter.', {
373
+ path: `${context.path}/adapterVersion`,
374
+ details: {
375
+ resourceType: context.resourceType,
376
+ key: context.key,
377
+ stateAdapterVersion: entry.adapterVersion,
378
+ adapterVersion: context.adapter.adapterVersion,
379
+ },
380
+ });
381
+ }
382
+ if (!entry.bindings || typeof entry.bindings !== 'object' || Array.isArray(entry.bindings)) {
383
+ throw schemaError('SCHEMA_STATE_INVALID', 'State resource bindings must be an object.', {
384
+ path: `${context.path}/bindings`,
385
+ });
386
+ }
387
+ for (const hashKey of ['lastAppliedHash', 'observedManagedHash', 'remoteSchemaHash']) {
388
+ if (entry[hashKey] !== undefined) {
389
+ assertHash(entry[hashKey], hashKey, `${context.path}/${hashKey}`);
390
+ }
391
+ }
392
+ if (entry.lastApplied !== undefined && (!entry.lastApplied || typeof entry.lastApplied !== 'object' || Array.isArray(entry.lastApplied))) {
393
+ throw schemaError('SCHEMA_STATE_INVALID', 'State lastApplied must be a compact managed object.', {
394
+ path: `${context.path}/lastApplied`,
395
+ });
396
+ }
397
+ if (typeof context.adapter.validateStateResource === 'function') {
398
+ context.adapter.validateStateResource({
399
+ key: context.key,
400
+ resourceType: context.resourceType,
401
+ state: entry,
402
+ path: context.path,
403
+ });
404
+ }
405
+ }
406
+
407
+ function validateEnvironmentShape(environment) {
408
+ if (!environment || typeof environment !== 'object' || Array.isArray(environment)) {
409
+ throw schemaError('SCHEMA_STATE_INVALID', 'State environment must be an object.', {
410
+ path: '/environment',
411
+ });
412
+ }
413
+ assertAllowedKeys(environment, ['environmentKey', 'corpIdHash'], '/environment');
414
+ assertHash(environment.environmentKey, 'environmentKey', '/environment/environmentKey');
415
+ assertHash(environment.corpIdHash, 'corpIdHash', '/environment/corpIdHash');
416
+ }
417
+
418
+ function validateForbiddenStateKeys(value, pathSegments = []) {
419
+ if (!value || typeof value !== 'object') {
420
+ return;
421
+ }
422
+ if (Array.isArray(value)) {
423
+ value.forEach((item, index) => validateForbiddenStateKeys(item, pathSegments.concat(String(index))));
424
+ return;
425
+ }
426
+
427
+ for (const [key, child] of Object.entries(value)) {
428
+ const canonical = canonicalizeKey(key);
429
+ if (SENSITIVE_STATE_KEY_CANONICALS.has(canonical) || isForbiddenRealIdLocation(pathSegments, key, canonical)) {
430
+ throw schemaError('SCHEMA_STATE_FORBIDDEN_FIELD', 'State must not contain credentials, internal paths, or remote IDs outside adapter bindings.', {
431
+ path: formatJsonPointer(pathSegments.concat(key)),
432
+ details: { key },
433
+ });
434
+ }
435
+ validateForbiddenStateKeys(child, pathSegments.concat(key));
436
+ }
437
+ }
438
+
439
+ function isForbiddenRealIdLocation(pathSegments, key, canonical) {
440
+ if (!REAL_ID_KEY_CANONICALS.has(canonical)) {
441
+ return false;
442
+ }
443
+ const segments = pathSegments.concat(key);
444
+ if (segments.length < 5 || segments[0] !== 'resources') {
445
+ return true;
446
+ }
447
+ const resourceType = segments[1];
448
+ if (canonical === 'apptype') {
449
+ return !(
450
+ segments.length === 5 &&
451
+ segments[3] === 'bindings' &&
452
+ segments[4] === key &&
453
+ (resourceType === 'app' || resourceType === 'form' || resourceType === 'page' || resourceType === 'process')
454
+ );
455
+ }
456
+ if (canonical === 'formuuid') {
457
+ return !(
458
+ segments.length === 5 &&
459
+ (resourceType === 'form' || resourceType === 'page' || resourceType === 'process') &&
460
+ segments[3] === 'bindings' &&
461
+ segments[4] === key
462
+ );
463
+ }
464
+ if (canonical === 'fieldid') {
465
+ return !(segments.length === 7 && resourceType === 'form' && segments[3] === 'bindings' && segments[4] === 'fieldBindings' && segments[6] === key);
466
+ }
467
+ if (canonical === 'processcode') {
468
+ return !(
469
+ segments.length === 5 &&
470
+ segments[3] === 'bindings' &&
471
+ segments[4] === key
472
+ );
473
+ }
474
+ if (canonical === 'processid' || canonical === 'processversion') {
475
+ return !(segments.length === 5 && segments[3] === 'bindings' && segments[4] === key);
476
+ }
477
+ if (canonical === 'nodeid') {
478
+ return !(
479
+ segments.length === 7 &&
480
+ segments[3] === 'bindings' &&
481
+ segments[4] === 'nodeBindings' &&
482
+ segments[6] === key
483
+ );
484
+ }
485
+ return true;
486
+ }
487
+
488
+ function assertEnvironmentMatches(actual, expected) {
489
+ if (
490
+ actual.environmentKey !== expected.environmentKey ||
491
+ actual.corpIdHash !== expected.corpIdHash
492
+ ) {
493
+ throw schemaError('SCHEMA_STATE_ENVIRONMENT_MISMATCH', 'State belongs to a different environment.', {
494
+ path: '/environment',
495
+ details: {
496
+ environmentKey: actual.environmentKey,
497
+ corpIdHash: actual.corpIdHash,
498
+ },
499
+ });
500
+ }
501
+ }
502
+
503
+ function assertAllowedKeys(value, allowedKeys, pointer) {
504
+ const allowed = new Set(allowedKeys);
505
+ for (const key of Object.keys(value || {})) {
506
+ if (!allowed.has(key)) {
507
+ throw schemaError('SCHEMA_STATE_INVALID', 'State contains an unknown property.', {
508
+ path: pointer === '/' ? `/${escapePointer(key)}` : `${pointer}/${escapePointer(key)}`,
509
+ details: { property: key },
510
+ });
511
+ }
512
+ }
513
+ }
514
+
515
+ function assertHash(value, name, pointer) {
516
+ if (typeof value !== 'string' || !HASH_PATTERN.test(value)) {
517
+ throw schemaError('SCHEMA_STATE_INVALID', `${name} must be a sha256 hash.`, {
518
+ path: pointer,
519
+ details: { field: name },
520
+ });
521
+ }
522
+ }
523
+
524
+ function hasNonEmptyString(value) {
525
+ return typeof value === 'string' && value.trim().length > 0;
526
+ }
527
+
528
+ function normalizeEndpoint(endpoint) {
529
+ return String(endpoint || '').trim().replace(/\/+$/, '').toLowerCase();
530
+ }
531
+
532
+ function fsyncDirectoryBestEffort(fsImpl, dir) {
533
+ if (typeof fsImpl.openSync !== 'function' || typeof fsImpl.fsyncSync !== 'function') {
534
+ return;
535
+ }
536
+ let dirFd;
537
+ try {
538
+ dirFd = fsImpl.openSync(dir, 'r');
539
+ fsImpl.fsyncSync(dirFd);
540
+ } catch (error) {
541
+ // Directory fsync is not portable across all filesystems.
542
+ } finally {
543
+ if (dirFd !== undefined) {
544
+ try {
545
+ fsImpl.closeSync(dirFd);
546
+ } catch (closeError) {
547
+ // Best effort cleanup.
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+ function clonePlain(value) {
554
+ if (value === undefined || value === null || typeof value !== 'object') {
555
+ return value;
556
+ }
557
+ return JSON.parse(JSON.stringify(value));
558
+ }
559
+
560
+ function formatJsonPointer(segments) {
561
+ if (!segments || segments.length === 0) {
562
+ return '/';
563
+ }
564
+ return '/' + segments.map(escapePointer).join('/');
565
+ }
566
+
567
+ function escapePointer(value) {
568
+ return String(value).replace(/~/g, '~0').replace(/\//g, '~1');
569
+ }
570
+
571
+ function compareResourceIds(left, right) {
572
+ return compareCodePoints(`${left.resourceType}:${left.key}`, `${right.resourceType}:${right.key}`);
573
+ }
574
+
575
+ module.exports = {
576
+ STATE_KIND,
577
+ STATE_CONTRACT_VERSION,
578
+ compareResourceIds,
579
+ createEmptyState,
580
+ createEnvironmentIdentity,
581
+ createSha256,
582
+ getResourceState,
583
+ hashStable,
584
+ readState,
585
+ resolveDefaultStatePath,
586
+ upsertResourceState,
587
+ validateState,
588
+ writeStateAtomic,
589
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.7.18",
3
+ "version": "2026.7.21",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -11,18 +11,13 @@
11
11
  "lib/",
12
12
  "agent/",
13
13
  "project/config.json",
14
- "project/pages/src/demo-*.js",
15
- "project/pages/src/demo-*.oyd.jsx",
16
- "!project/pages/src/demo-agent-chatbox.oyd.jsx",
17
- "!project/pages/src/demo-dingtalk-ai-solution-center.oyd.jsx",
18
- "!project/pages/src/demo-openyida-image2-slider.oyd.jsx",
19
- "project/pages/src/openyida-knowledge-doc.oyd.jsx",
20
14
  "project/prd/demo-*.md",
21
15
  "yida-skills/",
22
16
  "!lib/samples/**/assets/**",
23
17
  "scripts/",
24
18
  "!scripts/e2e-real/",
25
19
  "!scripts/eval/",
20
+ "docs/capabilities.md",
26
21
  "README.md",
27
22
  "LICENSE"
28
23
  ],
@@ -37,7 +32,13 @@
37
32
  "eval:routing": "node scripts/eval/runner.js --mode routing",
38
33
  "eval:generate": "node scripts/eval/runner.js --mode generate",
39
34
  "eval:all": "node scripts/eval/runner.js --mode all",
35
+ "eval:doc-quality": "node scripts/eval/runner.js --mode doc-quality",
36
+ "eval:safety": "node scripts/eval/runner.js --mode safety",
37
+ "eval:comprehensive": "node scripts/eval/runner.js --mode comprehensive",
38
+ "eval:coverage": "node scripts/eval/runner.js --mode coverage",
40
39
  "eval:dashboard": "node scripts/eval/dashboard/server.js",
40
+ "eval:baseline": "node scripts/eval/runner.js --mode baseline",
41
+ "eval:pipeline": "node scripts/eval/runner.js --mode pipeline",
41
42
  "test:coverage": "jest --coverage",
42
43
  "lint": "eslint bin/ lib/ scripts/ tests/ --ext .js",
43
44
  "lint:fix": "eslint bin/ lib/ scripts/ tests/ --ext .js --fix",
@@ -53,6 +54,7 @@
53
54
  "check:i18n:audit": "node scripts/validate-i18n.js",
54
55
  "check:i18n:baseline": "node scripts/validate-i18n.js --update-baseline",
55
56
  "check:syntax": "node scripts/check-syntax.js",
57
+ "check:release-risks": "node scripts/check-release-risks.js",
56
58
  "check:package-size": "node scripts/validate-package-size.js",
57
59
  "check:package": "npm pack --dry-run",
58
60
  "check:release": "npm run check:ci",
@@ -83,7 +85,7 @@
83
85
  "homepage": "https://github.com/openyida/openyida#readme",
84
86
  "dependencies": {
85
87
  "@babel/standalone": "^7.15.1",
86
- "qrcode": "^1.5.4",
88
+ "ajv": "^8.20.0",
87
89
  "uglify-js": "^3.19.3"
88
90
  },
89
91
  "devDependencies": {