@stalfh233/omc-cli 0.0.0-stage → 0.4.10

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 (181) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -3
  3. package/coverage/m1-coverage-manifest-v1.json +1278 -0
  4. package/dist/approval-token.js +102 -0
  5. package/dist/args.js +25 -0
  6. package/dist/artifacts.js +119 -0
  7. package/dist/bench/call-face-eval.js +256 -0
  8. package/dist/bench/context-attribution.js +151 -0
  9. package/dist/bench/discovery-cost-eval.js +230 -0
  10. package/dist/bench/driver.js +81 -0
  11. package/dist/bench/evals.js +236 -0
  12. package/dist/bench/fake-http-server.js +65 -0
  13. package/dist/bench/instrument.js +87 -0
  14. package/dist/bench/intent-face-eval.js +343 -0
  15. package/dist/bench/run.js +166 -0
  16. package/dist/bench/scenario.js +343 -0
  17. package/dist/bench/types.js +76 -0
  18. package/dist/bi-wire.js +41 -0
  19. package/dist/bizservice-config.js +581 -0
  20. package/dist/call.js +153 -0
  21. package/dist/capability-absences.js +23 -0
  22. package/dist/capability-overview.js +492 -0
  23. package/dist/capability-shape.js +154 -0
  24. package/dist/cli-contract.js +70 -0
  25. package/dist/cli-output.js +73 -0
  26. package/dist/cli.js +1418 -0
  27. package/dist/code-rules.js +69 -0
  28. package/dist/command-transport.js +155 -0
  29. package/dist/config-store.js +195 -0
  30. package/dist/context.js +21 -0
  31. package/dist/contract-consistency.js +66 -0
  32. package/dist/contract-resources.js +62 -0
  33. package/dist/coverage-consistency.js +62 -0
  34. package/dist/coverage-registry.js +76 -0
  35. package/dist/coverage.js +130 -0
  36. package/dist/data-list-filter.js +114 -0
  37. package/dist/discovery.js +390 -0
  38. package/dist/endpoints.js +154 -0
  39. package/dist/environment-policy.js +26 -0
  40. package/dist/execution-metadata.js +1092 -0
  41. package/dist/fake/app.js +45 -0
  42. package/dist/fake/b2-registration.js +594 -0
  43. package/dist/fake/businessrule.js +242 -0
  44. package/dist/fake/datarule.js +72 -0
  45. package/dist/fake/dictionary.js +108 -0
  46. package/dist/fake/environment.js +30 -0
  47. package/dist/fake/field.js +167 -0
  48. package/dist/fake/form.js +101 -0
  49. package/dist/fake/index.js +121 -0
  50. package/dist/fake/list-view.js +289 -0
  51. package/dist/fake/model.js +136 -0
  52. package/dist/fake/online-js.js +18 -0
  53. package/dist/fake/report.js +253 -0
  54. package/dist/fake/routes.js +47 -0
  55. package/dist/fake/rule-lifecycle.js +37 -0
  56. package/dist/fake/runtime-data.js +367 -0
  57. package/dist/fake/state.js +67 -0
  58. package/dist/fake/workflow.js +364 -0
  59. package/dist/field-change.js +200 -0
  60. package/dist/field-families.js +896 -0
  61. package/dist/form-layout.js +111 -0
  62. package/dist/form-support.js +821 -0
  63. package/dist/goal-routes.js +468 -0
  64. package/dist/governed-execution.js +87 -0
  65. package/dist/human-summary.js +212 -0
  66. package/dist/identity.js +62 -0
  67. package/dist/intent/baseline.js +57 -0
  68. package/dist/intent/capabilities/bizservice.js +274 -0
  69. package/dist/intent/capabilities/businessrule.js +493 -0
  70. package/dist/intent/capabilities/datarule.js +187 -0
  71. package/dist/intent/capabilities/field.js +545 -0
  72. package/dist/intent/capabilities/form.js +136 -0
  73. package/dist/intent/capabilities/index.js +64 -0
  74. package/dist/intent/capabilities/listview.js +157 -0
  75. package/dist/intent/capabilities/model.js +100 -0
  76. package/dist/intent/capabilities/onlinejs.js +108 -0
  77. package/dist/intent/capabilities/report.js +355 -0
  78. package/dist/intent/capabilities/workflow.js +458 -0
  79. package/dist/intent/capability.js +6 -0
  80. package/dist/intent/cli.js +91 -0
  81. package/dist/intent/compare.js +56 -0
  82. package/dist/intent/compiler.js +79 -0
  83. package/dist/intent/dsl.js +129 -0
  84. package/dist/intent/plan-file.js +63 -0
  85. package/dist/intent/readback.js +65 -0
  86. package/dist/intent/schema.js +158 -0
  87. package/dist/intent/validation.js +30 -0
  88. package/dist/intent/yaml.js +315 -0
  89. package/dist/json-column.js +68 -0
  90. package/dist/lanes/app-contract.js +95 -0
  91. package/dist/lanes/app-coverage.js +16 -0
  92. package/dist/lanes/app.js +174 -0
  93. package/dist/lanes/apply-changes.js +231 -0
  94. package/dist/lanes/b2-registration-contract.js +292 -0
  95. package/dist/lanes/b2-registration-coverage.js +48 -0
  96. package/dist/lanes/b2-registration.js +1187 -0
  97. package/dist/lanes/businessrule-contract.js +232 -0
  98. package/dist/lanes/businessrule-coverage.js +16 -0
  99. package/dist/lanes/businessrule.js +221 -0
  100. package/dist/lanes/contract-support.js +65 -0
  101. package/dist/lanes/coverage-declaration.js +9 -0
  102. package/dist/lanes/datarule-contract.js +155 -0
  103. package/dist/lanes/datarule-coverage.js +19 -0
  104. package/dist/lanes/datarule-protocol.js +308 -0
  105. package/dist/lanes/datarule.js +818 -0
  106. package/dist/lanes/dictionary-contract.js +78 -0
  107. package/dist/lanes/dictionary-coverage.js +24 -0
  108. package/dist/lanes/dictionary.js +235 -0
  109. package/dist/lanes/environment-contract.js +70 -0
  110. package/dist/lanes/environment-coverage.js +14 -0
  111. package/dist/lanes/environment.js +163 -0
  112. package/dist/lanes/field-contract.js +223 -0
  113. package/dist/lanes/field-coverage.js +27 -0
  114. package/dist/lanes/field.js +374 -0
  115. package/dist/lanes/form-contract.js +97 -0
  116. package/dist/lanes/form-coverage.js +16 -0
  117. package/dist/lanes/form.js +185 -0
  118. package/dist/lanes/lane-ids.js +34 -0
  119. package/dist/lanes/list-view-contract.js +175 -0
  120. package/dist/lanes/list-view-coverage.js +20 -0
  121. package/dist/lanes/list-view-shapes.js +1207 -0
  122. package/dist/lanes/list-view.js +578 -0
  123. package/dist/lanes/meta-contract.js +85 -0
  124. package/dist/lanes/meta.js +255 -0
  125. package/dist/lanes/model-contract.js +168 -0
  126. package/dist/lanes/model-coverage.js +20 -0
  127. package/dist/lanes/model.js +986 -0
  128. package/dist/lanes/online-js-contract.js +99 -0
  129. package/dist/lanes/online-js-coverage.js +28 -0
  130. package/dist/lanes/online-js.js +127 -0
  131. package/dist/lanes/report-contract.js +144 -0
  132. package/dist/lanes/report-coverage.js +21 -0
  133. package/dist/lanes/report.js +476 -0
  134. package/dist/lanes/rule-graph.js +1846 -0
  135. package/dist/lanes/rule-lifecycle-contract.js +92 -0
  136. package/dist/lanes/rule-lifecycle-coverage.js +20 -0
  137. package/dist/lanes/rule-lifecycle.js +176 -0
  138. package/dist/lanes/runtime-data-contract.js +264 -0
  139. package/dist/lanes/runtime-data-coverage.js +25 -0
  140. package/dist/lanes/runtime-data.js +1054 -0
  141. package/dist/lanes/workflow-contract.js +223 -0
  142. package/dist/lanes/workflow-coverage.js +40 -0
  143. package/dist/lanes/workflow.js +1813 -0
  144. package/dist/online-js-layout.js +58 -0
  145. package/dist/online-js-source.js +276 -0
  146. package/dist/package-tool.js +51 -0
  147. package/dist/package.js +73 -0
  148. package/dist/plan.js +73 -0
  149. package/dist/read.js +144 -0
  150. package/dist/redact.js +28 -0
  151. package/dist/rule-support.js +587 -0
  152. package/dist/runtime-support.js +134 -0
  153. package/dist/server.js +92 -0
  154. package/dist/session-manager.js +30 -0
  155. package/dist/session.js +149 -0
  156. package/dist/skills.js +112 -0
  157. package/dist/support.js +98 -0
  158. package/dist/tool-types.js +127 -0
  159. package/dist/tools.js +59 -0
  160. package/dist/usage-log.js +197 -0
  161. package/dist/wire.js +287 -0
  162. package/dist/workflow-support.js +99 -0
  163. package/dist/write-lease.js +26 -0
  164. package/dist/write-lock.js +109 -0
  165. package/dist/write.js +176 -0
  166. package/dist/zip.js +156 -0
  167. package/docs/tool-surface-map.md +42 -0
  168. package/package.json +71 -6
  169. package/skills/omc-acceptance-criteria.md +47 -0
  170. package/skills/omc-business-configuration.md +257 -0
  171. package/skills/omc-capabilities.md +197 -0
  172. package/skills/omc-capability-scouting.md +55 -0
  173. package/skills/omc-config-draft-review.md +171 -0
  174. package/skills/omc-five-piece-flow.md +35 -0
  175. package/skills/omc-glossary.md +86 -0
  176. package/skills/omc-refusals.md +110 -0
  177. package/skills/omc-requirement-analysis.md +161 -0
  178. package/skills/omc-requirement-vocabulary.md +51 -0
  179. package/skills/omc-start-here.md +82 -0
  180. package/skills/omc-tool-selection.md +119 -0
  181. package/skills/omc-write-hazards.md +87 -0
@@ -0,0 +1,99 @@
1
+ import { assertDescriptionCarries, assertLaneContract, behaviorBinding, CONTRACT_FAMILY, CONTRACT_REFERENCE_VERSION, emitterBinding } from "./contract-support.js";
2
+ import { assertPlatformOnlineJsComposition, PLATFORM_DEFAULT_LIFECYCLE_SCRIPT, PLATFORM_LIFECYCLE_WRAPPER_MARKER } from "../online-js-source.js";
3
+ import { assertPlatformOnlineJsLayout } from "../online-js-layout.js";
4
+ import { LANES } from "./lane-ids.js";
5
+ /**
6
+ * online-js wire facts (live-proven). The customScript element composition,
7
+ * the complete-array preservation, and the verbatim readback are the single
8
+ * source for the handler descriptions and the coverage declarations.
9
+ */
10
+ export const ONLINE_JS_WIRE = Object.freeze({
11
+ composeElement: `canonical customScript element {tagName:'script', id:'customScript', innerHTML:<platform lifecycle wrapper containing source>, attrs:[]} (must contain ${PLATFORM_LIFECYCLE_WRAPPER_MARKER}; designer chunk 54286 calls e.attrs.some(...): attrs MUST be an array)`,
12
+ composePreserve: `reads the existing draftHtmlJson, JSON-parses the COMPLETE element array, preserves the platform template including the ${PLATFORM_LIFECYCLE_WRAPPER_MARKER} lifecycle body — the style, toolbar, template, beforeCustomScript, and afterCustomScript elements verbatim (attrs included), plus every other layout/control element — fills in missing skeleton elements with platform defaults, replaces ONLY the customScript element, then stringifies the COMPLETE array`,
13
+ composePublish: "bizsheet/update then bizsheet/publish (force:true) promoting the full layout; publishedHtmlJson is read back verbatim and SHA-256-fingerprinted for byte-equality verification",
14
+ regression: "issue 11: never overwrite the layout with a standalone script object or a partial [customScript]-only array",
15
+ programmingRemoved: "the former onlinejs.draft/publish tools wrapped the design-time 在线开发 face (POST /api/api/programming/get_source|saveSourceCode|publish; base is the DOUBLED /api/api/programming under the /api context-path, live 2026-09-21; the earlier single-/api guess 404s). That face authors backend JAVA (business-rule/SPI/service-component source), which is written through 二开扩展包, NOT form Online JS — so the CLI exposes no tool for it and the two misleadingly-named tools were removed. onlinejs.compose is the only Online JS tool",
16
+ });
17
+ const ONLINE_JS_SCOPE = "draft promotion publish verbatim readback";
18
+ export const ONLINE_JS_LANE_CONTRACT = Object.freeze({
19
+ lane: LANES.onlineJs,
20
+ family: CONTRACT_FAMILY,
21
+ referenceVersion: CONTRACT_REFERENCE_VERSION,
22
+ endpoints: Object.freeze({
23
+ sheetGet: "sheetGet",
24
+ sheetUpdate: "sheetUpdate",
25
+ sheetPublish: "sheetPublish",
26
+ }),
27
+ wire: Object.freeze({
28
+ composeElement: ONLINE_JS_WIRE.composeElement,
29
+ composePreserve: ONLINE_JS_WIRE.composePreserve,
30
+ composePublish: ONLINE_JS_WIRE.composePublish,
31
+ regression: ONLINE_JS_WIRE.regression,
32
+ programmingRemoved: ONLINE_JS_WIRE.programmingRemoved,
33
+ }),
34
+ wireBindings: Object.freeze({
35
+ composeElement: Object.freeze([
36
+ Object.freeze({
37
+ kind: "emitter-constant",
38
+ ref: "online-js-source.PLATFORM_DEFAULT_LIFECYCLE_SCRIPT",
39
+ verify: () => {
40
+ if (!PLATFORM_DEFAULT_LIFECYCLE_SCRIPT.includes(PLATFORM_LIFECYCLE_WRAPPER_MARKER))
41
+ throw new Error("platform lifecycle wrapper is missing");
42
+ },
43
+ }),
44
+ Object.freeze({
45
+ kind: "behavior-test",
46
+ ref: "online-js-source.assertPlatformOnlineJsComposition",
47
+ verify: assertPlatformOnlineJsComposition,
48
+ }),
49
+ Object.freeze({
50
+ kind: "behavior-test",
51
+ ref: "online-js-layout.assertPlatformOnlineJsLayout",
52
+ verify: assertPlatformOnlineJsLayout,
53
+ }),
54
+ ]),
55
+ composePreserve: Object.freeze([
56
+ emitterBinding("online-js-layout.composeLayoutElements", assertOnlineJsContract),
57
+ behaviorBinding("test/issue-11-online-js.test.ts#onlinejs.compose merges customScript into the existing draftHtmlJson layout", assertOnlineJsContract),
58
+ ]),
59
+ composePublish: Object.freeze([
60
+ behaviorBinding("test/issue-11-online-js.test.ts#onlinejs.compose merges customScript into the existing draftHtmlJson layout", assertOnlineJsContract),
61
+ ]),
62
+ regression: Object.freeze([
63
+ behaviorBinding("test/issue-11-online-js.test.ts#onlinejs.compose refuses to overwrite the layout with a standalone script object", assertOnlineJsContract),
64
+ ]),
65
+ programmingRemoved: Object.freeze([
66
+ behaviorBinding("test/onlinejs-no-programming-tool.test.ts#the removed online-development tools are absent from the registry", assertOnlineJsContract),
67
+ ]),
68
+ }),
69
+ evidence: Object.freeze([
70
+ "packages/omc-cli/src/lanes/online-js.ts",
71
+ ".scratch/omc-route-wayfinder/leg4-closeout.md",
72
+ "packages/omc-cli/test/issue-11-online-js.test.ts",
73
+ ]),
74
+ tools: Object.freeze({
75
+ "onlinejs.compose": Object.freeze({
76
+ scope: ONLINE_JS_SCOPE,
77
+ description: `Compose the Online JS source as the customScript element into the form's draftHtmlJson layout array (then publish, promoting it verbatim to publishedHtmlJson). Core contract: preserve the platform template and only extend customScript.innerHTML — the six-element skeleton includes the ${PLATFORM_LIFECYCLE_WRAPPER_MARKER} lifecycle wrapper; the style, toolbar, template, beforeCustomScript, customScript, and afterCustomScript elements are kept or synthesized with platform defaults, while every layout/control element is preserved. customScript is rebuilt canonically as {tagName:'script', id:'customScript', innerHTML:<platform lifecycle wrapper containing source>, attrs:[]} because the designer requires an ARRAY attrs (e.attrs.some) and tagName, else the Online JS editor fails with t.some is not a function. Drives bizsheet/update + bizsheet/publish; publishedHtmlJson is read back verbatim and SHA-256-fingerprinted so the caller can verify byte equality. Never overwrites the layout with a standalone script object or a partial [customScript]-only array (regression for issue 11's root cause).`,
78
+ }),
79
+ }),
80
+ });
81
+ export function assertOnlineJsContract() {
82
+ assertLaneContract(ONLINE_JS_LANE_CONTRACT);
83
+ if (!ONLINE_JS_WIRE.composePreserve.includes("COMPLETE"))
84
+ throw new Error("online-js contract pins the complete-array preservation");
85
+ if (!ONLINE_JS_WIRE.composePublish.includes("bizsheet/publish"))
86
+ throw new Error("online-js contract must pin the publish chain");
87
+ if (!ONLINE_JS_WIRE.regression.includes("partial [customScript]-only"))
88
+ throw new Error("online-js contract must pin the issue-11 regression shape");
89
+ if (!ONLINE_JS_WIRE.programmingRemoved.includes("二开扩展包"))
90
+ throw new Error("online-js contract must record why the programming tools are absent");
91
+ if (!PLATFORM_DEFAULT_LIFECYCLE_SCRIPT.includes(PLATFORM_LIFECYCLE_WRAPPER_MARKER))
92
+ throw new Error("online-js emitter must contain the platform lifecycle wrapper");
93
+ if (!ONLINE_JS_WIRE.composeElement.includes(PLATFORM_LIFECYCLE_WRAPPER_MARKER))
94
+ throw new Error("online-js contract must pin the platform lifecycle wrapper");
95
+ assertDescriptionCarries(ONLINE_JS_LANE_CONTRACT, "onlinejs.compose", ["customScript", "draftHtmlJson", "publishedHtmlJson", "SHA-256", "issue 11", PLATFORM_LIFECYCLE_WRAPPER_MARKER]);
96
+ if ("onlinejs.draft" in ONLINE_JS_LANE_CONTRACT.tools || "onlinejs.publish" in ONLINE_JS_LANE_CONTRACT.tools)
97
+ throw new Error("online-js contract must not carry the removed programming tools");
98
+ }
99
+ //# sourceMappingURL=online-js-contract.js.map
@@ -0,0 +1,28 @@
1
+ import { claim, declareLaneCoverage } from "./coverage-declaration.js";
2
+ import { ONLINE_JS_LANE_CONTRACT } from "./online-js-contract.js";
3
+ const T = ONLINE_JS_LANE_CONTRACT.tools;
4
+ /**
5
+ * The lane is a single EXECUTABLE composer: onlinejs.compose drives the
6
+ * live-verified bizsheet html chain (draft carrying the layout skeleton →
7
+ * publish → verbatim publishedHtmlJson; ticket 73 pinned skeleton fidelity and
8
+ * ticket 110 upgraded it to the SIX-element platform skeleton: style +
9
+ * section#toolbar + section#template + before/custom/afterCustomScript, live row
10
+ * dev_repair_order).
11
+ *
12
+ * The former onlinejs.draft/publish tools wrapped the design-time 在线开发 face
13
+ * (/api/api/programming/*, backend JAVA source) and were removed: that face is
14
+ * authored through 二开扩展包, not form Online JS, so it is out of this CLI's
15
+ * scope rather than a blocked capability.
16
+ */
17
+ export const ONLINE_JS_COVERAGE = declareLaneCoverage(ONLINE_JS_LANE_CONTRACT.lane, [
18
+ {
19
+ capability: "Online JS composer (onlinejs.compose, draftHtmlJson customScript element)",
20
+ evidence: [
21
+ "packages/omc-cli/src/lanes/online-js.ts",
22
+ ".scratch/omc-route-wayfinder/leg4-closeout.md",
23
+ "packages/omc-cli/test/ticket-73-onlinejs-template-fidelity.test.ts",
24
+ ],
25
+ tools: [claim("onlinejs.compose", T["onlinejs.compose"].scope)],
26
+ },
27
+ ]);
28
+ //# sourceMappingURL=online-js-coverage.js.map
@@ -0,0 +1,127 @@
1
+ import { z } from "zod";
2
+ import { createHash } from "node:crypto";
3
+ import { ENDPOINTS } from "../endpoints.js";
4
+ import { assertHtmlRender, executeFormDraftWrite, executeFormPublishWrite, validateHtmlRender } from "../form-support.js";
5
+ import { writeTool } from "../write.js";
6
+ import { wireCall } from "../wire.js";
7
+ import { composeCustomScript, lintOnlineJsSource } from "../online-js-source.js";
8
+ import { composeLayoutElements } from "../online-js-layout.js";
9
+ import { ONLINE_JS_LANE_CONTRACT } from "./online-js-contract.js";
10
+ const ONLINE_JS_LANE = ONLINE_JS_LANE_CONTRACT.lane;
11
+ const ONLINE_JS_TOOLS = ONLINE_JS_LANE_CONTRACT.tools;
12
+ /**
13
+ * Parse a draftHtmlJson / publishedHtmlJson string into a well-formed
14
+ * element array. Handles the legacy "{}" case (empty object → empty array)
15
+ * and filters out non-object entries so compose/verify can rely on the
16
+ * array shape without per-call defensive parsing.
17
+ */
18
+ function parseLayoutElements(rawHtml) {
19
+ if (rawHtml === undefined || rawHtml === null || rawHtml.trim() === "")
20
+ return [];
21
+ try {
22
+ const parsed = JSON.parse(rawHtml);
23
+ if (Array.isArray(parsed))
24
+ return parsed;
25
+ }
26
+ catch {
27
+ // The caller reports malformed persisted HTML before composition.
28
+ }
29
+ return [];
30
+ }
31
+ /**
32
+ * Platform layout skeleton (live capture of the designer's own save,
33
+ * POST /api/api/app/bizsheet/update; designer chunk 54286 + ticket 110 live
34
+ * row dev_repair_order, h_biz_sheet):
35
+ * [style, section#toolbar, section#template, beforeCustomScript,
36
+ * customScript, afterCustomScript] — every element carries tagName and an
37
+ * ARRAY attrs. The designer's isLinkScript/findElementsByClass call
38
+ * e.attrs.some(...), so a missing tagName or a non-array attrs breaks the
39
+ * Online JS editor with `TypeError: t.some is not a function`; the template
40
+ * section is what convertElement keys on (id === "template") to render the
41
+ * template area — omitting toolbar/template leaves the panel regions empty.
42
+ */
43
+ export function registerOnlineJsLane(tools) {
44
+ writeTool(tools, "onlinejs.compose", ONLINE_JS_LANE, ONLINE_JS_TOOLS["onlinejs.compose"].scope, ONLINE_JS_TOOLS["onlinejs.compose"].description, {
45
+ schemaCode: z.string().min(1),
46
+ sheetCode: z.string().min(1),
47
+ source: z.string().min(1).describe("在线 JS 代码。默认 INCREMENTAL:并入平台 (function(form){…}) 模板的既有脚本,模板与既有注册全部保留;配 replace:true 才是整段替换。脚本不得使用 export/import;事件名必须是平台事件(onLoad/onRendered/onValidate/onPreAction/onCustomAction/onActionDone/onPrintFormDataHandle/onPrintWorkflowLogDataHandle)"),
48
+ replace: z.boolean().optional().describe("true = 以 source 整体替换 customScript(含完整 (function(form){…}) 脚本)。默认 false = 增量并入既有脚本,保留平台模板与既有逻辑"),
49
+ publish: z.boolean().optional(),
50
+ }, async (session, args) => {
51
+ const shouldPublish = args.publish !== false;
52
+ // 1. Read the existing draftHtmlJson.
53
+ const current = await wireCall(session, { path: ENDPOINTS.sheetGet, query: { schemaCode: args.schemaCode, sheetCode: args.sheetCode } });
54
+ const existingSheet = (current.data ?? null);
55
+ const existingRaw = typeof existingSheet?.draftHtmlJson === "string" ? existingSheet.draftHtmlJson : undefined;
56
+ const existingCompat = validateHtmlRender(existingRaw);
57
+ // A persisted legacy face may contain an object or malformed elements.
58
+ // Do not pass any of it through: discard the unproven face and rebuild
59
+ // only the canonical platform skeleton below.
60
+ const existingElements = existingCompat.ok ? parseLayoutElements(existingRaw) : [];
61
+ // 2. Script-level INCREMENTAL merge. The layout read-modify-write above
62
+ // preserved the element skeleton, but the customScript innerHTML was
63
+ // being replaced wholesale — that is how a bare `form.on(...)` (or an
64
+ // `export function`) landed as the ENTIRE script, leaving `form`
65
+ // undefined / a SyntaxError and rendering the form BLANK. Read the
66
+ // existing script and merge the caller's code into it; the platform
67
+ // default (an empty script) is seeded with the lifecycle scaffold.
68
+ const existingScript = String(existingElements.find((element) => element.id === "customScript")?.innerHTML ?? "");
69
+ const composedScript = composeCustomScript(existingScript, args.source, args.replace === true ? "replace" : "merge");
70
+ // 3. Preserve the platform template read-modify-write: keep the
71
+ // style/beforeCustomScript/afterCustomScript skeleton and every
72
+ // layout/control element; customScript carries the MERGED script.
73
+ const composedElements = composeLayoutElements(existingElements, composedScript);
74
+ assertHtmlRender(JSON.stringify(composedElements), { schemaCode: args.schemaCode, sheetCode: args.sheetCode, face: "composedDraftHtmlJson" }, true);
75
+ // 4. Stringify the COMPLETE element array (never partial).
76
+ const composedDraftHtml = JSON.stringify(composedElements);
77
+ // 5. bizsheet/update with the new draftHtmlJson (delegated to the
78
+ // shared form.draft write body so view/attributes scaffolds stay
79
+ // intact when present).
80
+ await executeFormDraftWrite(session, {
81
+ schemaCode: args.schemaCode,
82
+ sheetCode: args.sheetCode,
83
+ draftHtmlJson: composedDraftHtml,
84
+ });
85
+ // 6. publish promotes the FULL layout (including customScript). Use
86
+ // force:true so compose re-promotes even when the form was
87
+ // previously published — otherwise onlinejs.compose would
88
+ // leave the stale publishedHtmlJson in place after the user
89
+ // already published once.
90
+ let published = false;
91
+ if (shouldPublish) {
92
+ const publishOutcome = await executeFormPublishWrite(session, {
93
+ schemaCode: args.schemaCode,
94
+ sheetCode: args.sheetCode,
95
+ force: true,
96
+ });
97
+ published = publishOutcome.readback.published === true;
98
+ }
99
+ // 7. Readback publishedHtmlJson VERBATIM.
100
+ const readback = await wireCall(session, { path: ENDPOINTS.sheetGet, query: { schemaCode: args.schemaCode, sheetCode: args.sheetCode } });
101
+ const publishedSheet = (readback.data ?? {});
102
+ const publishedRaw = typeof publishedSheet.publishedHtmlJson === "string" ? publishedSheet.publishedHtmlJson : "";
103
+ if (publishedRaw !== "")
104
+ assertHtmlRender(publishedRaw, { schemaCode: args.schemaCode, sheetCode: args.sheetCode, face: "publishedHtmlJson" }, true);
105
+ const publishedElements = parseLayoutElements(publishedRaw);
106
+ // 8. SHA-256 of the verbatim content.
107
+ const publishedSha256 = createHash("sha256").update(publishedRaw).digest("hex");
108
+ return {
109
+ performed: { errcode: 0, published },
110
+ readback: {
111
+ composedDraftHtmlJson: composedDraftHtml,
112
+ publishedHtmlJson: publishedRaw,
113
+ publishedSha256,
114
+ publishedElementCount: publishedElements.length,
115
+ scriptElementPresent: publishedElements.some((element) => element.id === "customScript"),
116
+ customScript: composedScript,
117
+ customScriptMerged: args.replace !== true,
118
+ htmlRenderCompat: { draft: validateHtmlRender(composedDraftHtml, true), published: validateHtmlRender(publishedRaw, true) },
119
+ },
120
+ };
121
+ },
122
+ // Refuse a source that cannot run in the script slot (export/import, unknown
123
+ // form.on event) BEFORE the write permission gate. This is the exact
124
+ // class of mistake that blanked a live form page with no harness signal.
125
+ (args) => lintOnlineJsSource(args.source));
126
+ }
127
+ //# sourceMappingURL=online-js.js.map
@@ -0,0 +1,144 @@
1
+ import { assertDescriptionCarries, assertLaneContract, behaviorBinding, CONTRACT_FAMILY, CONTRACT_REFERENCE_VERSION } from "./contract-support.js";
2
+ import { LANES } from "./lane-ids.js";
3
+ /**
4
+ * R1-report wire facts (live-proven on the aozhe tenant, AI-Platform-v1.1.22,
5
+ * engineCode aozhe). The report surface is two channels glued by the report
6
+ * page: the platform channel `/api/api/report/*` (errcode envelope) owns the
7
+ * design-time page/menu entry; the BI channel `/dashboard/v1/*` (NO errcode
8
+ * envelope) owns the dashboard config and charts. See
9
+ * `.scratch/omc-report/recon.md` for the full capture.
10
+ */
11
+ export const REPORT_WIRE = Object.freeze({
12
+ surface: "报表是两层:平台通道 /api/api/report/* 维护报表页(app 功能树 type=Report,errcode 信封);BI 通道 /dashboard/v1/* 维护 dashboard 配置与图表(成功 {data},失败 {errorCode,errorMessage,errorType:BIZ},HTTP 仍 200)。BI 的 objectId = report/get 的 data.id(首次保存后 reportObjectId 同值)。",
13
+ authConfig: "BI 每个请求 body 必须带 config:{token,reportCode,appCode} 与外层 corpId(实测缺 config 的写会返回 {data:true} 但不生效——静默 no-op);token 取会话登录 token,corpId 为该部署 BI corp id(aozhe 实测 \"a\")。平台通道照旧 Authorization + X-LowCode-Corpid。",
14
+ reportPage: "report/create body {code,name,name_i18n:'{\"zh\":\"...\"}',parentId:<folder id>,icon,pcAble,mobileAble,appCode}(parentId 必填,否则断言失败);report/update 同形再加 id;report/logical_delete?code=。",
15
+ reportPageSave: "report/v2/reportpage body {report:{objectId,title,attributes:'<json字符串>',global:'<json字符串>'},corpId,config} → {data:'<objectId>'};用于首次创建 BI dashboard(全新报表页在 BI 侧不存在,需先 save 再读写图表)。",
16
+ chartWrite: "chart/addChart body {charts:[...]}、chart/updateChart body {charts:[...]}、chart/removeCharts body {objectIds:[<chart uuid>...]}、chart/removeChart body {objectId:<uuid>}(均需 corpId+config)。图表字段 uuid/type/position/dataSourceId/mainTable/data 等,position/data/styles 多为 JSON 字符串。",
17
+ globalAttributes: "report/saveGlobal body {objectId,global}、report/saveAttributes body {attributes,objectId}(均需 corpId+config);global/attributes 自身是 JSON 字符串。",
18
+ readback: "BI 配置读 report/v2/config body {corpId,objectId,config} → {data:{title,global,attributes,charts[]}};BI 侧不存在时返回 errorCode dashboard.not.exist(读时应报 present:false,不当作错误)。删除后以报表树(queryReportChartTreeByApp)缺席为准。",
19
+ datasource: "数据集读:report/v3/datasourcelist {}(业务模型表,nodeType=0)、dashboard/datasource/v2/datasource_list {}(同)、dashboard/datasource/advanced_list {}(自定义 SQL 数据集,nodeType=100/200)→ {data:[{dataSourceId,displayName,nodeType,useType,objectId,...}]}。关联:report/v3/datasource body {dataSourceInfos:[{dataSourceId,useType:1}]} → 返回该报表可用数据集模型(幂等重链)。",
20
+ chartdata: "图表数据读 datalogic/v3/chartdata body {chart,dataSourceId,corpId,config}:chart 是存储图表的 data 展平后(dimension/metric/filter/sort 提到顶层)且 limit 归一为 Integer(存储里是 {value,showOthers} 对象,直接回放会被拒 server.error);id 取 uuid。",
21
+ });
22
+ const REPORT_SCOPE = "report tree read page metadata BI config chart data create update delete configure";
23
+ export const REPORT_LANE_CONTRACT = Object.freeze({
24
+ lane: LANES.report,
25
+ family: CONTRACT_FAMILY,
26
+ referenceVersion: CONTRACT_REFERENCE_VERSION,
27
+ endpoints: Object.freeze({
28
+ treeAll: "reportTreeAll",
29
+ treeByApp: "reportTreeByApp",
30
+ get: "reportGet",
31
+ create: "reportCreate",
32
+ update: "reportUpdate",
33
+ delete: "reportDelete",
34
+ biConfig: "biReportConfig",
35
+ biPageSave: "biReportPageSave",
36
+ biRemove: "biReportRemove",
37
+ biSaveGlobal: "biReportSaveGlobal",
38
+ biSaveAttributes: "biReportSaveAttributes",
39
+ biChartAdd: "biChartAdd",
40
+ biChartUpdate: "biChartUpdate",
41
+ biChartRemove: "biChartRemove",
42
+ biChartRemoveMany: "biChartRemoveMany",
43
+ biChartData: "biChartData",
44
+ biDatasourceModelList: "biDatasourceModelList",
45
+ biDatasourceModelLink: "biDatasourceModelLink",
46
+ biDatasourceAdvancedList: "biDatasourceAdvancedList",
47
+ biDatasourceList: "biDatasourceList",
48
+ }),
49
+ wire: Object.freeze({
50
+ surface: REPORT_WIRE.surface,
51
+ authConfig: REPORT_WIRE.authConfig,
52
+ reportPage: REPORT_WIRE.reportPage,
53
+ reportPageSave: REPORT_WIRE.reportPageSave,
54
+ chartWrite: REPORT_WIRE.chartWrite,
55
+ globalAttributes: REPORT_WIRE.globalAttributes,
56
+ readback: REPORT_WIRE.readback,
57
+ datasource: REPORT_WIRE.datasource,
58
+ chartdata: REPORT_WIRE.chartdata,
59
+ }),
60
+ wireBindings: Object.freeze({
61
+ surface: Object.freeze([behaviorBinding("test/report.test.ts#report lane pins the platform + BI channel split", assertReportContract)]),
62
+ authConfig: Object.freeze([behaviorBinding("test/report.test.ts#report lane pins the platform + BI channel split", assertReportContract)]),
63
+ reportPage: Object.freeze([behaviorBinding("test/report.test.ts#report.create creates the page then seeds the BI dashboard", assertReportContract)]),
64
+ reportPageSave: Object.freeze([behaviorBinding("test/report.test.ts#report.create creates the page then seeds the BI dashboard", assertReportContract)]),
65
+ chartWrite: Object.freeze([behaviorBinding("test/report.test.ts#report.configure diffs charts and saves global/attributes", assertReportContract)]),
66
+ globalAttributes: Object.freeze([behaviorBinding("test/report.test.ts#report.configure diffs charts and saves global/attributes", assertReportContract)]),
67
+ readback: Object.freeze([behaviorBinding("test/report.test.ts#report.get reports present:false when the BI dashboard is missing", assertReportContract)]),
68
+ datasource: Object.freeze([behaviorBinding("test/report.test.ts#report.datasource.list reads the three sources and link posts dataSourceInfos", assertReportContract)]),
69
+ chartdata: Object.freeze([behaviorBinding("test/report.test.ts#report.chartdata flattens the stored chart and normalizes limit", assertReportContract)]),
70
+ }),
71
+ evidence: Object.freeze([
72
+ ".scratch/omc-report/recon.md",
73
+ "packages/omc-cli/src/lanes/report.ts",
74
+ "packages/omc-cli/src/bi-wire.ts",
75
+ "packages/omc-cli/test/report.test.ts",
76
+ ]),
77
+ tools: Object.freeze({
78
+ "report.tree": Object.freeze({
79
+ scope: REPORT_SCOPE,
80
+ description: "读取报表树:`appCode` 省略时读全量(app/folders/queryReportChartTree),提供时读该应用(runtime/app/queryReportChartTreeByApp)。返回报表页扁平清单(appCode/code/name/objectId)及其图表摘要(uuid/title/type)。只读。",
81
+ }),
82
+ "report.get": Object.freeze({
83
+ scope: REPORT_SCOPE,
84
+ description: "读取报表页元数据(/api/api/report/get,code)并合读 BI 配置(report/v2/config,objectId=元数据 id):present、title、图表清单、global/attributes 是否非空。BI dashboard 不存在时 present:false(errorCode dashboard.not.exist 非错误)。`full:true` 返回两侧原始报文。只读。",
85
+ }),
86
+ "report.chartdata": Object.freeze({
87
+ scope: REPORT_SCOPE,
88
+ description: "按图表定义取运行时数据(datalogic/v3/chartdata):入参 reportCode/appCode/chart(来自 report.get 的图表对象)/dataSourceId。工具把存储图表的 data 展平并归一化 limit 为 Integer 后查询(查看器同款),返回平台原始 {data}。运行时读,不占写锁。",
89
+ }),
90
+ "report.datasource.list": Object.freeze({
91
+ scope: REPORT_SCOPE,
92
+ description: "读取报表可用数据集:kind 取 model(report/v3/datasourcelist,业务模型表 nodeType=0)/ advanced(dashboard/datasource/advanced_list,自定义 SQL 数据集 nodeType=100/200)/ all(两者合并去重)。返回 dataSourceId/displayName/nodeType/useType。只读。",
93
+ }),
94
+ "report.datasource.link": Object.freeze({
95
+ scope: REPORT_SCOPE,
96
+ description: "把数据集关联到报表页(report/v3/datasource,body {dataSourceInfos:[{dataSourceId,useType}]});返回该报表可用的数据集模型。幂等重链。",
97
+ }),
98
+ "report.create": Object.freeze({
99
+ scope: REPORT_SCOPE,
100
+ description: "新建报表页:平台 report/create(code,name,appCode,parentId 必填;parentId 取所属分组 folder id)再 BI report/v2/reportpage 初始化 dashboard(global 用默认主题)。readback 见 report.get。",
101
+ }),
102
+ "report.update": Object.freeze({
103
+ scope: REPORT_SCOPE,
104
+ description: "更新报表页元数据(report/update):name/name_i18n/icon/pcAble/mobileAble/parentId;先 report/get 取 id。readback 见 report/get。",
105
+ }),
106
+ "report.delete": Object.freeze({
107
+ scope: REPORT_SCOPE,
108
+ description: "删除报表页:先 BI report/removeReport 删 dashboard,再平台 report/logical_delete?code=。readback 以报表树缺席为准(report/get 可能仍返回软删记录)。",
109
+ }),
110
+ "report.configure": Object.freeze({
111
+ scope: REPORT_SCOPE,
112
+ description: "配置既有报表页:`global`→saveGlobal、`attributes`→saveAttributes(对象或 JSON 字符串,缺省不触碰);`charts` 按 uuid diff——已存在 updateChart、缺失 addChart、`removeUnlistedCharts` 为真时删除未列出的既有图表(removeCharts);执行后 report/v2/config 读回。BI 侧不存在则先报错提示用 report.create。",
113
+ }),
114
+ }),
115
+ });
116
+ export function assertReportContract() {
117
+ assertLaneContract(REPORT_LANE_CONTRACT);
118
+ if (!REPORT_WIRE.surface.includes("/dashboard/v1/"))
119
+ throw new Error("report contract must pin the BI channel");
120
+ if (!REPORT_WIRE.authConfig.includes("config"))
121
+ throw new Error("report contract must pin the in-body config auth");
122
+ if (!REPORT_WIRE.reportPage.includes("parentId"))
123
+ throw new Error("report contract must pin the required parentId");
124
+ if (!REPORT_WIRE.reportPageSave.includes("report/v2/reportpage"))
125
+ throw new Error("report contract must pin the BI page save");
126
+ if (!REPORT_WIRE.chartWrite.includes("addChart"))
127
+ throw new Error("report contract must pin addChart");
128
+ if (!REPORT_WIRE.chartWrite.includes("removeCharts"))
129
+ throw new Error("report contract must pin removeCharts");
130
+ if (!REPORT_WIRE.globalAttributes.includes("saveGlobal"))
131
+ throw new Error("report contract must pin saveGlobal");
132
+ if (!REPORT_WIRE.readback.includes("dashboard.not.exist"))
133
+ throw new Error("report contract must pin the missing-dashboard read");
134
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.tree", ["queryReportChartTree", "queryReportChartTreeByApp"]);
135
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.get", ["report/get", "report/v2/config", "present"]);
136
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.chartdata", ["chartdata", "report.get", "limit"]);
137
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.create", ["report/create", "parentId"]);
138
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.update", ["report/update"]);
139
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.delete", ["removeReport", "logical_delete"]);
140
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.configure", ["saveGlobal", "addChart", "updateChart", "removeCharts"]);
141
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.datasource.list", ["datasourcelist", "advanced_list"]);
142
+ assertDescriptionCarries(REPORT_LANE_CONTRACT, "report.datasource.link", ["v3/datasource", "dataSourceInfos"]);
143
+ }
144
+ //# sourceMappingURL=report-contract.js.map
@@ -0,0 +1,21 @@
1
+ import { claim, declareLaneCoverage } from "./coverage-declaration.js";
2
+ import { REPORT_LANE_CONTRACT } from "./report-contract.js";
3
+ const T = REPORT_LANE_CONTRACT.tools;
4
+ export const REPORT_COVERAGE = declareLaneCoverage(REPORT_LANE_CONTRACT.lane, [
5
+ {
6
+ capability: "R1 report page and BI chart lifecycle",
7
+ evidence: ["packages/omc-cli/src/lanes/report.ts", "packages/omc-cli/test/report.test.ts", ".scratch/omc-report/recon.md"],
8
+ tools: [
9
+ claim("report.tree", T["report.tree"].scope),
10
+ claim("report.get", T["report.get"].scope),
11
+ claim("report.chartdata", T["report.chartdata"].scope),
12
+ claim("report.datasource.list", T["report.datasource.list"].scope),
13
+ claim("report.datasource.link", T["report.datasource.link"].scope),
14
+ claim("report.create", T["report.create"].scope),
15
+ claim("report.update", T["report.update"].scope),
16
+ claim("report.delete", T["report.delete"].scope),
17
+ claim("report.configure", T["report.configure"].scope),
18
+ ],
19
+ },
20
+ ]);
21
+ //# sourceMappingURL=report-coverage.js.map