orizu 0.5.38 → 0.5.40

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 (162) hide show
  1. package/README.md +95 -3
  2. package/dist/app-commands.d.ts.map +1 -1
  3. package/dist/app-commands.js +215 -57
  4. package/dist/app-publish-failure.d.ts +6 -0
  5. package/dist/app-publish-failure.d.ts.map +1 -0
  6. package/dist/app-publish-failure.js +9 -0
  7. package/dist/app-publish-paths.d.ts +4 -0
  8. package/dist/app-publish-paths.d.ts.map +1 -0
  9. package/dist/app-publish-paths.js +32 -0
  10. package/dist/app-publish-workspace.d.ts +16 -0
  11. package/dist/app-publish-workspace.d.ts.map +1 -0
  12. package/dist/app-publish-workspace.js +175 -0
  13. package/dist/artifacts-git-runtime.d.ts +5 -0
  14. package/dist/artifacts-git-runtime.d.ts.map +1 -1
  15. package/dist/artifacts-git-runtime.js +70 -25
  16. package/dist/artifacts-session-merge.d.ts +62 -0
  17. package/dist/artifacts-session-merge.d.ts.map +1 -0
  18. package/dist/artifacts-session-merge.js +123 -0
  19. package/dist/dataset-append-workflow.d.ts +12 -0
  20. package/dist/dataset-append-workflow.d.ts.map +1 -0
  21. package/dist/dataset-append-workflow.js +198 -0
  22. package/dist/dataset-commands.d.ts +3 -1
  23. package/dist/dataset-commands.d.ts.map +1 -1
  24. package/dist/dataset-commands.js +111 -191
  25. package/dist/dataset-delete-workflow.d.ts +4 -0
  26. package/dist/dataset-delete-workflow.d.ts.map +1 -0
  27. package/dist/dataset-delete-workflow.js +75 -0
  28. package/dist/dataset-lock-workflow.d.ts +12 -0
  29. package/dist/dataset-lock-workflow.d.ts.map +1 -0
  30. package/dist/dataset-lock-workflow.js +76 -0
  31. package/dist/dataset-readme-workflow.d.ts +13 -0
  32. package/dist/dataset-readme-workflow.d.ts.map +1 -0
  33. package/dist/dataset-readme-workflow.js +82 -0
  34. package/dist/dataset-row-workflow.d.ts +14 -0
  35. package/dist/dataset-row-workflow.d.ts.map +1 -0
  36. package/dist/dataset-row-workflow.js +202 -0
  37. package/dist/dataset-split-reads.d.ts +28 -0
  38. package/dist/dataset-split-reads.d.ts.map +1 -0
  39. package/dist/dataset-split-reads.js +47 -0
  40. package/dist/dataset-transfer-download.js +6 -6
  41. package/dist/dataset-transfer-upload.js +8 -8
  42. package/dist/git-credential.d.ts +1 -1
  43. package/dist/git-credential.d.ts.map +1 -1
  44. package/dist/git-credential.js +8 -1
  45. package/dist/help.d.ts.map +1 -1
  46. package/dist/help.js +32 -6
  47. package/dist/hosted-boot.d.ts +12 -0
  48. package/dist/hosted-boot.d.ts.map +1 -1
  49. package/dist/hosted-boot.js +63 -1
  50. package/dist/hosted-harness-opencode.d.ts +4 -5
  51. package/dist/hosted-harness-opencode.d.ts.map +1 -1
  52. package/dist/hosted-harness-opencode.js +66 -52
  53. package/dist/hosted-loop-lifecycle.d.ts +4 -10
  54. package/dist/hosted-loop-lifecycle.d.ts.map +1 -1
  55. package/dist/hosted-loop-lifecycle.js +4 -10
  56. package/dist/hosted-loop.d.ts +2 -0
  57. package/dist/hosted-loop.d.ts.map +1 -1
  58. package/dist/hosted-loop.js +5 -4
  59. package/dist/hosted-session-cli.d.ts.map +1 -1
  60. package/dist/hosted-session-cli.js +6 -1
  61. package/dist/hosted-session-seed.d.ts +45 -0
  62. package/dist/hosted-session-seed.d.ts.map +1 -0
  63. package/dist/hosted-session-seed.js +61 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +9 -1
  66. package/dist/instruction-delivery.d.ts +14 -0
  67. package/dist/instruction-delivery.d.ts.map +1 -0
  68. package/dist/instruction-delivery.js +103 -0
  69. package/dist/instruction-set-sync/index.d.ts +17 -0
  70. package/dist/instruction-set-sync/index.d.ts.map +1 -1
  71. package/dist/instruction-set-sync/index.js +44 -17
  72. package/dist/instruction-set-update/index.d.ts +2 -2
  73. package/dist/instruction-set-update/index.d.ts.map +1 -1
  74. package/dist/instruction-set-update/index.js +2 -2
  75. package/dist/instruction-sets-cli.d.ts.map +1 -1
  76. package/dist/instruction-sets-cli.js +19 -27
  77. package/dist/json-response.d.ts +1 -0
  78. package/dist/json-response.d.ts.map +1 -1
  79. package/dist/json-response.js +7 -0
  80. package/dist/jsonl-stream.d.ts +1 -0
  81. package/dist/jsonl-stream.d.ts.map +1 -1
  82. package/dist/jsonl-stream.js +7 -0
  83. package/dist/preview-runtime.d.ts +2 -2
  84. package/dist/preview-runtime.d.ts.map +1 -1
  85. package/dist/preview-runtime.js +37 -7
  86. package/dist/provider-list-workflow.d.ts +3 -0
  87. package/dist/provider-list-workflow.d.ts.map +1 -0
  88. package/dist/provider-list-workflow.js +95 -0
  89. package/dist/provider-wire-record.d.ts +3 -0
  90. package/dist/provider-wire-record.d.ts.map +1 -0
  91. package/dist/provider-wire-record.js +4 -0
  92. package/dist/providers-cli.d.ts.map +1 -1
  93. package/dist/providers-cli.js +5 -15
  94. package/dist/publish-merge-job.d.ts +68 -0
  95. package/dist/publish-merge-job.d.ts.map +1 -0
  96. package/dist/publish-merge-job.js +320 -0
  97. package/dist/publish-merge-timing.d.ts +18 -0
  98. package/dist/publish-merge-timing.d.ts.map +1 -0
  99. package/dist/publish-merge-timing.js +23 -0
  100. package/dist/task-export-workflow.d.ts +4 -0
  101. package/dist/task-export-workflow.d.ts.map +1 -0
  102. package/dist/task-export-workflow.js +46 -0
  103. package/dist/workbench-cli.d.ts +4 -0
  104. package/dist/workbench-cli.d.ts.map +1 -1
  105. package/dist/workbench-cli.js +11 -1
  106. package/dist/workspace-bootstrap-job.d.ts +1 -0
  107. package/dist/workspace-bootstrap-job.d.ts.map +1 -1
  108. package/dist/workspace-bootstrap-job.js +1 -1
  109. package/package.json +5 -2
  110. package/src/app-commands.ts +234 -66
  111. package/src/app-publish-failure.ts +7 -0
  112. package/src/app-publish-paths.ts +27 -0
  113. package/src/app-publish-workspace.ts +207 -0
  114. package/src/artifacts-git-runtime.ts +73 -31
  115. package/src/artifacts-session-merge.ts +253 -0
  116. package/src/dataset-append-workflow.ts +205 -0
  117. package/src/dataset-commands.ts +101 -261
  118. package/src/dataset-delete-workflow.ts +72 -0
  119. package/src/dataset-lock-workflow.ts +74 -0
  120. package/src/dataset-readme-workflow.ts +80 -0
  121. package/src/dataset-row-workflow.ts +248 -0
  122. package/src/dataset-split-reads.ts +43 -0
  123. package/src/dataset-transfer-download.ts +5 -5
  124. package/src/dataset-transfer-upload.ts +7 -7
  125. package/src/git-credential.ts +8 -1
  126. package/src/help.ts +32 -6
  127. package/src/hosted-boot.ts +72 -2
  128. package/src/hosted-harness-opencode.ts +67 -65
  129. package/src/hosted-loop-lifecycle.ts +4 -10
  130. package/src/hosted-loop.ts +6 -4
  131. package/src/hosted-model-cache.d.mts +2 -0
  132. package/src/hosted-model-cache.mjs +53 -0
  133. package/src/hosted-session-cli.ts +6 -1
  134. package/src/hosted-session-seed.ts +78 -0
  135. package/src/index.ts +10 -0
  136. package/src/instruction-delivery.ts +123 -0
  137. package/src/instruction-set-sync/index.ts +61 -14
  138. package/src/instruction-set-update/index.ts +4 -3
  139. package/src/instruction-sets-cli.ts +19 -27
  140. package/src/json-response.ts +8 -0
  141. package/src/jsonl-stream.ts +8 -0
  142. package/src/preview-runtime.ts +40 -10
  143. package/src/provider-list-workflow.ts +108 -0
  144. package/src/provider-wire-record.ts +4 -0
  145. package/src/providers-cli.ts +5 -13
  146. package/src/publish-merge-job.ts +350 -0
  147. package/src/publish-merge-timing.ts +27 -0
  148. package/src/task-export-workflow.ts +56 -0
  149. package/src/workbench-cli.ts +15 -1
  150. package/src/workspace-bootstrap-job.ts +1 -1
  151. package/vendor/skills/orizu/flows/onboard.md +1 -1
  152. package/vendor/skills/orizu/references/authority-map.md +2 -2
  153. package/vendor/skills/orizu/references/building-apps.md +24 -0
  154. package/vendor/skills/orizu/references/cli-reference.md +47 -4
  155. package/vendor/skills/orizu/references/dataset-design.md +1 -1
  156. package/vendor/skills/orizu/references/optimization-reports.md +1 -1
  157. package/vendor/skills/orizu/references/primer.md +1 -0
  158. package/vendor/skills/orizu/references/prompt-control-plane.md +9 -5
  159. package/dist/dataset-edit-rows.d.ts +0 -10
  160. package/dist/dataset-edit-rows.d.ts.map +0 -1
  161. package/dist/dataset-edit-rows.js +0 -90
  162. package/src/dataset-edit-rows.ts +0 -124
@@ -0,0 +1,198 @@
1
+ import { statSync } from 'node:fs';
2
+ import { extname } from 'node:path';
3
+ import { Context, Effect, Result, Schema } from 'effect';
4
+ import { parseDatasetFile } from './file-parser.js';
5
+ import { datasetTransferTimeoutMs } from './dataset-transfer-policy.js';
6
+ import { authedFetch } from './http.js';
7
+ import { streamJsonlRowChunks } from './jsonl-stream.js';
8
+ import { sanitizeTerminalText } from './json-response.js';
9
+ class AppendFailure extends Error {
10
+ outcome;
11
+ _tag = 'AppendFailure';
12
+ constructor(message, outcome) {
13
+ super(sanitizeTerminalText(message));
14
+ this.outcome = outcome;
15
+ }
16
+ }
17
+ const Acknowledgement = Schema.Struct({
18
+ dataset: Schema.Struct({ id: Schema.String, name: Schema.String, rowCount: Schema.Natural }),
19
+ appendedCount: Schema.Natural,
20
+ });
21
+ const RowsSchema = Schema.Array(Schema.Record(Schema.String, Schema.Unknown));
22
+ const appendTransport = Context.Service('orizu/cli/DatasetAppendTransport');
23
+ // Only responses naming an existing rows-route rejection establish a known
24
+ // refusal. A proxy body or a lost body is not evidence that nothing committed.
25
+ function isKnownRefusal(message, status) {
26
+ // These exact templates come from artifact preparation before the append RPC.
27
+ // Status alone or an arbitrary artifact/proxy prefix cannot prove rejection.
28
+ if (status === 400 && (message === 'Dataset row id cannot be stored as an artifact' ||
29
+ /^Invalid dataset row artifact reference at .+$/.test(message) ||
30
+ /^Dataset row artifact ref at .+ (?:is nested; v1 supports top-level fields only|was not issued by this server|belongs to a different project|has been deleted|has not been finalized|is expired|was issued to a different user|is not attachable|does not match server metadata|targets a different (?:dataset|field|row id))$/.test(message)))
31
+ return true;
32
+ if (status === 413 && (/^Dataset row .+ exceeds 65536 bytes after externalizing top-level fields$/.test(message) ||
33
+ /^.+ exceeds (?:26214400 bytes before compression|10485760 bytes after compression)$/.test(message)))
34
+ return true;
35
+ return /^(Missing bearer token|Unauthorized|Dataset not found|Only project curators\/admins can modify dataset rows|Dataset is locked and cannot be mutated|Duplicate row ids provided|One or more row ids already exist in this dataset|rows must contain at least one item|rows\[\d+\] must be an object|Dataset row is too large|Each row in p_rows must)/.test(message);
36
+ }
37
+ function liveTransport(timeoutMs, commandSignal, progress) {
38
+ return {
39
+ append: (datasetId, rows) => Effect.suspend(() => {
40
+ let admitted = false;
41
+ let timedOut = false;
42
+ const attempt = new AbortController();
43
+ let timer;
44
+ return Effect.tryPromise({
45
+ try: async (signal) => {
46
+ const abortFromEffect = () => attempt.abort(signal.reason);
47
+ const abortFromCommand = () => attempt.abort(commandSignal.reason);
48
+ try {
49
+ // Node 20.0 has no AbortSignal.any. This attempt owns both links
50
+ // and the physical fetch/body signal until its receipt is consumed.
51
+ if (signal.aborted)
52
+ abortFromEffect();
53
+ else
54
+ signal.addEventListener('abort', abortFromEffect, { once: true });
55
+ if (commandSignal.aborted)
56
+ abortFromCommand();
57
+ else
58
+ commandSignal.addEventListener('abort', abortFromCommand, { once: true });
59
+ const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
60
+ method: 'POST', headers: { 'Content-Type': 'application/json' },
61
+ body: JSON.stringify({ rows }), signal: attempt.signal,
62
+ }, () => {
63
+ admitted = true;
64
+ if (progress.chunk)
65
+ progress.chunk.outcome = 'unknown';
66
+ if (timer)
67
+ clearTimeout(timer);
68
+ timer = setTimeout(() => { timedOut = true; attempt.abort(); }, timeoutMs);
69
+ });
70
+ // The single admitted-attempt deadline includes the complete body.
71
+ const text = await response.text();
72
+ let value;
73
+ try {
74
+ value = JSON.parse(text);
75
+ }
76
+ catch {
77
+ throw new AppendFailure('Append returned an invalid acknowledgement', 'unknown');
78
+ }
79
+ if (!response.ok) {
80
+ const message = value && typeof value === 'object' && 'error' in value && typeof value.error === 'string' ? value.error : '';
81
+ const known = response.status >= 400 && response.status < 500 && isKnownRefusal(message, response.status);
82
+ throw new AppendFailure(message ? `Append failed: ${message}` : 'Append failed', known ? 'rejected' : 'unknown');
83
+ }
84
+ const result = Schema.decodeUnknownResult(Acknowledgement)(value);
85
+ if (Result.isFailure(result) || result.success.dataset.id.toLowerCase() !== datasetId.toLowerCase() || result.success.appendedCount !== rows.length)
86
+ throw new AppendFailure('Append returned an invalid acknowledgement', 'unknown');
87
+ return result.success;
88
+ }
89
+ finally {
90
+ if (timer)
91
+ clearTimeout(timer);
92
+ signal.removeEventListener('abort', abortFromEffect);
93
+ commandSignal.removeEventListener('abort', abortFromCommand);
94
+ attempt.abort();
95
+ }
96
+ },
97
+ catch: cause => cause instanceof AppendFailure ? cause : new AppendFailure(timedOut ? 'DATASET_TRANSFER_TIMEOUT: Dataset append exceeded its deadline' : admitted ? 'fetch failed' : cause instanceof Error ? cause.message : 'Append failed before the request was sent', admitted ? 'unknown' : 'not_sent'),
98
+ });
99
+ }),
100
+ };
101
+ }
102
+ function recovery(progress) {
103
+ if (progress.chunk?.outcome === 'unknown')
104
+ return 'This chunk may already be committed. Inspect the dataset and reconcile its rows before rerunning; do not blindly repeat this write.';
105
+ if (progress.confirmedRows > 0)
106
+ return 'Earlier acknowledged rows remain appended. Inspect the confirmed source prefix before retrying the remaining input.';
107
+ return 'Resolve the reported error before rerunning the command.';
108
+ }
109
+ function appendProgram(input, timeoutMs, progress, io, signal) {
110
+ return Effect.gen(function* () {
111
+ const rows = yield* Effect.try({
112
+ try: () => {
113
+ if (extname(input.file).toLowerCase() === '.jsonl')
114
+ return undefined;
115
+ let bytes;
116
+ try {
117
+ bytes = statSync(input.file).size;
118
+ }
119
+ catch (cause) {
120
+ const error = cause;
121
+ if (error.code === 'ENOENT')
122
+ throw new Error(`File not found: ${input.file}. Check the path and filename, then retry.`);
123
+ if (error.code === 'EPERM' || error.code === 'EACCES')
124
+ throw new Error(`Cannot read file: ${input.file}. Grant folder permission to your terminal app and retry.`);
125
+ throw new Error(`Failed to access file ${input.file}: ${error.message}`);
126
+ }
127
+ if (bytes > 50 * 1024 * 1024)
128
+ throw new Error(`Input file is ${(bytes / (1024 * 1024)).toFixed(1)} MB, which exceeds the 50 MB limit. Split the file into smaller parts and append each separately.`);
129
+ const parsed = parseDatasetFile(input.file).rows;
130
+ if (!Array.isArray(parsed) || parsed.length === 0)
131
+ throw new Error('Dataset append file must contain at least one row');
132
+ return parsed;
133
+ },
134
+ catch: cause => new AppendFailure(cause instanceof Error ? cause.message : 'Could not read append input', 'not_sent'),
135
+ });
136
+ const source = yield* Effect.acquireRelease(Effect.sync(() => rows ? (async function* () {
137
+ for (let offset = 0; offset < rows.length; offset += 500)
138
+ yield rows.slice(offset, offset + 500);
139
+ })() : streamJsonlRowChunks(input.file, { signal })), iterator => Effect.promise(async () => { await iterator.return(undefined); }));
140
+ const transport = liveTransport(timeoutMs, signal, progress);
141
+ let acknowledgement;
142
+ let index = 0;
143
+ while (true) {
144
+ const next = yield* Effect.tryPromise({ try: () => source.next(), catch: cause => new AppendFailure(cause instanceof Error ? cause.message : 'Could not read append input', 'not_sent') });
145
+ if (next.done)
146
+ break;
147
+ index++;
148
+ progress.chunk = { index, inputRows: next.value.length, outcome: 'not_sent' };
149
+ const rows = yield* Schema.decodeUnknownEffect(RowsSchema)(next.value).pipe(Effect.mapError(() => new AppendFailure('Dataset rows must be JSON objects', 'not_sent')));
150
+ if (!io.json)
151
+ yield* Effect.sync(() => io.print(`Uploading chunk ${index} (${rows.length} rows)...`));
152
+ acknowledgement = yield* appendTransport.use(api => api.append(input.datasetId, rows)).pipe(Effect.provideService(appendTransport, transport));
153
+ progress.confirmedRows += acknowledgement.appendedCount;
154
+ progress.confirmedChunks++;
155
+ progress.chunk = null;
156
+ }
157
+ if (!acknowledgement)
158
+ return yield* Effect.fail(new AppendFailure('Dataset append file must contain at least one row', 'not_sent'));
159
+ return { dataset: acknowledgement.dataset, appendedCount: progress.confirmedRows };
160
+ }).pipe(Effect.scoped);
161
+ }
162
+ /** Owns standalone append's source, admitted writes, progress and recovery. */
163
+ export async function appendDatasetWorkflow(resolveInput, io) {
164
+ const controller = new AbortController();
165
+ const progress = { datasetId: null, confirmedRows: 0, confirmedChunks: 0, chunk: null };
166
+ let interrupted;
167
+ const interrupt = () => { interrupted = 130; controller.abort(); };
168
+ const terminate = () => { interrupted = 143; controller.abort(); };
169
+ const program = Effect.gen(function* () {
170
+ const timeoutMs = yield* Effect.try({ try: datasetTransferTimeoutMs, catch: cause => new AppendFailure(cause instanceof Error ? cause.message : 'Invalid append configuration', 'not_sent') });
171
+ const input = yield* Effect.tryPromise({ try: resolveInput, catch: cause => new AppendFailure(cause instanceof Error ? cause.message : 'Could not resolve append input', 'not_sent') });
172
+ progress.datasetId = input.datasetId;
173
+ // Retained interactive selection does not accept a signal. Preserve
174
+ // natural Node termination until we own cancellable source/transport work.
175
+ return yield* Effect.acquireUseRelease(Effect.sync(() => { process.once('SIGINT', interrupt); process.once('SIGTERM', terminate); }), () => appendProgram(input, timeoutMs, progress, io, controller.signal), () => Effect.sync(() => { process.removeListener('SIGINT', interrupt); process.removeListener('SIGTERM', terminate); }));
176
+ });
177
+ const report = (message) => {
178
+ const error = sanitizeTerminalText(message);
179
+ const advice = recovery(progress);
180
+ io.print(io.json ? JSON.stringify({ error, datasetId: progress.datasetId, confirmedRows: progress.confirmedRows, confirmedChunks: progress.confirmedChunks, failedChunk: progress.chunk, recovery: advice })
181
+ : `${error}\n${progress.confirmedRows} rows from ${progress.confirmedChunks} chunk(s) were already appended. ${advice}`);
182
+ };
183
+ try {
184
+ const result = await Effect.runPromise(Effect.result(program), { signal: controller.signal });
185
+ if (Result.isFailure(result)) {
186
+ if (progress.chunk)
187
+ progress.chunk.outcome = result.failure.outcome;
188
+ report(result.failure.message);
189
+ return 1;
190
+ }
191
+ io.print(io.json ? JSON.stringify(result.success) : `Appended ${result.success.appendedCount} rows to dataset ${sanitizeTerminalText(result.success.dataset.name)} (${sanitizeTerminalText(result.success.dataset.id)}). New row count: ${result.success.dataset.rowCount}`);
192
+ return 0;
193
+ }
194
+ catch {
195
+ report(interrupted ? 'Dataset append interrupted' : 'Dataset append failed');
196
+ return interrupted ?? 1;
197
+ }
198
+ }
@@ -1,4 +1,6 @@
1
1
  declare function createDatasetVersion(): Promise<void>;
2
+ declare function listDatasetSplitSets(): Promise<void>;
3
+ declare function showDatasetSplitSet(): Promise<void>;
2
4
  declare function createDatasetSplitSet(): Promise<void>;
3
5
  declare function listDatasets(): Promise<void>;
4
6
  declare function uploadDataset(): Promise<void>;
@@ -12,5 +14,5 @@ declare function deleteDataset(): Promise<void>;
12
14
  declare function lockDataset(): Promise<void>;
13
15
  declare function cloneDataset(): Promise<void>;
14
16
  declare function downloadAnnotations(): Promise<void>;
15
- export { uploadDataset, listDatasets, pushDataset, downloadDataset, appendDatasetRows, setDatasetReadme, createDatasetVersion, createDatasetSplitSet, editDatasetRows, deleteDatasetRows, deleteDataset, lockDataset, cloneDataset, downloadAnnotations, };
17
+ export { uploadDataset, listDatasets, pushDataset, downloadDataset, appendDatasetRows, setDatasetReadme, createDatasetVersion, createDatasetSplitSet, listDatasetSplitSets, showDatasetSplitSet, editDatasetRows, deleteDatasetRows, deleteDataset, lockDataset, cloneDataset, downloadAnnotations, };
16
18
  //# sourceMappingURL=dataset-commands.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-commands.d.ts","sourceRoot":"","sources":["../src/dataset-commands.ts"],"names":[],"mappings":"AA8IA,iBAAe,oBAAoB,kBAiClC;AAED,iBAAe,qBAAqB,kBAkDnC;AAED,iBAAe,YAAY,kBAW1B;AAsBD,iBAAe,aAAa,kBAiC3B;AAED,iBAAe,WAAW,kBAwCzB;AAED,iBAAe,gBAAgB,kBA+C9B;AAgBD,iBAAe,eAAe,kBA8B7B;AA0ED,iBAAe,iBAAiB,kBAiG/B;AAED,iBAAe,eAAe,kBAyB7B;AAED,iBAAe,iBAAiB,kBAyC/B;AA0BD,iBAAe,aAAa,kBA8B3B;AAED,iBAAe,WAAW,kBAwCzB;AAED,iBAAe,YAAY,kBAuC1B;AAED,iBAAe,mBAAmB,kBA+BjC;AAED,OAAO,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,CAAA"}
1
+ {"version":3,"file":"dataset-commands.d.ts","sourceRoot":"","sources":["../src/dataset-commands.ts"],"names":[],"mappings":"AAuJA,iBAAe,oBAAoB,kBAiClC;AAED,iBAAe,oBAAoB,kBAYlC;AAED,iBAAe,mBAAmB,kBAcjC;AAED,iBAAe,qBAAqB,kBAkDnC;AAED,iBAAe,YAAY,kBAW1B;AAsBD,iBAAe,aAAa,kBAiC3B;AAED,iBAAe,WAAW,kBAwCzB;AAED,iBAAe,gBAAgB,kBA+B9B;AAgBD,iBAAe,eAAe,kBA6C7B;AAED,iBAAe,iBAAiB,kBAU/B;AAED,iBAAe,eAAe,kBA2B7B;AAED,iBAAe,iBAAiB,kBA2B/B;AA0BD,iBAAe,aAAa,kBAuB3B;AAED,iBAAe,WAAW,kBAuBzB;AAED,iBAAe,YAAY,kBAuC1B;AAED,iBAAe,mBAAmB,kBA0BjC;AAED,OAAO,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,mBAAmB,GACpB,CAAA"}
@@ -1,9 +1,9 @@
1
1
  // ORI-2044: moved from index.ts to keep dataset commands together.
2
- import { readFileSync, statSync, writeFileSync } from 'fs';
2
+ import { readFileSync } from 'fs';
3
3
  import { basename, extname } from 'path';
4
4
  import { createInterface } from 'readline/promises';
5
5
  import { stdin as input, stdout as output } from 'process';
6
- import { getArg, expandHomePath, getPositionalArg, hasJsonFlag, getArchiveListStatus, cliArgs, isInteractiveTerminal, } from './command-line-arguments.js';
6
+ import { getArg, hasArg, expandHomePath, getPositionalArg, hasJsonFlag, getArchiveListStatus, cliArgs, isInteractiveTerminal, } from './command-line-arguments.js';
7
7
  import { resolveProjectSlug, fetchDatasets, selectDatasetInteractively, selectTaskIdInteractively, } from './account-directory.js';
8
8
  import { sanitizeTerminalText, parseJsonResponse } from './json-response.js';
9
9
  import { authedFetch } from './http.js';
@@ -14,10 +14,18 @@ import { printDatasetSummaries } from './archive-artifacts-cli.js';
14
14
  import { formatTerminalLink } from './auth-commands.js';
15
15
  import { parseDatasetFile } from './file-parser.js';
16
16
  import { parseDatasetReference } from './dataset-download.js';
17
- import { streamJsonlRowChunks } from './jsonl-stream.js';
18
- import { editDatasetRows as runEditDatasetRows } from './dataset-edit-rows.js';
19
17
  import { parseCommaSeparated } from './task-commands.js';
20
18
  const MAX_README_LENGTH = 200_000;
19
+ function readReadmeFile(readmeFile) {
20
+ try {
21
+ return readFileSync(expandHomePath(readmeFile), 'utf8');
22
+ }
23
+ catch (error) {
24
+ const missing = error instanceof Error && 'code' in error && error.code === 'ENOENT';
25
+ const reason = missing ? 'file not found' : error instanceof Error ? error.message : String(error);
26
+ throw new Error(`Could not read README file ${readmeFile}: ${reason}`);
27
+ }
28
+ }
21
29
  function readReadmeMarkdownFromArgs(usage) {
22
30
  const readmeFile = getArg('--readme-file');
23
31
  const readmeText = getArg('--readme-text');
@@ -25,7 +33,7 @@ function readReadmeMarkdownFromArgs(usage) {
25
33
  throw new Error(`Use either --readme-file or --readme-text, not both.\n${usage}`);
26
34
  }
27
35
  const markdown = readmeFile !== null
28
- ? readFileSync(expandHomePath(readmeFile), 'utf8')
36
+ ? readReadmeFile(readmeFile)
29
37
  : readmeText;
30
38
  if (markdown !== null && markdown.length > MAX_README_LENGTH) {
31
39
  throw new Error(`README markdown is too large. Maximum size is ${MAX_README_LENGTH} characters.`);
@@ -117,6 +125,41 @@ async function createDatasetVersion() {
117
125
  printLine(`Created dataset version ${sanitizeTerminalText(data.datasetVersion.id)}` +
118
126
  (details ? ` (${sanitizeTerminalText(details)})` : ''));
119
127
  }
128
+ async function listDatasetSplitSets() {
129
+ const versionId = getPositionalArg(3);
130
+ if (!versionId)
131
+ throw new Error('Usage: orizu datasets splits list <datasetVersionId> [--json]');
132
+ const { listDatasetSplits } = await import('./dataset-split-reads.js');
133
+ const data = await listDatasetSplits(versionId);
134
+ if (hasJsonFlag())
135
+ return printJson({ ...data });
136
+ printLine(`Dataset version ${sanitizeTerminalText(data.dataset_version_id)}`);
137
+ for (const set of data.split_sets) {
138
+ printLine(`${sanitizeTerminalText(set.name)} (${sanitizeTerminalText(set.id)})`);
139
+ for (const partition of set.partitions)
140
+ printLine(` ${sanitizeTerminalText(partition.name)}: ${partition.row_count} rows`);
141
+ }
142
+ if (!data.split_sets.length)
143
+ printLine('No saved split sets.');
144
+ }
145
+ async function showDatasetSplitSet() {
146
+ const setId = getPositionalArg(3);
147
+ if (!setId)
148
+ throw new Error('Usage: orizu datasets splits show <splitSetId> [--json]');
149
+ const { showDatasetSplit } = await import('./dataset-split-reads.js');
150
+ const data = await showDatasetSplit(setId);
151
+ if (hasJsonFlag())
152
+ return printJson({ ...data });
153
+ printLine(`${sanitizeTerminalText(data.name)} (${sanitizeTerminalText(data.split_set_id)})`);
154
+ printLine(`Dataset version: ${sanitizeTerminalText(data.dataset_version_id)}`);
155
+ printLine(`Strategy: ${sanitizeTerminalText(data.strategy)}; seed: ${data.seed ?? 'none'}`);
156
+ printLine(`Metadata: ${sanitizeTerminalText(JSON.stringify(data.metadata))}`);
157
+ for (const partition of data.partitions) {
158
+ printLine(`${sanitizeTerminalText(partition.name)}: ${partition.row_ids.length} rows`);
159
+ for (const id of partition.row_ids)
160
+ printLine(` ${sanitizeTerminalText(id)}`);
161
+ }
162
+ }
120
163
  async function createDatasetSplitSet() {
121
164
  const datasetVersionId = getPositionalArg(3) || getArg('--dataset-version');
122
165
  const splitFile = getArg('--from-file');
@@ -133,7 +176,7 @@ async function createDatasetSplitSet() {
133
176
  throw new Error('Usage: orizu datasets splits create <datasetVersionId> [--from-file <split.json>] [--name <name>] [--seed <n>] [--train <ratio>] [--validation <ratio>] [--test <ratio>] [--json]');
134
177
  }
135
178
  const partitions = splitSpec && Array.isArray(splitSpec.partitions) ? splitSpec.partitions : undefined;
136
- const metadata = splitSpec && typeof splitSpec.metadata === 'object' && splitSpec.metadata !== null
179
+ const metadata = splitSpec && Object.prototype.hasOwnProperty.call(splitSpec, 'metadata')
137
180
  ? splitSpec.metadata
138
181
  : undefined;
139
182
  const response = await authedFetch(`/api/cli/dataset-versions/${encodeURIComponent(datasetVersionId)}/split-sets`, {
@@ -265,25 +308,18 @@ async function setDatasetReadme() {
265
308
  throw new Error(usage);
266
309
  }
267
310
  const resolvedDatasetId = await resolveDatasetIdForProject(datasetId, project);
268
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(resolvedDatasetId)}/readme`, {
269
- method: 'POST',
270
- headers: { 'Content-Type': 'application/json' },
271
- body: JSON.stringify({ markdown: readmeMarkdown }),
272
- });
273
- if (!response.ok) {
274
- throw new Error(`Failed to save dataset README: ${await response.text()}`);
275
- }
276
- const data = await parseJsonResponse(response, 'Dataset README save');
311
+ const { saveDatasetReadme } = await import('./dataset-readme-workflow.js');
312
+ const version = await saveDatasetReadme(resolvedDatasetId, readmeMarkdown);
277
313
  if (hasJsonFlag()) {
278
314
  printJson({
279
- dataset_id: data.version.dataset_id,
280
- readme_version_id: data.version.id,
281
- readme_version_num: data.version.version_num,
315
+ dataset_id: version.dataset_id,
316
+ readme_version_id: version.id,
317
+ readme_version_num: version.version_num,
282
318
  });
283
319
  return;
284
320
  }
285
- printLine(`Saved README v${data.version.version_num} for dataset ` +
286
- `${sanitizeTerminalText(data.version.dataset_id)} (${sanitizeTerminalText(data.version.id)}).`);
321
+ printLine(`Saved README v${version.version_num} for dataset ` +
322
+ `${sanitizeTerminalText(version.dataset_id)} (${sanitizeTerminalText(version.id)}).`);
287
323
  }
288
324
  function getDatasetReferenceInput() {
289
325
  const fromFlag = getArg('--dataset');
@@ -304,6 +340,24 @@ async function downloadDataset() {
304
340
  if (!['csv', 'json', 'jsonl'].includes(format)) {
305
341
  throw new Error('format must be one of: csv, json, jsonl');
306
342
  }
343
+ const versionId = getArg('--dataset-version'), setId = getArg('--split-set');
344
+ const inlineSplit = cliArgs.find(argument => argument.startsWith('--split='));
345
+ const split = inlineSplit === undefined ? getArg('--split') : inlineSplit.slice('--split='.length);
346
+ if (['--dataset-version', '--split-set', '--split'].some(flag => hasArg(flag) || cliArgs.some(argument => argument.startsWith(`${flag}=`)))) {
347
+ if (!versionId || !setId || !split || [versionId, setId].some(value => value.startsWith('--')) || (inlineSplit === undefined && split.startsWith('--')))
348
+ throw new Error('Pinned download requires --dataset-version, --split-set and --split together');
349
+ if (datasetInput)
350
+ throw new Error('Use --dataset-version with split selectors without a live --dataset or dataset argument');
351
+ if (format === 'csv')
352
+ throw new Error('Pinned download format must be json or jsonl');
353
+ const filename = outPathArg ? expandHomePath(outPathArg) : `${versionId}.${format}`;
354
+ const { downloadPinnedDatasetSplit } = await import('./dataset-split-reads.js');
355
+ await downloadPinnedDatasetSplit(versionId, setId, split, format, filename);
356
+ if (hasJsonFlag())
357
+ return printJson({ dataset_version_id: versionId, split_set_id: setId, split, format, savedTo: filename });
358
+ printLine(`Saved split ${sanitizeTerminalText(split)} from dataset version ${sanitizeTerminalText(versionId)} (${format.toUpperCase()}) to ${sanitizeTerminalText(filename)}`);
359
+ return;
360
+ }
307
361
  let datasetId;
308
362
  if (datasetInput) {
309
363
  datasetId = parseDatasetReference(datasetInput).datasetId;
@@ -323,135 +377,17 @@ async function downloadDataset() {
323
377
  }
324
378
  printLine(`Saved dataset ${sanitizeTerminalText(datasetId)} (${format.toUpperCase()}) to ${sanitizeTerminalText(filename)}`);
325
379
  }
326
- const MAX_INPUT_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50 MB
327
- const APPEND_CHUNK_SIZE_ROWS = 500;
328
- async function appendChunk(datasetId, rows) {
329
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
330
- method: 'POST',
331
- headers: { 'Content-Type': 'application/json' },
332
- body: JSON.stringify({ rows }),
333
- });
334
- if (!response.ok) {
335
- throw new Error(`Append failed: ${await response.text()}`);
336
- }
337
- return parseJsonResponse(response, 'Dataset append');
338
- }
339
- async function appendJsonlDatasetRowsInChunks(datasetId, file) {
340
- let totalAppended = 0;
341
- let lastResult = null;
342
- let chunkIndex = 0;
343
- const chunks = streamJsonlRowChunks(file)[Symbol.asyncIterator]();
344
- while (true) {
345
- let nextChunk;
346
- try {
347
- nextChunk = await chunks.next();
348
- }
349
- catch (error) {
350
- const message = error instanceof Error ? error.message : String(error);
351
- throw new Error(`Append stopped while reading the next JSONL chunk: ${message}\n` +
352
- `${totalAppended} rows from ${chunkIndex} chunk(s) were already appended. ` +
353
- `Fix the file, remove the first ${totalAppended} rows, and re-run the command.`);
354
- }
355
- if (nextChunk.done) {
356
- break;
357
- }
358
- const chunk = nextChunk.value;
359
- chunkIndex += 1;
360
- printLine(`Uploading chunk ${chunkIndex} (${chunk.length} rows)...`);
361
- try {
362
- const data = await appendChunk(datasetId, chunk);
363
- totalAppended += data.appendedCount;
364
- lastResult = data;
365
- }
366
- catch (error) {
367
- const message = error instanceof Error ? error.message : String(error);
368
- throw new Error(`Chunk ${chunkIndex} failed: ${message}\n` +
369
- `${totalAppended} rows from ${chunkIndex - 1} chunk(s) were already appended. ` +
370
- `To retry, remove the first ${totalAppended} rows from your file and re-run the command.`);
371
- }
372
- }
373
- if (!lastResult) {
374
- throw new Error('Dataset append file must contain at least one row');
375
- }
376
- printLine(`Appended ${totalAppended} rows to dataset ${sanitizeTerminalText(lastResult.dataset.name)} (${sanitizeTerminalText(lastResult.dataset.id)}). New row count: ${lastResult.dataset.rowCount}`);
377
- }
378
380
  async function appendDatasetRows() {
379
- const projectArg = getArg('--project');
380
- const datasetInput = getDatasetReferenceInput();
381
- const fileArg = getArg('--file');
382
- if (!fileArg) {
383
- throw new Error('Usage: orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>');
384
- }
385
- let datasetId;
386
- if (datasetInput) {
387
- datasetId = parseDatasetReference(datasetInput).datasetId;
388
- }
389
- else {
390
- const selected = await selectDatasetInteractively(projectArg);
391
- datasetId = selected.datasetId;
392
- }
393
- const file = expandHomePath(fileArg);
394
- if (extname(file).toLowerCase() === '.jsonl') {
395
- await appendJsonlDatasetRowsInChunks(datasetId, file);
396
- return;
397
- }
398
- // Check file size before reading to prevent OOM on large files (ALI-565).
399
- // Wrap statSync in try/catch so missing/inaccessible files get friendly
400
- // errors instead of raw Node.js ENOENT/EPERM (ALI-554).
401
- let fileSizeBytes;
402
- try {
403
- fileSizeBytes = statSync(file).size;
404
- }
405
- catch (error) {
406
- const maybeError = error;
407
- if (maybeError.code === 'ENOENT') {
408
- throw new Error(`File not found: ${file}. Check the path and filename, then retry.`);
409
- }
410
- if (maybeError.code === 'EPERM' || maybeError.code === 'EACCES') {
411
- throw new Error(`Cannot read file: ${file}. Grant folder permission to your terminal app and retry.`);
412
- }
413
- throw new Error(`Failed to access file ${file}: ${maybeError.message}`);
414
- }
415
- if (fileSizeBytes > MAX_INPUT_FILE_SIZE_BYTES) {
416
- const sizeMb = (fileSizeBytes / (1024 * 1024)).toFixed(1);
417
- throw new Error(`Input file is ${sizeMb} MB, which exceeds the 50 MB limit. Split the file into smaller parts and append each separately.`);
418
- }
419
- const { rows } = parseDatasetFile(file);
420
- if (!Array.isArray(rows) || rows.length === 0) {
421
- throw new Error('Dataset append file must contain at least one row');
422
- }
423
- if (rows.length <= APPEND_CHUNK_SIZE_ROWS) {
424
- const data = await appendChunk(datasetId, rows);
425
- printLine(`Appended ${data.appendedCount} rows to dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). New row count: ${data.dataset.rowCount}`);
426
- return;
427
- }
428
- // Chunked upload for large row counts (ALI-555: track partial progress)
429
- let totalAppended = 0;
430
- let lastResult = null;
431
- const totalChunks = Math.ceil(rows.length / APPEND_CHUNK_SIZE_ROWS);
432
- for (let offset = 0; offset < rows.length; offset += APPEND_CHUNK_SIZE_ROWS) {
433
- const chunk = rows.slice(offset, offset + APPEND_CHUNK_SIZE_ROWS);
434
- const chunkIndex = Math.floor(offset / APPEND_CHUNK_SIZE_ROWS) + 1;
435
- printLine(`Uploading chunk ${chunkIndex}/${totalChunks} (${chunk.length} rows)...`);
436
- try {
437
- const data = await appendChunk(datasetId, chunk);
438
- totalAppended += data.appendedCount;
439
- lastResult = data;
440
- }
441
- catch (error) {
442
- const msg = error instanceof Error ? error.message : String(error);
443
- throw new Error(`Chunk ${chunkIndex}/${totalChunks} failed: ${msg}\n` +
444
- `${totalAppended} rows from ${chunkIndex - 1} chunk(s) were already appended. ` +
445
- `To retry, remove the first ${totalAppended} rows from your file and re-run the command.`);
446
- }
447
- }
448
- if (lastResult) {
449
- if (hasJsonFlag()) {
450
- printJson({ dataset: lastResult.dataset, appendedCount: totalAppended });
451
- return;
452
- }
453
- printLine(`Appended ${totalAppended} rows to dataset ${sanitizeTerminalText(lastResult.dataset.name)} (${sanitizeTerminalText(lastResult.dataset.id)}). New row count: ${lastResult.dataset.rowCount}`);
454
- }
381
+ const { appendDatasetWorkflow } = await import('./dataset-append-workflow.js');
382
+ process.exitCode = await appendDatasetWorkflow(async () => {
383
+ const projectArg = getArg('--project');
384
+ const datasetInput = getDatasetReferenceInput();
385
+ const fileArg = getArg('--file');
386
+ if (!fileArg)
387
+ throw new Error('Usage: orizu datasets append [--dataset <datasetId|datasetUrl>] [--project <team/project>] --file <path>');
388
+ const datasetId = datasetInput ? parseDatasetReference(datasetInput).datasetId : (await selectDatasetInteractively(projectArg)).datasetId;
389
+ return { datasetId, file: expandHomePath(fileArg) };
390
+ }, { json: hasJsonFlag(), print: printLine });
455
391
  }
456
392
  async function editDatasetRows() {
457
393
  const projectArg = getArg('--project');
@@ -468,7 +404,8 @@ async function editDatasetRows() {
468
404
  const selected = await selectDatasetInteractively(projectArg);
469
405
  datasetId = selected.datasetId;
470
406
  }
471
- await runEditDatasetRows({
407
+ const { editDatasetRows: runEditDatasetRows } = await import('./dataset-row-workflow.js');
408
+ const exitCode = await runEditDatasetRows({
472
409
  datasetId,
473
410
  file: expandHomePath(fileArg),
474
411
  json: hasJsonFlag(),
@@ -476,6 +413,8 @@ async function editDatasetRows() {
476
413
  printLine,
477
414
  sanitize: sanitizeTerminalText,
478
415
  });
416
+ if (exitCode !== 0)
417
+ process.exitCode = exitCode;
479
418
  }
480
419
  async function deleteDatasetRows() {
481
420
  const projectArg = getArg('--project');
@@ -492,22 +431,17 @@ async function deleteDatasetRows() {
492
431
  const selected = await selectDatasetInteractively(projectArg);
493
432
  datasetId = selected.datasetId;
494
433
  }
495
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/rows`, {
496
- method: 'DELETE',
497
- headers: { 'Content-Type': 'application/json' },
498
- body: JSON.stringify({
499
- rowIds,
500
- }),
434
+ const { deleteDatasetRows: runDeleteDatasetRows } = await import('./dataset-row-workflow.js');
435
+ const exitCode = await runDeleteDatasetRows({
436
+ datasetId,
437
+ rowIds,
438
+ json: hasJsonFlag(),
439
+ printJson,
440
+ printLine,
441
+ sanitize: sanitizeTerminalText,
501
442
  });
502
- if (!response.ok) {
503
- throw new Error(`Delete rows failed: ${await response.text()}`);
504
- }
505
- const data = await parseJsonResponse(response, 'Dataset delete rows');
506
- if (hasJsonFlag()) {
507
- printJson({ dataset: data.dataset, deletedCount: data.deletedCount });
508
- return;
509
- }
510
- printLine(`Deleted ${data.deletedCount} rows from dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}). New row count: ${data.dataset.rowCount}`);
443
+ if (exitCode !== 0)
444
+ process.exitCode = exitCode;
511
445
  }
512
446
  async function confirmDatasetDeletion(dataset) {
513
447
  if (!isInteractiveTerminal()) {
@@ -538,18 +472,15 @@ async function deleteDataset() {
538
472
  dataset = await selectDatasetInteractively(projectArg);
539
473
  }
540
474
  await confirmDatasetDeletion(dataset);
541
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(dataset.datasetId)}`, {
542
- method: 'DELETE',
543
- });
544
- if (!response.ok) {
545
- throw new Error(`Delete failed: ${await response.text()}`);
546
- }
547
- const data = await parseJsonResponse(response, 'Dataset delete');
475
+ const { deleteDataset: requestDelete } = await import('./dataset-delete-workflow.js');
476
+ // Only a dataset picked from a project's list has a known project; with
477
+ // --dataset, --project is never checked against the dataset.
478
+ const deleted = await requestDelete(dataset.datasetId, dataset.project ?? null);
548
479
  if (hasJsonFlag()) {
549
- printJson({ dataset: data.dataset, deleted: true });
480
+ printJson({ dataset: deleted, deleted: true });
550
481
  return;
551
482
  }
552
- printLine(`Deleted dataset ${sanitizeTerminalText(data.dataset.id)}.`);
483
+ printLine(`Deleted dataset ${sanitizeTerminalText(deleted.id)}.`);
553
484
  }
554
485
  async function lockDataset() {
555
486
  const projectArg = getArg('--project');
@@ -563,20 +494,13 @@ async function lockDataset() {
563
494
  const selected = await selectDatasetInteractively(projectArg);
564
495
  datasetId = selected.datasetId;
565
496
  }
566
- const response = await authedFetch(`/api/cli/datasets/${encodeURIComponent(datasetId)}/lock`, {
567
- method: 'POST',
568
- headers: { 'Content-Type': 'application/json' },
569
- body: JSON.stringify(reason ? { reason } : {}),
570
- });
571
- if (!response.ok) {
572
- throw new Error(`Lock failed: ${await response.text()}`);
573
- }
574
- const data = await parseJsonResponse(response, 'Dataset lock');
497
+ const { lockDataset: requestLock } = await import('./dataset-lock-workflow.js');
498
+ const dataset = await requestLock(datasetId, reason);
575
499
  if (hasJsonFlag()) {
576
- printJson({ dataset: data.dataset });
500
+ printJson({ dataset });
577
501
  return;
578
502
  }
579
- printLine(`Locked dataset ${sanitizeTerminalText(data.dataset.name)} (${sanitizeTerminalText(data.dataset.id)}) at ${sanitizeTerminalText(data.dataset.lockedAt)}. Row count: ${data.dataset.rowCount}`);
503
+ printLine(`Locked dataset ${sanitizeTerminalText(dataset.name)} (${sanitizeTerminalText(dataset.id)}) at ${sanitizeTerminalText(dataset.lockedAt)}. Row count: ${dataset.rowCount}`);
580
504
  }
581
505
  async function cloneDataset() {
582
506
  const projectArg = getArg('--project');
@@ -615,20 +539,16 @@ async function downloadAnnotations() {
615
539
  if (!taskId) {
616
540
  taskId = await selectTaskIdInteractively();
617
541
  }
618
- const response = await authedFetch(`/api/cli/tasks/${taskId}/export?format=${format}`);
619
- if (!response.ok) {
620
- throw new Error(`Download failed: ${await response.text()}`);
621
- }
622
542
  const fallbackName = `${taskId}.${format}`;
623
543
  const filename = outPathArg
624
544
  ? expandHomePath(outPathArg)
625
545
  : fallbackName;
626
- const bytes = new Uint8Array(await response.arrayBuffer());
627
- writeFileSync(filename, bytes);
546
+ const { runTaskExportDownload } = await import('./task-export-workflow.js');
547
+ await runTaskExportDownload(taskId, format, filename);
628
548
  if (hasJsonFlag()) {
629
549
  printJson({ taskId, format, savedTo: filename });
630
550
  return;
631
551
  }
632
552
  printLine(`Saved ${format.toUpperCase()} export to ${sanitizeTerminalText(filename)}`);
633
553
  }
634
- export { uploadDataset, listDatasets, pushDataset, downloadDataset, appendDatasetRows, setDatasetReadme, createDatasetVersion, createDatasetSplitSet, editDatasetRows, deleteDatasetRows, deleteDataset, lockDataset, cloneDataset, downloadAnnotations, };
554
+ export { uploadDataset, listDatasets, pushDataset, downloadDataset, appendDatasetRows, setDatasetReadme, createDatasetVersion, createDatasetSplitSet, listDatasetSplitSets, showDatasetSplitSet, editDatasetRows, deleteDatasetRows, deleteDataset, lockDataset, cloneDataset, downloadAnnotations, };
@@ -0,0 +1,4 @@
1
+ export declare function deleteDataset(datasetId: string, project: string | null): Promise<{
2
+ id: string;
3
+ }>;
4
+ //# sourceMappingURL=dataset-delete-workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-delete-workflow.d.ts","sourceRoot":"","sources":["../src/dataset-delete-workflow.ts"],"names":[],"mappings":"AAmEA,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAItG"}