@uipath/data-fabric-tool 1.195.0 → 1.196.0

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/data-fabric-tool",
3
3
  "license": "MIT",
4
- "version": "1.195.0",
4
+ "version": "1.196.0",
5
5
  "description": "Manage Data Fabric entities and records.",
6
6
  "type": "module",
7
7
  "main": "./dist/tool.js",
@@ -14,5 +14,5 @@
14
14
  "publishConfig": {
15
15
  "registry": "https://registry.npmjs.org/"
16
16
  },
17
- "gitHead": "65fabb84552758b2710d8ca68470e70a9b1d19bc"
17
+ "gitHead": "94d71f9c52214980a1f0ae62b3f5372095788553"
18
18
  }
@@ -557,7 +557,7 @@ describe("choice-sets delete", () => {
557
557
  );
558
558
  });
559
559
 
560
- it("should require --confirm", async () => {
560
+ it("should require confirmation (no --yes/--confirm): exit 1, SDK not called", async () => {
561
561
  const sdk = mockSdk();
562
562
  const program = buildProgram();
563
563
  await program.parseAsync([
@@ -570,13 +570,30 @@ describe("choice-sets delete", () => {
570
570
  "cleanup",
571
571
  ]);
572
572
  expect(sdk.entities.choicesets.deleteById).not.toHaveBeenCalled();
573
- expect(OutputFormatter.error).toHaveBeenCalledWith(
573
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
574
+ expect(process.exitCode).toBe(1);
575
+ });
576
+
577
+ it("should accept --yes (canonical confirmation flag)", async () => {
578
+ const sdk = mockSdk();
579
+ const program = buildProgram();
580
+ await program.parseAsync([
581
+ "node",
582
+ "test",
583
+ "choice-sets",
584
+ "delete",
585
+ "cs-1",
586
+ "--yes",
587
+ "--reason",
588
+ "cleanup",
589
+ ]);
590
+ expect(sdk.entities.choicesets.deleteById).toHaveBeenCalledWith("cs-1");
591
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
574
592
  expect.objectContaining({
575
- Result: "Failure",
576
- Message: "Confirmation required for destructive operation",
593
+ Result: "Success",
594
+ Code: "ChoiceSetDeleted",
577
595
  }),
578
596
  );
579
- expect(process.exitCode).toBe(1);
580
597
  });
581
598
 
582
599
  it("should require --reason", async () => {
@@ -800,7 +817,7 @@ describe("choice-set-values", () => {
800
817
  expect(process.exitCode).toBe(1);
801
818
  });
802
819
 
803
- it("should require --confirm for value delete", async () => {
820
+ it("should require confirmation for value delete: exit 1, SDK not called", async () => {
804
821
  const sdk = mockSdk();
805
822
  const program = buildValuesProgram();
806
823
  await program.parseAsync([
@@ -815,15 +832,31 @@ describe("choice-set-values", () => {
815
832
  "cleanup",
816
833
  ]);
817
834
  expect(sdk.entities.choicesets.deleteValuesById).not.toHaveBeenCalled();
818
- expect(OutputFormatter.error).toHaveBeenCalledWith(
819
- expect.objectContaining({
820
- Result: "Failure",
821
- Message: "Confirmation required for destructive operation",
822
- }),
823
- );
835
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
824
836
  expect(process.exitCode).toBe(1);
825
837
  });
826
838
 
839
+ it("should accept --yes for value delete (canonical flag)", async () => {
840
+ const sdk = mockSdk();
841
+ const program = buildValuesProgram();
842
+ await program.parseAsync([
843
+ "node",
844
+ "test",
845
+ "choice-set-values",
846
+ "delete",
847
+ "cs-1",
848
+ "--ids",
849
+ "v-1",
850
+ "--yes",
851
+ "--reason",
852
+ "cleanup",
853
+ ]);
854
+ expect(sdk.entities.choicesets.deleteValuesById).toHaveBeenCalled();
855
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
856
+ expect.objectContaining({ Result: "Success" }),
857
+ );
858
+ });
859
+
827
860
  it("should require --reason for value delete", async () => {
828
861
  const sdk = mockSdk();
829
862
  const program = buildValuesProgram();
@@ -13,7 +13,7 @@ import type {
13
13
  ChoiceSetUpdateOptions,
14
14
  ChoiceSetValueInsertOptions,
15
15
  } from "@uipath/uipath-typescript";
16
- import type { Command } from "commander";
16
+ import { type Command, Option } from "commander";
17
17
  import { fail, requireDestructiveConfirmation } from "../utils/output";
18
18
  import { connectOrFail } from "../utils/sdk-client";
19
19
 
@@ -54,6 +54,7 @@ interface UpdateOptions {
54
54
 
55
55
  interface DeleteOptions {
56
56
  tenant?: string;
57
+ yes?: boolean;
57
58
  confirm?: boolean;
58
59
  reason?: string;
59
60
  }
@@ -70,6 +71,7 @@ interface ValueUpdateOptions {
70
71
  interface ValueDeleteOptions {
71
72
  tenant?: string;
72
73
  ids?: string;
74
+ yes?: boolean;
73
75
  confirm?: boolean;
74
76
  reason?: string;
75
77
  }
@@ -417,7 +419,10 @@ export const registerChoiceSetsCommand = (program: Command) => {
417
419
  .addOption(
418
420
  createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
419
421
  )
420
- .option("--confirm", "Acknowledge this is an irreversible operation")
422
+ .option("-y, --yes", "Acknowledge this is an irreversible operation")
423
+ .addOption(
424
+ new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
425
+ )
421
426
  .option(
422
427
  "--reason <reason>",
423
428
  "Reason for the deletion — echoed back in the response so the caller can log it",
@@ -428,6 +433,7 @@ export const registerChoiceSetsCommand = (program: Command) => {
428
433
  async (choiceSetId: string, options: DeleteOptions) => {
429
434
  const reason = requireDestructiveConfirmation(
430
435
  options,
436
+ `delete choice set '${choiceSetId}'`,
431
437
  'Pass --reason "<text>" to record why the choice set is being deleted.',
432
438
  );
433
439
  if (reason === null) return;
@@ -633,7 +639,10 @@ export const registerChoiceSetValuesCommand = (program: Command) => {
633
639
  createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
634
640
  )
635
641
  .option("--ids <ids>", "Comma-separated list of value IDs to delete")
636
- .option("--confirm", "Acknowledge this is an irreversible operation")
642
+ .option("-y, --yes", "Acknowledge this is an irreversible operation")
643
+ .addOption(
644
+ new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
645
+ )
637
646
  .option(
638
647
  "--reason <reason>",
639
648
  "Reason for the deletion — echoed back in the response so the caller can log it",
@@ -656,6 +665,7 @@ export const registerChoiceSetValuesCommand = (program: Command) => {
656
665
 
657
666
  const reason = requireDestructiveConfirmation(
658
667
  options,
668
+ `delete ${valueIds.length} value(s) from choice set '${choiceSetId}'`,
659
669
  'Pass --reason "<text>" to record why the values are being deleted.',
660
670
  );
661
671
  if (reason === null) return;
@@ -1217,7 +1217,7 @@ describe("entities update", () => {
1217
1217
  expect(process.exitCode).toBe(1);
1218
1218
  });
1219
1219
 
1220
- it("should reject removeFields without --confirm", async () => {
1220
+ it("should reject removeFields without confirmation: exit 1, SDK not called", async () => {
1221
1221
  const sdk = mockSdk();
1222
1222
  vi.mocked(readJsonInput).mockResolvedValue({
1223
1223
  removeFields: [{ fieldName: "oldField" }],
@@ -1237,15 +1237,36 @@ describe("entities update", () => {
1237
1237
  ]);
1238
1238
 
1239
1239
  expect(sdk.entities.updateById).not.toHaveBeenCalled();
1240
- expect(OutputFormatter.error).toHaveBeenCalledWith(
1241
- expect.objectContaining({
1242
- Result: "Failure",
1243
- Message: "Confirmation required for destructive operation",
1244
- }),
1245
- );
1240
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
1246
1241
  expect(process.exitCode).toBe(1);
1247
1242
  });
1248
1243
 
1244
+ it("should accept removeFields with --yes (canonical flag)", async () => {
1245
+ const sdk = mockSdk();
1246
+ vi.mocked(readJsonInput).mockResolvedValue({
1247
+ removeFields: [{ fieldName: "oldField" }],
1248
+ });
1249
+
1250
+ const program = buildProgram();
1251
+ await program.parseAsync([
1252
+ "node",
1253
+ "test",
1254
+ "entities",
1255
+ "update",
1256
+ "entity-id",
1257
+ "--body",
1258
+ '{"removeFields":[{"fieldName":"oldField"}]}',
1259
+ "--yes",
1260
+ "--reason",
1261
+ "drop legacy",
1262
+ ]);
1263
+
1264
+ expect(sdk.entities.updateById).toHaveBeenCalled();
1265
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
1266
+ expect.objectContaining({ Result: "Success" }),
1267
+ );
1268
+ });
1269
+
1249
1270
  it("should reject removeFields without --reason", async () => {
1250
1271
  const sdk = mockSdk();
1251
1272
  vi.mocked(readJsonInput).mockResolvedValue({
@@ -1764,7 +1785,7 @@ describe("entities delete", () => {
1764
1785
  );
1765
1786
  });
1766
1787
 
1767
- it("should error when --confirm is missing", async () => {
1788
+ it("should error when confirmation is missing: exit 1, SDK not called", async () => {
1768
1789
  const sdk = mockSdk();
1769
1790
 
1770
1791
  const program = buildProgram();
@@ -1779,15 +1800,31 @@ describe("entities delete", () => {
1779
1800
  ]);
1780
1801
 
1781
1802
  expect(sdk.entities.deleteById).not.toHaveBeenCalled();
1782
- expect(OutputFormatter.error).toHaveBeenCalledWith(
1783
- expect.objectContaining({
1784
- Result: "Failure",
1785
- Message: "Confirmation required for destructive operation",
1786
- }),
1787
- );
1803
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
1788
1804
  expect(process.exitCode).toBe(1);
1789
1805
  });
1790
1806
 
1807
+ it("should delete with --yes (canonical confirmation flag)", async () => {
1808
+ const sdk = mockSdk();
1809
+
1810
+ const program = buildProgram();
1811
+ await program.parseAsync([
1812
+ "node",
1813
+ "test",
1814
+ "entities",
1815
+ "delete",
1816
+ "entity-id",
1817
+ "--yes",
1818
+ "--reason",
1819
+ "cleanup",
1820
+ ]);
1821
+
1822
+ expect(sdk.entities.deleteById).toHaveBeenCalledWith("entity-id");
1823
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
1824
+ expect.objectContaining({ Result: "Success" }),
1825
+ );
1826
+ });
1827
+
1791
1828
  it("should error when --reason is missing", async () => {
1792
1829
  const sdk = mockSdk();
1793
1830
 
@@ -15,7 +15,7 @@ import type {
15
15
  RawEntityGetResponse,
16
16
  } from "@uipath/uipath-typescript";
17
17
  import { EntityFieldDataType } from "@uipath/uipath-typescript";
18
- import type { Command } from "commander";
18
+ import { type Command, Option } from "commander";
19
19
  import { readJsonInput } from "../utils/input";
20
20
  import { fail, requireDestructiveConfirmation } from "../utils/output";
21
21
  import { connectOrFail } from "../utils/sdk-client";
@@ -39,12 +39,14 @@ interface UpdateEntityOptions {
39
39
  tenant?: string;
40
40
  file?: string;
41
41
  body?: string;
42
+ yes?: boolean;
42
43
  confirm?: boolean;
43
44
  reason?: string;
44
45
  }
45
46
 
46
47
  interface DeleteOptions {
47
48
  tenant?: string;
49
+ yes?: boolean;
48
50
  confirm?: boolean;
49
51
  reason?: string;
50
52
  }
@@ -278,7 +280,10 @@ export const registerEntitiesCommand = (program: Command) => {
278
280
  "-f, --file <path>",
279
281
  "Path to JSON file with entity definition (fields array required; displayName, description, isRbacEnabled optional)",
280
282
  )
281
- .option("--body <json>", "Inline JSON entity definition")
283
+ .option(
284
+ "--body <json>",
285
+ "Inline JSON entity definition (use `-` to read from stdin)",
286
+ )
282
287
  .examples(ENTITIES_CREATE_EXAMPLES)
283
288
  .trackedAction(
284
289
  processContext,
@@ -390,11 +395,17 @@ export const registerEntitiesCommand = (program: Command) => {
390
395
  "-f, --file <path>",
391
396
  "Path to JSON file with update options (addFields, updateFields, removeFields, displayName, description, isRbacEnabled)",
392
397
  )
393
- .option("--body <json>", "Inline JSON update options")
394
398
  .option(
395
- "--confirm",
399
+ "--body <json>",
400
+ "Inline JSON update options (use `-` to read from stdin)",
401
+ )
402
+ .option(
403
+ "-y, --yes",
396
404
  "Required when 'removeFields' is non-empty — acknowledges the field deletion is irreversible",
397
405
  )
406
+ .addOption(
407
+ new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
408
+ )
398
409
  .option(
399
410
  "--reason <reason>",
400
411
  "Required when 'removeFields' is non-empty — echoed back in the response so the caller can log it",
@@ -482,6 +493,7 @@ export const registerEntitiesCommand = (program: Command) => {
482
493
 
483
494
  const reason = requireDestructiveConfirmation(
484
495
  options,
496
+ `remove fields from entity '${id}'`,
485
497
  'Pass --reason "<text>" to record why fields are being removed.',
486
498
  );
487
499
  if (reason === null) return;
@@ -593,7 +605,10 @@ export const registerEntitiesCommand = (program: Command) => {
593
605
  .addOption(
594
606
  createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
595
607
  )
596
- .option("--confirm", "Acknowledge this is an irreversible operation")
608
+ .option("-y, --yes", "Acknowledge this is an irreversible operation")
609
+ .addOption(
610
+ new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
611
+ )
597
612
  .option(
598
613
  "--reason <reason>",
599
614
  "Reason for the deletion — echoed back in the response so the caller can log it",
@@ -604,6 +619,7 @@ export const registerEntitiesCommand = (program: Command) => {
604
619
  async (id: string, options: DeleteOptions) => {
605
620
  const reason = requireDestructiveConfirmation(
606
621
  options,
622
+ `delete entity '${id}'`,
607
623
  'Pass --reason "<text>" to record why the entity is being deleted.',
608
624
  );
609
625
  if (reason === null) return;
@@ -237,7 +237,31 @@ describe("files delete", () => {
237
237
  it("should delete and return FileDeleted on success", async () => {
238
238
  const sdk = mockSdk();
239
239
  const program = buildProgram();
240
- await runCommand(program, "files delete entity-1 record-1 attachment");
240
+ await runCommand(
241
+ program,
242
+ "files delete entity-1 record-1 attachment --yes --reason cleanup",
243
+ );
244
+ expect(sdk.entities.deleteAttachment).toHaveBeenCalledWith(
245
+ "entity-1",
246
+ "record-1",
247
+ "attachment",
248
+ );
249
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
250
+ expect.objectContaining({
251
+ Result: "Success",
252
+ Code: "FileDeleted",
253
+ Data: expect.objectContaining({ Reason: "cleanup" }),
254
+ }),
255
+ );
256
+ });
257
+
258
+ it("should accept --confirm as a deprecated alias for --yes", async () => {
259
+ const sdk = mockSdk();
260
+ const program = buildProgram();
261
+ await runCommand(
262
+ program,
263
+ "files delete entity-1 record-1 attachment --confirm --reason cleanup",
264
+ );
241
265
  expect(sdk.entities.deleteAttachment).toHaveBeenCalledWith(
242
266
  "entity-1",
243
267
  "record-1",
@@ -248,11 +272,26 @@ describe("files delete", () => {
248
272
  );
249
273
  });
250
274
 
275
+ it("should require confirmation: without --yes, exit 1 and SDK not called", async () => {
276
+ const sdk = mockSdk();
277
+ const program = buildProgram();
278
+ await runCommand(
279
+ program,
280
+ "files delete entity-1 record-1 attachment --reason cleanup",
281
+ );
282
+ expect(sdk.entities.deleteAttachment).not.toHaveBeenCalled();
283
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
284
+ expect(process.exitCode).toBe(1);
285
+ });
286
+
251
287
  it("should error when delete API fails", async () => {
252
288
  const sdk = mockSdk();
253
289
  sdk.entities.deleteAttachment.mockRejectedValue(new Error("Forbidden"));
254
290
  const program = buildProgram();
255
- await runCommand(program, "files delete entity-1 record-1 attachment");
291
+ await runCommand(
292
+ program,
293
+ "files delete entity-1 record-1 attachment --yes --reason cleanup",
294
+ );
256
295
  expect(OutputFormatter.error).toHaveBeenCalledWith(
257
296
  expect.objectContaining({
258
297
  Result: "Failure",
@@ -265,7 +304,10 @@ describe("files delete", () => {
265
304
  const sdk = mockSdk();
266
305
  vi.mocked(connectOrFail).mockResolvedValue(undefined);
267
306
  const program = buildProgram();
268
- await runCommand(program, "files delete entity-1 record-1 attachment");
307
+ await runCommand(
308
+ program,
309
+ "files delete entity-1 record-1 attachment --yes --reason cleanup",
310
+ );
269
311
  expect(sdk.entities.deleteAttachment).not.toHaveBeenCalled();
270
312
  expect(OutputFormatter.success).not.toHaveBeenCalled();
271
313
  });
@@ -8,9 +8,9 @@ import {
8
8
  RESULTS,
9
9
  } from "@uipath/common";
10
10
  import { getFileSystem } from "@uipath/filesystem";
11
- import type { Command } from "commander";
11
+ import { type Command, Option } from "commander";
12
12
  import { readFileBinary } from "../utils/input";
13
- import { fail } from "../utils/output";
13
+ import { fail, requireDestructiveConfirmation } from "../utils/output";
14
14
  import { connectOrFail } from "../utils/sdk-client";
15
15
 
16
16
  interface UploadOptions {
@@ -25,6 +25,9 @@ interface DownloadOptions {
25
25
 
26
26
  interface DeleteOptions {
27
27
  tenant?: string;
28
+ yes?: boolean;
29
+ confirm?: boolean;
30
+ reason?: string;
28
31
  }
29
32
 
30
33
  const FILES_UPLOAD_EXAMPLES: CommandExample[] = [
@@ -241,6 +244,14 @@ export const registerFilesCommand = (program: Command) => {
241
244
  .addOption(
242
245
  createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
243
246
  )
247
+ .option("-y, --yes", "Acknowledge this is an irreversible operation")
248
+ .addOption(
249
+ new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
250
+ )
251
+ .option(
252
+ "--reason <reason>",
253
+ "Reason for the deletion — echoed back in the response so the caller can log it",
254
+ )
244
255
  .examples(FILES_DELETE_EXAMPLES)
245
256
  .trackedAction(
246
257
  processContext,
@@ -250,6 +261,13 @@ export const registerFilesCommand = (program: Command) => {
250
261
  fieldName: string,
251
262
  options: DeleteOptions,
252
263
  ) => {
264
+ const reason = requireDestructiveConfirmation(
265
+ options,
266
+ `delete the file in field '${fieldName}'`,
267
+ 'Pass --reason "<text>" to record why the file is being deleted.',
268
+ );
269
+ if (reason === null) return;
270
+
253
271
  const sdk = await connectOrFail(options.tenant);
254
272
  if (!sdk) return;
255
273
 
@@ -275,6 +293,7 @@ export const registerFilesCommand = (program: Command) => {
275
293
  EntityId: entityId,
276
294
  RecordId: recordId,
277
295
  FieldName: fieldName,
296
+ Reason: reason,
278
297
  },
279
298
  });
280
299
  },
@@ -1067,6 +1067,9 @@ describe("records delete", () => {
1067
1067
  "entity-id",
1068
1068
  "rec-1",
1069
1069
  "rec-2",
1070
+ "--yes",
1071
+ "--reason",
1072
+ "test cleanup",
1070
1073
  ]);
1071
1074
 
1072
1075
  expect(sdk.entities.deleteRecordsById).toHaveBeenCalledWith(
@@ -1093,6 +1096,9 @@ describe("records delete", () => {
1093
1096
  "delete",
1094
1097
  "entity-id",
1095
1098
  "rec-1",
1099
+ "--yes",
1100
+ "--reason",
1101
+ "test cleanup",
1096
1102
  ]);
1097
1103
  expect(sdk.entities.deleteRecordsById).toHaveBeenCalled();
1098
1104
  expect(OutputFormatter.success).toHaveBeenCalledWith(
@@ -1119,6 +1125,9 @@ describe("records delete", () => {
1119
1125
  "delete",
1120
1126
  "entity-id",
1121
1127
  "rec-1",
1128
+ "--yes",
1129
+ "--reason",
1130
+ "test cleanup",
1122
1131
  ]);
1123
1132
 
1124
1133
  expect(OutputFormatter.error).toHaveBeenCalledWith(
@@ -1142,6 +1151,9 @@ describe("records delete", () => {
1142
1151
  "entity-id",
1143
1152
  "rec-1",
1144
1153
  "rec-2",
1154
+ "--yes",
1155
+ "--reason",
1156
+ "test cleanup",
1145
1157
  ]);
1146
1158
  expect(OutputFormatter.success).toHaveBeenCalledWith(
1147
1159
  expect.objectContaining({
@@ -1155,6 +1167,78 @@ describe("records delete", () => {
1155
1167
  );
1156
1168
  expect(process.exitCode).toBe(1);
1157
1169
  });
1170
+
1171
+ it("should accept --confirm as a deprecated alias for --yes", async () => {
1172
+ const sdk = mockSdk();
1173
+
1174
+ const program = buildProgram();
1175
+ await program.parseAsync([
1176
+ "node",
1177
+ "test",
1178
+ "records",
1179
+ "delete",
1180
+ "entity-id",
1181
+ "rec-1",
1182
+ "--confirm",
1183
+ "--reason",
1184
+ "test cleanup",
1185
+ ]);
1186
+
1187
+ expect(sdk.entities.deleteRecordsById).toHaveBeenCalledWith(
1188
+ "entity-id",
1189
+ ["rec-1"],
1190
+ );
1191
+ expect(OutputFormatter.success).toHaveBeenCalledWith(
1192
+ expect.objectContaining({
1193
+ Result: "Success",
1194
+ Code: "RecordsDeleted",
1195
+ }),
1196
+ );
1197
+ });
1198
+
1199
+ it("should require confirmation: without --yes, exit 1 and SDK not called", async () => {
1200
+ const sdk = mockSdk();
1201
+
1202
+ const program = buildProgram();
1203
+ await program.parseAsync([
1204
+ "node",
1205
+ "test",
1206
+ "records",
1207
+ "delete",
1208
+ "entity-id",
1209
+ "rec-1",
1210
+ "--reason",
1211
+ "test cleanup",
1212
+ ]);
1213
+
1214
+ expect(sdk.entities.deleteRecordsById).not.toHaveBeenCalled();
1215
+ expect(OutputFormatter.success).not.toHaveBeenCalled();
1216
+ expect(process.exitCode).toBe(1);
1217
+ });
1218
+
1219
+ it("should require --reason when confirmation is present", async () => {
1220
+ const sdk = mockSdk();
1221
+
1222
+ const program = buildProgram();
1223
+ await program.parseAsync([
1224
+ "node",
1225
+ "test",
1226
+ "records",
1227
+ "delete",
1228
+ "entity-id",
1229
+ "rec-1",
1230
+ "--yes",
1231
+ ]);
1232
+
1233
+ expect(sdk.entities.deleteRecordsById).not.toHaveBeenCalled();
1234
+ expect(OutputFormatter.error).toHaveBeenCalledWith(
1235
+ expect.objectContaining({
1236
+ Result: "Failure",
1237
+ Message: "Reason required for destructive operation",
1238
+ }),
1239
+ );
1240
+ expect(process.exitCode).toBe(1);
1241
+ });
1158
1242
  });
1159
1243
 
1160
1244
  describe("records delete client error", () => {
@@ -2242,6 +2326,9 @@ describe("records — negative scenarios", () => {
2242
2326
  "delete",
2243
2327
  "entity-id",
2244
2328
  "nonexistent-record-id",
2329
+ "--yes",
2330
+ "--reason",
2331
+ "test cleanup",
2245
2332
  ]);
2246
2333
 
2247
2334
  expect(OutputFormatter.error).toHaveBeenCalledWith(