orizu 0.0.6 → 0.0.8

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/http.js CHANGED
@@ -19,6 +19,17 @@ export function resolveBaseUrl(flags = runtimeFlags) {
19
19
  }
20
20
  return 'https://orizu.ai';
21
21
  }
22
+ export function resolveLoginBaseUrl(flags = runtimeFlags) {
23
+ const fromFlags = getFlagBaseUrl(flags);
24
+ if (fromFlags) {
25
+ return fromFlags;
26
+ }
27
+ const fromEnv = process.env.ORIZU_BASE_URL;
28
+ if (fromEnv) {
29
+ return normalizeBaseUrl(fromEnv);
30
+ }
31
+ return 'https://orizu.ai';
32
+ }
22
33
  export function getBaseUrl() {
23
34
  return resolveBaseUrl();
24
35
  }
package/dist/index.js CHANGED
@@ -10,9 +10,9 @@ import { clearServerCredentials, getServerCredentials, saveServerCredentials } f
10
10
  import { parseDatasetFile } from './file-parser.js';
11
11
  import { parseDatasetReference } from './dataset-download.js';
12
12
  import { parseGlobalFlags } from './global-flags.js';
13
- import { authedFetch, getBaseUrl, setGlobalFlags } from './http.js';
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 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 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>]`);
16
16
  }
17
17
  let cliArgs = process.argv.slice(2);
18
18
  function getArg(name) {
@@ -341,7 +341,7 @@ function printTaskStatusSummary(data) {
341
341
  }
342
342
  }
343
343
  async function login() {
344
- const baseUrl = getBaseUrl();
344
+ const baseUrl = resolveLoginBaseUrl();
345
345
  const codeVerifier = createCodeVerifier();
346
346
  const codeChallenge = createCodeChallenge(codeVerifier);
347
347
  const callbackCode = await new Promise((resolve, reject) => {
@@ -792,7 +792,7 @@ async function uploadDataset() {
792
792
  console.log(`View dataset: ${formatTerminalLink(data.dataset.url)}`);
793
793
  }
794
794
  }
795
- function getDatasetDownloadInput() {
795
+ function getDatasetReferenceInput() {
796
796
  const fromFlag = getArg('--dataset');
797
797
  if (fromFlag) {
798
798
  return fromFlag;
@@ -805,7 +805,7 @@ function getDatasetDownloadInput() {
805
805
  }
806
806
  async function downloadDataset() {
807
807
  const projectArg = getArg('--project');
808
- const datasetInput = getDatasetDownloadInput();
808
+ const datasetInput = getDatasetReferenceInput();
809
809
  const format = (getArg('--format') || 'jsonl');
810
810
  const outPathArg = getArg('--out');
811
811
  if (!['csv', 'json', 'jsonl'].includes(format)) {
@@ -830,6 +830,82 @@ async function downloadDataset() {
830
830
  writeFileSync(filename, bytes);
831
831
  console.log(`Saved dataset ${datasetId} (${format.toUpperCase()}) to ${filename}`);
832
832
  }
833
+ async function appendDatasetRows() {
834
+ const projectArg = getArg('--project');
835
+ const datasetInput = getDatasetReferenceInput();
836
+ const fileArg = getArg('--file');
837
+ if (!fileArg) {
838
+ throw new Error('Usage: orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>');
839
+ }
840
+ let datasetId;
841
+ if (datasetInput) {
842
+ datasetId = parseDatasetReference(datasetInput).datasetId;
843
+ }
844
+ else {
845
+ const selected = await selectDatasetInteractively(projectArg);
846
+ datasetId = selected.datasetId;
847
+ }
848
+ const file = expandHomePath(fileArg);
849
+ const { rows } = parseDatasetFile(file);
850
+ if (!Array.isArray(rows) || rows.length === 0) {
851
+ throw new Error('Dataset append file must contain at least one row');
852
+ }
853
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
854
+ method: 'POST',
855
+ headers: { 'Content-Type': 'application/json' },
856
+ body: JSON.stringify({ rows }),
857
+ });
858
+ if (!response.ok) {
859
+ throw new Error(`Append failed: ${await response.text()}`);
860
+ }
861
+ const data = await parseJsonResponse(response, 'Dataset append');
862
+ console.log(`Appended ${data.appendedCount} rows to dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`);
863
+ }
864
+ function parseCommaSeparatedIntegers(value) {
865
+ if (!value) {
866
+ return [];
867
+ }
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');
876
+ }
877
+ return parsed;
878
+ }
879
+ async function deleteDatasetRows() {
880
+ const projectArg = getArg('--project');
881
+ const datasetInput = getDatasetReferenceInput();
882
+ 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>]');
886
+ }
887
+ let datasetId;
888
+ if (datasetInput) {
889
+ datasetId = parseDatasetReference(datasetInput).datasetId;
890
+ }
891
+ else {
892
+ const selected = await selectDatasetInteractively(projectArg);
893
+ datasetId = selected.datasetId;
894
+ }
895
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
896
+ method: 'DELETE',
897
+ headers: { 'Content-Type': 'application/json' },
898
+ body: JSON.stringify({
899
+ rowIds,
900
+ rowIndices,
901
+ }),
902
+ });
903
+ if (!response.ok) {
904
+ throw new Error(`Delete rows failed: ${await response.text()}`);
905
+ }
906
+ const data = await parseJsonResponse(response, 'Dataset delete rows');
907
+ console.log(`Deleted ${data.deletedCount} rows from dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`);
908
+ }
833
909
  async function downloadAnnotations() {
834
910
  let taskId = getArg('--task');
835
911
  const format = (getArg('--format') || 'jsonl');
@@ -947,6 +1023,14 @@ async function main() {
947
1023
  await downloadDataset();
948
1024
  return;
949
1025
  }
1026
+ if (command === 'datasets' && subcommand === 'append') {
1027
+ await appendDatasetRows();
1028
+ return;
1029
+ }
1030
+ if (command === 'datasets' && subcommand === 'delete-rows') {
1031
+ await deleteDatasetRows();
1032
+ return;
1033
+ }
950
1034
  if (command === 'tasks' && subcommand === 'export') {
951
1035
  await downloadAnnotations();
952
1036
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/http.ts CHANGED
@@ -27,6 +27,20 @@ export function resolveBaseUrl(flags: GlobalFlags = runtimeFlags): string {
27
27
  return 'https://orizu.ai'
28
28
  }
29
29
 
30
+ export function resolveLoginBaseUrl(flags: GlobalFlags = runtimeFlags): string {
31
+ const fromFlags = getFlagBaseUrl(flags)
32
+ if (fromFlags) {
33
+ return fromFlags
34
+ }
35
+
36
+ const fromEnv = process.env.ORIZU_BASE_URL
37
+ if (fromEnv) {
38
+ return normalizeBaseUrl(fromEnv)
39
+ }
40
+
41
+ return 'https://orizu.ai'
42
+ }
43
+
30
44
  export function getBaseUrl(): string {
31
45
  return resolveBaseUrl()
32
46
  }
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ import { clearServerCredentials, getServerCredentials, saveServerCredentials } f
10
10
  import { parseDatasetFile } from './file-parser.js'
11
11
  import { parseDatasetReference } from './dataset-download.js'
12
12
  import { parseGlobalFlags } from './global-flags.js'
13
- import { authedFetch, getBaseUrl, setGlobalFlags } from './http.js'
13
+ import { authedFetch, getBaseUrl, resolveLoginBaseUrl, setGlobalFlags } from './http.js'
14
14
  import { LoginResponse } from './types.js'
15
15
 
16
16
  interface Team {
@@ -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 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 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>]`)
110
110
  }
111
111
 
112
112
  let cliArgs = process.argv.slice(2)
@@ -594,7 +594,7 @@ function printTaskStatusSummary(data: TaskStatusPayload) {
594
594
  }
595
595
 
596
596
  async function login() {
597
- const baseUrl = getBaseUrl()
597
+ const baseUrl = resolveLoginBaseUrl()
598
598
  const codeVerifier = createCodeVerifier()
599
599
  const codeChallenge = createCodeChallenge(codeVerifier)
600
600
 
@@ -1173,7 +1173,7 @@ async function uploadDataset() {
1173
1173
  }
1174
1174
  }
1175
1175
 
1176
- function getDatasetDownloadInput(): string | null {
1176
+ function getDatasetReferenceInput(): string | null {
1177
1177
  const fromFlag = getArg('--dataset')
1178
1178
  if (fromFlag) {
1179
1179
  return fromFlag
@@ -1189,7 +1189,7 @@ function getDatasetDownloadInput(): string | null {
1189
1189
 
1190
1190
  async function downloadDataset() {
1191
1191
  const projectArg = getArg('--project')
1192
- const datasetInput = getDatasetDownloadInput()
1192
+ const datasetInput = getDatasetReferenceInput()
1193
1193
  const format = (getArg('--format') || 'jsonl') as 'csv' | 'json' | 'jsonl'
1194
1194
  const outPathArg = getArg('--out')
1195
1195
 
@@ -1222,6 +1222,108 @@ async function downloadDataset() {
1222
1222
  console.log(`Saved dataset ${datasetId} (${format.toUpperCase()}) to ${filename}`)
1223
1223
  }
1224
1224
 
1225
+ async function appendDatasetRows() {
1226
+ const projectArg = getArg('--project')
1227
+ const datasetInput = getDatasetReferenceInput()
1228
+ const fileArg = getArg('--file')
1229
+
1230
+ if (!fileArg) {
1231
+ throw new Error('Usage: orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>')
1232
+ }
1233
+
1234
+ let datasetId: string
1235
+ if (datasetInput) {
1236
+ datasetId = parseDatasetReference(datasetInput).datasetId
1237
+ } else {
1238
+ const selected = await selectDatasetInteractively(projectArg)
1239
+ datasetId = selected.datasetId
1240
+ }
1241
+
1242
+ const file = expandHomePath(fileArg)
1243
+ const { rows } = parseDatasetFile(file)
1244
+ if (!Array.isArray(rows) || rows.length === 0) {
1245
+ throw new Error('Dataset append file must contain at least one row')
1246
+ }
1247
+
1248
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
1249
+ method: 'POST',
1250
+ headers: { 'Content-Type': 'application/json' },
1251
+ body: JSON.stringify({ rows }),
1252
+ })
1253
+
1254
+ if (!response.ok) {
1255
+ throw new Error(`Append failed: ${await response.text()}`)
1256
+ }
1257
+
1258
+ const data = await parseJsonResponse<{
1259
+ dataset: { id: string; name: string; rowCount: number }
1260
+ appendedCount: number
1261
+ }>(response, 'Dataset append')
1262
+
1263
+ console.log(
1264
+ `Appended ${data.appendedCount} rows to dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`
1265
+ )
1266
+ }
1267
+
1268
+ function parseCommaSeparatedIntegers(value: string | null): number[] {
1269
+ if (!value) {
1270
+ return []
1271
+ }
1272
+
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')
1281
+ }
1282
+
1283
+ return parsed
1284
+ }
1285
+
1286
+ async function deleteDatasetRows() {
1287
+ const projectArg = getArg('--project')
1288
+ const datasetInput = getDatasetReferenceInput()
1289
+ const rowIds = parseCommaSeparated(getArg('--row-ids'))
1290
+ const rowIndices = parseCommaSeparatedIntegers(getArg('--row-indices'))
1291
+
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>]')
1294
+ }
1295
+
1296
+ let datasetId: string
1297
+ if (datasetInput) {
1298
+ datasetId = parseDatasetReference(datasetInput).datasetId
1299
+ } else {
1300
+ const selected = await selectDatasetInteractively(projectArg)
1301
+ datasetId = selected.datasetId
1302
+ }
1303
+
1304
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
1305
+ method: 'DELETE',
1306
+ headers: { 'Content-Type': 'application/json' },
1307
+ body: JSON.stringify({
1308
+ rowIds,
1309
+ rowIndices,
1310
+ }),
1311
+ })
1312
+
1313
+ if (!response.ok) {
1314
+ throw new Error(`Delete rows failed: ${await response.text()}`)
1315
+ }
1316
+
1317
+ const data = await parseJsonResponse<{
1318
+ dataset: { id: string; name: string; rowCount: number }
1319
+ deletedCount: number
1320
+ }>(response, 'Dataset delete rows')
1321
+
1322
+ console.log(
1323
+ `Deleted ${data.deletedCount} rows from dataset ${data.dataset.name} (${data.dataset.id}). New row count: ${data.dataset.rowCount}`
1324
+ )
1325
+ }
1326
+
1225
1327
  async function downloadAnnotations() {
1226
1328
  let taskId = getArg('--task')
1227
1329
  const format = (getArg('--format') || 'jsonl') as 'csv' | 'json' | 'jsonl'
@@ -1367,6 +1469,16 @@ async function main() {
1367
1469
  return
1368
1470
  }
1369
1471
 
1472
+ if (command === 'datasets' && subcommand === 'append') {
1473
+ await appendDatasetRows()
1474
+ return
1475
+ }
1476
+
1477
+ if (command === 'datasets' && subcommand === 'delete-rows') {
1478
+ await deleteDatasetRows()
1479
+ return
1480
+ }
1481
+
1370
1482
  if (command === 'tasks' && subcommand === 'export') {
1371
1483
  await downloadAnnotations()
1372
1484
  return