@stalfh233/omc-cli 0.6.1 → 0.6.2

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/cli.js CHANGED
@@ -749,8 +749,34 @@ async function cmdArtifactGet(id, transport, options = {}) {
749
749
  }, transport);
750
750
  }
751
751
  const result = { status: "ok", artifactId: id, sha256: artifact.sha256, content };
752
- if (Buffer.byteLength(JSON.stringify(result), "utf8") > transport.maxOutputBytes)
753
- return emitTransportResult({ status: "ok", artifactId: id, sha256: artifact.sha256, bytes: artifact.content.length, fetch: artifactFetchHint(id) }, transport);
752
+ if (Buffer.byteLength(JSON.stringify(result), "utf8") > transport.maxOutputBytes) {
753
+ // 2026-11-04 r70: `--full` used to fall back to the same bare `fetch`
754
+ // pointer it had just been asked to bypass — re-running `--full` re-hits
755
+ // the same ceiling, so a caller that genuinely needs the body loops
756
+ // forever (observed live: three consecutive `--full` calls returned the
757
+ // same id with bytes 90K→151K→227K of pointer metadata). Say what
758
+ // actually happened and give the two projections that DO work.
759
+ const record = content && typeof content === "object" && !Array.isArray(content) ? content : undefined;
760
+ const keys = record
761
+ ? Object.entries(record)
762
+ .map(([key, value]) => ({ key, bytes: Buffer.byteLength(JSON.stringify(value) ?? "null", "utf8") }))
763
+ .sort((left, right) => right.bytes - left.bytes)
764
+ .slice(0, 3)
765
+ .map((entry) => entry.key)
766
+ : [];
767
+ return emitTransportResult({
768
+ status: "ok",
769
+ artifactId: id,
770
+ sha256: artifact.sha256,
771
+ bytes: artifact.content.length,
772
+ fullRejected: true,
773
+ reason: `整包 ${Math.round(artifact.content.length / 1024)}KB 超过本通道输出上限 ${transport.maxOutputBytes}B;--full 无法一次返回,再跑一次结果相同`,
774
+ ...(keys.length > 0 ? { keysCommand: `omc artifact get ${id} --keys ${keys.join(",")}`, sampledKeys: keys } : {}),
775
+ jqCommand: `omc artifact get ${id} --jq '<path>'`,
776
+ raiseCeilingCommand: `omc artifact get ${id} --full --max-output-bytes ${Math.max(artifact.content.length + 1024, transport.maxOutputBytes * 2)}`,
777
+ hint: "二选一:用 --jq/--keys 取你真正需要的那部分(推荐),或显式抬高 --max-output-bytes",
778
+ }, transport);
779
+ }
754
780
  return emitTransportResult(result, transport);
755
781
  }
756
782
  catch (error) {
@@ -74,6 +74,83 @@ function deptTypeCode(value) {
74
74
  return code;
75
75
  }
76
76
  const orgQuery = (session) => ({ corpId: session.enterpriseId() });
77
+ /**
78
+ * Read the role tree (`/role/list?expandAll=true`) and flatten it, keeping the
79
+ * **id** alongside code/name.
80
+ *
81
+ * Why this exists (r70, live 1.1.25): `org.role.list`'s compact projection emits
82
+ * `code|name` pairs and drops the id, while `add_role` / `add_role_user` /
83
+ * `update_ouscope` all want the id. Worse, the platform stores a wrong
84
+ * `roleGroupId` verbatim (`h_org_role.groupId` is not an FK): passing the group
85
+ * *code* that the read face shows yields errcode 0 and an orphan role — the row
86
+ * exists, `role/users` finds it, `role/list` never returns it, `role/get`
87
+ * answers 50000. Resolving code→id here removes the trap for every caller.
88
+ */
89
+ async function readRoleTree(session) {
90
+ const data = (await wireCall(session, {
91
+ path: ENDPOINTS.organizationRoleList,
92
+ query: { corpId: session.enterpriseId(), expandAll: "true" },
93
+ })).data;
94
+ const groups = [];
95
+ const roles = [];
96
+ const childKeys = ["children", "roles", "childRoles", "childList", "list"];
97
+ const childrenOf = (row) => {
98
+ for (const key of childKeys) {
99
+ const value = row[key];
100
+ if (Array.isArray(value))
101
+ return value;
102
+ }
103
+ return [];
104
+ };
105
+ const walk = (rows) => {
106
+ for (const row of rows) {
107
+ const kids = childrenOf(row);
108
+ // A container carries group===true, or has children and no groupId; a leaf
109
+ // role always carries groupId (mirrors flattenRoleTree's rule).
110
+ const hasGroupId = row.groupId !== undefined && row.groupId !== null;
111
+ const isGroup = row.group === true || (!hasGroupId && kids.length > 0);
112
+ if (!isGroup) {
113
+ const id = String(row.id ?? "");
114
+ if (id !== "")
115
+ roles.push({ id, code: String(row.code ?? ""), name: String(row.name ?? "") });
116
+ continue;
117
+ }
118
+ groups.push({ id: String(row.id ?? ""), code: String(row.code ?? ""), name: String(row.name ?? "") });
119
+ if (kids.length > 0)
120
+ walk(kids);
121
+ }
122
+ };
123
+ walk(wireRows(data));
124
+ return { groups, roles };
125
+ }
126
+ /**
127
+ * Resolve a caller-supplied role reference (32-hex id, or the `code` / `name`
128
+ * that `org.role.list` actually shows) to the platform role id. A reference that
129
+ * matches nothing is refused with the list of real roles — never written blind.
130
+ */
131
+ async function resolveRoleRef(session, args, tool) {
132
+ const requested = args.roleId ?? args.roleCode;
133
+ if (!requested)
134
+ throw new ToolInputError({ status: "error", blocker: "tool-input-invalid", tool, message: "需要 roleId 或 roleCode(org.role.list 的 roles 码表给的是 code)" });
135
+ // An explicit roleCode must resolve — never forward it as an id.
136
+ if (args.roleId !== undefined && args.roleCode === undefined && /^[0-9a-f]{32}$/i.test(requested))
137
+ return requested;
138
+ const { roles } = await readRoleTree(session);
139
+ const match = roles.find((role) => role.code === requested) ?? roles.find((role) => role.name === requested);
140
+ if (match)
141
+ return match.id;
142
+ // Not a known code/name. `roleId` may still be a valid id the tree does not
143
+ // surface (e.g. a role in another corp); forward it and let the platform
144
+ // judge, rather than breaking callers that hold an id we cannot see.
145
+ if (args.roleId !== undefined)
146
+ return requested;
147
+ throw new ToolInputError({
148
+ status: "error",
149
+ blocker: "tool-input-invalid",
150
+ tool,
151
+ message: `角色 ${requested} 不存在。可用角色:${roles.slice(0, 30).map((role) => `${role.code}(${role.name})`).join(";")}`,
152
+ });
153
+ }
77
154
  const roleUserId = (row) => String(row.id ?? row.userId ?? row.recId ?? "");
78
155
  async function memberRows(session, roleId) {
79
156
  const data = (await wireCall(session, {
@@ -226,22 +303,43 @@ export function registerOrganizationLane(tools) {
226
303
  },
227
304
  };
228
305
  });
229
- writeTool(tools, "org.role.create", LANE, SCOPES.roleCreate, "创建角色(界面「分组」;`POST organization/role/add_role`)。返回 roleId;code 创建时 null、随后补 SYS<时间戳>,要稳定编码就传 code。", {
306
+ writeTool(tools, "org.role.create", LANE, SCOPES.roleCreate, "创建角色(界面「分组」;`POST organization/role/add_role`)。返回 roleId;code 创建时 null、随后补 SYS<时间戳>,要稳定编码就传 code。**所属角色组推荐用 `roleGroupCode`(如 SYS_1000000)**:`org.role.list` 的紧凑码表只给 `code|name`、不显示组 id,而平台对错的 roleGroupId **静默接受**——存进去的值不是真实组 id 时角色会变成看不见的孤儿(r70 实测:在库里、role/users 查得到,role/list 永不返回、role/get 50000)。工具会把 code 归一成真实 id,并在创建后回读可见性。", {
230
307
  roleName: z.string().min(1),
231
- roleGroupId: z.string().min(1).describe("所属角色组 id(org.role.list 的 groups[].id)"),
308
+ roleGroupCode: z.string().min(1).optional().describe("所属角色组的 code(org.role.list 的 groups 码表,如 SYS_1000000)或名称。**推荐**;与 roleGroupId 二选一"),
309
+ roleGroupId: z.string().min(1).optional().describe("所属角色组 id(32 位 hex,只能从 artifact get <role.list 的 detailArtifactId> --jq groups 取到)。误传组 code 时工具会归一成真实 id"),
232
310
  roleGroupName: z.string().optional(),
233
311
  roleType: z.enum(["SYS", "CUSTOMIZE", "OTHER"]).optional().describe("默认 SYS(平台会把角色统一落成 SYS,见 RoleHelper.createRoleModel)"),
234
312
  code: z.string().optional(),
235
313
  remarks: z.string().optional(),
236
314
  corpId: z.string().min(1).optional().describe("组织 corpId,默认当前登录企业;传 \"other\" 表示非组织分组角色"),
237
315
  }, async (session, args) => {
316
+ if (!args.roleGroupCode && !args.roleGroupId) {
317
+ throw new ToolInputError({ message: "必须给 roleGroupCode(推荐)或 roleGroupId;先 org.role.list 取 groups 码表" });
318
+ }
319
+ const { groups } = await readRoleTree(session);
320
+ if (groups.length === 0) {
321
+ throw new ToolRefusalError({ status: "refused", blocker: "wire-shape", message: "org.role.list 未解析出任何角色组;先确认组织树可读,不要盲建角色" });
322
+ }
323
+ const requested = args.roleGroupId ?? args.roleGroupCode;
324
+ const match = groups.find((group) => group.id === requested) ??
325
+ groups.find((group) => group.code === requested) ??
326
+ groups.find((group) => group.name === requested);
327
+ // A code/name that resolves to nothing is a definite typo → refuse.
328
+ // A 32-hex id absent from the tree may be a group created moments ago in
329
+ // this same session; let it through and rely on the visibility backstop.
330
+ if (!match && args.roleGroupCode) {
331
+ throw new ToolInputError({
332
+ message: `角色组 ${requested} 不存在。可用组:${groups.map((group) => `${group.code}(id=${group.id},${group.name})`).join(";")}`,
333
+ });
334
+ }
335
+ const roleGroupId = match?.id ?? String(requested);
238
336
  const corpId = args.corpId ?? session.enterpriseId();
239
337
  const data = (await wireCall(session, {
240
338
  path: ENDPOINTS.organizationRoleAdd, method: "POST",
241
339
  query: orgQuery(session),
242
340
  body: {
243
341
  roleName: args.roleName,
244
- roleGroupId: args.roleGroupId,
342
+ roleGroupId,
245
343
  ...(args.roleGroupName ? { roleGroupName: args.roleGroupName } : {}),
246
344
  roleType: args.roleType ?? "SYS",
247
345
  corpId,
@@ -252,15 +350,29 @@ export function registerOrganizationLane(tools) {
252
350
  const roleId = String(data?.roleId ?? data?.id ?? "");
253
351
  if (!roleId)
254
352
  throw new ToolRefusalError({ status: "refused", blocker: "wire-shape", message: "平台未返回 roleId;先 org.role.list 回读确认" });
353
+ // Backstop against the silent-orphan trap: re-read the tree and report the
354
+ // truth instead of reporting success for a role nobody can see.
355
+ const visible = (await readRoleTree(session)).roles.some((role) => role.id === roleId);
255
356
  const readbackCorpId = data?.corpId ?? null;
357
+ const warnings = [];
358
+ if (!visible) {
359
+ warnings.push(`角色 ${roleId} 创建后不在 org.role.list 任何组下(孤儿角色):groupId 很可能没落到真实组 id。请 org.role.delete 后按 roleGroupCode 重建`);
360
+ }
361
+ if (readbackCorpId !== null && String(readbackCorpId) !== corpId) {
362
+ warnings.push(`平台回读 corpId=${String(readbackCorpId)},与请求的 ${corpId} 不一致`);
363
+ }
256
364
  return {
257
365
  performed: { errcode: 0 },
258
366
  readback: {
259
367
  roleId,
260
368
  roleName: data?.roleName ?? args.roleName,
261
369
  code: data?.code ?? null,
370
+ roleGroupId,
371
+ roleGroupCode: match?.code ?? null,
372
+ roleGroupName: match?.name ?? null,
373
+ visibleInRoleList: visible,
262
374
  corpId: readbackCorpId,
263
- ...(readbackCorpId === null || String(readbackCorpId) === corpId ? {} : { warning: `平台回读 corpId=${String(readbackCorpId)},与请求的 ${corpId} 不一致` }),
375
+ ...(warnings.length > 0 ? { warning: warnings.join(";") } : {}),
264
376
  },
265
377
  };
266
378
  });
@@ -634,21 +746,23 @@ export function registerOrganizationLane(tools) {
634
746
  return { userId: String(args.userId), count: departments.length, departments };
635
747
  }),
636
748
  }));
637
- writeTool(tools, "org.role.delete", LANE, SCOPES.roleDelete, "删除角色(`GET organization/role/strike_out_role?ids=`)。平台**拒绝删除仍有成员的角色**(`-1 角色下已经包含用户数据!`,实测 1.1.25):默认先读成员数、非空即拒绝并给出人数;`force:true` 才会先逐人移出再删。", {
638
- roleId: z.string().min(1),
749
+ writeTool(tools, "org.role.delete", LANE, SCOPES.roleDelete, "删除角色(`GET organization/role/strike_out_role?ids=`)。平台**拒绝删除仍有成员的角色**(`-1 角色下已经包含用户数据!`,实测 1.1.25):默认先读成员数、非空即拒绝并给出人数;`force:true` 才会先逐人移出再删。**可用 roleCode 代替 roleId**(org.role.list 的码表只有 code)。", {
750
+ roleId: z.string().min(1).optional().describe("角色 id(32 位 hex);与 roleCode 二选一"),
751
+ roleCode: z.string().min(1).optional().describe("角色 code(org.role.list 的 roles 码表,如 qc_manager)或名称"),
639
752
  force: z.boolean().optional().describe("true = 先移出全部成员再删角色"),
640
753
  }, async (session, args) => {
641
- const rows = await memberRows(session, String(args.roleId));
754
+ const roleId = await resolveRoleRef(session, { roleId: args.roleId, roleCode: args.roleCode }, "org.role.delete");
755
+ const rows = await memberRows(session, roleId);
642
756
  if (rows.length > 0 && args.force !== true)
643
757
  throw new ToolRefusalError({
644
- status: "refused", blocker: "role-has-members", roleId: String(args.roleId), members: rows.length,
645
- nextCommand: `omc call org.role.delete --args '${JSON.stringify({ roleId: String(args.roleId), force: true })}'`,
758
+ status: "refused", blocker: "role-has-members", roleId, members: rows.length,
759
+ nextCommand: `omc call org.role.delete --args '${JSON.stringify({ roleId, force: true })}'`,
646
760
  message: `角色下还有 ${rows.length} 名成员,平台拒绝删除(errmsg:角色下已经包含用户数据)。先 org.role.removeUsers,或传 force:true 让工具移出后再删。`,
647
761
  });
648
762
  if (rows.length > 0)
649
- await removeMembers(session, String(args.roleId), rows.map(roleUserId));
650
- await wireCall(session, { path: ENDPOINTS.organizationRoleDelete, query: { ...orgQuery(session), ids: String(args.roleId) } });
651
- return { performed: { errcode: 0 }, readback: { roleId: String(args.roleId), deleted: true, removedMembers: rows.length } };
763
+ await removeMembers(session, roleId, rows.map(roleUserId));
764
+ await wireCall(session, { path: ENDPOINTS.organizationRoleDelete, query: { ...orgQuery(session), ids: roleId } });
765
+ return { performed: { errcode: 0 }, readback: { roleId, deleted: true, removedMembers: rows.length } };
652
766
  });
653
767
  writeTool(tools, "org.roleGroup.delete", LANE, SCOPES.roleGroupDelete, "删除角色组(`GET organization/role/strike_out_role_group?ids=`)。平台**拒绝删除仍含角色的组**(`-1 角色组下已经包含角色数据!`):默认先数角色、非空即拒绝;`force:true` 会逐个删角色(含其成员)再删组。", {
654
768
  roleGroupId: z.string().min(1),
@@ -730,7 +844,8 @@ export function registerOrganizationLane(tools) {
730
844
  };
731
845
  });
732
846
  writeTool(tools, "org.role.addUsers", LANE, SCOPES.addUsers, "加成员并(可选)一次设好管理范围(`add_role_user` + 逐人 `update_ouscope`,一个工具调用)。users[].id 必须是 recId(org.user.search 的 id);传 `scopes` 会应用到本次新增的每个人。**平台的 add_role_user 虽然收 `ouScope` 但会忽略它**(实测 1.1.25,回读仍为空),所以范围必须单独写——工具内部已按顺序完成。加完回读成员与范围。", {
733
- roleId: z.string().min(1),
847
+ roleId: z.string().min(1).optional().describe("角色 id(32 位 hex);与 roleCode 二选一"),
848
+ roleCode: z.string().min(1).optional().describe("角色 code(org.role.list 的 roles 码表)或名称——省掉取 artifact 找 id"),
734
849
  users: z.array(z.object({ id: z.string().min(1).describe("用户记录 id(recId)"), name: z.string().min(1) })).min(1),
735
850
  scopes: z.array(z.object({
736
851
  id: z.string().min(1).describe("部门 id"),
@@ -744,15 +859,16 @@ export function registerOrganizationLane(tools) {
744
859
  const users = args.users ?? args.userIds ?? [];
745
860
  if (users.length === 0)
746
861
  throw new ToolInputError({ status: "error", blocker: "tool-input-invalid", tool: "org.role.addUsers", message: "需要 users(或 userIds)至少一人" });
862
+ const roleId = await resolveRoleRef(session, { roleId: args.roleId, roleCode: args.roleCode }, "org.role.addUsers");
747
863
  await wireCall(session, {
748
864
  path: ENDPOINTS.organizationRoleAddUser, method: "POST",
749
865
  query: orgQuery(session),
750
- body: { roleId: args.roleId, sortKey: args.sortKey ?? 999, userIds: users.map((user) => ({ id: user.id, name: user.name, type: 3, unitType: "3" })) },
866
+ body: { roleId, sortKey: args.sortKey ?? 999, userIds: users.map((user) => ({ id: user.id, name: user.name, type: 3, unitType: "3" })) },
751
867
  });
752
868
  const readback = async () => {
753
869
  const data = (await wireCall(session, {
754
870
  path: ENDPOINTS.organizationRoleUsers,
755
- query: { ...orgQuery(session), roleId: String(args.roleId), page: "0", size: "500" },
871
+ query: { ...orgQuery(session), roleId: roleId, page: "0", size: "500" },
756
872
  })).data;
757
873
  return Array.isArray(data?.content) ? data.content : wireRows(data);
758
874
  };
@@ -766,11 +882,11 @@ export function registerOrganizationLane(tools) {
766
882
  for (const id of added) {
767
883
  await wireCall(session, {
768
884
  path: ENDPOINTS.organizationRoleUpdateOuScope, method: "POST", query: orgQuery(session),
769
- body: { roleId: String(args.roleId), userId: id, unitType: 3, sortKey: args.sortKey ?? 999, ouScopeList },
885
+ body: { roleId: roleId, userId: id, unitType: 3, sortKey: args.sortKey ?? 999, ouScopeList },
770
886
  });
771
887
  const scope = wireRows((await wireCall(session, {
772
888
  path: ENDPOINTS.organizationRoleGetOuScope,
773
- query: { ...orgQuery(session), roleId: String(args.roleId), userId: id },
889
+ query: { ...orgQuery(session), roleId: roleId, userId: id },
774
890
  })).data);
775
891
  scopeResults.push({ userId: id, scopes: scope.length });
776
892
  }
@@ -778,7 +894,7 @@ export function registerOrganizationLane(tools) {
778
894
  return {
779
895
  performed: { errcode: 0 },
780
896
  readback: {
781
- roleId: String(args.roleId), added,
897
+ roleId: roleId, added,
782
898
  ...(missing.length > 0 ? { missing, hint: "这些 recId 未出现在成员列表:确认 id 是 recId、用户未离职/禁用" } : {}),
783
899
  ...(scopeResults.length > 0 ? { scopeResults } : {}),
784
900
  // ouScope 是流程角色参与人解析的过滤维度:平台
@@ -802,12 +918,14 @@ export function registerOrganizationLane(tools) {
802
918
  };
803
919
  });
804
920
  writeTool(tools, "org.role.removeUsers", LANE, SCOPES.removeUsers, "把成员移出角色(`POST organization/role/strike_out_role_user`)。**平台要求 JSON body `{roleId,userIds:[...]}`**——用 query 或 `ids` 会报 10009 `Required request body is missing`(实测 1.1.25)。只移出角色,不删用户。", {
805
- roleId: z.string().min(1),
921
+ roleId: z.string().min(1).optional().describe("角色 id(32 位 hex);与 roleCode 二选一"),
922
+ roleCode: z.string().min(1).optional().describe("角色 code(org.role.list 的 roles 码表)或名称"),
806
923
  ids: z.array(z.string().min(1)).min(1).describe("要移出的成员 recId 列表"),
807
924
  }, async (session, args) => {
925
+ const roleId = await resolveRoleRef(session, { roleId: args.roleId, roleCode: args.roleCode }, "org.role.removeUsers");
808
926
  await wireCall(session, {
809
927
  path: ENDPOINTS.organizationRoleRemoveUser, method: "POST", query: orgQuery(session),
810
- body: { roleId: String(args.roleId), userIds: args.ids },
928
+ body: { roleId, userIds: args.ids },
811
929
  });
812
930
  const data = (await wireCall(session, {
813
931
  path: ENDPOINTS.organizationRoleUsers,
@@ -818,7 +936,8 @@ export function registerOrganizationLane(tools) {
818
936
  return { performed: { errcode: 0 }, readback: { roleId: String(args.roleId), removed: args.ids.filter((id) => !present.has(id)), stillPresent: args.ids.filter((id) => present.has(id)), total: data?.totalElements ?? rows.length } };
819
937
  });
820
938
  writeTool(tools, "org.role.setUserScope", LANE, SCOPES.setScope, "设置成员管理范围(`POST organization/role/update_ouscope`)。平台覆盖语义、无回滚:默认读旧值合并(mode:\"merge\"),mode:\"replace\" 才整体替换。unitType 传数字 3(addUsers 里是字符串 \"3\")。节点 {id,name,type:\"1\",deptPath}。", {
821
- roleId: z.string().min(1),
939
+ roleId: z.string().min(1).optional().describe("角色 id(32 位 hex);与 roleCode 二选一"),
940
+ roleCode: z.string().min(1).optional().describe("角色 code(org.role.list 的 roles 码表)或名称"),
822
941
  userId: z.string().min(1).describe("成员 recId"),
823
942
  scopes: z.array(z.object({
824
943
  id: z.string().min(1).describe("部门 id"),
@@ -832,9 +951,10 @@ export function registerOrganizationLane(tools) {
832
951
  mode: z.enum(["merge", "replace"]).optional().describe("默认 merge(读旧值合并);replace = 覆盖整个范围"),
833
952
  dryRun: z.boolean().optional(),
834
953
  }, async (session, args) => {
954
+ const roleId = await resolveRoleRef(session, { roleId: args.roleId, roleCode: args.roleCode }, "org.role.setUserScope");
835
955
  const before = wireRows((await wireCall(session, {
836
956
  path: ENDPOINTS.organizationRoleGetOuScope,
837
- query: { ...orgQuery(session), roleId: args.roleId, userId: args.userId },
957
+ query: { ...orgQuery(session), roleId, userId: args.userId },
838
958
  })).data);
839
959
  const wanted = args.scopes.map((scope) => ({ id: scope.id, name: scope.name, type: scope.type === undefined ? "1" : String(scope.type), ...(scope.deptPath ? { deptPath: scope.deptPath } : {}) }));
840
960
  const merged = args.mode === "replace"
@@ -850,15 +970,15 @@ export function registerOrganizationLane(tools) {
850
970
  await wireCall(session, {
851
971
  path: ENDPOINTS.organizationRoleUpdateOuScope, method: "POST",
852
972
  query: orgQuery(session),
853
- body: { roleId: args.roleId, userId: args.userId, unitType: 3, sortKey: 999, ouScopeList: merged },
973
+ body: { roleId, userId: args.userId, unitType: 3, sortKey: 999, ouScopeList: merged },
854
974
  });
855
975
  const after = wireRows((await wireCall(session, {
856
976
  path: ENDPOINTS.organizationRoleGetOuScope,
857
- query: { ...orgQuery(session), roleId: args.roleId, userId: args.userId },
977
+ query: { ...orgQuery(session), roleId, userId: args.userId },
858
978
  })).data).map((row) => ({ id: row.id ?? null, name: row.name ?? null, type: row.type ?? null, deptPath: row.deptPath ?? null }));
859
979
  return {
860
980
  performed: { errcode: 0 },
861
- readback: { roleId: args.roleId, userId: args.userId, mode: args.mode ?? "merge", before: before.length, after: after.length, scopes: after, ...(removed.length > 0 ? { removedScopeIds: removed } : {}) },
981
+ readback: { roleId, userId: args.userId, mode: args.mode ?? "merge", before: before.length, after: after.length, scopes: after, ...(removed.length > 0 ? { removedScopeIds: removed } : {}) },
862
982
  };
863
983
  });
864
984
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "CloudPivot 8.6 configuration capability CLI — governed, fail-closed, coverage-manifest bounded.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,9 +52,9 @@
52
52
  "access": "public"
53
53
  },
54
54
  "dependencies": {
55
- "@stalfh233/omc-fake-platform": "0.6.0",
55
+ "@stalfh233/omc-fake-platform": "0.6.2",
56
56
  "commander": "14.0.3",
57
- "omc-core": "0.6.0",
57
+ "omc-core": "0.6.2",
58
58
  "proper-lockfile": "4.1.2",
59
59
  "write-file-atomic": "6.0.0",
60
60
  "zod": "^3.23.8",