@stalfh233/omc-cli 0.4.50 → 0.4.52

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.
@@ -0,0 +1,129 @@
1
+ /**
2
+ * `omc approval-flow` — 审批流拼装器(v1:线性多级审批)。
3
+ *
4
+ * r75-T2a/r68 实测:一条两级审批流要整轮对话手拼——participant 解析陷阱、
5
+ * 审批节点字段权限默认 editable:true 是错的(r75 agent 自纠过)、驳回路由。
6
+ * 本命令把线性审批链压成一条命令:
7
+ *
8
+ * omc approval-flow --schema s --steps "采购经理@role:crm_mgr,总监@role:crm_dir" \
9
+ * [--originator-node] [--reject-to-start] [--apply]
10
+ *
11
+ * 步骤 DSL:`名称@role:<角色code>`(FindUserByRole 按发起人部门找人)或
12
+ * `名称@user:<用户id>`(参与者对象)。编译为 recipe 验证形状(workflow-approval-
13
+ * template-update):START → [填写申请单{Originator}] → 审批链 → END;审批节点
14
+ * 全字段 visible:true/editable:false(r75 规范修正);工具自动补设计器默认
15
+ * (sheetCode 回填/链路接入/permittedAction/rejectToStart)。
16
+ * --apply 执行链:workflow.create(模型无流程时)→ field.list(取权限字段)→
17
+ * workflow.update(模板) → workflow.publish;默认 dry-run 只编译模板预览。
18
+ */
19
+ import { runToolCall } from "./call.js";
20
+ import { envelope, requestId, classifyResult, CLI_EXIT_CODES } from "./cli-contract.js";
21
+ import { writeEnvelope } from "./cli-output.js";
22
+ /** 解析步骤 DSL 为 {name, participant}(导出供测试)。 */
23
+ export function parseStep(raw) {
24
+ const match = /^(.+?)@(role|user):([A-Za-z0-9_.:-]+)$/.exec(raw.trim());
25
+ if (!match)
26
+ throw new Error(`--steps "${raw}" 解析失败:形如 名称@role:<角色code> 或 名称@user:<用户id>(自由文本角色名能发布但解析不到人、不生成待办)`);
27
+ const [, name, kind, code] = match;
28
+ if (kind === "role")
29
+ return { name: name.trim(), participant: `FindUserByRole({Originator.OU},"${code}","random")` };
30
+ return { name: name.trim(), participant: JSON.stringify([{ code, corpId: "other", id: code, name: name.trim(), type: 3 }]) };
31
+ }
32
+ /** 编译完整模板(recipe 验证形状)。 */
33
+ export function composeApprovalTemplate(options) {
34
+ if (options.steps.length === 0)
35
+ throw new Error("至少一个 --steps 审批步骤");
36
+ const activities = [
37
+ { activityCode: "Activity1", activityType: "START", activityName: "开始", i18nMessage: "开始" },
38
+ ];
39
+ let n = 2;
40
+ if (options.originatorNode) {
41
+ activities.push({ activityCode: `Activity${n}`, activityType: "PARTICIPANT", activityName: "填写申请单", i18nMessage: "填写申请单", participant: "{Originator}" });
42
+ n += 1;
43
+ }
44
+ for (const raw of options.steps) {
45
+ const { name, participant } = parseStep(raw);
46
+ activities.push({
47
+ activityCode: `Activity${n}`, activityType: "PARTICIPANT", activityName: name, i18nMessage: name,
48
+ participant,
49
+ ...(options.rejectToStart ? { permittedAction: { rejectToStart: true } } : {}),
50
+ });
51
+ n += 1;
52
+ }
53
+ activities.push({ activityCode: `Activity${n}`, activityType: "END", activityName: "结束", i18nMessage: "结束" });
54
+ return { workflowCode: `${options.schema}_wf`, activities };
55
+ }
56
+ export async function cmdApprovalFlow(args) {
57
+ const request = requestId();
58
+ const flag = (name) => {
59
+ const index = args.indexOf(name);
60
+ return index >= 0 ? args[index + 1] : undefined;
61
+ };
62
+ const multi = (name) => {
63
+ const values = [];
64
+ for (let i = 0; i < args.length; i++) {
65
+ if (args[i] === name && args[i + 1] !== undefined)
66
+ values.push(args[i + 1]);
67
+ }
68
+ return values;
69
+ };
70
+ const schema = flag("--schema") ?? flag("--schema-code");
71
+ const steps = multi("--steps");
72
+ const environment = flag("--env") ?? flag("--environment");
73
+ const apply = args.includes("--apply");
74
+ const originatorNode = !args.includes("--no-originator-node");
75
+ const rejectToStart = !args.includes("--no-reject-to-start");
76
+ const usage = '用法:omc approval-flow --schema <模型> --steps "节点名@role:<角色code>" [--steps ...多级] [--no-originator-node] [--no-reject-to-start] [--apply]\n步骤也可用 名称@user:<用户id> 绑定具体审批人。默认 dry-run(编译模板预览);--apply 建/改流程+字段权限+发布。';
77
+ const invalid = (message) => {
78
+ writeEnvelope(envelope("error", {}, request, { code: "invalid-input", message: `${message}\n${usage}`, retryable: false }));
79
+ return CLI_EXIT_CODES.invalidInput;
80
+ };
81
+ if (!schema)
82
+ return invalid("--schema 必填");
83
+ let compiled;
84
+ try {
85
+ compiled = composeApprovalTemplate({ schema, steps, originatorNode, rejectToStart, environment, apply });
86
+ }
87
+ catch (error) {
88
+ return invalid(error instanceof Error ? error.message : String(error));
89
+ }
90
+ if (!apply) {
91
+ writeEnvelope(envelope("ok", { schemaCode: schema, ...compiled, dryRun: true, note: "dry-run 仅编译预览;--apply 执行 workflow.create(无流程时)→update(模板+字段权限)→publish" }, request));
92
+ return 0;
93
+ }
94
+ // 1) 确保流程存在(一个模型只能有一个:已存在则直接 update)
95
+ const createOutcome = await runToolCall("workflow.create", { args: { schemaCode: schema, code: compiled.workflowCode, name: `${schema} 审批流`, ...(environment ? { environment } : {}) }, requestId: request, environment });
96
+ if (createOutcome.exitCode !== 0) {
97
+ const result = createOutcome.result;
98
+ const blocker = String(result.blocker ?? "");
99
+ if (!blocker.includes("workflow-exists") && !String(result.message ?? "").includes("已存在") && !String(result.message ?? "").includes("only one")) {
100
+ writeEnvelope(envelope(classifyResult(result).status, result, request, classifyResult(result).error));
101
+ return createOutcome.exitCode;
102
+ }
103
+ }
104
+ // 2) 取字段清单构建审批节点只读权限(r75 修正:审批节点 editable:false)
105
+ const fieldList = await runToolCall("field.list", { args: { schemaCode: schema, published: true, ...(environment ? { environment } : {}) }, requestId: request, environment });
106
+ const fieldRows = (fieldList.result?.fields ?? fieldList.result?.items ?? []);
107
+ const propertyCodes = fieldRows.map((row) => String(row.code ?? row.propertyCode ?? "")).filter(Boolean);
108
+ const approvalNodes = compiled.activities.filter((a) => a.activityType === "PARTICIPANT" && a.participant !== "{Originator}");
109
+ const activitiesWithPermissions = compiled.activities.map((a) => approvalNodes.includes(a) && propertyCodes.length > 0
110
+ ? { ...a, propertyPermissions: propertyCodes.map((propertyCode) => ({ propertyCode, visible: true, editable: false, required: false })) }
111
+ : a);
112
+ // 3) update 模板(merge 语义;工具自动补 sheetCode/链路/设计器默认)
113
+ const updateOutcome = await runToolCall("workflow.update", {
114
+ args: { schemaCode: schema, code: compiled.workflowCode, template: { workflowCode: compiled.workflowCode, activities: activitiesWithPermissions }, ...(environment ? { environment } : {}) },
115
+ requestId: request, environment,
116
+ });
117
+ if (updateOutcome.exitCode !== 0) {
118
+ writeEnvelope(envelope(classifyResult(updateOutcome.result).status, updateOutcome.result, request, classifyResult(updateOutcome.result).error));
119
+ return updateOutcome.exitCode;
120
+ }
121
+ // 4) publish
122
+ const publishOutcome = await runToolCall("workflow.publish", { args: { schemaCode: schema, code: compiled.workflowCode, ...(environment ? { environment } : {}) }, requestId: request, environment });
123
+ const classified = classifyResult(publishOutcome.result);
124
+ writeEnvelope(envelope(classified.status, { schemaCode: schema, workflowCode: compiled.workflowCode, steps: steps.length, publish: publishOutcome.result }, request, classified.error));
125
+ if (publishOutcome.exitCode === 0)
126
+ process.stderr.write("[omc] 前台生效验证清单:1) 造一条数据提交走流程;2) 每级审批人在门户有待办(角色用 FindUserByRole 需审批人挂在发起人同部门,否则 PENDING 不来);3) 审批节点字段只读(不可改单);4) 驳回退发起人核对;5) 设计器打开流程确认节点链显示正常。\n");
127
+ return publishOutcome.exitCode;
128
+ }
129
+ //# sourceMappingURL=approval-flow.js.map
package/dist/cli.js CHANGED
@@ -21,6 +21,8 @@ import { buildToolRegistry } from "./tools.js";
21
21
  import { acquireWriteLock } from "./write-lock.js";
22
22
  import { cmdCompute } from "./compute.js";
23
23
  import { cmdRuleWhen } from "./rule-when.js";
24
+ import { cmdApprovalFlow } from "./approval-flow.js";
25
+ import { cmdFormDefault } from "./form-default.js";
24
26
  // --utf8:单次调用明文输出(等效 OMC_ASCII_STDOUT=0)。在 asciiStdout 缓存读取前生效。
25
27
  if (process.argv.includes("--utf8"))
26
28
  process.env.OMC_ASCII_STDOUT = "0";
@@ -952,6 +954,14 @@ async function main() {
952
954
  const rest = ["rule-when", ...(options.schema ? ["--schema", options.schema] : []), ...(options.schemaCode ? ["--schema-code", options.schemaCode] : []), ...(options.on ? ["--on", options.on] : []), ...(Array.isArray(options.when) ? options.when.flatMap((w) => ["--when", w]) : []), ...(Array.isArray(options.then) ? options.then.flatMap((a) => ["--then", a]) : []), ...(options.name ? ["--name", options.name] : []), ...(options.env ? ["--env", options.env] : []), ...(options.environment ? ["--environment", options.environment] : []), ...(options.apply ? ["--apply"] : [])];
953
955
  commandExitCode = await cmdRuleWhen(rest);
954
956
  });
957
+ command.command("approval-flow").option("--schema <schemaCode>").option("--schema-code <schemaCode>").option("--steps <step>", undefined, { variadic: true }).option("--env <environment>").option("--environment <environment>").option("--apply").option("--no-originator-node").option("--no-reject-to-start").addHelpText("after", "\n审批流拼装器:--steps 名称@role:<角色code>(多级给多个)。编译为验证模板(START→填写→审批链→END,审批节点字段只读),--apply 建流+权限+发布。\n").action(async (options) => {
958
+ const rest = ["approval-flow", ...(options.schema ? ["--schema", options.schema] : []), ...(options.schemaCode ? ["--schema-code", options.schemaCode] : []), ...(Array.isArray(options.steps) ? options.steps.flatMap((s) => ["--steps", s]) : []), ...(options.env ? ["--env", options.env] : []), ...(options.environment ? ["--environment", options.environment] : []), ...(options.apply ? ["--apply"] : []), ...(options.originatorNode === false ? ["--no-originator-node"] : []), ...(options.rejectToStart === false ? ["--no-reject-to-start"] : [])];
959
+ commandExitCode = await cmdApprovalFlow(rest);
960
+ });
961
+ command.command("form-default").option("--schema <schemaCode>").option("--schema-code <schemaCode>").option("--field <field>").option("--default <value>").option("--env <environment>").option("--environment <environment>").option("--apply").addHelpText("after", "\n表单默认值拼装器:字段默认值在表单控件层(control.options.defaultValue),本命令一条命令完成 draft→publish→权威回读。\n").action(async (options) => {
962
+ const rest = ["form-default", ...(options.schema ? ["--schema", options.schema] : []), ...(options.schemaCode ? ["--schema-code", options.schemaCode] : []), ...(options.field ? ["--field", options.field] : []), ...(options.default !== undefined ? ["--default", options.default] : []), ...(options.env ? ["--env", options.env] : []), ...(options.environment ? ["--environment", options.environment] : []), ...(options.apply ? ["--apply"] : [])];
963
+ commandExitCode = await cmdFormDefault(rest);
964
+ });
955
965
  command.command("script [file]").option("--env <environment>", "行内无 env 时的默认环境").option("--continue", "某行失败后继续执行剩余行(默认停在首个失败)").description("NDJSON 多调脚本:每行 {\"tool\":\"<名称>\",\"args\":{...},\"env\":\"<环境>\",\"dryRun\":true}(# 注释/空行忽略;file 为 - 读 stdin);一个进程一次会话跑完全部,逐行输出 {index,tool,exitCode,result}").action(async (file, options) => {
956
966
  const { runScript, parseScript, readScriptInput } = await import("./script.js");
957
967
  let lines;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * `omc form-default` — 表单控件默认值拼装器。
3
+ *
4
+ * r68-t3 与 r75-a1 两次实测:「字段默认值」不在 field.create/update(字段级无此
5
+ * 参数),而在**表单控件层**(control.options.defaultValue)——agent 每次都要
6
+ * form.get → 手改 draftAttributesJson → form.draft → form.publish 全链。
7
+ * 本命令一条命令完成:
8
+ *
9
+ * omc form-default --schema s --field status --default 履行中 [--apply]
10
+ *
11
+ * 执行链(--apply):form.get(controls:[field] 取控件全对象)→ 修改
12
+ * options.defaultValue → form.draft(draftAttributesJson 全量回写,保布局)→
13
+ * form.publish → form.get 权威回读确认 defaultValue 落库。默认 dry-run 只回显
14
+ * 将要做的修改。
15
+ */
16
+ import { runToolCall } from "./call.js";
17
+ import { envelope, requestId, classifyResult, CLI_EXIT_CODES } from "./cli-contract.js";
18
+ import { writeEnvelope } from "./cli-output.js";
19
+ /** 从 form.get 结果提取控件数组(draft 优先,published 兜底)。 */
20
+ function toControlList(value) {
21
+ if (Array.isArray(value))
22
+ return value;
23
+ // form.get controls:<选择> 返回按字段码为键的对象(实测:{"status":{...}})
24
+ if (value && typeof value === "object")
25
+ return Object.values(value);
26
+ return [];
27
+ }
28
+ function extractControls(formGet) {
29
+ const draft = toControlList(formGet.draftControls);
30
+ if (draft.length > 0)
31
+ return { controls: draft, face: "draft" };
32
+ const published = toControlList(formGet.publishedControls);
33
+ if (published.length > 0)
34
+ return { controls: published, face: "published" };
35
+ return undefined;
36
+ }
37
+ export async function cmdFormDefault(args) {
38
+ const request = requestId();
39
+ const flag = (name) => {
40
+ const index = args.indexOf(name);
41
+ return index >= 0 ? args[index + 1] : undefined;
42
+ };
43
+ const schema = flag("--schema") ?? flag("--schema-code");
44
+ const field = flag("--field");
45
+ const value = flag("--default");
46
+ const environment = flag("--env") ?? flag("--environment");
47
+ const apply = args.includes("--apply");
48
+ const usage = '用法:omc form-default --schema <模型> --field <字段code> --default <默认值> [--apply]\n默认 dry-run(回显将要做的修改);--apply 执行 form.draft→publish 并权威回读。';
49
+ const invalid = (message) => {
50
+ writeEnvelope(envelope("error", {}, request, { code: "invalid-input", message: `${message}\n${usage}`, retryable: false }));
51
+ return CLI_EXIT_CODES.invalidInput;
52
+ };
53
+ if (!schema || !field || value === undefined)
54
+ return invalid("--schema/--field/--default 均必填");
55
+ // 1) 读控件(单控件投影,拿全对象含 options)
56
+ const getOutcome = await runToolCall("form.get", { args: { schemaCode: schema, controls: [field], ...(environment ? { environment } : {}) }, requestId: request, environment });
57
+ if (getOutcome.exitCode !== 0) {
58
+ const classified = classifyResult(getOutcome.result);
59
+ writeEnvelope(envelope(classified.status, getOutcome.result, request, classified.error));
60
+ return getOutcome.exitCode;
61
+ }
62
+ const extracted = extractControls(getOutcome.result ?? {});
63
+ const control = extracted?.controls.find((c) => String(c.key ?? c.dataItemName ?? "") === field || String(c.code ?? "") === field);
64
+ if (!control)
65
+ return invalid(`form.get 未取到字段 "${field}" 的控件——先确认字段已发布且已进表单(新字段先 form.draft rebuild:true)`);
66
+ const nextControl = JSON.parse(JSON.stringify(control));
67
+ const options = (nextControl.options ?? {});
68
+ // 单选/多选类默认值是数组(form-support:136 证据),文本类是字符串;按现值类型对齐
69
+ if (Array.isArray(options.defaultValue))
70
+ options.defaultValue = [value];
71
+ else
72
+ options.defaultValue = value;
73
+ nextControl.options = options;
74
+ if (!apply) {
75
+ writeEnvelope(envelope("ok", { schemaCode: schema, field, from: options.defaultValue === value ? undefined : control, to: nextControl, dryRun: true, note: "--apply 执行 form.draft→form.publish" }, request));
76
+ return 0;
77
+ }
78
+ // 2) form.draft:需要完整 draftAttributesJson——单控件投影不够,取全量控件面
79
+ const getAll = await runToolCall("form.get", { args: { schemaCode: schema, controls: true, ...(environment ? { environment } : {}) }, requestId: request, environment });
80
+ if (getAll.exitCode !== 0) {
81
+ const classified = classifyResult(getAll.result);
82
+ writeEnvelope(envelope(classified.status, getAll.result, request, classified.error));
83
+ return getAll.exitCode;
84
+ }
85
+ const fullExtracted = extractControls(getAll.result ?? {});
86
+ if (!fullExtracted)
87
+ return invalid("form.get 未取到任何控件(表单为空?先发布默认表单)");
88
+ const fullControls = fullExtracted.controls.map((c) => (String(c.key ?? c.dataItemName ?? "") === field ? nextControl : c));
89
+ const draftOutcome = await runToolCall("form.draft", {
90
+ args: { schemaCode: schema, draftAttributesJson: JSON.stringify(fullControls), ...(environment ? { environment } : {}) },
91
+ requestId: request, environment,
92
+ });
93
+ if (draftOutcome.exitCode !== 0) {
94
+ const classified = classifyResult(draftOutcome.result);
95
+ writeEnvelope(envelope(classified.status, draftOutcome.result, request, classified.error));
96
+ return draftOutcome.exitCode;
97
+ }
98
+ const publishOutcome = await runToolCall("form.publish", { args: { schemaCode: schema, ...(environment ? { environment } : {}) }, requestId: request, environment });
99
+ if (publishOutcome.exitCode !== 0) {
100
+ const classified = classifyResult(publishOutcome.result);
101
+ writeEnvelope(envelope(classified.status, publishOutcome.result, request, classified.error));
102
+ return publishOutcome.exitCode;
103
+ }
104
+ // 3) 权威回读
105
+ const verify = await runToolCall("form.get", { args: { schemaCode: schema, controls: [field], ...(environment ? { environment } : {}) }, requestId: request, environment });
106
+ const verifyResult = verify.result ?? {};
107
+ const verifyControls = extractControls(verifyResult)?.controls ?? [];
108
+ const verifyControl = verifyControls.find((c) => String(c.key ?? c.dataItemName ?? "") === field);
109
+ const appliedDefault = verifyControl ? (verifyControl.options?.defaultValue ?? null) : null;
110
+ const ok = JSON.stringify(appliedDefault) === JSON.stringify(Array.isArray(options.defaultValue) ? [value] : value);
111
+ writeEnvelope(envelope(ok ? "ok" : "uncertain", { schemaCode: schema, field, default: value, published: ok, readback: { defaultValue: appliedDefault }, ...(ok ? {} : { nextAction: "回读默认值与目标不一致,设计器人工核对" }) }, request));
112
+ if (ok)
113
+ process.stderr.write("[omc] 前台生效验证清单:门户新建该模型记录,确认控件预填默认值;改默认值同理重跑本命令。\n");
114
+ return ok ? 0 : 1;
115
+ }
116
+ //# sourceMappingURL=form-default.js.map
@@ -352,6 +352,7 @@ export function registerRuntimeDataLane(tools) {
352
352
  showTotal: z.boolean().default(true),
353
353
  page: z.number().int().min(0).default(0),
354
354
  size: z.number().int().min(1).max(200).default(10),
355
+ all: z.boolean().optional().describe("true 时自动翻页聚合全部结果(内部按 size=200 逐页拉取,安全上限 1000 行,超出截断并标记 capped)——存量盘点/数据核对用,替代手动循环翻页"),
355
356
  full: z.boolean().optional().describe("内联完整列表结果;默认大结果只返回计数与 detailFile"),
356
357
  capability: capabilityArg,
357
358
  },
@@ -426,6 +427,36 @@ export function registerRuntimeDataLane(tools) {
426
427
  };
427
428
  // An empty model answers with a business error (301005) on this face;
428
429
  // that is "no data yet", not a query failure.
430
+ if (args.all === true) {
431
+ const CAP = 1000;
432
+ const pageSize = 200;
433
+ const firstBody = { ...body, page: 0, size: pageSize };
434
+ const first = await wireCall(session, { path: ENDPOINTS.runtimeQueryList, method: "POST", body: firstBody });
435
+ const firstPage = extractBizObjectPage(first.data);
436
+ const total = Number(firstPage.total ?? 0);
437
+ if (total === 0 || firstPage.content.length === 0)
438
+ return { schemaCode: args.schemaCode, total: 0, page: "all", size: 0, pagesFetched: 0, items: [] };
439
+ const rows = [...firstPage.content];
440
+ const target = Math.min(total, CAP);
441
+ let pageIndex = 1;
442
+ while (rows.length < target) {
443
+ const next = await wireCall(session, { path: ENDPOINTS.runtimeQueryList, method: "POST", body: { ...body, page: pageIndex, size: pageSize } });
444
+ const nextPage = extractBizObjectPage(next.data);
445
+ if (nextPage.content.length === 0)
446
+ break;
447
+ rows.push(...nextPage.content);
448
+ pageIndex += 1;
449
+ }
450
+ const capped = rows.length > CAP;
451
+ const items = (capped ? rows.slice(0, CAP) : rows).map((row0) => {
452
+ const row = row0;
453
+ const rawData = row.data && typeof row.data === "object" ? row.data : {};
454
+ const data = args.full === true ? rawData : compactRuntimeRecord(rawData);
455
+ const selected = fields ?? Object.keys(data).filter((field) => !["id", "bizObjectId", "schemaCode", "sequenceStatus", "createdTime", "updatedTime", "creator", "updater"].includes(field));
456
+ return { id: row.bizObjectId ?? row.id ?? data.id, fields: Object.fromEntries(selected.map((field) => [field, data[field] ?? null])) };
457
+ });
458
+ return { schemaCode: args.schemaCode, total, page: "all", size: rows.length, pagesFetched: pageIndex, ...(capped ? { capped: true, capNotice: `结果超过安全上限 ${CAP},已截断;请加 filters 分批` } : {}), items };
459
+ }
429
460
  let result;
430
461
  try {
431
462
  result = await wireCall(session, { path: ENDPOINTS.runtimeQueryList, method: "POST", body });
package/dist/write.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { existsSync, readdirSync, readFileSync } from "node:fs";
4
- import { join } from "node:path";
4
+ import { basename, join } from "node:path";
5
5
  /** Parse a JSON string for the dry-lint; unparseable input returns undefined so the shape validators report it. */
6
6
  function parseJsonOrUndefined(text) {
7
7
  try {
@@ -151,7 +151,7 @@ async function governedWrite(ctx, tool, args, execute, dryRunPayload) {
151
151
  rollbackable: rollbackBefore !== undefined && !rollbackCaptureError,
152
152
  ...(rollbackCaptureError ? { note: `before-capture failed: ${rollbackCaptureError}` } : {}),
153
153
  artifactFile: artifactRef.detailFile,
154
- artifactId: artifactRef.detailFile.split("/").pop()?.replace(/\.json$/, "") ?? "",
154
+ artifactId: basename(artifactRef.detailFile).replace(/\.artifact$/, "") || basename(artifactRef.detailFile),
155
155
  artifactSha: artifactRef.detailSha256,
156
156
  });
157
157
  rollbackRef = { seq: entry.seq, hint: `omc rollback plan ${entry.seq}(--env ${entry.environment})` };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-cli",
3
- "version": "0.4.50",
3
+ "version": "0.4.52",
4
4
  "description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
5
5
  "type": "module",
6
6
  "bin": {