orizu 0.0.8 → 0.0.9

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 (3) hide show
  1. package/dist/index.js +103 -17
  2. package/package.json +1 -1
  3. package/src/index.ts +147 -17
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { parseDatasetReference } from './dataset-download.js';
12
12
  import { parseGlobalFlags } from './global-flags.js';
13
13
  import { authedFetch, getBaseUrl, resolveLoginBaseUrl, setGlobalFlags } from './http.js';
14
14
  function printUsage() {
15
- console.log(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n\norizu commands:\n\n orizu login\n orizu logout\n orizu whoami\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userId1,userId2> [--instructions <text>] [--labels-per-item <n>]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--row-ids <id1,id2>] [--row-indices <n1,n2>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`);
15
+ console.log(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n\norizu commands:\n\n orizu login\n orizu logout\n orizu whoami\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userId1,userId2> [--instructions <text>] [--labels-per-item <n>]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>\n orizu datasets lock [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--reason <text>]\n orizu datasets clone [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--name <name>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`);
16
16
  }
17
17
  let cliArgs = process.argv.slice(2);
18
18
  function getArg(name) {
@@ -861,28 +861,57 @@ async function appendDatasetRows() {
861
861
  const data = await parseJsonResponse(response, 'Dataset append');
862
862
  console.log(`Appended ${data.appendedCount} rows to dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`);
863
863
  }
864
- function parseCommaSeparatedIntegers(value) {
865
- if (!value) {
866
- return [];
864
+ async function editDatasetRows() {
865
+ const projectArg = getArg('--project');
866
+ const datasetInput = getDatasetReferenceInput();
867
+ const fileArg = getArg('--file');
868
+ if (!fileArg) {
869
+ throw new Error('Usage: orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>');
867
870
  }
868
- const rawItems = value
869
- .split(',')
870
- .map(item => item.trim())
871
- .filter(Boolean);
872
- const parsed = rawItems.map(item => Number(item));
873
- const invalid = parsed.some(item => !Number.isInteger(item) || item < 0);
874
- if (invalid) {
875
- throw new Error('row-indices must be comma-separated non-negative integers');
871
+ let datasetId;
872
+ if (datasetInput) {
873
+ datasetId = parseDatasetReference(datasetInput).datasetId;
874
+ }
875
+ else {
876
+ const selected = await selectDatasetInteractively(projectArg);
877
+ datasetId = selected.datasetId;
878
+ }
879
+ const file = expandHomePath(fileArg);
880
+ const { rows } = parseDatasetFile(file);
881
+ if (!Array.isArray(rows) || rows.length === 0) {
882
+ throw new Error('Dataset edit file must contain at least one row');
876
883
  }
877
- return parsed;
884
+ const normalizedRows = rows.map((row, index) => {
885
+ if (typeof row !== 'object' || row === null || Array.isArray(row)) {
886
+ throw new Error(`Dataset edit file rows[${index}] must be an object`);
887
+ }
888
+ const rowRecord = row;
889
+ const rowId = typeof rowRecord.id === 'string' ? rowRecord.id.trim() : '';
890
+ if (!rowId) {
891
+ throw new Error(`Dataset edit file rows[${index}] must include a non-empty string id`);
892
+ }
893
+ return {
894
+ ...rowRecord,
895
+ id: rowId,
896
+ };
897
+ });
898
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
899
+ method: 'PATCH',
900
+ headers: { 'Content-Type': 'application/json' },
901
+ body: JSON.stringify({ rows: normalizedRows }),
902
+ });
903
+ if (!response.ok) {
904
+ throw new Error(`Edit rows failed: ${await response.text()}`);
905
+ }
906
+ const data = await parseJsonResponse(response, 'Dataset edit rows');
907
+ console.log(`Updated ${data.updatedCount} rows in dataset ${data.dataset.name} (${data.dataset.id}). Current row count: ${data.dataset.rowCount}`);
878
908
  }
879
909
  async function deleteDatasetRows() {
880
910
  const projectArg = getArg('--project');
881
911
  const datasetInput = getDatasetReferenceInput();
882
912
  const rowIds = parseCommaSeparated(getArg('--row-ids'));
883
- const rowIndices = parseCommaSeparatedIntegers(getArg('--row-indices'));
884
- if (rowIds.length === 0 && rowIndices.length === 0) {
885
- throw new Error('Usage: orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--row-ids <id1,id2>] [--row-indices <n1,n2>]');
913
+ if (rowIds.length === 0) {
914
+ throw new Error('Usage: orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>');
886
915
  }
887
916
  let datasetId;
888
917
  if (datasetInput) {
@@ -897,7 +926,6 @@ async function deleteDatasetRows() {
897
926
  headers: { 'Content-Type': 'application/json' },
898
927
  body: JSON.stringify({
899
928
  rowIds,
900
- rowIndices,
901
929
  }),
902
930
  });
903
931
  if (!response.ok) {
@@ -906,6 +934,52 @@ async function deleteDatasetRows() {
906
934
  const data = await parseJsonResponse(response, 'Dataset delete rows');
907
935
  console.log(`Deleted ${data.deletedCount} rows from dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`);
908
936
  }
937
+ async function lockDataset() {
938
+ const projectArg = getArg('--project');
939
+ const datasetInput = getDatasetReferenceInput();
940
+ const reason = getArg('--reason');
941
+ let datasetId;
942
+ if (datasetInput) {
943
+ datasetId = parseDatasetReference(datasetInput).datasetId;
944
+ }
945
+ else {
946
+ const selected = await selectDatasetInteractively(projectArg);
947
+ datasetId = selected.datasetId;
948
+ }
949
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/lock`, {
950
+ method: 'POST',
951
+ headers: { 'Content-Type': 'application/json' },
952
+ body: JSON.stringify(reason ? { reason } : {}),
953
+ });
954
+ if (!response.ok) {
955
+ throw new Error(`Lock failed: ${await response.text()}`);
956
+ }
957
+ const data = await parseJsonResponse(response, 'Dataset lock');
958
+ console.log(`Locked dataset ${data.dataset.name} (${data.dataset.id}) at ${data.dataset.lockedAt}. Row count: ${data.dataset.rowCount}`);
959
+ }
960
+ async function cloneDataset() {
961
+ const projectArg = getArg('--project');
962
+ const datasetInput = getDatasetReferenceInput();
963
+ const name = getArg('--name');
964
+ let datasetId;
965
+ if (datasetInput) {
966
+ datasetId = parseDatasetReference(datasetInput).datasetId;
967
+ }
968
+ else {
969
+ const selected = await selectDatasetInteractively(projectArg);
970
+ datasetId = selected.datasetId;
971
+ }
972
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/clone`, {
973
+ method: 'POST',
974
+ headers: { 'Content-Type': 'application/json' },
975
+ body: JSON.stringify(name ? { name } : {}),
976
+ });
977
+ if (!response.ok) {
978
+ throw new Error(`Clone failed: ${await response.text()}`);
979
+ }
980
+ const data = await parseJsonResponse(response, 'Dataset clone');
981
+ console.log(`Cloned dataset ${data.dataset.parentDatasetId} -> ${data.dataset.name} (${data.dataset.id}). Row count: ${data.dataset.rowCount}`);
982
+ }
909
983
  async function downloadAnnotations() {
910
984
  let taskId = getArg('--task');
911
985
  const format = (getArg('--format') || 'jsonl');
@@ -1027,10 +1101,22 @@ async function main() {
1027
1101
  await appendDatasetRows();
1028
1102
  return;
1029
1103
  }
1104
+ if (command === 'datasets' && subcommand === 'edit-rows') {
1105
+ await editDatasetRows();
1106
+ return;
1107
+ }
1030
1108
  if (command === 'datasets' && subcommand === 'delete-rows') {
1031
1109
  await deleteDatasetRows();
1032
1110
  return;
1033
1111
  }
1112
+ if (command === 'datasets' && subcommand === 'lock') {
1113
+ await lockDataset();
1114
+ return;
1115
+ }
1116
+ if (command === 'datasets' && subcommand === 'clone') {
1117
+ await cloneDataset();
1118
+ return;
1119
+ }
1034
1120
  if (command === 'tasks' && subcommand === 'export') {
1035
1121
  await downloadAnnotations();
1036
1122
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -106,7 +106,7 @@ interface TaskStatusPayload {
106
106
  }
107
107
 
108
108
  function printUsage() {
109
- console.log(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n\norizu commands:\n\n orizu login\n orizu logout\n orizu whoami\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userId1,userId2> [--instructions <text>] [--labels-per-item <n>]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--row-ids <id1,id2>] [--row-indices <n1,n2>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`)
109
+ console.log(`orizu global options:\n\n --local Use http://localhost:3000\n --server <url> Use a specific server origin (for example: https://preview.example.com)\n\norizu commands:\n\n orizu login\n orizu logout\n orizu whoami\n orizu teams list\n orizu teams create [--name <name>]\n orizu teams members list [--team <teamSlug>]\n orizu teams members add --email <email> [--team <teamSlug>]\n orizu teams members remove --email <email> [--team <teamSlug>]\n orizu teams members role --team <teamSlug> --email <email> --role <admin|member>\n orizu projects list [--team <teamSlug>]\n orizu projects create --name <name> [--team <teamSlug>]\n orizu apps list [--project <team/project>]\n orizu apps create --project <team/project> --name <name> --dataset <datasetId> --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps update [--app <appId>] [--project <team/project>] --file <path> --input-schema <json-path> --output-schema <json-path> [--component <name>]\n orizu apps link-dataset --dataset <datasetId> [--app <appId>] [--project <team/project>] [--version <n>]\n orizu tasks list [--project <team/project>]\n orizu tasks create --project <team/project> --dataset <datasetId> --app <appId> --title <title> --assignees <userId1,userId2> [--instructions <text>] [--labels-per-item <n>]\n orizu tasks assign --task <taskId> --assignees <userId1,userId2>\n orizu tasks status --task <taskId> [--json]\n orizu datasets upload --file <path> [--project <team/project>] [--name <name>]\n orizu datasets download [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--format <csv|json|jsonl>] [--out <path>]\n orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>\n orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>\n orizu datasets lock [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--reason <text>]\n orizu datasets clone [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--name <name>]\n orizu tasks export [--task <taskId>] [--format <csv|json|jsonl>] [--out <path>]`)
110
110
  }
111
111
 
112
112
  let cliArgs = process.argv.slice(2)
@@ -1265,32 +1265,73 @@ async function appendDatasetRows() {
1265
1265
  )
1266
1266
  }
1267
1267
 
1268
- function parseCommaSeparatedIntegers(value: string | null): number[] {
1269
- if (!value) {
1270
- return []
1268
+ async function editDatasetRows() {
1269
+ const projectArg = getArg('--project')
1270
+ const datasetInput = getDatasetReferenceInput()
1271
+ const fileArg = getArg('--file')
1272
+
1273
+ if (!fileArg) {
1274
+ throw new Error('Usage: orizu datasets edit-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>')
1271
1275
  }
1272
1276
 
1273
- const rawItems = value
1274
- .split(',')
1275
- .map(item => item.trim())
1276
- .filter(Boolean)
1277
- const parsed = rawItems.map(item => Number(item))
1278
- const invalid = parsed.some(item => !Number.isInteger(item) || item < 0)
1279
- if (invalid) {
1280
- throw new Error('row-indices must be comma-separated non-negative integers')
1277
+ let datasetId: string
1278
+ if (datasetInput) {
1279
+ datasetId = parseDatasetReference(datasetInput).datasetId
1280
+ } else {
1281
+ const selected = await selectDatasetInteractively(projectArg)
1282
+ datasetId = selected.datasetId
1283
+ }
1284
+
1285
+ const file = expandHomePath(fileArg)
1286
+ const { rows } = parseDatasetFile(file)
1287
+ if (!Array.isArray(rows) || rows.length === 0) {
1288
+ throw new Error('Dataset edit file must contain at least one row')
1289
+ }
1290
+
1291
+ const normalizedRows = rows.map((row, index) => {
1292
+ if (typeof row !== 'object' || row === null || Array.isArray(row)) {
1293
+ throw new Error(`Dataset edit file rows[${index}] must be an object`)
1294
+ }
1295
+
1296
+ const rowRecord = row as Record<string, unknown>
1297
+ const rowId = typeof rowRecord.id === 'string' ? rowRecord.id.trim() : ''
1298
+ if (!rowId) {
1299
+ throw new Error(`Dataset edit file rows[${index}] must include a non-empty string id`)
1300
+ }
1301
+
1302
+ return {
1303
+ ...rowRecord,
1304
+ id: rowId,
1305
+ }
1306
+ })
1307
+
1308
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
1309
+ method: 'PATCH',
1310
+ headers: { 'Content-Type': 'application/json' },
1311
+ body: JSON.stringify({ rows: normalizedRows }),
1312
+ })
1313
+
1314
+ if (!response.ok) {
1315
+ throw new Error(`Edit rows failed: ${await response.text()}`)
1281
1316
  }
1282
1317
 
1283
- return parsed
1318
+ const data = await parseJsonResponse<{
1319
+ dataset: { id: string; name: string; rowCount: number }
1320
+ updatedCount: number
1321
+ }>(response, 'Dataset edit rows')
1322
+
1323
+ console.log(
1324
+ `Updated ${data.updatedCount} rows in dataset ${data.dataset.name} (${data.dataset.id}). Current row count: ${data.dataset.rowCount}`
1325
+ )
1284
1326
  }
1285
1327
 
1286
1328
  async function deleteDatasetRows() {
1287
1329
  const projectArg = getArg('--project')
1288
1330
  const datasetInput = getDatasetReferenceInput()
1289
1331
  const rowIds = parseCommaSeparated(getArg('--row-ids'))
1290
- const rowIndices = parseCommaSeparatedIntegers(getArg('--row-indices'))
1291
1332
 
1292
- if (rowIds.length === 0 && rowIndices.length === 0) {
1293
- throw new Error('Usage: orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] [--row-ids <id1,id2>] [--row-indices <n1,n2>]')
1333
+ if (rowIds.length === 0) {
1334
+ throw new Error('Usage: orizu datasets delete-rows [--dataset <datasetId|datasetUrl>] [--project <team/project>] --row-ids <id1,id2>')
1294
1335
  }
1295
1336
 
1296
1337
  let datasetId: string
@@ -1306,7 +1347,6 @@ async function deleteDatasetRows() {
1306
1347
  headers: { 'Content-Type': 'application/json' },
1307
1348
  body: JSON.stringify({
1308
1349
  rowIds,
1309
- rowIndices,
1310
1350
  }),
1311
1351
  })
1312
1352
 
@@ -1324,6 +1364,81 @@ async function deleteDatasetRows() {
1324
1364
  )
1325
1365
  }
1326
1366
 
1367
+ async function lockDataset() {
1368
+ const projectArg = getArg('--project')
1369
+ const datasetInput = getDatasetReferenceInput()
1370
+ const reason = getArg('--reason')
1371
+
1372
+ let datasetId: string
1373
+ if (datasetInput) {
1374
+ datasetId = parseDatasetReference(datasetInput).datasetId
1375
+ } else {
1376
+ const selected = await selectDatasetInteractively(projectArg)
1377
+ datasetId = selected.datasetId
1378
+ }
1379
+
1380
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/lock`, {
1381
+ method: 'POST',
1382
+ headers: { 'Content-Type': 'application/json' },
1383
+ body: JSON.stringify(reason ? { reason } : {}),
1384
+ })
1385
+
1386
+ if (!response.ok) {
1387
+ throw new Error(`Lock failed: ${await response.text()}`)
1388
+ }
1389
+
1390
+ const data = await parseJsonResponse<{
1391
+ dataset: {
1392
+ id: string
1393
+ name: string
1394
+ rowCount: number
1395
+ lockedAt: string
1396
+ lockedBy: string | null
1397
+ }
1398
+ }>(response, 'Dataset lock')
1399
+
1400
+ console.log(
1401
+ `Locked dataset ${data.dataset.name} (${data.dataset.id}) at ${data.dataset.lockedAt}. Row count: ${data.dataset.rowCount}`
1402
+ )
1403
+ }
1404
+
1405
+ async function cloneDataset() {
1406
+ const projectArg = getArg('--project')
1407
+ const datasetInput = getDatasetReferenceInput()
1408
+ const name = getArg('--name')
1409
+
1410
+ let datasetId: string
1411
+ if (datasetInput) {
1412
+ datasetId = parseDatasetReference(datasetInput).datasetId
1413
+ } else {
1414
+ const selected = await selectDatasetInteractively(projectArg)
1415
+ datasetId = selected.datasetId
1416
+ }
1417
+
1418
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/clone`, {
1419
+ method: 'POST',
1420
+ headers: { 'Content-Type': 'application/json' },
1421
+ body: JSON.stringify(name ? { name } : {}),
1422
+ })
1423
+
1424
+ if (!response.ok) {
1425
+ throw new Error(`Clone failed: ${await response.text()}`)
1426
+ }
1427
+
1428
+ const data = await parseJsonResponse<{
1429
+ dataset: {
1430
+ id: string
1431
+ name: string
1432
+ rowCount: number
1433
+ parentDatasetId: string
1434
+ }
1435
+ }>(response, 'Dataset clone')
1436
+
1437
+ console.log(
1438
+ `Cloned dataset ${data.dataset.parentDatasetId} -> ${data.dataset.name} (${data.dataset.id}). Row count: ${data.dataset.rowCount}`
1439
+ )
1440
+ }
1441
+
1327
1442
  async function downloadAnnotations() {
1328
1443
  let taskId = getArg('--task')
1329
1444
  const format = (getArg('--format') || 'jsonl') as 'csv' | 'json' | 'jsonl'
@@ -1474,11 +1589,26 @@ async function main() {
1474
1589
  return
1475
1590
  }
1476
1591
 
1592
+ if (command === 'datasets' && subcommand === 'edit-rows') {
1593
+ await editDatasetRows()
1594
+ return
1595
+ }
1596
+
1477
1597
  if (command === 'datasets' && subcommand === 'delete-rows') {
1478
1598
  await deleteDatasetRows()
1479
1599
  return
1480
1600
  }
1481
1601
 
1602
+ if (command === 'datasets' && subcommand === 'lock') {
1603
+ await lockDataset()
1604
+ return
1605
+ }
1606
+
1607
+ if (command === 'datasets' && subcommand === 'clone') {
1608
+ await cloneDataset()
1609
+ return
1610
+ }
1611
+
1482
1612
  if (command === 'tasks' && subcommand === 'export') {
1483
1613
  await downloadAnnotations()
1484
1614
  return