@stalfh233/omc-cli 0.4.69 → 0.4.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/endpoints.js +1 -0
- package/dist/lanes/rule-lifecycle.js +20 -2
- package/dist/rule-support.js +82 -1
- package/package.json +3 -3
package/dist/endpoints.js
CHANGED
|
@@ -55,6 +55,7 @@ export const ENDPOINTS = {
|
|
|
55
55
|
businessRuleCreate: "/api/api/app/businessrule/create",
|
|
56
56
|
businessRuleUpdate: "/api/api/app/businessrule/update",
|
|
57
57
|
businessRulePublish: "/api/api/app/businessrule/publish",
|
|
58
|
+
businessRuleNodeRunMap: "/api/api/app/businessrule/node_run_map",
|
|
58
59
|
businessRuleEnable: "/api/api/app/businessrule/enable",
|
|
59
60
|
businessRuleDelete: "/api/api/app/businessrule/delete",
|
|
60
61
|
dataRuleCreate: "/api/api/app/bizdatarule/create",
|
|
@@ -3,7 +3,7 @@ import { ENDPOINTS } from "../endpoints.js";
|
|
|
3
3
|
import { writeTool } from "../write.js";
|
|
4
4
|
import { registerPackageTool } from "../package-tool.js";
|
|
5
5
|
import { writeSummary } from "../human-summary.js";
|
|
6
|
-
import { executeRuleSaveWrite, ruleNodeGraphArg, assertRuleSchemaExists } from "../rule-support.js";
|
|
6
|
+
import { executeRuleSaveWrite, ruleNodeGraphArg, assertRuleSchemaExists, explainRuleSelfCheck } from "../rule-support.js";
|
|
7
7
|
import { ToolRefusalError } from "../tool-types.js";
|
|
8
8
|
import { prepareRuleGraph, validateRuleNodeGraph, PLATFORM_TRIGGER_RULE_CODES } from "./rule-graph.js";
|
|
9
9
|
import { wireCall, wireRows, WireError } from "../wire.js";
|
|
@@ -52,7 +52,25 @@ export async function executeRuleEnableWrite(session, args) {
|
|
|
52
52
|
const full = (await wireCall(session, { path: ENDPOINTS.businessRuleGet, query: { id: String(row.id) } })).data;
|
|
53
53
|
if (!full)
|
|
54
54
|
throw new WireError("business", `rule ${args.ruleCode} 完整模型读回为空(businessrule/get id ${row.id}),拒绝用列表投影发布`, 302024);
|
|
55
|
-
|
|
55
|
+
let published;
|
|
56
|
+
try {
|
|
57
|
+
published = await wireCall(session, { path: ENDPOINTS.businessRulePublish, method: "POST", body: { ...full, enabled: true, status: "ENABLED" } });
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// 550018 is the platform's self-check refusal (see explainRuleSelfCheck).
|
|
61
|
+
if (error instanceof WireError && error.errcode === 550018) {
|
|
62
|
+
const detail = await explainRuleSelfCheck(session, { ...full, enabled: true, status: "ENABLED" });
|
|
63
|
+
throw new ToolRefusalError({
|
|
64
|
+
status: "refused",
|
|
65
|
+
blocker: "rule-self-check-failed",
|
|
66
|
+
schemaCode: args.schemaCode,
|
|
67
|
+
ruleCode: args.ruleCode,
|
|
68
|
+
...detail,
|
|
69
|
+
message: `规则 ${args.ruleCode} 启用时被平台自检拒绝(550018)。${detail.nodeChecks.length > 0 ? `问题节点:${JSON.stringify(detail.nodeChecks).slice(0, 600)}` : "先用 field.list(all:true) 核对引用的字段是否已发布。"}`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
56
74
|
let enableErrcode = 0;
|
|
57
75
|
let alreadyEnabled = false;
|
|
58
76
|
try {
|
package/dist/rule-support.js
CHANGED
|
@@ -463,6 +463,71 @@ export async function computeCarriedNodeCodes(session, schemaCode, ruleCode, pre
|
|
|
463
463
|
return undefined; // 取不到存量图 → 维持严格闭集,行为与放宽前一致
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* 550018 is the platform's catch-all "rule self-check failed" (ErrorCode
|
|
468
|
+
* BUSINESS_RULE_PARAM_ERROR from BusinessRuleFacadeImpl.publishBusinessRule when
|
|
469
|
+
* checkBizRuleIsEnable() is false). The message names nothing, and the real原因
|
|
470
|
+
* is one of: a referenced property that does not exist, a missing org object, or
|
|
471
|
+
* a dead cycle. `businessrule/node_run_map` (BusinessRuleController.getNodeRunMaps
|
|
472
|
+
* → checkBizRuleError) returns exactly that per node, so a refusal can name the
|
|
473
|
+
* offending node and field instead of asking the caller to open the designer.
|
|
474
|
+
*/
|
|
475
|
+
const RULE_SELF_CHECK_ERRCODE = 550018;
|
|
476
|
+
function ruleSelfCheckMessage(ruleCode, checks) {
|
|
477
|
+
if (checks.length === 0)
|
|
478
|
+
return `规则 ${ruleCode} 发布被平台自检拒绝(550018「保存规则失败,规则存在异常」),但 node_run_map 未给出具体节点——常见原因:引用的字段未发布/不存在、组织对象失效、或存在死循环。先用 field.list(all:true) 核对引用的字段是否已发布。`;
|
|
479
|
+
const detail = checks.map((check) => {
|
|
480
|
+
const parts = [];
|
|
481
|
+
const missing = check.missingProperties;
|
|
482
|
+
if (missing?.length)
|
|
483
|
+
parts.push(`字段不存在/未发布:${missing.map((item) => `${item.objectName ?? "?"}.${item.propertyName ?? item.propertyCode ?? "?"}`).join("、")}`);
|
|
484
|
+
if (check.missingOrgObjects)
|
|
485
|
+
parts.push("组织对象不存在");
|
|
486
|
+
if (check.deadCycles)
|
|
487
|
+
parts.push("存在死循环");
|
|
488
|
+
return `${String(check.nodeCode ?? "?")}${check.nodeName ? `(${String(check.nodeName)})` : ""} ${parts.join(";")}`;
|
|
489
|
+
});
|
|
490
|
+
return `规则 ${ruleCode} 发布被平台自检拒绝(550018):${detail.join(" | ")}。节点内引用了不存在或未发布的字段时,保存能过、发布必拒——先补字段并 field.publish,再重发。`;
|
|
491
|
+
}
|
|
492
|
+
export async function explainRuleSelfCheck(session, model) {
|
|
493
|
+
try {
|
|
494
|
+
const response = await wireCall(session, { path: ENDPOINTS.businessRuleNodeRunMap, method: "POST", body: model });
|
|
495
|
+
const rows = wireRows(response.data);
|
|
496
|
+
const nodeChecks = rows.flatMap((row) => {
|
|
497
|
+
// Wire shape (QuoteObjectVO): {objectCode, objectName, quotePropertyList:
|
|
498
|
+
// [{propertyCode, propertyName, exist, propertyPublished}]} — the property
|
|
499
|
+
// sits one level deeper than the object.
|
|
500
|
+
const missingProperties = Array.isArray(row.notExistPropertyObjectList)
|
|
501
|
+
? row.notExistPropertyObjectList.flatMap((object) => {
|
|
502
|
+
const properties = Array.isArray(object.quotePropertyList) ? object.quotePropertyList : [];
|
|
503
|
+
const broken = properties.filter((property) => property.exist === false || property.propertyPublished === false);
|
|
504
|
+
const source = broken.length > 0 ? broken : properties;
|
|
505
|
+
return source.map((property) => ({
|
|
506
|
+
objectName: object.objectName ?? object.objectCode ?? null,
|
|
507
|
+
propertyCode: property.propertyCode ?? null,
|
|
508
|
+
propertyName: property.propertyName ?? null,
|
|
509
|
+
published: property.propertyPublished ?? null,
|
|
510
|
+
}));
|
|
511
|
+
})
|
|
512
|
+
: [];
|
|
513
|
+
const missingOrgObjects = Array.isArray(row.notExistOrgObjectList) ? row.notExistOrgObjectList : [];
|
|
514
|
+
const deadCycles = Array.isArray(row.deadCycleRunMapList) ? row.deadCycleRunMapList : [];
|
|
515
|
+
if (missingProperties.length === 0 && missingOrgObjects.length === 0 && deadCycles.length === 0)
|
|
516
|
+
return [];
|
|
517
|
+
return [{
|
|
518
|
+
nodeCode: row.nodeCode ?? null,
|
|
519
|
+
nodeName: row.nodeName ?? null,
|
|
520
|
+
...(missingProperties.length > 0 ? { missingProperties } : {}),
|
|
521
|
+
...(missingOrgObjects.length > 0 ? { missingOrgObjects } : {}),
|
|
522
|
+
...(deadCycles.length > 0 ? { deadCycles } : {}),
|
|
523
|
+
}];
|
|
524
|
+
});
|
|
525
|
+
return { nodeChecks };
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
return { nodeChecks: [] };
|
|
529
|
+
}
|
|
530
|
+
}
|
|
466
531
|
export async function executeRuleSaveWrite(session, args) {
|
|
467
532
|
// Pre-flight dry lint (ticket 14): a mis-shaped graph must be refused BEFORE
|
|
468
533
|
// any wire call, with structured blockers locating the node/key — never
|
|
@@ -594,7 +659,23 @@ export async function executeRuleSaveWrite(session, args) {
|
|
|
594
659
|
// schedule and a TIMING_TASK rule never gets a quartz job (2026-10-06). Use
|
|
595
660
|
// the authoritative `businessrule/get?id` model (same as rule.get/enable).
|
|
596
661
|
const full = (await wireCall(session, { path: ENDPOINTS.businessRuleGet, query: { id: String(row.id) } })).data;
|
|
597
|
-
|
|
662
|
+
try {
|
|
663
|
+
await wireCall(session, { path: ENDPOINTS.businessRulePublish, method: "POST", body: full ?? row });
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
if (error instanceof WireError && error.errcode === RULE_SELF_CHECK_ERRCODE) {
|
|
667
|
+
const detail = await explainRuleSelfCheck(session, (full ?? row));
|
|
668
|
+
throw new ToolRefusalError({
|
|
669
|
+
status: "refused",
|
|
670
|
+
blocker: "rule-self-check-failed",
|
|
671
|
+
schemaCode: args.schemaCode,
|
|
672
|
+
ruleCode: args.ruleCode,
|
|
673
|
+
...detail,
|
|
674
|
+
message: ruleSelfCheckMessage(args.ruleCode, detail.nodeChecks),
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
throw error;
|
|
678
|
+
}
|
|
598
679
|
}
|
|
599
680
|
const effective = await currentRow();
|
|
600
681
|
// Live 8.6.26 (2026-09-17): businessrule/publish mints a version but does
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stalfh233/omc-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.70",
|
|
4
4
|
"description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@stalfh233/omc-fake-platform": "0.4.
|
|
53
|
+
"@stalfh233/omc-fake-platform": "0.4.70",
|
|
54
54
|
"commander": "14.0.3",
|
|
55
|
-
"omc-core": "0.4.
|
|
55
|
+
"omc-core": "0.4.70",
|
|
56
56
|
"proper-lockfile": "4.1.2",
|
|
57
57
|
"write-file-atomic": "6.0.0",
|
|
58
58
|
"zod": "^3.23.8",
|