@stalfh233/omc-cli 0.5.6 → 0.5.8

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 (228) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +359 -359
  3. package/coverage/m1-coverage-manifest-v1.json +1414 -1414
  4. package/dist/approval-flow.js +0 -0
  5. package/dist/args.js +0 -0
  6. package/dist/artifacts.js +0 -0
  7. package/dist/batch-call.js +0 -0
  8. package/dist/bench/call-face-eval.js +0 -0
  9. package/dist/bench/context-attribution.js +0 -0
  10. package/dist/bench/discovery-cost-eval.js +0 -0
  11. package/dist/bench/driver.js +0 -0
  12. package/dist/bench/evals.js +0 -0
  13. package/dist/bench/instrument.js +0 -0
  14. package/dist/bench/intent-face-eval.js +40 -40
  15. package/dist/bench/run.js +0 -0
  16. package/dist/bench/scenario.js +0 -0
  17. package/dist/bench/types.js +0 -0
  18. package/dist/bi-wire.js +0 -0
  19. package/dist/bizservice-config.js +0 -0
  20. package/dist/call.js +0 -0
  21. package/dist/capability-absences.js +0 -0
  22. package/dist/capability-overview.js +0 -0
  23. package/dist/capability-shape.js +0 -0
  24. package/dist/cli-contract.js +0 -0
  25. package/dist/cli-output.js +0 -0
  26. package/dist/cli.js +31 -1
  27. package/dist/closest-match.js +0 -0
  28. package/dist/code-rules.js +0 -0
  29. package/dist/command-transport.js +0 -0
  30. package/dist/compound-writes.js +0 -0
  31. package/dist/compute.js +0 -0
  32. package/dist/config-store.js +0 -0
  33. package/dist/context.js +0 -0
  34. package/dist/contract-consistency.js +0 -0
  35. package/dist/contract-resources.js +0 -0
  36. package/dist/coverage-consistency.js +0 -0
  37. package/dist/coverage-registry.js +0 -0
  38. package/dist/coverage.js +0 -0
  39. package/dist/data-list-filter.js +0 -0
  40. package/dist/describe-cache.js +0 -0
  41. package/dist/discovery.js +0 -0
  42. package/dist/endpoints.js +0 -0
  43. package/dist/environment-policy.js +0 -0
  44. package/dist/execution-metadata.js +0 -0
  45. package/dist/field-add.js +314 -0
  46. package/dist/field-change.js +0 -0
  47. package/dist/field-families.js +0 -0
  48. package/dist/form-default.js +0 -0
  49. package/dist/form-layout.js +0 -0
  50. package/dist/form-support.js +9 -0
  51. package/dist/formula-lint.js +0 -0
  52. package/dist/goal-routes.js +28 -16
  53. package/dist/governed-execution.js +0 -0
  54. package/dist/graph.js +50 -33
  55. package/dist/human-summary.js +1 -1
  56. package/dist/identity.js +0 -0
  57. package/dist/intent/baseline.js +0 -0
  58. package/dist/intent/capabilities/bizservice.js +0 -0
  59. package/dist/intent/capabilities/businessrule.js +0 -0
  60. package/dist/intent/capabilities/datarule.js +0 -0
  61. package/dist/intent/capabilities/field.js +0 -0
  62. package/dist/intent/capabilities/form.js +0 -0
  63. package/dist/intent/capabilities/index.js +0 -0
  64. package/dist/intent/capabilities/listview.js +0 -0
  65. package/dist/intent/capabilities/model.js +0 -0
  66. package/dist/intent/capabilities/onlinejs.js +0 -0
  67. package/dist/intent/capabilities/report.js +0 -0
  68. package/dist/intent/capabilities/workflow.js +0 -0
  69. package/dist/intent/capability.js +0 -0
  70. package/dist/intent/cli.js +0 -0
  71. package/dist/intent/compare.js +0 -0
  72. package/dist/intent/compiler.js +0 -0
  73. package/dist/intent/dsl.js +0 -0
  74. package/dist/intent/plan-apply.js +0 -0
  75. package/dist/intent/plan-file.js +0 -0
  76. package/dist/intent/readback.js +0 -0
  77. package/dist/intent/schema.js +0 -0
  78. package/dist/intent/validation.js +0 -0
  79. package/dist/intent/yaml.js +0 -0
  80. package/dist/journal.js +0 -0
  81. package/dist/json-column.js +0 -0
  82. package/dist/lanes/app-contract.js +0 -0
  83. package/dist/lanes/app-coverage.js +0 -0
  84. package/dist/lanes/app.js +0 -0
  85. package/dist/lanes/apply-changes.js +0 -0
  86. package/dist/lanes/b2-registration-contract.js +0 -0
  87. package/dist/lanes/b2-registration-coverage.js +0 -0
  88. package/dist/lanes/b2-registration.js +0 -0
  89. package/dist/lanes/businessrule-contract.js +0 -0
  90. package/dist/lanes/businessrule-coverage.js +0 -0
  91. package/dist/lanes/businessrule.js +11 -3
  92. package/dist/lanes/contract-support.js +0 -0
  93. package/dist/lanes/coverage-declaration.js +0 -0
  94. package/dist/lanes/custom-page.js +0 -0
  95. package/dist/lanes/datarule-contract.js +0 -0
  96. package/dist/lanes/datarule-coverage.js +0 -0
  97. package/dist/lanes/datarule-protocol.js +0 -0
  98. package/dist/lanes/datarule.js +6 -0
  99. package/dist/lanes/dictionary-contract.js +0 -0
  100. package/dist/lanes/dictionary-coverage.js +0 -0
  101. package/dist/lanes/dictionary.js +0 -0
  102. package/dist/lanes/environment-contract.js +0 -0
  103. package/dist/lanes/environment-coverage.js +0 -0
  104. package/dist/lanes/environment.js +0 -0
  105. package/dist/lanes/field-contract.js +0 -0
  106. package/dist/lanes/field-coverage.js +0 -0
  107. package/dist/lanes/field.js +0 -0
  108. package/dist/lanes/folder-contract.js +0 -0
  109. package/dist/lanes/folder-coverage.js +0 -0
  110. package/dist/lanes/folder.js +0 -0
  111. package/dist/lanes/form-contract.js +0 -0
  112. package/dist/lanes/form-coverage.js +0 -0
  113. package/dist/lanes/form.js +0 -0
  114. package/dist/lanes/lane-ids.js +0 -0
  115. package/dist/lanes/list-view-contract.js +0 -0
  116. package/dist/lanes/list-view-coverage.js +0 -0
  117. package/dist/lanes/list-view-shapes.js +0 -0
  118. package/dist/lanes/list-view.js +6 -0
  119. package/dist/lanes/meta-contract.js +0 -0
  120. package/dist/lanes/meta.js +0 -0
  121. package/dist/lanes/model-contract.js +0 -0
  122. package/dist/lanes/model-coverage.js +0 -0
  123. package/dist/lanes/model.js +0 -0
  124. package/dist/lanes/online-js-contract.js +0 -0
  125. package/dist/lanes/online-js-coverage.js +0 -0
  126. package/dist/lanes/online-js.js +0 -0
  127. package/dist/lanes/org-tree.js +0 -0
  128. package/dist/lanes/organization-coverage.js +27 -0
  129. package/dist/lanes/organization.js +10 -1
  130. package/dist/lanes/report-contract.js +0 -0
  131. package/dist/lanes/report-coverage.js +0 -0
  132. package/dist/lanes/report.js +0 -0
  133. package/dist/lanes/rule-graph.js +0 -0
  134. package/dist/lanes/rule-lifecycle-contract.js +0 -0
  135. package/dist/lanes/rule-lifecycle-coverage.js +0 -0
  136. package/dist/lanes/rule-lifecycle.js +0 -0
  137. package/dist/lanes/runtime-data-contract.js +0 -0
  138. package/dist/lanes/runtime-data-coverage.js +0 -0
  139. package/dist/lanes/runtime-data.js +24 -0
  140. package/dist/lanes/workflow-contract.js +0 -0
  141. package/dist/lanes/workflow-coverage.js +0 -0
  142. package/dist/lanes/workflow.js +7 -2
  143. package/dist/mcp-graph.js +0 -0
  144. package/dist/model-purge.js +0 -0
  145. package/dist/model-record.js +0 -0
  146. package/dist/model-scaffold.js +0 -0
  147. package/dist/omc-core-lazy.js +0 -0
  148. package/dist/online-js-layout.js +0 -0
  149. package/dist/online-js-source.js +28 -28
  150. package/dist/package-tool.js +0 -0
  151. package/dist/package.js +0 -0
  152. package/dist/path-projection.js +19 -1
  153. package/dist/plan.js +0 -0
  154. package/dist/read.js +0 -0
  155. package/dist/recipes/b2-registration.js +0 -0
  156. package/dist/recipes/businessrule.js +0 -0
  157. package/dist/recipes/datarule.js +0 -0
  158. package/dist/recipes/dictionary.js +0 -0
  159. package/dist/recipes/field.js +0 -0
  160. package/dist/recipes/form.js +0 -0
  161. package/dist/recipes/list-view.js +0 -0
  162. package/dist/recipes/model.js +0 -0
  163. package/dist/recipes/online-js.js +0 -0
  164. package/dist/recipes/runtime-data.js +0 -0
  165. package/dist/recipes/shared.js +0 -0
  166. package/dist/recipes/workflow.js +0 -0
  167. package/dist/redact.js +0 -0
  168. package/dist/refusal-guidance.js +0 -0
  169. package/dist/rollback-spec.js +0 -0
  170. package/dist/rollback.js +0 -0
  171. package/dist/rule-support.js +0 -0
  172. package/dist/rule-when.js +4 -3
  173. package/dist/runtime-support.js +0 -0
  174. package/dist/script.js +0 -0
  175. package/dist/service-doctor.js +0 -0
  176. package/dist/session-manager.js +0 -0
  177. package/dist/session.js +0 -0
  178. package/dist/skills.js +0 -0
  179. package/dist/sqlite-warning-filter.js +0 -0
  180. package/dist/support.js +0 -0
  181. package/dist/token-cache.js +0 -0
  182. package/dist/tool-types.js +0 -0
  183. package/dist/tools.js +0 -0
  184. package/dist/usage-log.js +0 -0
  185. package/dist/wire.js +0 -0
  186. package/dist/workflow-support.js +0 -0
  187. package/dist/write-lease.js +0 -0
  188. package/dist/write-lock.js +0 -0
  189. package/dist/write.js +0 -0
  190. package/dist/zip.js +0 -0
  191. package/docs/images/omc-nixi/README.md +41 -41
  192. package/docs/omc-introduction.md +851 -851
  193. package/docs/tool-surface-map.md +42 -42
  194. package/package.json +3 -3
  195. package/skills/omc-acceptance-criteria.md +50 -50
  196. package/skills/omc-business-configuration.md +336 -335
  197. package/skills/omc-capabilities.md +214 -214
  198. package/skills/omc-capability-scouting.md +55 -55
  199. package/skills/omc-config-draft-review.md +175 -175
  200. package/skills/omc-five-piece-flow.md +35 -35
  201. package/skills/omc-glossary.md +86 -86
  202. package/skills/omc-refusals.md +129 -129
  203. package/skills/omc-requirement-analysis.md +161 -161
  204. package/skills/omc-requirement-vocabulary.md +61 -61
  205. package/skills/omc-start-here.md +107 -106
  206. package/skills/omc-tool-selection.md +119 -119
  207. package/skills/omc-write-hazards.md +222 -200
  208. package/dist/approval-token.js +0 -102
  209. package/dist/bench/fake-http-server.js +0 -65
  210. package/dist/fake/app.js +0 -45
  211. package/dist/fake/b2-registration.js +0 -594
  212. package/dist/fake/businessrule.js +0 -242
  213. package/dist/fake/datarule.js +0 -72
  214. package/dist/fake/dictionary.js +0 -108
  215. package/dist/fake/environment.js +0 -30
  216. package/dist/fake/field.js +0 -167
  217. package/dist/fake/form.js +0 -101
  218. package/dist/fake/index.js +0 -121
  219. package/dist/fake/list-view.js +0 -289
  220. package/dist/fake/model.js +0 -136
  221. package/dist/fake/online-js.js +0 -18
  222. package/dist/fake/report.js +0 -253
  223. package/dist/fake/routes.js +0 -47
  224. package/dist/fake/rule-lifecycle.js +0 -37
  225. package/dist/fake/runtime-data.js +0 -367
  226. package/dist/fake/state.js +0 -67
  227. package/dist/fake/workflow.js +0 -364
  228. package/dist/server.js +0 -92
@@ -44,22 +44,22 @@ function intentGuidance() {
44
44
  return {
45
45
  path: "declarative",
46
46
  why: "整包需求:用一份声明式意图文件描述 models/fields/form/listview/rules/workflow/onlinejs/services,由编译器合成平台原生结构并按依赖顺序执行;比逐能力拼装更省上下文、更不易漂移。",
47
- starter: `intentVersion: 1
48
- models:
49
- - code: <模型code> # 如 omcTodoTask(小写下划线也合规;字段码必须 lowerCamelCase ≤25 字符——产品实施规范)
50
- name: <业务名>
51
- fields:
52
- - {code: title, name: 标题, type: SHORT_TEXT}
53
- - {code: amount, name: 数量, type: NUMERICAL, options: {scale: 2}} # NUMERICAL 必带 scale
54
- - {code: level, name: 等级, type: RADIO, choices: [高, 中, 低]} # 选择族用顶层 choices
55
- form: {publish: true}
56
- listview: {fieldCodes: [title, level]}
57
- rules:
58
- - code: Create # 平台预置触发行(name 省略)
59
- enabled: true
60
- actions:
61
- - when: [{field: amount, gt: 10}]
62
- set: [{field: title, value: "超限"}]
47
+ starter: `intentVersion: 1
48
+ models:
49
+ - code: <模型code> # 如 omcTodoTask(小写下划线也合规;字段码必须 lowerCamelCase ≤25 字符——产品实施规范)
50
+ name: <业务名>
51
+ fields:
52
+ - {code: title, name: 标题, type: SHORT_TEXT}
53
+ - {code: amount, name: 数量, type: NUMERICAL, options: {scale: 2}} # NUMERICAL 必带 scale
54
+ - {code: level, name: 等级, type: RADIO, choices: [高, 中, 低]} # 选择族用顶层 choices
55
+ form: {publish: true}
56
+ listview: {fieldCodes: [title, level]}
57
+ rules:
58
+ - code: Create # 平台预置触发行(name 省略)
59
+ enabled: true
60
+ actions:
61
+ - when: [{field: amount, gt: 10}]
62
+ set: [{field: title, value: "超限"}]
63
63
  `,
64
64
  commands: [
65
65
  "把上面的 starter 存成 <file>.yaml 按需求改字段后:omc intent validate <file>.yaml(离线)→ omc intent plan <file>.yaml --env <env> → omc intent apply <file>.yaml --env <env>(apply 也能直接吃 YAML)",
@@ -381,6 +381,17 @@ const COMPOSER_ROUTES = Object.freeze([
381
381
  avoid: ["嵌套子表", "子表套子表"],
382
382
  topics: ["omc-business-configuration"],
383
383
  },
384
+ {
385
+ id: "field-add",
386
+ command: "omc field-add --schema <存量模型code> --fields '<JSON数组>' --apply",
387
+ usage: "omc field-add --help",
388
+ summary: "存量模型加字段一条命令:建字段 → 发布 → 重建表单 → 列表追加列(增量合并);4 次写调合成 1 条命令",
389
+ // (add verb) × (field noun)——「给既有/存量模型加字段」是变更类需求的最高频动作(r30/r31 探针实证手工链 4 调)
390
+ groups: [["加", "新增", "添加", "补", "增加"], ["字段"]],
391
+ // 只收「加字段本体」;规则/校验/计算/编号/流程语义各有归宿(round10:'给金额字段加自动校验规则' 应归 datarule,不能被本 composer 抢走)
392
+ avoid: ["新建模型", "建模型", "从零", "子表", "childFields", "编号规则", "序列号", "规则", "校验", "计算", "默认值", "流程", "权限", "按钮"],
393
+ topics: ["omc-write-hazards"],
394
+ },
384
395
  {
385
396
  id: "approval-flow",
386
397
  command: "omc approval-flow --schema <模型code> --steps '<节点名>@role:<角色code>' --apply",
@@ -441,6 +452,7 @@ export const COMPOSER_ROUTES_FOR_TEST = COMPOSER_ROUTES;
441
452
  const COMPOSER_QUESTIONS = Object.freeze({
442
453
  "model-purge": "要清理哪个模型?给我 schemaCode(不确定就先跑下面的只读判别动作拿清单)",
443
454
  "model-scaffold": "给我模型 code、显示名和字段清单(每字段 code/名称/类型;子表放 subFields),我一条命令建完",
455
+ "field-add": "目标存量模型 schemaCode 和字段清单(每字段 code/名称/类型;choices 给字符串数组、字典给 options)是什么?建完自动发布、重建表单、列表加列",
444
456
  "approval-flow": "目标模型 schemaCode 和每级审批节点(节点名@角色code,多级用重复 --steps)是什么?",
445
457
  compute: "目标模型 schemaCode、结果字段 code、公式是什么?(子表条件聚合再加 --where \"子列 = 值\")",
446
458
  "rule-when": "目标模型 schemaCode、触发时机(Create/Update…)、条件(--when)和动作(--then)各是什么?",
File without changes
package/dist/graph.js CHANGED
@@ -466,30 +466,30 @@ export async function publishGraphPull(session, concurrency = DEFAULT_PULL_CONCU
466
466
  // D-state in folio_wait_bit_common). One transaction + memory journal
467
467
  // + synchronous=OFF makes the build effectively free.
468
468
  db.exec("PRAGMA journal_mode=MEMORY; PRAGMA synchronous=OFF;");
469
- db.exec(`BEGIN;
470
- CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
471
- CREATE TABLE rules (
472
- schema_code TEXT NOT NULL,
473
- rule_code TEXT NOT NULL,
474
- name TEXT,
475
- enabled INTEGER,
476
- status TEXT,
477
- default_rule INTEGER,
478
- row_id TEXT NOT NULL,
479
- graph_sha256 TEXT NOT NULL,
480
- PRIMARY KEY (schema_code, rule_code)
481
- );
482
- CREATE TABLE edges (
483
- kind TEXT NOT NULL,
484
- code TEXT NOT NULL,
485
- schema_code TEXT NOT NULL,
486
- rule_code TEXT NOT NULL,
487
- node_code TEXT,
488
- node_type TEXT,
489
- via TEXT NOT NULL
490
- );
491
- CREATE INDEX edges_lookup ON edges(kind, code);
492
- CREATE TABLE gaps (kind TEXT NOT NULL, ref TEXT NOT NULL, note TEXT);
469
+ db.exec(`BEGIN;
470
+ CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
471
+ CREATE TABLE rules (
472
+ schema_code TEXT NOT NULL,
473
+ rule_code TEXT NOT NULL,
474
+ name TEXT,
475
+ enabled INTEGER,
476
+ status TEXT,
477
+ default_rule INTEGER,
478
+ row_id TEXT NOT NULL,
479
+ graph_sha256 TEXT NOT NULL,
480
+ PRIMARY KEY (schema_code, rule_code)
481
+ );
482
+ CREATE TABLE edges (
483
+ kind TEXT NOT NULL,
484
+ code TEXT NOT NULL,
485
+ schema_code TEXT NOT NULL,
486
+ rule_code TEXT NOT NULL,
487
+ node_code TEXT,
488
+ node_type TEXT,
489
+ via TEXT NOT NULL
490
+ );
491
+ CREATE INDEX edges_lookup ON edges(kind, code);
492
+ CREATE TABLE gaps (kind TEXT NOT NULL, ref TEXT NOT NULL, note TEXT);
493
493
  `);
494
494
  const insertMeta = db.prepare("INSERT INTO meta (key, value) VALUES (?, ?)");
495
495
  // `applicationResolution` is an object; String(value) would persist
@@ -508,9 +508,9 @@ export async function publishGraphPull(session, concurrency = DEFAULT_PULL_CONCU
508
508
  insertGap.run(gap.kind, gap.ref, gap.note ?? null);
509
509
  // FTS5 mirrors rules (code+name) for `graph search`; one rebuild after
510
510
  // the bulk insert is cheaper than per-row triggers on a wholesale rebuild.
511
- db.exec(`
512
- CREATE VIRTUAL TABLE rules_fts USING fts5(rule_code, name, content='rules', content_rowid='rowid');
513
- INSERT INTO rules_fts(rules_fts) VALUES('rebuild');
511
+ db.exec(`
512
+ CREATE VIRTUAL TABLE rules_fts USING fts5(rule_code, name, content='rules', content_rowid='rowid');
513
+ INSERT INTO rules_fts(rules_fts) VALUES('rebuild');
514
514
  `);
515
515
  db.exec("COMMIT;");
516
516
  }
@@ -578,6 +578,21 @@ function openGraphIndex() {
578
578
  throw error instanceof GraphIndexAbsentError ? error : new GraphIndexAbsentError(`索引不可读(schema 不匹配或文件损坏):${error instanceof Error ? error.message : String(error)};重跑 omc graph pull`);
579
579
  }
580
580
  }
581
+ /**
582
+ * Zero-hit disambiguation (2026-10-31 capability-test friction, hit twice in
583
+ * one session): querying `impact field mcc_supplier` returns an empty result
584
+ * that is indistinguishable from "no references". If the code appears in the
585
+ * index under a DIFFERENT kind — or as a schema_code, i.e. a model — say so
586
+ * instead of leaving the caller to guess.
587
+ */
588
+ function zeroHitKindHint(db, kind, code, command) {
589
+ const kinds = db.prepare("SELECT DISTINCT kind FROM edges WHERE code = ? AND kind <> ? ORDER BY kind").all(code, kind).map((row) => row.kind);
590
+ if (kinds.length === 0 && kind !== "model" && db.prepare("SELECT 1 FROM edges WHERE schema_code = ? LIMIT 1").get(code) !== undefined)
591
+ kinds.push("model");
592
+ if (kinds.length === 0)
593
+ return undefined;
594
+ return `;注意:${code} 在索引中以 ${kinds.join("/")} 身份出现——kind 可能选错,试 omc graph ${command} ${kinds[0]} ${code}`;
595
+ }
581
596
  export function queryGraphReferences(kind, code) {
582
597
  const { db, summary } = openGraphIndex();
583
598
  try {
@@ -599,9 +614,10 @@ export function queryGraphReferences(kind, code) {
599
614
  index: summary,
600
615
  ...(matches.length === 0
601
616
  ? {
602
- note: gapped
617
+ note: (gapped
603
618
  ? "零命中,但索引存在扫描缺口——不可作为「无引用」证明;先 omc graph pull 重建再查"
604
- : "零命中=索引覆盖范围内没有引用它(规则面:service→methodMapping.serviceCode;model→targetObjectCode/methodMapping.schemaCode;field→dataActions.targetDataItem/映射 bizCode;数据规则面:propertyCodes 目标与 options {字段} 引用;视图面:列/排序/条件的 propertyCode。不含规则条件叶子/流程绑定)",
619
+ : "零命中=索引覆盖范围内没有引用它(规则面:service→methodMapping.serviceCode;model→targetObjectCode/methodMapping.schemaCode;field→dataActions.targetDataItem/映射 bizCode;数据规则面:propertyCodes 目标与 options {字段} 引用;视图面:列/排序/条件的 propertyCode。不含规则条件叶子/流程绑定)") +
620
+ (zeroHitKindHint(db, kind, code, "references") ?? ""),
605
621
  }
606
622
  : {}),
607
623
  ...(gapped
@@ -638,8 +654,8 @@ export function searchGraphRules(term, limit = 20) {
638
654
  if (tokens.length > 0) {
639
655
  const quoted = tokens.map((token, index) => `"${token.replaceAll('"', '""')}"${index === tokens.length - 1 ? "*" : ""}`).join(" ");
640
656
  const rows = db
641
- .prepare(`SELECT r.schema_code, r.rule_code, r.name, r.enabled, r.status
642
- FROM rules_fts JOIN rules r ON r.rowid = rules_fts.rowid
657
+ .prepare(`SELECT r.schema_code, r.rule_code, r.name, r.enabled, r.status
658
+ FROM rules_fts JOIN rules r ON r.rowid = rules_fts.rowid
643
659
  WHERE rules_fts MATCH ? ORDER BY bm25(rules_fts), r.schema_code, r.rule_code LIMIT ?`)
644
660
  .all(quoted, limit);
645
661
  const refsFor = db.prepare("SELECT kind, code FROM edges WHERE schema_code = ? AND rule_code = ? ORDER BY kind, code");
@@ -743,9 +759,10 @@ export function impactGraph(kind, code) {
743
759
  index: summary,
744
760
  ...(hop1.length === 0 && dataruleHits.length === 0 && listViewHits.length === 0
745
761
  ? {
746
- note: gapped
762
+ note: (gapped
747
763
  ? "零命中,但索引存在扫描缺口——不可作为「无影响」证明;先 omc graph pull 重建再查"
748
- : "零命中=索引覆盖范围内没有引用它(规则面+数据规则面+视图列/排序/条件面;流程绑定暂不在索引内)",
764
+ : "零命中=索引覆盖范围内没有引用它(规则面+数据规则面+视图列/排序/条件面;流程绑定暂不在索引内)") +
765
+ (zeroHitKindHint(db, kind, code, "impact") ?? ""),
749
766
  }
750
767
  : {}),
751
768
  ...(capped || dataruleHits.length > 20 || listViewHits.length > 20
@@ -126,7 +126,7 @@ function phraseOf(tool, args, outcome) {
126
126
  case "field.publish":
127
127
  return `发布模型 ${schemaCode ?? "?"} 的全部草稿字段(模型级一次发布)`;
128
128
  case "form.draft":
129
- return `保存表单 ${stringArg(args, "sheetCode") ?? "?"}(模型 ${schemaCode ?? "?"})的草稿布局`;
129
+ return `保存表单 ${stringArg(args, "sheetCode") ?? (schemaCode !== undefined ? String(schemaCode) : "?")}(模型 ${schemaCode ?? "?"})的草稿布局——sheetCode 省略时实际写入 = 模型 code 槽位`;
130
130
  case "form.publish":
131
131
  // r26 finding: sheetCode is optional (resolved from schemaCode for the
132
132
  // default form) — the summary showed "?" when the agent omitted it.
package/dist/identity.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/dist/journal.js CHANGED
File without changes
File without changes
File without changes
File without changes
package/dist/lanes/app.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -196,7 +196,7 @@ export function registerBusinessRuleLane(tools) {
196
196
  else {
197
197
  if (["CREATE", "UPDATE", "DELETE"].includes(nodeType) && Array.isArray(rawNode.dataActions)
198
198
  && rawNode.dataActions.some((action) => String(action.targetDataItem ?? "") === wanted))
199
- matches.push({ schemaCode, ruleCode, nodeCode, nodeType, via: "dataActions.targetDataItem" });
199
+ matches.push({ schemaCode, ruleCode, nodeCode, nodeType, via: "dataActions.targetDataItem", ...(String(rawNode.targetObjectCode ?? "") !== "" ? { targetObjectCode: String(rawNode.targetObjectCode) } : {}) });
200
200
  if (mapping) {
201
201
  for (const [key, label] of [["inputMappings", "inputMappings.bizCode"], ["outputMappings", "outputMappings.bizCode"]]) {
202
202
  if (Array.isArray(mapping[key]) && mapping[key].some((row2) => String(row2.bizCode ?? "") === wanted && (row2.codeType === undefined || row2.codeType === 1)))
@@ -215,10 +215,18 @@ export function registerBusinessRuleLane(tools) {
215
215
  ...(scope !== undefined ? { applicationResolution: applicationResolutionOf(scope) } : {}),
216
216
  ...(matches.length === 0
217
217
  ? {
218
- note: "零命中=全平台(或指定 schemaCodes 范围内)没有规则引用它。范围:service→methodMapping.serviceCode;model→targetObjectCode/methodMapping.schemaCode;field→dataActions.targetDataItem/映射 bizCode(不含条件叶子与 datarule,第一版边界)",
218
+ note: "零命中=" +
219
+ (args.schemaCodes !== undefined
220
+ ? `仅扫描了 schemaCodes 收窄的 ${scoped.length} 个模型(${scoped.slice(0, 5).join(", ")}${scoped.length > 5 ? "…" : ""})——引用常发生在**其他**模型上;要全平台结论请去掉 schemaCodes`
221
+ : "全平台没有规则引用它") +
222
+ "。范围:service→methodMapping.serviceCode;model→targetObjectCode/methodMapping.schemaCode;field→dataActions.targetDataItem/映射 bizCode(不含条件叶子与 datarule,第一版边界)。本工具是在线单点扫描;要离线毫秒级复询、字段级影响面或两跳爆炸半径,先 `omc graph pull --env <env>` 再 `omc graph references|impact <kind> <code>`",
219
223
  ...(scope !== undefined ? { hint: applicationScopeHint(scope, "引用") } : {}),
220
224
  }
221
- : {}),
225
+ : {
226
+ // r31(2026-10-31):影响评估场景 agent 已路由到本工具——在必经之路
227
+ // 上一行 cross-sell 离线索引(graph 面的知识条目只回节索引时不可见)。
228
+ hint: "在线扫描完成;同问要再问/要两跳影响面(改 X 会波及哪些规则,那些规则还碰什么)时,先 `omc graph pull --env <env>` 建离线索引,之后 `omc graph references|impact <kind> <code>` 毫秒级复询",
229
+ }),
222
230
  };
223
231
  }, { target: `rule.references:${args.kind}:${args.code}` }),
224
232
  }));
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -805,6 +805,12 @@ export function registerDataRuleLane(tools) {
805
805
  matchedCount: rules.length,
806
806
  rules: rules.map(decodeDataRule),
807
807
  ...(args.dataRuleType >= 3 ? { advisory: DATARULE_FORM_INTERACTION_ADVISORY } : {}),
808
+ // r35(2026-10-31 真机):type1 校验规则建好读回一致,但 REST `data.submit`
809
+ // 提交违规数据(-50 / 超阈值)errcode 0 放行、原值落库——校验在门户前端
810
+ // 提交管线执行,REST 不拦。先告知执行面,省掉「先实测两轮才发现不生效」。
811
+ ...(args.dataRuleType === 1
812
+ ? { executionWarning: "校验规则在门户前端提交时执行;REST `data.submit` 不拦截违规数据(r35 真机:-50 与超阈值均 errcode 0 放行)。验收拦截效果需走门户,或改用业务规则(BIZ_ACTION/条件)在服务端拦。" }
813
+ : {}),
808
814
  ...(() => { const w = dataRuleFormulaWarnings(args.dataRuleType, args.options); return w.length ? { lintWarnings: w } : {}; })(),
809
815
  },
810
816
  };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -715,6 +715,12 @@ export function registerListViewLane(tools) {
715
715
  .map(decodeConditionRow)
716
716
  .sort((a, b) => String(a.propertyCode ?? "").localeCompare(String(b.propertyCode ?? "")));
717
717
  const readback = { code, added, updated, columns: afterCols, sorts, conditions };
718
+ // r35(2026-10-31 真机):视图固定条件读回正确,但 `data.list --queryCode <视图>`
719
+ // 不应用该过滤(4 条未过滤返回)——视图条件的运行时过滤语义未取证(门户 vs
720
+ // REST queryCode),coverage 已声明 "filtering … not probed"。前置声明省 3 轮排查。
721
+ if (conditions.length > 0)
722
+ readback.conditionRuntimeNote =
723
+ "视图条件的运行时过滤语义未取证:REST `data.list --queryCode <本视图>` 实测不应用固定条件(r35:读回 Gte/5000 正确、返回未过滤 4 条)。别用 queryCode 断言过滤生效;REST 侧过滤用 `data.list` 显式 `filter`。";
718
724
  // Post-write semantic readback (dogfood R2): the platform MODELS a list
719
725
  // condition as a filter CONTROL definition, so a requested condition whose
720
726
  // propertyCode does not survive the round-trip was lost. Surface that as
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,27 @@
1
+ import { claim, declareLaneCoverage } from "./coverage-declaration.js";
2
+ import { LANES } from "./lane-ids.js";
3
+ /**
4
+ * Organization writes (role group / role / members / management scope) sit on
5
+ * the same live-proven template lane; the scopes below are claimed here so the
6
+ * runtime gate can resolve them without a second manifest item.
7
+ */
8
+ export const ORGANIZATION_COVERAGE = declareLaneCoverage(LANES.workflow, [
9
+ {
10
+ capability: "W7 S29 greenfield workflow authoring",
11
+ evidence: [
12
+ "packages/omc-cli/src/lanes/organization.ts",
13
+ "OpenAPI /api/v3/api-docs (1.1.25): organization/role/add_role, add_role_user, update_ouscope",
14
+ ],
15
+ tools: [
16
+ claim("org.role.users", "organization role member read (role/users)"),
17
+ claim("org.role.userScope", "organization role member management scope read (role/get_ouscope)"),
18
+ claim("org.roleGroup.create", "organization role group create (role/add_role_group)"),
19
+ claim("org.role.create", "organization role create (role/add_role)"),
20
+ claim("org.role.update", "organization role update (role/modify_role)"),
21
+ claim("org.role.addUsers", "organization role member add (role/add_role_user)"),
22
+ claim("org.role.removeUsers", "organization role member remove (role/strike_out_role_user)"),
23
+ claim("org.role.setUserScope", "organization role member scope update (role/update_ouscope)"),
24
+ ],
25
+ },
26
+ ]);
27
+ //# sourceMappingURL=organization-coverage.js.map
@@ -151,6 +151,9 @@ export function registerOrganizationLane(tools) {
151
151
  };
152
152
  const members = rows.map((row) => ({
153
153
  id: roleUserId(row),
154
+ // r32 探针:把角色 id 当成员 id 传给 userScope/addUsers → 查询为空。
155
+ // 明示这个 id 的身份与正确来源,防角色/用户 id 混用。
156
+ idType: "user",
154
157
  name: row.name ?? null,
155
158
  username: row.username ?? null,
156
159
  departmentId: memberDepartment(row),
@@ -160,7 +163,13 @@ export function registerOrganizationLane(tools) {
160
163
  scopeCount: Array.isArray(row.ouScope) ? row.ouScope.length : null,
161
164
  unitType: row.unitType ?? null,
162
165
  }));
163
- return { roleId: String(args.roleId), count: members.length, total: data?.totalElements ?? members.length, members };
166
+ return {
167
+ roleId: String(args.roleId),
168
+ count: members.length,
169
+ total: data?.totalElements ?? members.length,
170
+ members,
171
+ note: "members[].id 是用户 id(可直接作为 addUsers 的 userIds / userScope 的 userId;不是角色 id——角色 id 在 org.role.list 的行里)",
172
+ };
164
173
  }),
165
174
  }));
166
175
  tools.push(defineTool({
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -688,9 +688,21 @@ export function registerRuntimeDataLane(tools) {
688
688
  size: z.number().int().min(1).max(200).default(10),
689
689
  all: z.boolean().optional().describe("true 时自动翻页聚合全部结果(内部按 size=200 逐页拉取,安全上限 1000 行,超出截断并标记 capped)——存量盘点/数据核对用,替代手动循环翻页"),
690
690
  full: z.boolean().optional().describe("内联完整列表结果;默认大结果只返回计数与 detailFile"),
691
+ // r31 (2026-10-31 real machine): agents pass `query: {field: value}` as a
692
+ // filter — zod would STRIP the unknown key silently and the server
693
+ // returns the unfiltered total, a false "no match / filter applied".
694
+ // Accept-and-refuse with the correct shape beats silent ignore.
695
+ query: z.unknown().optional(),
691
696
  capability: capabilityArg,
692
697
  },
693
698
  handler: async (ctx, args, self) => {
699
+ if (args.query !== undefined)
700
+ throw new ToolInputError({
701
+ status: "error",
702
+ blocker: "invalid-input",
703
+ tool: "data.list",
704
+ message: '没有 `query` 参数——过滤用 `filter: {"op":"eq","field":"<字段>","value":"<值>"}`(或 `filters` 数组=AND、`filterGroup` 嵌套)。r31 真机:`query:{...}` 被静默忽略、total 不变,极易误判为"无数据/已过滤"。',
705
+ });
694
706
  let condition;
695
707
  let fromDsl = false;
696
708
  try {
@@ -1220,6 +1232,18 @@ export function registerRuntimeDataLane(tools) {
1220
1232
  const ids = args.bizObjectIds && args.bizObjectIds.length > 0 ? args.bizObjectIds : args.bizObjectId ? [args.bizObjectId] : [];
1221
1233
  if (ids.length === 0)
1222
1234
  throw new ToolInputError({ status: "error", blocker: "tool-input-invalid", tool: "data.delete", message: "需要 bizObjectId(单个)或 bizObjectIds(数组,批量)" });
1235
+ // r30 (2026-10-31, 1.1.25 real machine): the batch form fake-succeeds —
1236
+ // DELIVERED + absent:true + a DECREASING modelResidue.total while the
1237
+ // rows are still queryable (data.list unchanged, data.load exists:true).
1238
+ // Re-issuing the same ids one at a time deleted them for real. Refuse
1239
+ // the batch shape and teach the per-id loop until the platform path is
1240
+ // understood; single-id deletes go through the exact same deleteOne.
1241
+ if (ids.length > 1)
1242
+ throw new ToolRefusalError({
1243
+ status: "refused",
1244
+ blocker: "data-delete-batch-fake-success",
1245
+ message: "批量删除(bizObjectIds 多个)在 1.1.25 真机实证为假成功:回执 DELIVERED + absent:true + modelResidue.total 递减,但行仍在(data.list 不变、data.load exists:true);同样的 id 改单条逐个删才真删掉。请用 bizObjectId(单个)逐个删,每条删完用 data.load 确认 exists:false(absent:true 不是删除成功的证明)。",
1246
+ });
1223
1247
  const deleteOne = async (bizObjectId) => {
1224
1248
  // Delete is destructive: probe the authoritative object first so an
1225
1249
  // absent id is an idempotent no-op, never a blind runtime delete.
File without changes
File without changes
@@ -1495,7 +1495,7 @@ function mergeCallerDelta(template, draft, options = {}) {
1495
1495
  throw new ToolRefusalError({
1496
1496
  status: "refused",
1497
1497
  blocker: "workflow-activity-type-missing",
1498
- message: `workflow.update: 新节点 ${String(activity.activityCode ?? "")} 缺 type/activityType(权限编辑行可省类型仅当 activityCode 命中草稿既有节点)`,
1498
+ message: `workflow.update: 新节点 ${String(activity.activityCode ?? "")} 缺 type/activityType(权限编辑行可省类型仅当 activityCode 命中草稿既有节点)。r32 实测:只改 participant/btnConfigList 的行也必须显式带 type——省略豁免仅限权限编辑行(带 propertyPermissions)。`,
1499
1499
  });
1500
1500
  }
1501
1501
  // Insert added nodes BEFORE the terminal END, so the auto-chain reads
@@ -2831,7 +2831,12 @@ export function registerWorkflowLane(tools) {
2831
2831
  });
2832
2832
  }
2833
2833
  }
2834
- const selected = page.items;
2834
+ // r32(2026-10-31):`participant` 分支此前忽略 workflowInstanceId——按人查
2835
+ // 时同回全部实例的待办,与参数语义(exact-match 过滤)不符。两个分支统一
2836
+ // 在客户端做实例过滤。
2837
+ const selected = args.workflowInstanceId !== undefined
2838
+ ? page.items.filter((item) => wireString(item.instanceId) === args.workflowInstanceId)
2839
+ : page.items;
2835
2840
  // Resolve the in-flight bizObject id per distinct instance. Authoritative
2836
2841
  // source: getBizObjectByWfInstanceId -> BizObjectCreatedModel.id/schemaCode.
2837
2842
  // Best-effort: a failed lookup leaves the identity null, never drops the todo.
package/dist/mcp-graph.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes