@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,390 @@
1
+ import { zodToJsonSchema } from "zod-to-json-schema";
2
+ import { z } from "zod";
3
+ import { LANE_CONTRACTS } from "./contract-resources.js";
4
+ import { intentCapabilityBlock } from "./intent/cli.js";
5
+ import { listSkills } from "./skills.js";
6
+ import { capabilityRouteForTool, capabilityRouteForLane, capabilityRouteIndex, DISCOVERY_AUTHORITY } from "./capability-overview.js";
7
+ /**
8
+ * `commands --json` — the tool catalogue.
9
+ *
10
+ * Round 13 slimmed it. It used to inline `discovery` (the full 14-capability
11
+ * route projection, ~11.4 KB, byte-identical to `omc capabilities`), and every
12
+ * tool row repeated `writeGate` (7.5 KB), `timeout` (7.7 KB), and a full
13
+ * `capability` object (10.5 KB) whose `nickname` == `id` and whose `lane` is
14
+ * already the row's own lane. That was ~37 KB of repetition in a 56 KB payload
15
+ * read once and re-sent every later turn. The route projection stays one
16
+ * command away (`omc capabilities`), and the per-kind governance constants move
17
+ * to one top-level `governance` block; each row keeps the bare `capability` id
18
+ * so `--compact --filter/--lane` still matches capabilities.
19
+ *
20
+ * `--compact` (round 3) drops the catalogue prose blocks and per-tool example
21
+ * args, leaving a bounded `purpose` line per tool.
22
+ */
23
+ export function commandInventory(registry, options = {}) {
24
+ const routeByLane = capabilityRouteIndex(registry).routeByLane;
25
+ // One row shape for both modes (round 13). Recipe ids stay on every row: they
26
+ // let the agent run `describe <tool> --example <id>` (~1–2 KB) instead of
27
+ // `--full` (16 KB). The row no longer repeats `writeGate`/`timeout` (per-kind
28
+ // constants, in the top-level `governance` block) or a full `capability`
29
+ // object (the bare id; `nickname` == `id`, `lane` == the row's own lane,
30
+ // aliases come from `omc capabilities`).
31
+ const rows = registry.map((tool) => {
32
+ const capability = typeof tool.lane === "string" ? routeByLane.get(tool.lane) : undefined;
33
+ const recipes = (tool.executionMetadata?.recipes ?? []).map((recipe) => recipe.id);
34
+ return {
35
+ name: tool.name,
36
+ lane: tool.lane ?? null,
37
+ kind: tool.kind,
38
+ requiredArgs: requiredArgs(tool),
39
+ ...(capability ? { capability: capability.id } : {}),
40
+ ...(recipes.length > 0 ? { recipes } : {}),
41
+ };
42
+ });
43
+ if (options.compact === true) {
44
+ // The machine inventory: rows only, no catalogue prose. `--compact` used to
45
+ // trade boilerplate for a bounded `purpose` line; with the rows slimmed
46
+ // (round 13) the prose is the only difference left, so a compact query is
47
+ // now a strict subset of the full catalogue.
48
+ return {
49
+ discovery: { authoritative: DISCOVERY_AUTHORITY.authoritative, route: DISCOVERY_AUTHORITY.route },
50
+ tools: rows,
51
+ };
52
+ }
53
+ return {
54
+ // The authoritative route, identical to `omc help` / `omc capabilities`
55
+ // (ticket-07 pins the four-surface agreement). The heavy part that used to
56
+ // live here was the 11.4 KB capability projection, byte-identical to `omc
57
+ // capabilities`; that is now named, not copied.
58
+ discovery: { ...DISCOVERY_AUTHORITY },
59
+ // Per-kind constants, stated once (round 13). `kind` on each row is the
60
+ // discriminator; the write gate applies only to `kind:"write"`.
61
+ governance: {
62
+ writeGate: {
63
+ write: "environment writable permission; production needs confirmProduction",
64
+ read: "none",
65
+ governance: "none",
66
+ meta: "none",
67
+ },
68
+ timeout: { behavior: "bounded per call with --timeout-ms; timeout returns uncertain" },
69
+ },
70
+ tools: rows,
71
+ // Ticket 122 (Spec 107): the methodology layer — reachable via `omc help
72
+ // <topic>`, which lists this same inventory.
73
+ skills: listSkills(),
74
+ // Ticket 117 (Spec 107): the declarative usage face — agents discover the
75
+ // intent layer (families, lifecycle, constraints) here, wire details stay
76
+ // in the per-tool entries.
77
+ intent: intentCapabilityBlock(),
78
+ // Ticket 125: the Configuration capability overview lives one command away;
79
+ // this is only a pointer so `commands --json` stays a tool catalogue.
80
+ capabilities: {
81
+ command: "omc capabilities",
82
+ detail: "omc capability <id>",
83
+ note: "capability / order / declarative-coverage overview; not inlined here",
84
+ },
85
+ };
86
+ }
87
+ /**
88
+ * Bare `omc commands` (no `--json`, no `--compact`, no scope): a bounded INDEX,
89
+ * not the 54 KB catalogue.
90
+ *
91
+ * Round 9 heavy-task measurement (sandbox 38): an agent exploring cold ran bare
92
+ * `commands` 4× at ~54 KB each — ~216 KB, 28% of the whole task — even though
93
+ * the full rows are the fallback face and `next`/`--compact --lane` exist. The
94
+ * bytes were paid before any hint could be read. So the DEFAULT face is now the
95
+ * lean index (name/lane/kind + lane counts + how to expand); the full rows
96
+ * require the documented machine entry `commands --json`, and one capability is
97
+ * `commands --json --compact --lane <lane>`.
98
+ */
99
+ export function commandIndex(registry) {
100
+ const byLane = new Map();
101
+ for (const tool of registry) {
102
+ const lane = tool.lane ?? "(unbound)";
103
+ byLane.set(lane, (byLane.get(lane) ?? 0) + 1);
104
+ }
105
+ return {
106
+ discovery: { authoritative: DISCOVERY_AUTHORITY.authoritative, route: DISCOVERY_AUTHORITY.route },
107
+ toolCount: registry.length,
108
+ lanes: [...byLane.entries()].map(([lane, tools]) => ({ lane, tools })).sort((left, right) => left.lane.localeCompare(right.lane)),
109
+ tools: registry.map((tool) => ({ name: tool.name, lane: tool.lane ?? null, kind: tool.kind })),
110
+ hint: "裸 `commands` 是有界索引(name/lane/kind)。全量行用 `omc commands --json`;单能力用 `omc commands --json --compact --lane <lane>`;关键词用 `--filter <word>`;目标→路线优先 `omc next \"<目标>\"`。",
111
+ };
112
+ }
113
+ const convertToJsonSchema = zodToJsonSchema;
114
+ function jsonSchemaFor(shape) {
115
+ const objectSchema = z.object(shape);
116
+ return convertToJsonSchema(objectSchema, { target: "jsonSchema7", $refStrategy: "none" });
117
+ }
118
+ /**
119
+ * Context-cost projection: the default `describe` must stay small. A tool
120
+ * contract used to be 14–20 KB (`inputSchema` alone was >50%), and an agent
121
+ * reading it 19 times paid ~100k tokens for a handful of facts. The compact
122
+ * form answers "what can I pass, what is required, what is one runnable call"
123
+ * in ~1–2 KB; the full schema, recipes, and capability route live behind
124
+ * `describe <tool> --full` and `describe <tool> --param <name>`.
125
+ */
126
+ /** First sentence, whitespace-collapsed and bounded — enough to pick a tool. */
127
+ function summarizeDescription(description) {
128
+ const collapsed = description.replace(/\s+/g, " ").trim();
129
+ const firstStop = collapsed.search(/[。.;;!!??]/);
130
+ const sentence = firstStop >= 0 ? collapsed.slice(0, firstStop + 1) : collapsed;
131
+ return sentence.length > 200 ? `${sentence.slice(0, 197)}...` : sentence;
132
+ }
133
+ /** A terse type label: `string`, `integer`, `array<string>`, `string: A|B`. */
134
+ function terseType(node) {
135
+ if (!node)
136
+ return "any";
137
+ if (Array.isArray(node.enum) && node.enum.length > 0) {
138
+ const values = node.enum.map((value) => String(value));
139
+ const label = `${node.type ?? "string"}: ${values.join("|")}`;
140
+ return label.length > 80 ? `${node.type ?? "string"} (enum)` : label;
141
+ }
142
+ if (node.type === "array")
143
+ return `array<${terseType(node.items)}>`;
144
+ return node.type ?? "any";
145
+ }
146
+ /** Compact params: `required` list + `param -> type`, no per-param prose. */
147
+ function compactParams(schema) {
148
+ const required = [...(schema.required ?? [])];
149
+ const params = {};
150
+ for (const [key, node] of Object.entries(schema.properties ?? {}))
151
+ params[key] = terseType(node);
152
+ return { required, params };
153
+ }
154
+ /**
155
+ * The example list: every recipe's id/title/status, but none of its args. This
156
+ * keeps the default `describe` small while still telling the agent which shapes
157
+ * exist; the full args come from `describe <tool> --example <id>`. A tool with
158
+ * no recipe says so explicitly and names the precondition rather than returning
159
+ * a silent `available:false`.
160
+ */
161
+ function exampleList(tool) {
162
+ const recipes = tool.executionMetadata?.recipes ?? [];
163
+ if (recipes.length === 0) {
164
+ // Read/plain tools have no authored recipe because `required` + `params`
165
+ // already fully describe the call. Pointing them at `--full` (5–20 KB) made
166
+ // dogfood agents pay for it anyway (sandbox20: ~10 KB of read-tool --full
167
+ // calls). Name the cheap faces instead.
168
+ return [{ requiresPriorReadback: tool.kind === "write", reason: "no authored recipe needed: `required` + `params` above describe the call; per-param prose via --param <name>" }];
169
+ }
170
+ return recipes.map((recipe) => ({
171
+ id: recipe.id,
172
+ title: recipe.title,
173
+ status: recipe.status,
174
+ requiresPriorReadback: recipe.requiresEnvironmentDerivedIds,
175
+ }));
176
+ }
177
+ /** Default `omc describe`: the compact contract projection. */
178
+ export function describeTool(registry, name) {
179
+ const tool = registry.find((entry) => entry.name === name);
180
+ if (!tool)
181
+ return undefined;
182
+ const schema = jsonSchemaFor(tool.inputSchema);
183
+ const { required, params } = compactParams(schema);
184
+ const examples = exampleList(tool);
185
+ const hasRecipe = (tool.executionMetadata?.recipes.length ?? 0) > 0;
186
+ return {
187
+ name: tool.name,
188
+ lane: tool.lane ?? null,
189
+ kind: tool.kind,
190
+ summary: summarizeDescription(tool.description),
191
+ required,
192
+ params,
193
+ examples,
194
+ // Point cold callers at the cheap runnable face BEFORE they reach for
195
+ // --full: a recipe is ~1–2 KB and a single --param is a few hundred bytes,
196
+ // while --full is 5–20 KB. Benchmark (bench13): two --full calls were 34 KB
197
+ // of a 133 KB task even though a matching recipe existed.
198
+ ...(hasRecipe ? { exampleHint: `可运行参数用 --example <id>(~1–2KB);单参数用 --param <name>;仅当二者都缺形状才 --full` } : {}),
199
+ ...(!hasRecipe ? { exampleHint: `无静态 recipe:required + params 已够常规调用;单参数说明用 --param <name>;仅当需要全部参数注释/拒绝形状才 --full(5–20KB)` } : {}),
200
+ // Keep the cost salient at the decision point: agents reached for --full even
201
+ // when --example/--param existed (sandbox22: 8 --full calls, one 19 KB).
202
+ full: `omc describe ${tool.name} --full(5–20KB;先试 --example/--param)`,
203
+ };
204
+ }
205
+ /** `omc describe <tool> --example <id>`: one recipe in full, by id. */
206
+ export function describeExample(registry, name, exampleId) {
207
+ const tool = registry.find((entry) => entry.name === name);
208
+ if (!tool)
209
+ return undefined;
210
+ const recipes = tool.executionMetadata?.recipes ?? [];
211
+ const recipe = exampleId === undefined ? undefined : recipes.find((entry) => entry.id === exampleId);
212
+ if (!recipe) {
213
+ // No id (or an unknown one) lists the runnable ids instead of a dead end, so
214
+ // an agent that guessed never burns a retry (sandbox26: `--example` with no
215
+ // id was a hard commander error; an unknown id already listed `available`).
216
+ return {
217
+ name: tool.name,
218
+ ...(exampleId !== undefined ? { example: exampleId } : {}),
219
+ found: false,
220
+ available: recipes.map((entry) => entry.id),
221
+ ...(recipes[0] ? { hint: `本工具的例子 id 是 ${recipes.map((entry) => entry.id).join("、")};用 describe ${tool.name} --example ${recipes[0].id} 取可运行参数` } : {}),
222
+ };
223
+ }
224
+ return {
225
+ name: tool.name,
226
+ example: recipe.id,
227
+ title: recipe.title,
228
+ recipeStatus: recipe.status,
229
+ tool: recipe.tool,
230
+ args: recipe.args,
231
+ command: `omc call ${recipe.tool} --args '<json>'`,
232
+ preconditions: recipe.preconditions,
233
+ conditionalRequirements: recipe.conditionalRequirements,
234
+ priorToolReferences: recipe.priorToolReferences,
235
+ dryRun: recipe.dryRun,
236
+ expectedReadback: recipe.expectedReadback,
237
+ refusalRecovery: recipe.refusalRecovery,
238
+ };
239
+ }
240
+ /** One param's full schema and prose — the targeted replacement for reading the whole contract. */
241
+ export function describeParam(registry, name, param) {
242
+ const tool = registry.find((entry) => entry.name === name);
243
+ if (!tool)
244
+ return undefined;
245
+ const schema = jsonSchemaFor(tool.inputSchema);
246
+ const node = schema.properties?.[param];
247
+ if (!node) {
248
+ return { name: tool.name, param, found: false, available: Object.keys(schema.properties ?? {}) };
249
+ }
250
+ return {
251
+ name: tool.name,
252
+ param,
253
+ required: (schema.required ?? []).includes(param),
254
+ type: terseType(node),
255
+ ...(node.description ? { description: node.description } : {}),
256
+ schema: node,
257
+ };
258
+ }
259
+ /**
260
+ * `omc describe <tool> --full`: the complete contract (schema, capability route).
261
+ *
262
+ * Round 13: `--full` used to also inline `executionMetadata` — the whole recipe
263
+ * set with full args, expectedReadback and refusalRecovery (7–8 KB for
264
+ * field.create / rule.save). That is reachable two cheaper ways already: the
265
+ * default `describe` lists the recipe ids, and `describe <tool> --example <id>`
266
+ * returns one recipe in ~1–2 KB. `commands --json` also carries the per-tool
267
+ * recipe ids. Bench (bench35 sandbox): a 77 k peak task spent 70 KB on four
268
+ * `describe --full` calls, of which the recipes were ~30 KB. `--full` now names
269
+ * the recipe ids (in `recipeIds`) and leaves the args to `--example`.
270
+ */
271
+ export function describeToolFull(registry, name) {
272
+ const tool = registry.find((entry) => entry.name === name);
273
+ if (!tool)
274
+ return undefined;
275
+ const schema = jsonSchemaFor(tool.inputSchema);
276
+ const recipes = tool.executionMetadata?.recipes ?? [];
277
+ const recipe = recipes[0];
278
+ const capability = capabilityRouteForTool(registry, tool.name);
279
+ return {
280
+ name: tool.name,
281
+ lane: tool.lane ?? null,
282
+ kind: tool.kind,
283
+ description: tool.description,
284
+ ...(capability ? { capability } : {}),
285
+ inputSchema: schema,
286
+ // Recipe ids only — the args live behind `--example <id>` (round 13). This
287
+ // keeps `--full` to its job (the schema + prose) instead of re-shipping the
288
+ // recipe set the default face and `--example` already cover.
289
+ ...(recipes.length > 0 ? { recipeIds: recipes.map((entry) => entry.id) } : {}),
290
+ // --full is 5–20 KB. When the tool has runnable recipes, remind the caller
291
+ // (bench17 still pulled 18 KB of field.create --full and 8 KB of
292
+ // workflow.update --full although matching recipes existed) that the recipe
293
+ // is the cheaper, authoritative shape.
294
+ ...(recipes.length > 0
295
+ ? { recipeHint: `本工具已有可运行 recipe(${recipes.map((entry) => entry.id).join("、")});用 --example <id>(~1–2KB)取可运行参数,不要在 --full 里找` }
296
+ : {}),
297
+ example: recipe
298
+ ? {
299
+ command: `omc call ${recipe.tool} --args '<json>'`,
300
+ tool: recipe.tool,
301
+ args: recipe.args,
302
+ recipeId: recipe.id,
303
+ status: recipe.status,
304
+ }
305
+ : {
306
+ tool: tool.name,
307
+ available: false,
308
+ reason: "no scenario-specific recipe; use inputSchema and discover prerequisites before execution",
309
+ },
310
+ };
311
+ }
312
+ /** `omc describe <tool> --schema-only`: the raw JSON schema, nothing else. */
313
+ export function describeSchemaOnly(registry, name) {
314
+ const tool = registry.find((entry) => entry.name === name);
315
+ if (!tool)
316
+ return undefined;
317
+ return { name: tool.name, inputSchema: jsonSchemaFor(tool.inputSchema) };
318
+ }
319
+ /**
320
+ * `omc contract <lane>` — the compact default: who the lane binds, which tools
321
+ * it owns, and the wire structure's key outline. The full wire payload (14–23 KB)
322
+ * lives behind `--full`; most of the time an agent needs the tool names and the
323
+ * shape's top-level keys, not the nested bodies.
324
+ */
325
+ export function describeContract(registry, lane) {
326
+ const contract = LANE_CONTRACTS.find((entry) => entry.lane === lane);
327
+ if (!contract)
328
+ return undefined;
329
+ const route = capabilityRouteForLane(registry, contract.lane);
330
+ return {
331
+ contract: {
332
+ lane: contract.lane,
333
+ family: contract.family,
334
+ referenceVersion: contract.referenceVersion,
335
+ tools: Object.keys(contract.tools),
336
+ wireKeys: Object.keys(contract.wire),
337
+ endpointKeys: Object.keys(contract.endpoints),
338
+ ...(route ? { capability: { nickname: route.nickname, id: route.id, lane: route.lane, aliases: route.aliases } } : {}),
339
+ full: `omc contract ${contract.lane} --full`,
340
+ },
341
+ };
342
+ }
343
+ /** `omc contract <lane> --full`: the complete wire contract. */
344
+ export function describeContractFull(registry, lane) {
345
+ const contract = LANE_CONTRACTS.find((entry) => entry.lane === lane);
346
+ if (!contract)
347
+ return undefined;
348
+ const route = capabilityRouteForLane(registry, contract.lane);
349
+ const shape = {
350
+ lane: contract.lane,
351
+ family: contract.family,
352
+ referenceVersion: contract.referenceVersion,
353
+ endpoints: contract.endpoints,
354
+ wire: contract.wire,
355
+ tools: contract.tools,
356
+ ...(route ? { capability: route } : {}),
357
+ };
358
+ return { contract: shape };
359
+ }
360
+ /**
361
+ * `omc contract <lane> --tool <name>` (round 3): one tool's authored lane
362
+ * contract slice. An agent that already knows the tool should not pull the
363
+ * whole 14–23 KB lane contract (the `tools` block alone is ~10 KB of prose).
364
+ * A missing tool names the available ones instead of silently returning empty.
365
+ */
366
+ export function describeContractTool(registry, lane, toolName) {
367
+ const contract = LANE_CONTRACTS.find((entry) => entry.lane === lane);
368
+ if (!contract)
369
+ return undefined;
370
+ const tool = contract.tools[toolName];
371
+ if (!tool) {
372
+ return { contract: { lane: contract.lane, family: contract.family, referenceVersion: contract.referenceVersion, tool: toolName, found: false, available: Object.keys(contract.tools) } };
373
+ }
374
+ const route = capabilityRouteForLane(registry, contract.lane);
375
+ return {
376
+ contract: {
377
+ lane: contract.lane,
378
+ family: contract.family,
379
+ referenceVersion: contract.referenceVersion,
380
+ tool: { name: toolName, scope: tool.scope, description: tool.description },
381
+ ...(route ? { capability: { nickname: route.nickname, id: route.id, lane: route.lane, aliases: route.aliases } } : {}),
382
+ full: `omc contract ${contract.lane} --full`,
383
+ },
384
+ };
385
+ }
386
+ function requiredArgs(tool) {
387
+ const schema = jsonSchemaFor(tool.inputSchema);
388
+ return schema.required ?? [];
389
+ }
390
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Live-proven CloudPivot 8.6 wire endpoints (from the M1 coverage manifest
3
+ * evidence chains). Every low-level tool drives exactly these paths — no
4
+ * invented surfaces.
5
+ */
6
+ export const ENDPOINTS = {
7
+ applicationList: "/api/api/app/apppackage/list",
8
+ applicationGroupList: "/api/api/app/apppackage/list_all_group",
9
+ applicationGet: "/api/api/app/apppackage/get",
10
+ applicationCreate: "/api/api/app/apppackage/create",
11
+ applicationUpdate: "/api/api/app/apppackage/update",
12
+ applicationDelete: "/api/api/app/apppackage/delete",
13
+ applicationTree: "/api/api/app/apppackage/trees",
14
+ modelList: "/api/api/app/bizmodels/list_schema",
15
+ modelGet: "/api/api/app/bizmodels/get_all",
16
+ modelCreate: "/api/api/app/bizmodels/create",
17
+ modelGetSummary: "/api/api/app/bizmodels/get_summary",
18
+ modelUpdateSummary: "/api/api/app/bizmodels/update_summary",
19
+ modelUpdate: "/api/api/app/bizmodels/update",
20
+ appPackagePhysicallyDelete: "/api/api/app/apppackage/physically_delete",
21
+ fieldList: "/api/api/app/bizproperty/list",
22
+ fieldGet: "/api/api/app/bizproperty/get",
23
+ fieldCreate: "/api/api/app/bizproperty/create",
24
+ fieldUpdate: "/api/api/app/bizproperty/update",
25
+ fieldPublish: "/api/api/app/bizproperty/publish",
26
+ fieldDelete: "/api/api/app/bizproperty/delete",
27
+ fieldForceDelete: "/api/api/app/bizproperty/force_delete",
28
+ dictionarySearch: "/api/api/data_dictionary/searchDictionary",
29
+ dictionaryGet: "/api/api/data_dictionary/getDictionaryById",
30
+ dictionaryGetByCode: "/api/api/data_dictionary/getDictionaryByCode",
31
+ dictionaryGetByType: "/api/api/data_dictionary/getDictionaryByType",
32
+ dictionaryIdAndNames: "/api/api/data_dictionary/getDictionaryIdAndNames",
33
+ dictionarySave: "/api/api/data_dictionary/saveDictionary",
34
+ dictionaryUpdateStatus: "/api/api/data_dictionary/updateDictionaryStatus",
35
+ dictionaryRecords: "/api/api/data_dictionary/searchDictionaryRecord",
36
+ dictionaryRecordsByCode: "/api/api/data_dictionary/searchDictionaryRecordByCode",
37
+ dictionaryEnabledRecords: "/api/api/data_dictionary/getEnableRecordsByDictionaryId",
38
+ dictionaryEnabledRecordsByCode: "/api/api/data_dictionary/getEnableRecordsByDictionaryCode",
39
+ dictionaryParentRecords: "/api/api/data_dictionary/getDictionaryRecordByParentId",
40
+ dictionaryRecordStatus: "/api/api/data_dictionary/updateDictionaryRecordStatus",
41
+ dictionaryRecordUsed: "/api/api/data_dictionary/updateDictionaryRecordUsed",
42
+ dictionaryClasses: "/api/api/data_dictionary/getDictionaryClass",
43
+ dictionaryClassDetail: "/api/api/data_dictionary/getDictionaryClassDetail",
44
+ dictionaryClassSave: "/api/api/data_dictionary/saveDictionaryClass",
45
+ dictionaryClassDelete: "/api/api/data_dictionary/deleteDictionaryClass",
46
+ dictionaryClassDeleteBatch: "/api/api/data_dictionary/deleteDictionaryClassBatch",
47
+ sheetGet: "/api/api/app/bizsheet/get",
48
+ sheetCreate: "/api/api/app/bizsheet/create",
49
+ sheetUpdate: "/api/api/app/bizsheet/update",
50
+ sheetPublish: "/api/api/app/bizsheet/publish",
51
+ sheetHistoryList: "/api/api/app/bizsheet/history/list",
52
+ businessRuleListBySchemaCode: "/api/api/app/businessrule/list_by_schemacode",
53
+ runtimeBusinessRuleListBySchemaCode: "/api/api/runtime/business_rule/list_by_schemacode",
54
+ businessRuleGet: "/api/api/app/businessrule/get",
55
+ businessRuleCreate: "/api/api/app/businessrule/create",
56
+ businessRuleUpdate: "/api/api/app/businessrule/update",
57
+ businessRulePublish: "/api/api/app/businessrule/publish",
58
+ businessRuleEnable: "/api/api/app/businessrule/enable",
59
+ businessRuleDelete: "/api/api/app/businessrule/delete",
60
+ dataRuleCreate: "/api/api/app/bizdatarule/create",
61
+ dataRuleList: "/api/api/app/bizdatarule/list",
62
+ dataRuleUpdate: "/api/api/app/bizdatarule/update",
63
+ dataRuleDelete: "/api/api/app/bizdatarule/delete",
64
+ runtimeFormSave: "/api/api/runtime/form/save",
65
+ runtimeFormLoad: "/api/api/runtime/form/load",
66
+ runtimeFormReplayToken: "/api/api/runtime/form/getReplayToken",
67
+ runtimeQueryList: "/api/api/runtime/query/list",
68
+ runtimeFormDelete: "/api/api/runtime/form/delete",
69
+ runtimeFormSubmit: "/api/api/runtime/form/submit",
70
+ bizServiceCreate: "/api/api/bizservice/service/create",
71
+ bizServiceUpdate: "/api/api/bizservice/service/update",
72
+ bizServiceGetByCode: "/api/api/bizservice/service/get_by_code",
73
+ bizServiceCategoryList: "/api/api/bizservice/category/list",
74
+ bizServiceCategoryCreate: "/api/api/bizservice/category/create",
75
+ bizServiceCategoryUpdate: "/api/api/bizservice/category/update",
76
+ bizServiceCategoryDelete: "/api/api/bizservice/category/delete",
77
+ bizDbConnPoolList: "/api/api/bizservice/dbconnpool/list",
78
+ bizDbConnPoolCreate: "/api/api/bizservice/dbconnpool/create",
79
+ bizDbConnPoolUpdate: "/api/api/bizservice/dbconnpool/update",
80
+ bizDbConnPoolDelete: "/api/api/bizservice/dbconnpool/delete",
81
+ bizServiceAdapterConfig: "/api/api/bizservice/service/adapter_config",
82
+ bizServiceTableList: "/api/api/bizservice/method/get_tablename_list",
83
+ bizServiceTableSql: "/api/api/bizservice/method/get_table_column",
84
+ bizServiceMethodCreate: "/api/api/bizservice/method/create",
85
+ bizServiceMethodUpdate: "/api/api/bizservice/method/update",
86
+ bizServiceMethodGet: "/api/api/bizservice/method/get",
87
+ bizServiceMethodDelete: "/api/api/bizservice/method/delete",
88
+ bizServiceMethodTest: "/api/api/bizservice/method/service_test",
89
+ bizServiceMethodList: "/api/api/bizservice/method/list_by_service_code",
90
+ bizServiceDelete: "/api/api/bizservice/service/delete",
91
+ bizServiceExport: "/api/api/bizservice/service/export",
92
+ bizServiceCheck: "/api/api/bizservice/service/check",
93
+ bizServiceImport: "/api/api/bizservice/service/import",
94
+ runtimeQueryUploadFile: "/api/api/runtime/query/upload_file",
95
+ // `/api/api/programming/*` (design-time 在线开发: business-rule / SPI /
96
+ // service-component JAVA source) is deliberately NOT wrapped. It is backend
97
+ // Java authored through 二开扩展包, not form Online JS, and no operator asked
98
+ // for it here — so the CLI exposes no tool for it. Live 2026-09-21 evidence
99
+ // (ProgrammingController.java:99, base is the doubled `/api/api/programming`
100
+ // under the `/api` context-path; the earlier single-`/api` form 404s) is
101
+ // recorded in the online-js contract's history note.
102
+ workflowCreate: "/api/api/workflow/create",
103
+ workflowGetHeader: "/api/api/workflow/get_header",
104
+ workflowGetDraft: "/api/api/workflow/get_draft",
105
+ workflowIsWorkflow: "/api/api/workflow/isworkflow",
106
+ workflowGetBySchema: "/api/api/workflow/getWorkflow",
107
+ workflowGetPublished: "/api/api/workflow/get_published",
108
+ workflowUpdate: "/api/api/workflow/update",
109
+ workflowValidate: "/api/api/workflow/validate",
110
+ workflowPublish: "/api/api/workflow/publish",
111
+ workflowDelete: "/api/api/workflow/delete",
112
+ workflowSearchWorkItems: "/api/api/runtime/workflow/search_workitems",
113
+ workflowGetBizObjectByWfInstanceId: "/api/api/runtime/workflow/getBizObjectByWfInstanceId",
114
+ organizationRoleList: "/api/api/organization/role/list",
115
+ organizationDepartmentTree: "/api/api/organization/department/tree",
116
+ organizationUserSearch: "/api/api/organization/user/search",
117
+ listQueryCreate: "/api/api/app/query/create",
118
+ listQueryGet: "/api/api/app/query/get",
119
+ listQueryUpdate: "/api/api/app/query/update",
120
+ listQueryUpdateHeader: "/api/api/app/query/update_header",
121
+ listQueryGetHeader: "/api/api/app/query/get_header",
122
+ listQueryList: "/api/api/app/query/list",
123
+ listQueryDelete: "/api/api/app/query/delete",
124
+ // R1-report — design-time report pages live on the platform channel
125
+ // (`/api/api/report/*`, errcode envelope); the BI chart/dashboard face lives
126
+ // on the separate `/dashboard/v1/*` channel (no errcode envelope; auth is a
127
+ // `config` object carried in the request body). Both are live-proven on the
128
+ // aozhe tenant (AI-Platform-v1.1.22, engineCode aozhe).
129
+ reportTreeAll: "/api/api/app/folders/queryReportChartTree",
130
+ reportTreeByApp: "/api/api/runtime/app/queryReportChartTreeByApp",
131
+ reportGet: "/api/api/report/get",
132
+ reportFrontGet: "/api/api/report/frontget",
133
+ reportCreate: "/api/api/report/create",
134
+ reportUpdate: "/api/api/report/update",
135
+ reportDelete: "/api/api/report/logical_delete",
136
+ biReportConfig: "/dashboard/v1/report/v2/config",
137
+ biReportPageSave: "/dashboard/v1/report/v2/reportpage",
138
+ biReportRemove: "/dashboard/v1/report/removeReport",
139
+ biReportSaveGlobal: "/dashboard/v1/report/saveGlobal",
140
+ biReportSaveAttributes: "/dashboard/v1/report/saveAttributes",
141
+ biReportGlobalFilters: "/dashboard/v1/report/local_global_filters",
142
+ biChartAdd: "/dashboard/v1/chart/addChart",
143
+ biChartUpdate: "/dashboard/v1/chart/updateChart",
144
+ biChartRemove: "/dashboard/v1/chart/removeChart",
145
+ biChartRemoveMany: "/dashboard/v1/chart/removeCharts",
146
+ biChartUpdateTitle: "/dashboard/v1/chart/updateTitle",
147
+ biChartUpdatePositions: "/dashboard/v1/chart/updatePositions",
148
+ biChartData: "/dashboard/v1/datalogic/v3/chartdata",
149
+ biDatasourceModelList: "/dashboard/v1/report/v3/datasourcelist",
150
+ biDatasourceModelLink: "/dashboard/v1/report/v3/datasource",
151
+ biDatasourceAdvancedList: "/dashboard/datasource/advanced_list",
152
+ biDatasourceList: "/dashboard/datasource/v2/datasource_list",
153
+ };
154
+ //# sourceMappingURL=endpoints.js.map
@@ -0,0 +1,26 @@
1
+ /** The environment's write permission: the single machine-side write gate. */
2
+ export function environmentWritable(profile) {
3
+ return profile.writable === true;
4
+ }
5
+ export function environmentKind(profile) {
6
+ return profile.production === true ? "生产环境" : "测试环境";
7
+ }
8
+ /**
9
+ * A production environment is a high-risk write target: writable exactly like
10
+ * any other, but every write must carry an explicit per-write confirmation that
11
+ * is recorded in the audit artifact. The mark is a risk label, not a gate.
12
+ */
13
+ export function requiresProductionConfirmation(profile) {
14
+ return profile.production === true;
15
+ }
16
+ export function environmentNotice(profile) {
17
+ if (profile.production === true) {
18
+ return environmentWritable(profile)
19
+ ? "当前是生产环境;写入前必须逐笔携带显式高危确认(confirmProduction:true),确认会记入审计工件。"
20
+ : "当前是生产环境;当前设置为只读,写入会被拒绝。";
21
+ }
22
+ return environmentWritable(profile)
23
+ ? "当前是测试环境;已允许写入,仅应使用测试数据。"
24
+ : "当前是测试环境;当前设置为只读,写入会被拒绝。";
25
+ }
26
+ //# sourceMappingURL=environment-policy.js.map